Bladeren bron

replace file system calls with IFileSystem when needed

Luke Pulverenti 11 jaren geleden
bovenliggende
commit
6c8d919298
80 gewijzigde bestanden met toevoegingen van 570 en 302 verwijderingen
  1. 2 1
      MediaBrowser.Api/Library/LibraryHelpers.cs
  2. 2 1
      MediaBrowser.Api/Library/LibraryStructureService.cs
  3. 5 2
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  4. 4 3
      MediaBrowser.Api/Playback/Hls/AudioHlsService.cs
  5. 3 3
      MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
  6. 4 3
      MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
  7. 4 3
      MediaBrowser.Api/Playback/Progressive/AudioService.cs
  8. 4 3
      MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
  9. 4 2
      MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
  10. 4 3
      MediaBrowser.Api/Playback/Progressive/VideoService.cs
  11. 8 2
      MediaBrowser.Api/SystemService.cs
  12. 7 4
      MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs
  13. 17 6
      MediaBrowser.Common.Implementations/BaseApplicationHost.cs
  14. 5 3
      MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
  15. 55 4
      MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs
  16. 1 0
      MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
  17. 7 3
      MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
  18. 6 2
      MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs
  19. 26 1
      MediaBrowser.Common/IO/IFileSystem.cs
  20. 1 0
      MediaBrowser.Common/MediaBrowser.Common.csproj
  21. 3 2
      MediaBrowser.Controller/Entities/BaseItem.cs
  22. 1 1
      MediaBrowser.Controller/Entities/User.cs
  23. 2 1
      MediaBrowser.Controller/IO/FileData.cs
  24. 0 71
      MediaBrowser.Controller/IO/FileSystem.cs
  25. 0 2
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  26. 6 2
      MediaBrowser.Controller/MediaInfo/FFMpegManager.cs
  27. 5 4
      MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs
  28. 8 9
      MediaBrowser.Mono.userprefs
  29. 6 3
      MediaBrowser.Providers/FolderProviderFromXml.cs
  30. 7 4
      MediaBrowser.Providers/Games/GameProviderFromXml.cs
  31. 6 3
      MediaBrowser.Providers/Games/GameSystemProviderFromXml.cs
  32. 2 1
      MediaBrowser.Providers/ImagesByNameProvider.cs
  33. 6 3
      MediaBrowser.Providers/Movies/BoxSetProviderFromXml.cs
  34. 6 3
      MediaBrowser.Providers/Movies/FanArtMovieProvider.cs
  35. 6 3
      MediaBrowser.Providers/Movies/FanArtMovieUpdatesPrescanTask.cs
  36. 6 8
      MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs
  37. 5 2
      MediaBrowser.Providers/Movies/MovieDbProvider.cs
  38. 6 4
      MediaBrowser.Providers/Movies/MovieProviderFromXml.cs
  39. 6 3
      MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs
  40. 6 3
      MediaBrowser.Providers/Movies/PersonProviderFromXml.cs
  41. 6 3
      MediaBrowser.Providers/Movies/PersonUpdatesPreScanTask.cs
  42. 6 3
      MediaBrowser.Providers/Movies/TmdbPersonProvider.cs
  43. 6 3
      MediaBrowser.Providers/Music/ArtistProviderFromXml.cs
  44. 6 3
      MediaBrowser.Providers/Music/FanArtAlbumProvider.cs
  45. 5 7
      MediaBrowser.Providers/Music/FanArtArtistByNameProvider.cs
  46. 9 8
      MediaBrowser.Providers/Music/FanArtArtistProvider.cs
  47. 6 3
      MediaBrowser.Providers/Music/FanArtUpdatesPrescanTask.cs
  48. 2 1
      MediaBrowser.Providers/RefreshIntrosTask.cs
  49. 6 3
      MediaBrowser.Providers/TV/EpisodeProviderFromXml.cs
  50. 6 3
      MediaBrowser.Providers/TV/FanArtSeasonProvider.cs
  51. 6 3
      MediaBrowser.Providers/TV/FanArtTVProvider.cs
  52. 6 3
      MediaBrowser.Providers/TV/FanArtTvUpdatesPrescanTask.cs
  53. 6 3
      MediaBrowser.Providers/TV/RemoteEpisodeProvider.cs
  54. 6 3
      MediaBrowser.Providers/TV/RemoteSeasonProvider.cs
  55. 8 4
      MediaBrowser.Providers/TV/RemoteSeriesProvider.cs
  56. 6 3
      MediaBrowser.Providers/TV/SeasonProviderFromXml.cs
  57. 7 4
      MediaBrowser.Providers/TV/SeriesProviderFromXml.cs
  58. 5 2
      MediaBrowser.Providers/TV/TvdbPrescanTask.cs
  59. 7 3
      MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs
  60. 6 3
      MediaBrowser.Server.Implementations/Drawing/ImageHeader.cs
  61. 13 10
      MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs
  62. 6 2
      MediaBrowser.Server.Implementations/EntryPoints/Notifications/RemoteNotifications.cs
  63. 6 3
      MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs
  64. 15 2
      MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs
  65. 2 1
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  66. 1 0
      MediaBrowser.Server.Implementations/Library/ResolverHelper.cs
  67. 8 3
      MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs
  68. 6 4
      MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs
  69. 4 2
      MediaBrowser.Server.Implementations/Providers/ImageSaver.cs
  70. 5 3
      MediaBrowser.Server.Implementations/Providers/ProviderManager.cs
  71. 21 0
      MediaBrowser.Server.Mono/IO/FileSystemFactory.cs
  72. 2 0
      MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
  73. 33 0
      MediaBrowser.Server.Mono/Program.cs
  74. 13 12
      MediaBrowser.ServerApplication/ApplicationHost.cs
  75. 6 4
      MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs
  76. 2 1
      MediaBrowser.ServerApplication/IO/FileSystemFactory.cs
  77. 3 2
      MediaBrowser.ServerApplication/IO/NativeFileSystem.cs
  78. 0 1
      MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
  79. 6 3
      MediaBrowser.WebDashboard/Api/DashboardService.cs
  80. 35 0
      MediaBrowser.sln.GhostDoc.xml

+ 2 - 1
MediaBrowser.Api/Library/LibraryHelpers.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.IO;
 using System;

+ 2 - 1
MediaBrowser.Api/Library/LibraryStructureService.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller;
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Entities;

+ 5 - 2
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -59,6 +59,8 @@ namespace MediaBrowser.Api.Playback
         protected IMediaEncoder MediaEncoder { get; private set; }
         protected IDtoService DtoService { get; private set; }
 
+        protected IFileSystem FileSystem { get; private set; }
+        
         /// <summary>
         /// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
         /// </summary>
@@ -67,8 +69,9 @@ namespace MediaBrowser.Api.Playback
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="isoManager">The iso manager.</param>
         /// <param name="mediaEncoder">The media encoder.</param>
-        protected BaseStreamingService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService)
+        protected BaseStreamingService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem)
         {
+            FileSystem = fileSystem;
             DtoService = dtoService;
             ApplicationPaths = appPaths;
             UserManager = userManager;
@@ -653,7 +656,7 @@ namespace MediaBrowser.Api.Playback
             var logFilePath = Path.Combine(ApplicationPaths.LogDirectoryPath, "ffmpeg-" + Guid.NewGuid() + ".txt");
 
             // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
-            state.LogFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous);
+            state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
 
             process.Exited += (sender, args) => OnFfMpegProcessExited(process, state);
 

+ 4 - 3
MediaBrowser.Api/Playback/Hls/AudioHlsService.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.MediaInfo;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Library;
@@ -32,8 +33,8 @@ namespace MediaBrowser.Api.Playback.Hls
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="isoManager">The iso manager.</param>
         /// <param name="mediaEncoder">The media encoder.</param>
-        public AudioHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService)
-            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService)
+        public AudioHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem)
+            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem)
         {
         }
 

+ 3 - 3
MediaBrowser.Api/Playback/Hls/BaseHlsService.cs

@@ -38,8 +38,8 @@ namespace MediaBrowser.Api.Playback.Hls
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="isoManager">The iso manager.</param>
         /// <param name="mediaEncoder">The media encoder.</param>
-        protected BaseHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService)
-            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService)
+        protected BaseHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem)
+            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem)
         {
         }
 
@@ -209,7 +209,7 @@ namespace MediaBrowser.Api.Playback.Hls
                 string fileText;
 
                 // Need to use FileShare.ReadWrite because we're reading the file at the same time it's being written
-                using (var fileStream = new FileStream(playlist, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+                using (var fileStream = FileSystem.GetFileStream(playlist, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
                 {
                     using (var reader = new StreamReader(fileStream))
                     {

+ 4 - 3
MediaBrowser.Api/Playback/Hls/VideoHlsService.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.MediaInfo;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Library;
@@ -39,8 +40,8 @@ namespace MediaBrowser.Api.Playback.Hls
         /// <param name="isoManager">The iso manager.</param>
         /// <param name="mediaEncoder">The media encoder.</param>
         /// <param name="dtoService">The dto service.</param>
-        public VideoHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService)
-            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService)
+        public VideoHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem)
+            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem)
         {
         }
 

+ 4 - 3
MediaBrowser.Api/Playback/Progressive/AudioService.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.MediaInfo;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Dto;
@@ -40,8 +41,8 @@ namespace MediaBrowser.Api.Playback.Progressive
     /// </summary>
     public class AudioService : BaseProgressiveStreamingService
     {
-        public AudioService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor)
-            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService, imageProcessor)
+        public AudioService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor, IFileSystem fileSystem)
+            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService, imageProcessor, fileSystem)
         {
         }
 

+ 4 - 3
MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Api.Images;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
@@ -27,8 +28,8 @@ namespace MediaBrowser.Api.Playback.Progressive
         protected readonly IItemRepository ItemRepository;
         protected readonly IImageProcessor ImageProcessor;
 
-        protected BaseProgressiveStreamingService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepository, IDtoService dtoService, IImageProcessor imageProcessor) :
-            base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService)
+        protected BaseProgressiveStreamingService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepository, IDtoService dtoService, IImageProcessor imageProcessor, IFileSystem fileSystem) :
+            base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem)
         {
             ItemRepository = itemRepository;
             ImageProcessor = imageProcessor;
@@ -346,7 +347,7 @@ namespace MediaBrowser.Api.Playback.Progressive
                 ApiEntryPoint.Instance.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive);
             }
 
-            var result = new ProgressiveStreamWriter(outputPath, Logger);
+            var result = new ProgressiveStreamWriter(outputPath, Logger, FileSystem);
 
             result.Options["Accept-Ranges"] = "none";
             result.Options["Content-Type"] = contentType;

+ 4 - 2
MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs

@@ -13,6 +13,7 @@ namespace MediaBrowser.Api.Playback.Progressive
     {
         private string Path { get; set; }
         private ILogger Logger { get; set; }
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// The _options
@@ -32,10 +33,11 @@ namespace MediaBrowser.Api.Playback.Progressive
         /// </summary>
         /// <param name="path">The path.</param>
         /// <param name="logger">The logger.</param>
-        public ProgressiveStreamWriter(string path, ILogger logger)
+        public ProgressiveStreamWriter(string path, ILogger logger, IFileSystem fileSystem)
         {
             Path = path;
             Logger = logger;
+            _fileSystem = fileSystem;
         }
 
         /// <summary>
@@ -83,7 +85,7 @@ namespace MediaBrowser.Api.Playback.Progressive
             var eofCount = 0;
             long position = 0;
 
-            using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+            using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
             {
                 while (eofCount < 15)
                 {

+ 4 - 3
MediaBrowser.Api/Playback/Progressive/VideoService.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.MediaInfo;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Dto;
@@ -54,8 +55,8 @@ namespace MediaBrowser.Api.Playback.Progressive
     /// </summary>
     public class VideoService : BaseProgressiveStreamingService
     {
-        public VideoService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor)
-            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService, imageProcessor)
+        public VideoService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor, IFileSystem fileSystem)
+            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService, imageProcessor, fileSystem)
         {
         }
 

+ 8 - 2
MediaBrowser.Api/SystemService.cs

@@ -1,6 +1,8 @@
 using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.System;
@@ -75,6 +77,9 @@ namespace MediaBrowser.Api
         /// </summary>
         private readonly IServerConfigurationManager _configurationManager;
 
+        private readonly IFileSystem _fileSystem;
+
+
         /// <summary>
         /// Initializes a new instance of the <see cref="SystemService" /> class.
         /// </summary>
@@ -82,7 +87,7 @@ namespace MediaBrowser.Api
         /// <param name="appHost">The app host.</param>
         /// <param name="configurationManager">The configuration manager.</param>
         /// <exception cref="System.ArgumentNullException">jsonSerializer</exception>
-        public SystemService(IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IServerConfigurationManager configurationManager)
+        public SystemService(IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
             : base()
         {
             if (jsonSerializer == null)
@@ -96,6 +101,7 @@ namespace MediaBrowser.Api
 
             _appHost = appHost;
             _configurationManager = configurationManager;
+            _fileSystem = fileSystem;
             _jsonSerializer = jsonSerializer;
         }
 
@@ -118,7 +124,7 @@ namespace MediaBrowser.Api
         /// <returns>System.Object.</returns>
         public object Get(GetConfiguration request)
         {
-            var dateModified = File.GetLastWriteTimeUtc(_configurationManager.ApplicationPaths.SystemConfigurationFilePath);
+            var dateModified = _fileSystem.GetLastWriteTimeUtc(_configurationManager.ApplicationPaths.SystemConfigurationFilePath);
 
             var cacheKey = (_configurationManager.ApplicationPaths.SystemConfigurationFilePath + dateModified.Ticks).GetMD5();
 

+ 7 - 4
MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Model.Logging;
 using System;
 using System.Collections.Generic;
@@ -27,16 +28,18 @@ namespace MediaBrowser.Api.WebSocket
         /// The _kernel
         /// </summary>
         private readonly ILogManager _logManager;
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="LogFileWebSocketListener" /> class.
         /// </summary>
         /// <param name="logger">The logger.</param>
         /// <param name="logManager">The log manager.</param>
-        public LogFileWebSocketListener(ILogger logger, ILogManager logManager)
+        public LogFileWebSocketListener(ILogger logger, ILogManager logManager, IFileSystem fileSystem)
             : base(logger)
         {
             _logManager = logManager;
+            _fileSystem = fileSystem;
             _logManager.LoggerLoaded += kernel_LoggerLoaded;
         }
 
@@ -53,7 +56,7 @@ namespace MediaBrowser.Api.WebSocket
                 state.StartLine = 0;
             }
 
-            var lines = await GetLogLines(state.LastLogFilePath, state.StartLine).ConfigureAwait(false);
+            var lines = await GetLogLines(state.LastLogFilePath, state.StartLine, _fileSystem).ConfigureAwait(false);
 
             state.StartLine += lines.Count;
 
@@ -96,11 +99,11 @@ namespace MediaBrowser.Api.WebSocket
         /// <param name="logFilePath">The log file path.</param>
         /// <param name="startLine">The start line.</param>
         /// <returns>Task{IEnumerable{System.String}}.</returns>
-        internal static async Task<List<string>> GetLogLines(string logFilePath, int startLine)
+        internal static async Task<List<string>> GetLogLines(string logFilePath, int startLine, IFileSystem fileSystem)
         {
             var lines = new List<string>();
 
-            using (var fs = new FileStream(logFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, StreamDefaults.DefaultFileStreamBufferSize, true))
+            using (var fs = fileSystem.GetFileStream(logFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
             {
                 using (var reader = new StreamReader(fs))
                 {

+ 17 - 6
MediaBrowser.Common.Implementations/BaseApplicationHost.cs

@@ -1,5 +1,4 @@
-using System.Net;
-using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Events;
 using MediaBrowser.Common.Implementations.Archiving;
 using MediaBrowser.Common.Implementations.IO;
@@ -7,6 +6,7 @@ using MediaBrowser.Common.Implementations.ScheduledTasks;
 using MediaBrowser.Common.Implementations.Security;
 using MediaBrowser.Common.Implementations.Serialization;
 using MediaBrowser.Common.Implementations.Updates;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Plugins;
 using MediaBrowser.Common.ScheduledTasks;
@@ -21,6 +21,7 @@ using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
+using System.Net;
 using System.Net.Http;
 using System.Reflection;
 using System.Threading;
@@ -150,15 +151,17 @@ namespace MediaBrowser.Common.Implementations
         /// Gets or sets the installation manager.
         /// </summary>
         /// <value>The installation manager.</value>
-        protected IInstallationManager InstallationManager { get; set; }
+        protected IInstallationManager InstallationManager { get; private set; }
 
+        protected IFileSystem FileSystemManager { get; private set; }
+        
         /// <summary>
         /// Gets or sets the zip client.
         /// </summary>
         /// <value>The zip client.</value>
-        protected IZipClient ZipClient { get; set; }
+        protected IZipClient ZipClient { get; private set; }
 
-        protected IIsoManager IsoManager { get; set; }
+        protected IIsoManager IsoManager { get; private set; }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="BaseApplicationHost{TApplicationPathsType}"/> class.
@@ -347,7 +350,10 @@ namespace MediaBrowser.Common.Implementations
 
                 RegisterSingleInstance(TaskManager);
 
-                HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, Logger, CreateHttpClient);
+                FileSystemManager = CreateFileSystemManager();
+                RegisterSingleInstance(FileSystemManager);
+
+                HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, Logger, CreateHttpClient, FileSystemManager);
                 RegisterSingleInstance(HttpClient);
 
                 NetworkManager = CreateNetworkManager();
@@ -367,6 +373,11 @@ namespace MediaBrowser.Common.Implementations
             });
         }
 
+        protected virtual IFileSystem CreateFileSystemManager()
+        {
+            return new CommonFileSystem(Logger, true);
+        }
+
         protected abstract HttpClient CreateHttpClient(bool enableHttpCompression);
 
         /// <summary>

+ 5 - 3
MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs

@@ -34,6 +34,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
         public delegate HttpClient GetHttpClientHandler(bool enableHttpCompression);
 
         private readonly GetHttpClientHandler _getHttpClientHandler;
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="HttpClientManager"/> class.
@@ -46,7 +47,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
         /// or
         /// logger
         /// </exception>
-        public HttpClientManager(IApplicationPaths appPaths, ILogger logger, GetHttpClientHandler getHttpClientHandler)
+        public HttpClientManager(IApplicationPaths appPaths, ILogger logger, GetHttpClientHandler getHttpClientHandler, IFileSystem fileSystem)
         {
             if (appPaths == null)
             {
@@ -59,6 +60,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
 
             _logger = logger;
             _getHttpClientHandler = getHttpClientHandler;
+            _fileSystem = fileSystem;
             _appPaths = appPaths;
         }
 
@@ -417,7 +419,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
                             // We're not able to track progress
                             using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
                             {
-                                using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+                                using (var fs = _fileSystem.GetFileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, true))
                                 {
                                     await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
                                 }
@@ -427,7 +429,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
                         {
                             using (var stream = ProgressStream.CreateReadProgressStream(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), options.Progress.Report, contentLength.Value))
                             {
-                                using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+                                using (var fs = _fileSystem.GetFileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, true))
                                 {
                                     await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
                                 }

+ 55 - 4
MediaBrowser.ServerApplication/IO/CommonFileSystem.cs → MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs

@@ -1,10 +1,10 @@
-using MediaBrowser.Controller.IO;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Model.Logging;
 using System;
 using System.IO;
 using System.Text;
 
-namespace MediaBrowser.ServerApplication.IO
+namespace MediaBrowser.Common.Implementations.IO
 {
     /// <summary>
     /// Class CommonFileSystem
@@ -13,9 +13,12 @@ namespace MediaBrowser.ServerApplication.IO
     {
         protected ILogger Logger;
 
-        public CommonFileSystem(ILogger logger)
+        private readonly bool _supportsAsyncFileStreams;
+
+        public CommonFileSystem(ILogger logger, bool supportsAsyncFileStreams)
         {
             Logger = logger;
+            _supportsAsyncFileStreams = supportsAsyncFileStreams;
         }
 
         /// <summary>
@@ -164,8 +167,56 @@ namespace MediaBrowser.ServerApplication.IO
                 return DateTime.MinValue;
             }
         }
-    }
 
+        /// <summary>
+        /// Gets the creation time UTC.
+        /// </summary>
+        /// <param name="info">The info.</param>
+        /// <param name="logger">The logger.</param>
+        /// <returns>DateTime.</returns>
+        public DateTime GetLastWriteTimeUtc(FileSystemInfo info)
+        {
+            // This could throw an error on some file systems that have dates out of range
+            try
+            {
+                return info.LastWriteTimeUtc;
+            }
+            catch (Exception ex)
+            {
+                Logger.ErrorException("Error determining LastAccessTimeUtc for {0}", ex, info.FullName);
+                return DateTime.MinValue;
+            }
+        }
+
+        /// <summary>
+        /// Gets the last write time UTC.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <returns>DateTime.</returns>
+        public DateTime GetLastWriteTimeUtc(string path)
+        {
+            return GetLastWriteTimeUtc(GetFileSystemInfo(path));
+        }
+
+        /// <summary>
+        /// Gets the file stream.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="mode">The mode.</param>
+        /// <param name="access">The access.</param>
+        /// <param name="share">The share.</param>
+        /// <param name="isAsync">if set to <c>true</c> [is asynchronous].</param>
+        /// <returns>FileStream.</returns>
+        public FileStream GetFileStream(string path, FileMode mode, FileAccess access, FileShare share, bool isAsync = false)
+        {
+            if (_supportsAsyncFileStreams && isAsync)
+            {
+                return new FileStream(path, mode, access, share, 4096, true);
+            }
+
+            return new FileStream(path, mode, access, share);
+        }
+    }
 
     /// <summary>
     ///  Adapted from http://stackoverflow.com/questions/309495/windows-shortcut-lnk-parser-in-java

+ 1 - 0
MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj

@@ -69,6 +69,7 @@
     <Compile Include="Configuration\BaseConfigurationManager.cs" />
     <Compile Include="HttpClientManager\HttpClientInfo.cs" />
     <Compile Include="HttpClientManager\HttpClientManager.cs" />
+    <Compile Include="IO\CommonFileSystem.cs" />
     <Compile Include="IO\IsoManager.cs" />
     <Compile Include="Logging\LogHelper.cs" />
     <Compile Include="Logging\NLogger.cs" />

+ 7 - 3
MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs

@@ -1,12 +1,13 @@
 using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Model.Logging;
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
-using MediaBrowser.Model.Logging;
 
 namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
 {
@@ -23,14 +24,17 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
 
         private readonly ILogger _logger;
 
+        private readonly IFileSystem _fileSystem;
+        
         /// <summary>
         /// Initializes a new instance of the <see cref="DeleteCacheFileTask" /> class.
         /// </summary>
         /// <param name="appPaths">The app paths.</param>
-        public DeleteCacheFileTask(IApplicationPaths appPaths, ILogger logger)
+        public DeleteCacheFileTask(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem)
         {
             ApplicationPaths = appPaths;
             _logger = logger;
+            _fileSystem = fileSystem;
         }
 
         /// <summary>
@@ -94,7 +98,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         private void DeleteCacheFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress<double> progress)
         {
             var filesToDelete = new DirectoryInfo(directory).EnumerateFiles("*", SearchOption.AllDirectories)
-                .Where(f => f.LastWriteTimeUtc < minDateModified)
+                .Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)
                 .ToList();
 
             var index = 0;

+ 6 - 2
MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Common.ScheduledTasks;
 using System;
 using System.Collections.Generic;
@@ -20,13 +21,16 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
         /// <value>The configuration manager.</value>
         private IConfigurationManager ConfigurationManager { get; set; }
 
+        private readonly IFileSystem _fileSystem;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="DeleteLogFileTask" /> class.
         /// </summary>
         /// <param name="configurationManager">The configuration manager.</param>
-        public DeleteLogFileTask(IConfigurationManager configurationManager)
+        public DeleteLogFileTask(IConfigurationManager configurationManager, IFileSystem fileSystem)
         {
             ConfigurationManager = configurationManager;
+            _fileSystem = fileSystem;
         }
 
         /// <summary>
@@ -58,7 +62,7 @@ namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks
             var minDateModified = DateTime.UtcNow.AddDays(-(ConfigurationManager.CommonConfiguration.LogFileRetentionDays));
 
             var filesToDelete = new DirectoryInfo(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath).EnumerateFileSystemInfos("*", SearchOption.AllDirectories)
-                          .Where(f => f.LastWriteTimeUtc < minDateModified)
+                          .Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)
                           .ToList();
 
             var index = 0;

+ 26 - 1
MediaBrowser.Controller/IO/IFileSystem.cs → MediaBrowser.Common/IO/IFileSystem.cs

@@ -1,7 +1,7 @@
 using System;
 using System.IO;
 
-namespace MediaBrowser.Controller.IO
+namespace MediaBrowser.Common.IO
 {
     /// <summary>
     /// Interface IFileSystem
@@ -49,5 +49,30 @@ namespace MediaBrowser.Controller.IO
         /// <param name="info">The info.</param>
         /// <returns>DateTime.</returns>
         DateTime GetCreationTimeUtc(FileSystemInfo info);
+
+        /// <summary>
+        /// Gets the last write time UTC.
+        /// </summary>
+        /// <param name="info">The information.</param>
+        /// <returns>DateTime.</returns>
+        DateTime GetLastWriteTimeUtc(FileSystemInfo info);
+
+        /// <summary>
+        /// Gets the last write time UTC.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <returns>DateTime.</returns>
+        DateTime GetLastWriteTimeUtc(string path);
+
+        /// <summary>
+        /// Gets the file stream.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="mode">The mode.</param>
+        /// <param name="access">The access.</param>
+        /// <param name="share">The share.</param>
+        /// <param name="isAsync">if set to <c>true</c> [is asynchronous].</param>
+        /// <returns>FileStream.</returns>
+        FileStream GetFileStream(string path, FileMode mode, FileAccess access, FileShare share, bool isAsync = false);
     }
 }

+ 1 - 0
MediaBrowser.Common/MediaBrowser.Common.csproj

@@ -60,6 +60,7 @@
     <Compile Include="Events\GenericEventArgs.cs" />
     <Compile Include="Extensions\ResourceNotFoundException.cs" />
     <Compile Include="IO\FileSystemRepository.cs" />
+    <Compile Include="IO\IFileSystem.cs" />
     <Compile Include="IO\ProgressStream.cs" />
     <Compile Include="IO\StreamDefaults.cs" />
     <Compile Include="MediaInfo\MediaInfoResult.cs" />

+ 3 - 2
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.IO;
@@ -1737,7 +1738,7 @@ namespace MediaBrowser.Controller.Entities
             if (locationType == LocationType.Remote ||
                 locationType == LocationType.Virtual)
             {
-                return File.GetLastWriteTimeUtc(imagePath);
+                return FileSystem.GetLastWriteTimeUtc(imagePath);
             }
 
             var metaFileEntry = ResolveArgs.GetMetaFileByPath(imagePath);
@@ -1754,7 +1755,7 @@ namespace MediaBrowser.Controller.Entities
             }
 
             // See if we can avoid a file system lookup by looking for the file in ResolveArgs
-            return metaFileEntry == null ? File.GetLastWriteTimeUtc(imagePath) : metaFileEntry.LastWriteTimeUtc;
+            return metaFileEntry == null ? FileSystem.GetLastWriteTimeUtc(imagePath) : FileSystem.GetLastWriteTimeUtc(metaFileEntry);
         }
     }
 }

+ 1 - 1
MediaBrowser.Controller/Entities/User.cs

@@ -165,7 +165,7 @@ namespace MediaBrowser.Controller.Entities
                 // Ensure it's been lazy loaded
                 var config = Configuration;
 
-                return File.GetLastWriteTimeUtc(ConfigurationFilePath);
+                return FileSystem.GetLastWriteTimeUtc(ConfigurationFilePath);
             }
         }
 

+ 2 - 1
MediaBrowser.Controller/IO/FileData.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Library;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Logging;
 using System;
 using System.Collections.Generic;

+ 0 - 71
MediaBrowser.Controller/IO/FileSystem.cs

@@ -1,71 +0,0 @@
-using MediaBrowser.Model.Logging;
-using System;
-using System.IO;
-
-namespace MediaBrowser.Controller.IO
-{
-    /// <summary>
-    /// Class FileSystem
-    /// </summary>
-    public static class FileSystem
-    {
-        /// <summary>
-        /// Gets the creation time UTC.
-        /// </summary>
-        /// <param name="info">The info.</param>
-        /// <param name="logger">The logger.</param>
-        /// <returns>DateTime.</returns>
-        public static DateTime GetLastWriteTimeUtc(FileSystemInfo info, ILogger logger)
-        {
-            // This could throw an error on some file systems that have dates out of range
-
-            try
-            {
-                return info.LastWriteTimeUtc;
-            }
-            catch (Exception ex)
-            {
-                logger.ErrorException("Error determining LastAccessTimeUtc for {0}", ex, info.FullName);
-                return DateTime.MinValue;
-            }
-        }
-
-        /// <summary>
-        /// Copies all.
-        /// </summary>
-        /// <param name="source">The source.</param>
-        /// <param name="target">The target.</param>
-        /// <exception cref="System.ArgumentNullException">source</exception>
-        /// <exception cref="System.ArgumentException">The source and target directories are the same</exception>
-        public static void CopyAll(string source, string target)
-        {
-            if (string.IsNullOrEmpty(source))
-            {
-                throw new ArgumentNullException("source");
-            }
-            if (string.IsNullOrEmpty(target))
-            {
-                throw new ArgumentNullException("target");
-            }
-
-            if (source.Equals(target, StringComparison.OrdinalIgnoreCase))
-            {
-                throw new ArgumentException("The source and target directories are the same");
-            }
-
-            // Check if the target directory exists, if not, create it. 
-            Directory.CreateDirectory(target);
-
-            foreach (var file in Directory.EnumerateFiles(source))
-            {
-                File.Copy(file, Path.Combine(target, Path.GetFileName(file)), true);
-            }
-
-            // Copy each subdirectory using recursion. 
-            foreach (var dir in Directory.EnumerateDirectories(source))
-            {
-                CopyAll(dir, Path.Combine(target, Path.GetFileName(dir)));
-            }
-        }
-    }
-}

+ 0 - 2
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -94,7 +94,6 @@
     <Compile Include="Entities\ImageSourceInfo.cs" />
     <Compile Include="Entities\LinkedChild.cs" />
     <Compile Include="Entities\MusicVideo.cs" />
-    <Compile Include="IO\IFileSystem.cs" />
     <Compile Include="Library\ILibraryPostScanTask.cs" />
     <Compile Include="Library\ILibraryPrescanTask.cs" />
     <Compile Include="Library\IMetadataSaver.cs" />
@@ -141,7 +140,6 @@
     <Compile Include="Entities\Video.cs" />
     <Compile Include="Entities\CollectionFolder.cs" />
     <Compile Include="Entities\Year.cs" />
-    <Compile Include="IO\FileSystem.cs" />
     <Compile Include="IO\IDirectoryWatchers.cs" />
     <Compile Include="IServerApplicationHost.cs" />
     <Compile Include="IServerApplicationPaths.cs" />

+ 6 - 2
MediaBrowser.Controller/MediaInfo/FFMpegManager.cs

@@ -1,6 +1,7 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
@@ -35,6 +36,8 @@ namespace MediaBrowser.Controller.MediaInfo
         private readonly ILogger _logger;
         private readonly IItemRepository _itemRepo;
 
+        private readonly IFileSystem _fileSystem;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="FFMpegManager" /> class.
         /// </summary>
@@ -43,12 +46,13 @@ namespace MediaBrowser.Controller.MediaInfo
         /// <param name="logger">The logger.</param>
         /// <param name="itemRepo">The item repo.</param>
         /// <exception cref="System.ArgumentNullException">zipClient</exception>
-        public FFMpegManager(IServerApplicationPaths appPaths, IMediaEncoder encoder, ILogger logger, IItemRepository itemRepo)
+        public FFMpegManager(IServerApplicationPaths appPaths, IMediaEncoder encoder, ILogger logger, IItemRepository itemRepo, IFileSystem fileSystem)
         {
             _appPaths = appPaths;
             _encoder = encoder;
             _logger = logger;
             _itemRepo = itemRepo;
+            _fileSystem = fileSystem;
 
             VideoImageCache = new FileSystemRepository(VideoImagesDataPath);
             SubtitleCache = new FileSystemRepository(SubtitleCachePath);
@@ -203,7 +207,7 @@ namespace MediaBrowser.Controller.MediaInfo
 
             if (stream.IsExternal)
             {
-                ticksParam += File.GetLastWriteTimeUtc(stream.Path).Ticks;
+                ticksParam += _fileSystem.GetLastWriteTimeUtc(stream.Path).Ticks;
             }
 
             return SubtitleCache.GetResourcePath(input.Id + "_" + subtitleStreamIndex + "_" + input.DateModified.Ticks + ticksParam, outputExtension);

+ 5 - 4
MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using System;
@@ -149,7 +150,7 @@ namespace MediaBrowser.Controller.Resolvers
                         item.DateCreated = fileSystem.GetCreationTimeUtc(childData);
                     }
 
-                    item.DateModified = childData.LastWriteTimeUtc;
+                    item.DateModified = fileSystem.GetLastWriteTimeUtc(childData);
                 }
                 else
                 {
@@ -161,7 +162,7 @@ namespace MediaBrowser.Controller.Resolvers
                         {
                             item.DateCreated = fileSystem.GetCreationTimeUtc(fileData);
                         }
-                        item.DateModified = fileData.LastWriteTimeUtc;
+                        item.DateModified = fileSystem.GetLastWriteTimeUtc(fileData);
                     }
                 }
             }
@@ -171,7 +172,7 @@ namespace MediaBrowser.Controller.Resolvers
                 {
                     item.DateCreated = fileSystem.GetCreationTimeUtc(args.FileInfo);
                 }
-                item.DateModified = args.FileInfo.LastWriteTimeUtc;
+                item.DateModified = fileSystem.GetLastWriteTimeUtc(args.FileInfo);
             }
         }
     }

+ 8 - 9
MediaBrowser.Mono.userprefs

@@ -1,25 +1,24 @@
 <Properties>
-  <MonoDevelop.Ide.Workspace ActiveConfiguration="Release|x86" />
+  <MonoDevelop.Ide.Workspace ActiveConfiguration="Debug|x86" />
   <MonoDevelop.Ide.Workbench ActiveDocument="MediaBrowser.Server.Mono\Program.cs">
     <Files>
-      <File FileName="MediaBrowser.Server.Mono\Program.cs" Line="60" Column="5" />
+      <File FileName="MediaBrowser.Server.Mono\Program.cs" Line="259" Column="4" />
+      <File FileName="MediaBrowser.ServerApplication\ApplicationHost.cs" Line="58" Column="12" />
+      <File FileName="MediaBrowser.Server.Mono\IO\FileSystemFactory.cs" Line="22" Column="1" />
     </Files>
     <Pads>
       <Pad Id="ProjectPad">
         <State expanded="True">
-          <Node name="MediaBrowser.Common.Implementations" expanded="True">
-            <Node name="HttpClientManager" expanded="True" />
-          </Node>
-          <Node name="MediaBrowser.Controller" expanded="True">
-            <Node name="Drawing" expanded="True" />
-          </Node>
+          <Node name="MediaBrowser.Common" expanded="True" />
+          <Node name="MediaBrowser.Common.Implementations" expanded="True" />
+          <Node name="MediaBrowser.Controller" expanded="True" />
           <Node name="MediaBrowser.Model" expanded="True">
             <Node name="References" expanded="True" />
             <Node name="Web" expanded="True" />
           </Node>
           <Node name="MediaBrowser.Server.Implementations" expanded="True" />
           <Node name="MediaBrowser.Server.Mono" expanded="True">
-            <Node name="FFMpeg" expanded="True" />
+            <Node name="IO" expanded="True" />
             <Node name="Program.cs" selected="True" />
           </Node>
         </State>

+ 6 - 3
MediaBrowser.Providers/FolderProviderFromXml.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Providers;
@@ -17,10 +18,12 @@ namespace MediaBrowser.Providers
     public class FolderProviderFromXml : BaseMetadataProvider
     {
         public static FolderProviderFromXml Current;
+        private readonly IFileSystem _fileSystem;
 
-        public FolderProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
+        public FolderProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
+            _fileSystem = fileSystem;
             Current = this;
         }
 
@@ -53,7 +56,7 @@ namespace MediaBrowser.Providers
                 return false;
             }
 
-            return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
+            return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
         }
 
         /// <summary>

+ 7 - 4
MediaBrowser.Providers/Games/GameProviderFromXml.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Providers;
@@ -13,15 +14,17 @@ namespace MediaBrowser.Providers.Games
 {
     public class GameProviderFromXml : BaseMetadataProvider
     {
+        private readonly IFileSystem _fileSystem;
+
         /// <summary>
         /// 
         /// </summary>
         /// <param name="logManager"></param>
         /// <param name="configurationManager"></param>
-        public GameProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
+        public GameProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
-
+            _fileSystem = fileSystem;
         }
 
         /// <summary>
@@ -45,7 +48,7 @@ namespace MediaBrowser.Providers.Games
                 return false;
             }
 
-            return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
+            return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
         }
 
         /// <summary>

+ 6 - 3
MediaBrowser.Providers/Games/GameSystemProviderFromXml.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Providers;
@@ -14,10 +15,12 @@ namespace MediaBrowser.Providers.Games
     public class GameSystemProviderFromXml : BaseMetadataProvider
     {
         internal static GameSystemProviderFromXml Current { get; private set; }
+        private readonly IFileSystem _fileSystem;
 
-        public GameSystemProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
+        public GameSystemProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
+            _fileSystem = fileSystem;
             Current = this;
         }
 
@@ -50,7 +53,7 @@ namespace MediaBrowser.Providers.Games
                 return false;
             }
 
-            return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
+            return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
         }
 
         /// <summary>

+ 2 - 1
MediaBrowser.Providers/ImagesByNameProvider.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.IO;
@@ -113,7 +114,7 @@ namespace MediaBrowser.Providers
 
             return files.Select(f =>
             {
-                var lastWriteTime = FileSystem.GetLastWriteTimeUtc(f, Logger);
+                var lastWriteTime = _fileSystem.GetLastWriteTimeUtc(f);
                 var creationTime = _fileSystem.GetCreationTimeUtc(f);
 
                 return creationTime > lastWriteTime ? creationTime : lastWriteTime;

+ 6 - 3
MediaBrowser.Providers/Movies/BoxSetProviderFromXml.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.IO;
@@ -18,10 +19,12 @@ namespace MediaBrowser.Providers.Movies
     public class BoxSetProviderFromXml : BaseMetadataProvider
     {
         public static BoxSetProviderFromXml Current;
+        private readonly IFileSystem _fileSystem;
 
-        public BoxSetProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
+        public BoxSetProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
+            _fileSystem = fileSystem;
             Current = this;
         }
 
@@ -54,7 +57,7 @@ namespace MediaBrowser.Providers.Movies
                 return false;
             }
 
-            return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
+            return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
         }
 
         /// <summary>

+ 6 - 3
MediaBrowser.Providers/Movies/FanArtMovieProvider.cs

@@ -4,6 +4,7 @@ using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
@@ -40,6 +41,7 @@ namespace MediaBrowser.Providers.Movies
         private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
 
         internal static FanArtMovieProvider Current { get; private set; }
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="FanArtMovieProvider" /> class.
@@ -49,7 +51,7 @@ namespace MediaBrowser.Providers.Movies
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="providerManager">The provider manager.</param>
         /// <exception cref="System.ArgumentNullException">httpClient</exception>
-        public FanArtMovieProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
+        public FanArtMovieProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             if (httpClient == null)
@@ -58,6 +60,7 @@ namespace MediaBrowser.Providers.Movies
             }
             HttpClient = httpClient;
             _providerManager = providerManager;
+            _fileSystem = fileSystem;
             Current = this;
         }
 
@@ -174,7 +177,7 @@ namespace MediaBrowser.Providers.Movies
                 {
                     var files = new DirectoryInfo(path)
                         .EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
-                        .Select(i => i.LastWriteTimeUtc)
+                        .Select(i => _fileSystem.GetLastWriteTimeUtc(i))
                         .ToList();
 
                     if (files.Count > 0)
@@ -275,7 +278,7 @@ namespace MediaBrowser.Providers.Movies
 
             }).ConfigureAwait(false))
             {
-                using (var xmlFileStream = new FileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+                using (var xmlFileStream = _fileSystem.GetFileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
                 {
                     await response.CopyToAsync(xmlFileStream).ConfigureAwait(false);
                 }

+ 6 - 3
MediaBrowser.Providers/Movies/FanArtMovieUpdatesPrescanTask.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Logging;
@@ -32,15 +33,17 @@ namespace MediaBrowser.Providers.Movies
         /// </summary>
         private readonly IServerConfigurationManager _config;
         private readonly IJsonSerializer _jsonSerializer;
+        private readonly IFileSystem _fileSystem;
 
         private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
 
-        public FanArtMovieUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient)
+        public FanArtMovieUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem)
         {
             _jsonSerializer = jsonSerializer;
             _config = config;
             _logger = logger;
             _httpClient = httpClient;
+            _fileSystem = fileSystem;
         }
 
         /// <summary>
@@ -66,7 +69,7 @@ namespace MediaBrowser.Providers.Movies
             var timestampFileInfo = new FileInfo(timestampFile);
 
             // Don't check for tvdb updates anymore frequently than 24 hours
-            if (timestampFileInfo.Exists && (DateTime.UtcNow - timestampFileInfo.LastWriteTimeUtc).TotalDays < 1)
+            if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 1)
             {
                 return;
             }

+ 6 - 8
MediaBrowser.Providers/Movies/MovieDbImagesProvider.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
@@ -21,11 +22,6 @@ namespace MediaBrowser.Providers.Movies
     /// </summary>
     public class MovieDbImagesProvider : BaseMetadataProvider
     {
-        /// <summary>
-        /// The get images
-        /// </summary>
-        private const string GetImages = @"http://api.themoviedb.org/3/{2}/{0}/images?api_key={1}";
-
         /// <summary>
         /// The _provider manager
         /// </summary>
@@ -35,6 +31,7 @@ namespace MediaBrowser.Providers.Movies
         /// The _json serializer
         /// </summary>
         private readonly IJsonSerializer _jsonSerializer;
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="MovieDbImagesProvider"/> class.
@@ -43,11 +40,12 @@ namespace MediaBrowser.Providers.Movies
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="providerManager">The provider manager.</param>
         /// <param name="jsonSerializer">The json serializer.</param>
-        public MovieDbImagesProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IJsonSerializer jsonSerializer)
+        public MovieDbImagesProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IJsonSerializer jsonSerializer, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             _providerManager = providerManager;
             _jsonSerializer = jsonSerializer;
+            _fileSystem = fileSystem;
         }
 
         /// <summary>
@@ -163,7 +161,7 @@ namespace MediaBrowser.Providers.Movies
 
                 if (fileInfo.Exists)
                 {
-                    return fileInfo.LastWriteTimeUtc > providerInfo.LastRefreshed;
+                    return _fileSystem.GetLastWriteTimeUtc(fileInfo) > providerInfo.LastRefreshed;
                 }
             }
 

+ 5 - 2
MediaBrowser.Providers/Movies/MovieDbProvider.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
@@ -47,6 +48,7 @@ namespace MediaBrowser.Providers.Movies
         /// </summary>
         /// <value>The HTTP client.</value>
         protected IHttpClient HttpClient { get; private set; }
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="MovieDbProvider" /> class.
@@ -56,12 +58,13 @@ namespace MediaBrowser.Providers.Movies
         /// <param name="jsonSerializer">The json serializer.</param>
         /// <param name="httpClient">The HTTP client.</param>
         /// <param name="providerManager">The provider manager.</param>
-        public MovieDbProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IHttpClient httpClient, IProviderManager providerManager)
+        public MovieDbProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IHttpClient httpClient, IProviderManager providerManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             JsonSerializer = jsonSerializer;
             HttpClient = httpClient;
             ProviderManager = providerManager;
+            _fileSystem = fileSystem;
             Current = this;
         }
 
@@ -216,7 +219,7 @@ namespace MediaBrowser.Providers.Movies
 
                 if (fileInfo.Exists)
                 {
-                    return fileInfo.LastWriteTimeUtc > providerInfo.LastRefreshed;
+                    return _fileSystem.GetLastWriteTimeUtc(fileInfo) > providerInfo.LastRefreshed;
                 }
 
                 return true;

+ 6 - 4
MediaBrowser.Providers/Movies/MovieProviderFromXml.cs

@@ -1,7 +1,7 @@
-using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
@@ -21,11 +21,13 @@ namespace MediaBrowser.Providers.Movies
     {
         internal static MovieProviderFromXml Current { get; private set; }
         private readonly IItemRepository _itemRepo;
+        private readonly IFileSystem _fileSystem;
 
-        public MovieProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IItemRepository itemRepo)
+        public MovieProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IItemRepository itemRepo, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             _itemRepo = itemRepo;
+            _fileSystem = fileSystem;
             Current = this;
         }
 
@@ -71,7 +73,7 @@ namespace MediaBrowser.Providers.Movies
                 return false;
             }
 
-            return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
+            return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
         }
 
         /// <summary>

+ 6 - 3
MediaBrowser.Providers/Movies/MovieUpdatesPrescanTask.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Progress;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Library;
@@ -35,6 +36,7 @@ namespace MediaBrowser.Providers.Movies
         /// </summary>
         private readonly IServerConfigurationManager _config;
         private readonly IJsonSerializer _json;
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="MovieUpdatesPreScanTask"/> class.
@@ -43,12 +45,13 @@ namespace MediaBrowser.Providers.Movies
         /// <param name="httpClient">The HTTP client.</param>
         /// <param name="config">The config.</param>
         /// <param name="json">The json.</param>
-        public MovieUpdatesPreScanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IJsonSerializer json)
+        public MovieUpdatesPreScanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IJsonSerializer json, IFileSystem fileSystem)
         {
             _logger = logger;
             _httpClient = httpClient;
             _config = config;
             _json = json;
+            _fileSystem = fileSystem;
         }
 
         protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
@@ -100,7 +103,7 @@ namespace MediaBrowser.Providers.Movies
             var refreshDays = _config.Configuration.EnableTmdbUpdates ? 1 : 7;
 
             // Don't check for tvdb updates anymore frequently than 24 hours
-            if (timestampFileInfo.Exists && (DateTime.UtcNow - timestampFileInfo.LastWriteTimeUtc).TotalDays < refreshDays)
+            if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < refreshDays)
             {
                 return;
             }

+ 6 - 3
MediaBrowser.Providers/Movies/PersonProviderFromXml.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Providers;
@@ -13,10 +14,12 @@ namespace MediaBrowser.Providers.Movies
     class PersonProviderFromXml : BaseMetadataProvider
     {
         internal static PersonProviderFromXml Current { get; private set; }
+        private readonly IFileSystem _fileSystem;
 
-        public PersonProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
+        public PersonProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
+            _fileSystem = fileSystem;
             Current = this;
         }
 
@@ -49,7 +52,7 @@ namespace MediaBrowser.Providers.Movies
                 return false;
             }
 
-            return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
+            return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
         }
 
         /// <summary>

+ 6 - 3
MediaBrowser.Providers/Movies/PersonUpdatesPreScanTask.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Logging;
@@ -34,6 +35,7 @@ namespace MediaBrowser.Providers.Movies
         /// </summary>
         private readonly IServerConfigurationManager _config;
         private readonly IJsonSerializer _json;
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="PersonUpdatesPreScanTask"/> class.
@@ -41,12 +43,13 @@ namespace MediaBrowser.Providers.Movies
         /// <param name="logger">The logger.</param>
         /// <param name="httpClient">The HTTP client.</param>
         /// <param name="config">The config.</param>
-        public PersonUpdatesPreScanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IJsonSerializer json)
+        public PersonUpdatesPreScanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IJsonSerializer json, IFileSystem fileSystem)
         {
             _logger = logger;
             _httpClient = httpClient;
             _config = config;
             _json = json;
+            _fileSystem = fileSystem;
         }
 
         protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
@@ -74,7 +77,7 @@ namespace MediaBrowser.Providers.Movies
             var timestampFileInfo = new FileInfo(timestampFile);
 
             // Don't check for tvdb updates anymore frequently than 24 hours
-            if (timestampFileInfo.Exists && (DateTime.UtcNow - timestampFileInfo.LastWriteTimeUtc).TotalDays < 1)
+            if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 1)
             {
                 return;
             }

+ 6 - 3
MediaBrowser.Providers/Movies/TmdbPersonProvider.cs

@@ -4,6 +4,7 @@ using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
@@ -30,8 +31,9 @@ namespace MediaBrowser.Providers.Movies
         internal static TmdbPersonProvider Current { get; private set; }
 
         const string DataFileName = "info.json";
+        private readonly IFileSystem _fileSystem;
 
-        public TmdbPersonProvider(IJsonSerializer jsonSerializer, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
+        public TmdbPersonProvider(IJsonSerializer jsonSerializer, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             if (jsonSerializer == null)
@@ -40,6 +42,7 @@ namespace MediaBrowser.Providers.Movies
             }
             JsonSerializer = jsonSerializer;
             ProviderManager = providerManager;
+            _fileSystem = fileSystem;
             Current = this;
         }
 
@@ -105,7 +108,7 @@ namespace MediaBrowser.Providers.Movies
 
                 if (fileInfo.Exists)
                 {
-                    return fileInfo.LastWriteTimeUtc > providerInfo.LastRefreshed;
+                    return _fileSystem.GetLastWriteTimeUtc(fileInfo) > providerInfo.LastRefreshed;
                 }
 
                 return true;
@@ -270,7 +273,7 @@ namespace MediaBrowser.Providers.Movies
             {
                 Directory.CreateDirectory(personDataPath);
 
-                using (var fs = new FileStream(Path.Combine(personDataPath, DataFileName), FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
+                using (var fs = _fileSystem.GetFileStream(Path.Combine(personDataPath, DataFileName), FileMode.Create, FileAccess.Write, FileShare.Read, true))
                 {
                     await json.CopyToAsync(fs).ConfigureAwait(false);
                 }

+ 6 - 3
MediaBrowser.Providers/Music/ArtistProviderFromXml.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.IO;
@@ -15,10 +16,12 @@ namespace MediaBrowser.Providers.Music
     class ArtistProviderFromXml : BaseMetadataProvider
     {
         public static ArtistProviderFromXml Current;
+        private readonly IFileSystem _fileSystem;
 
-        public ArtistProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
+        public ArtistProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
+            _fileSystem = fileSystem;
             Current = this;
         }
 
@@ -51,7 +54,7 @@ namespace MediaBrowser.Providers.Music
                 return false;
             }
 
-            return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
+            return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
         }
 
         /// <summary>

+ 6 - 3
MediaBrowser.Providers/Music/FanArtAlbumProvider.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
@@ -37,6 +38,7 @@ namespace MediaBrowser.Providers.Music
         protected IHttpClient HttpClient { get; private set; }
 
         internal static FanArtAlbumProvider Current { get; private set; }
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="FanArtAlbumProvider"/> class.
@@ -45,10 +47,11 @@ namespace MediaBrowser.Providers.Music
         /// <param name="logManager">The log manager.</param>
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="providerManager">The provider manager.</param>
-        public FanArtAlbumProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
+        public FanArtAlbumProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             _providerManager = providerManager;
+            _fileSystem = fileSystem;
             HttpClient = httpClient;
 
             Current = this;
@@ -140,7 +143,7 @@ namespace MediaBrowser.Providers.Music
 
                 if (file.Exists)
                 {
-                    return file.LastWriteTimeUtc;
+                    return _fileSystem.GetLastWriteTimeUtc(file);
                 }
             } 
             

+ 5 - 7
MediaBrowser.Providers/Music/FanArtArtistByNameProvider.cs

@@ -1,7 +1,9 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Logging;
 
@@ -15,12 +17,8 @@ namespace MediaBrowser.Providers.Music
         /// <summary>
         /// Initializes a new instance of the <see cref="FanArtArtistByNameProvider" /> class.
         /// </summary>
-        /// <param name="httpClient">The HTTP client.</param>
-        /// <param name="logManager">The log manager.</param>
-        /// <param name="configurationManager">The configuration manager.</param>
-        /// <param name="providerManager">The provider manager.</param>
-        public FanArtArtistByNameProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
-            : base(httpClient, logManager, configurationManager, providerManager)
+        public FanArtArtistByNameProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
+            : base(httpClient, logManager, configurationManager, providerManager, fileSystem)
         {
         }
 

+ 9 - 8
MediaBrowser.Providers/Music/FanArtArtistProvider.cs

@@ -1,24 +1,23 @@
-using System.Net;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Net;
 using System;
-using System.Collections.Generic;
 using System.Globalization;
 using System.IO;
 using System.Linq;
+using System.Net;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Xml;
-using MediaBrowser.Model.Net;
 
 namespace MediaBrowser.Providers.Music
 {
@@ -39,6 +38,7 @@ namespace MediaBrowser.Providers.Music
         private readonly IProviderManager _providerManager;
 
         internal static FanArtArtistProvider Current;
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="FanArtArtistProvider"/> class.
@@ -48,7 +48,7 @@ namespace MediaBrowser.Providers.Music
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="providerManager">The provider manager.</param>
         /// <exception cref="System.ArgumentNullException">httpClient</exception>
-        public FanArtArtistProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
+        public FanArtArtistProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             if (httpClient == null)
@@ -57,6 +57,7 @@ namespace MediaBrowser.Providers.Music
             }
             HttpClient = httpClient;
             _providerManager = providerManager;
+            _fileSystem = fileSystem;
 
             Current = this;
         }
@@ -167,7 +168,7 @@ namespace MediaBrowser.Providers.Music
                 {
                     var files = new DirectoryInfo(path)
                         .EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
-                        .Select(i => i.LastWriteTimeUtc)
+                        .Select(i => _fileSystem.GetLastWriteTimeUtc(i))
                         .ToList();
 
                     if (files.Count > 0)
@@ -284,7 +285,7 @@ namespace MediaBrowser.Providers.Music
 
             }).ConfigureAwait(false))
             {
-                using (var xmlFileStream = new FileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+                using (var xmlFileStream = _fileSystem.GetFileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
                 {
                     await response.CopyToAsync(xmlFileStream).ConfigureAwait(false);
                 }

+ 6 - 3
MediaBrowser.Providers/Music/FanArtUpdatesPrescanTask.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Logging;
@@ -31,15 +32,17 @@ namespace MediaBrowser.Providers.Music
         /// </summary>
         private readonly IServerConfigurationManager _config;
         private readonly IJsonSerializer _jsonSerializer;
+        private readonly IFileSystem _fileSystem;
 
         private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
 
-        public FanArtUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient)
+        public FanArtUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem)
         {
             _jsonSerializer = jsonSerializer;
             _config = config;
             _logger = logger;
             _httpClient = httpClient;
+            _fileSystem = fileSystem;
         }
 
         /// <summary>
@@ -65,7 +68,7 @@ namespace MediaBrowser.Providers.Music
             var timestampFileInfo = new FileInfo(timestampFile);
 
             // Don't check for tvdb updates anymore frequently than 24 hours
-            if (timestampFileInfo.Exists && (DateTime.UtcNow - timestampFileInfo.LastWriteTimeUtc).TotalDays < 1)
+            if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 1)
             {
                 return;
             }

+ 2 - 1
MediaBrowser.Providers/RefreshIntrosTask.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.IO;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Logging;
 using System;

+ 6 - 3
MediaBrowser.Providers/TV/EpisodeProviderFromXml.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.IO;
@@ -20,11 +21,13 @@ namespace MediaBrowser.Providers.TV
     {
         internal static EpisodeProviderFromXml Current { get; private set; }
         private readonly IItemRepository _itemRepo;
+        private readonly IFileSystem _fileSystem;
 
-        public EpisodeProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IItemRepository itemRepo)
+        public EpisodeProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IItemRepository itemRepo, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             _itemRepo = itemRepo;
+            _fileSystem = fileSystem;
             Current = this;
         }
 
@@ -76,7 +79,7 @@ namespace MediaBrowser.Providers.TV
                 return false;
             }
 
-            return FileSystem.GetLastWriteTimeUtc(file, Logger) > providerInfo.LastRefreshed;
+            return _fileSystem.GetLastWriteTimeUtc(file) > providerInfo.LastRefreshed;
         }
 
         /// <summary>

+ 6 - 3
MediaBrowser.Providers/TV/FanArtSeasonProvider.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
@@ -22,6 +23,7 @@ namespace MediaBrowser.Providers.TV
         /// The _provider manager
         /// </summary>
         private readonly IProviderManager _providerManager;
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="FanArtSeasonProvider"/> class.
@@ -29,10 +31,11 @@ namespace MediaBrowser.Providers.TV
         /// <param name="logManager">The log manager.</param>
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="providerManager">The provider manager.</param>
-        public FanArtSeasonProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
+        public FanArtSeasonProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             _providerManager = providerManager;
+            _fileSystem = fileSystem;
         }
 
         public override ItemUpdateType ItemUpdateType
@@ -76,7 +79,7 @@ namespace MediaBrowser.Providers.TV
 
                 if (imagesFileInfo.Exists)
                 {
-                    return imagesFileInfo.LastWriteTimeUtc;
+                    return _fileSystem.GetLastWriteTimeUtc(imagesFileInfo);
                 }
             }
 

+ 6 - 3
MediaBrowser.Providers/TV/FanArtTVProvider.cs

@@ -4,6 +4,7 @@ using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
@@ -31,8 +32,9 @@ namespace MediaBrowser.Providers.TV
         protected IHttpClient HttpClient { get; private set; }
 
         private readonly IProviderManager _providerManager;
+        private readonly IFileSystem _fileSystem;
 
-        public FanArtTvProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
+        public FanArtTvProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             if (httpClient == null)
@@ -41,6 +43,7 @@ namespace MediaBrowser.Providers.TV
             }
             HttpClient = httpClient;
             _providerManager = providerManager;
+            _fileSystem = fileSystem;
             Current = this;
         }
 
@@ -115,7 +118,7 @@ namespace MediaBrowser.Providers.TV
                 {
                     var files = new DirectoryInfo(path)
                         .EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
-                        .Select(i => i.LastWriteTimeUtc)
+                        .Select(i => _fileSystem.GetLastWriteTimeUtc(i))
                         .ToList();
 
                     if (files.Count > 0)
@@ -353,7 +356,7 @@ namespace MediaBrowser.Providers.TV
 
             }).ConfigureAwait(false))
             {
-                using (var xmlFileStream = new FileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+                using (var xmlFileStream = _fileSystem.GetFileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
                 {
                     await response.CopyToAsync(xmlFileStream).ConfigureAwait(false);
                 }

+ 6 - 3
MediaBrowser.Providers/TV/FanArtTvUpdatesPrescanTask.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Logging;
@@ -32,15 +33,17 @@ namespace MediaBrowser.Providers.TV
         /// </summary>
         private readonly IServerConfigurationManager _config;
         private readonly IJsonSerializer _jsonSerializer;
+        private readonly IFileSystem _fileSystem;
 
         private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
 
-        public FanArtTvUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient)
+        public FanArtTvUpdatesPrescanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem)
         {
             _jsonSerializer = jsonSerializer;
             _config = config;
             _logger = logger;
             _httpClient = httpClient;
+            _fileSystem = fileSystem;
         }
 
         /// <summary>
@@ -66,7 +69,7 @@ namespace MediaBrowser.Providers.TV
             var timestampFileInfo = new FileInfo(timestampFile);
 
             // Don't check for tvdb updates anymore frequently than 24 hours
-            if (timestampFileInfo.Exists && (DateTime.UtcNow - timestampFileInfo.LastWriteTimeUtc).TotalDays < 1)
+            if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 1)
             {
                 return;
             }

+ 6 - 3
MediaBrowser.Providers/TV/RemoteEpisodeProvider.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
@@ -36,6 +37,7 @@ namespace MediaBrowser.Providers.TV
         /// </summary>
         /// <value>The HTTP client.</value>
         protected IHttpClient HttpClient { get; private set; }
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="RemoteEpisodeProvider" /> class.
@@ -44,11 +46,12 @@ namespace MediaBrowser.Providers.TV
         /// <param name="logManager">The log manager.</param>
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="providerManager">The provider manager.</param>
-        public RemoteEpisodeProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
+        public RemoteEpisodeProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             HttpClient = httpClient;
             _providerManager = providerManager;
+            _fileSystem = fileSystem;
         }
 
         /// <summary>
@@ -149,7 +152,7 @@ namespace MediaBrowser.Providers.TV
 
                 if (files.Count > 0)
                 {
-                    return files.Select(i => i.LastWriteTimeUtc).Max() > providerInfo.LastRefreshed;
+                    return files.Select(i => _fileSystem.GetLastWriteTimeUtc(i)).Max() > providerInfo.LastRefreshed;
                 }
             }
             

+ 6 - 3
MediaBrowser.Providers/TV/RemoteSeasonProvider.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
@@ -23,6 +24,7 @@ namespace MediaBrowser.Providers.TV
         /// The _provider manager
         /// </summary>
         private readonly IProviderManager _providerManager;
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="RemoteSeasonProvider"/> class.
@@ -31,10 +33,11 @@ namespace MediaBrowser.Providers.TV
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="providerManager">The provider manager.</param>
         /// <exception cref="System.ArgumentNullException">httpClient</exception>
-        public RemoteSeasonProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
+        public RemoteSeasonProvider(ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             _providerManager = providerManager;
+            _fileSystem = fileSystem;
         }
 
         /// <summary>
@@ -115,7 +118,7 @@ namespace MediaBrowser.Providers.TV
 
                 if (imagesFileInfo.Exists)
                 {
-                    return imagesFileInfo.LastWriteTimeUtc > providerInfo.LastRefreshed;
+                    return _fileSystem.GetLastWriteTimeUtc(imagesFileInfo) > providerInfo.LastRefreshed;
                 }
             }
             return false;

+ 8 - 4
MediaBrowser.Providers/TV/RemoteSeriesProvider.cs

@@ -4,6 +4,7 @@ using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
@@ -49,6 +50,8 @@ namespace MediaBrowser.Providers.TV
         /// <value>The HTTP client.</value>
         protected IHttpClient HttpClient { get; private set; }
 
+        private readonly IFileSystem _fileSystem;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="RemoteSeriesProvider" /> class.
         /// </summary>
@@ -57,7 +60,7 @@ namespace MediaBrowser.Providers.TV
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="zipClient">The zip client.</param>
         /// <exception cref="System.ArgumentNullException">httpClient</exception>
-        public RemoteSeriesProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IZipClient zipClient)
+        public RemoteSeriesProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IZipClient zipClient, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             if (httpClient == null)
@@ -66,6 +69,7 @@ namespace MediaBrowser.Providers.TV
             }
             HttpClient = httpClient;
             _zipClient = zipClient;
+            _fileSystem = fileSystem;
             Current = this;
         }
 
@@ -176,7 +180,7 @@ namespace MediaBrowser.Providers.TV
                 {
                     var files = new DirectoryInfo(path)
                         .EnumerateFiles("*.xml", SearchOption.TopDirectoryOnly)
-                        .Select(i => i.LastWriteTimeUtc)
+                        .Select(i => _fileSystem.GetLastWriteTimeUtc(i))
                         .ToList();
 
                     if (files.Count > 0)
@@ -344,7 +348,7 @@ namespace MediaBrowser.Providers.TV
         {
             string validXml;
 
-            using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
+            using (var fileStream = _fileSystem.GetFileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, true))
             {
                 using (var reader = new StreamReader(fileStream))
                 {
@@ -354,7 +358,7 @@ namespace MediaBrowser.Providers.TV
                 }
             }
 
-            using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
+            using (var fileStream = _fileSystem.GetFileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read, true))
             {
                 using (var writer = new StreamWriter(fileStream))
                 {

+ 6 - 3
MediaBrowser.Providers/TV/SeasonProviderFromXml.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.IO;
@@ -18,10 +19,12 @@ namespace MediaBrowser.Providers.TV
     public class SeasonProviderFromXml : BaseMetadataProvider
     {
         public static SeasonProviderFromXml Current;
+        private readonly IFileSystem _fileSystem;
 
-        public SeasonProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
+        public SeasonProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
+            _fileSystem = fileSystem;
             Current = this;
         }
 
@@ -54,7 +57,7 @@ namespace MediaBrowser.Providers.TV
                 return false;
             }
 
-            return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
+            return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
         }
 
         /// <summary>

+ 7 - 4
MediaBrowser.Providers/TV/SeriesProviderFromXml.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.IO;
@@ -18,10 +19,12 @@ namespace MediaBrowser.Providers.TV
     public class SeriesProviderFromXml : BaseMetadataProvider
     {
         internal static SeriesProviderFromXml Current { get; private set; }
-        
-        public SeriesProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
+        private readonly IFileSystem _fileSystem;
+
+        public SeriesProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
+            _fileSystem = fileSystem;
             Current = this;
         }
 
@@ -54,7 +57,7 @@ namespace MediaBrowser.Providers.TV
                 return false;
             }
 
-            return FileSystem.GetLastWriteTimeUtc(xml, Logger) > providerInfo.LastRefreshed;
+            return _fileSystem.GetLastWriteTimeUtc(xml) > providerInfo.LastRefreshed;
         }
 
         /// <summary>

+ 5 - 2
MediaBrowser.Providers/TV/TvdbPrescanTask.cs

@@ -1,4 +1,5 @@
 using System.Globalization;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Library;
@@ -42,6 +43,7 @@ namespace MediaBrowser.Providers.TV
         /// The _config
         /// </summary>
         private readonly IServerConfigurationManager _config;
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="TvdbPrescanTask"/> class.
@@ -49,11 +51,12 @@ namespace MediaBrowser.Providers.TV
         /// <param name="logger">The logger.</param>
         /// <param name="httpClient">The HTTP client.</param>
         /// <param name="config">The config.</param>
-        public TvdbPrescanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config)
+        public TvdbPrescanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IFileSystem fileSystem)
         {
             _logger = logger;
             _httpClient = httpClient;
             _config = config;
+            _fileSystem = fileSystem;
         }
 
         protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
@@ -81,7 +84,7 @@ namespace MediaBrowser.Providers.TV
             var timestampFileInfo = new FileInfo(timestampFile);
 
             // Don't check for tvdb updates anymore frequently than 24 hours
-            if (timestampFileInfo.Exists && (DateTime.UtcNow - timestampFileInfo.LastWriteTimeUtc).TotalDays < 1)
+            if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 1)
             {
                 return;
             }

+ 7 - 3
MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs

@@ -1,7 +1,9 @@
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
@@ -30,6 +32,7 @@ namespace MediaBrowser.Providers.TV
         /// The _provider manager
         /// </summary>
         private readonly IProviderManager _providerManager;
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="TvdbSeriesImageProvider"/> class.
@@ -39,7 +42,7 @@ namespace MediaBrowser.Providers.TV
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="providerManager">The provider manager.</param>
         /// <exception cref="System.ArgumentNullException">httpClient</exception>
-        public TvdbSeriesImageProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager)
+        public TvdbSeriesImageProvider(IHttpClient httpClient, ILogManager logManager, IServerConfigurationManager configurationManager, IProviderManager providerManager, IFileSystem fileSystem)
             : base(logManager, configurationManager)
         {
             if (httpClient == null)
@@ -48,6 +51,7 @@ namespace MediaBrowser.Providers.TV
             }
             HttpClient = httpClient;
             _providerManager = providerManager;
+            _fileSystem = fileSystem;
         }
 
         /// <summary>
@@ -127,7 +131,7 @@ namespace MediaBrowser.Providers.TV
 
                 if (imagesFileInfo.Exists)
                 {
-                    return imagesFileInfo.LastWriteTimeUtc;
+                    return _fileSystem.GetLastWriteTimeUtc(imagesFileInfo);
                 }
             }
 

+ 6 - 3
MediaBrowser.Server.Implementations/Drawing/ImageHeader.cs

@@ -1,4 +1,6 @@
-using MediaBrowser.Model.Logging;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.IO;
+using MediaBrowser.Model.Logging;
 using System;
 using System.Collections.Generic;
 using System.Drawing;
@@ -40,9 +42,10 @@ namespace MediaBrowser.Server.Implementations.Drawing
         /// </summary>
         /// <param name="path">The path of the image to get the dimensions of.</param>
         /// <param name="logger">The logger.</param>
+        /// <param name="fileSystem">The file system.</param>
         /// <returns>The dimensions of the specified image.</returns>
         /// <exception cref="ArgumentException">The image was of an unrecognised format.</exception>
-        public static Size GetDimensions(string path, ILogger logger)
+        public static Size GetDimensions(string path, ILogger logger, IFileSystem fileSystem)
         {
             try
             {
@@ -60,7 +63,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
             }
 
             // Buffer to memory stream to avoid image locking file
-            using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
+            using (var fs = fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
             {
                 using (var memoryStream = new MemoryStream())
                 {

+ 13 - 10
MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs

@@ -3,6 +3,7 @@ using MediaBrowser.Common.IO;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Entities;
@@ -51,16 +52,18 @@ namespace MediaBrowser.Server.Implementations.Drawing
         /// The _app paths
         /// </summary>
         private readonly IServerApplicationPaths _appPaths;
+        private readonly IFileSystem _fileSystem;
 
         private readonly string _imageSizeCachePath;
         private readonly string _croppedWhitespaceImageCachePath;
         private readonly string _enhancedImageCachePath;
         private readonly string _resizedImageCachePath;
 
-        public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths)
+        public ImageProcessor(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem)
         {
             _logger = logger;
             _appPaths = appPaths;
+            _fileSystem = fileSystem;
 
             _imageSizeCachePath = Path.Combine(_appPaths.ImageCachePath, "image-sizes");
             _croppedWhitespaceImageCachePath = Path.Combine(_appPaths.ImageCachePath, "cropped-images");
@@ -113,7 +116,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
 
             try
             {
-                using (var fileStream = new FileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+                using (var fileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
                 {
                     await fileStream.CopyToAsync(toStream).ConfigureAwait(false);
                     return;
@@ -131,7 +134,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
             // Check again in case of lock contention
             try
             {
-                using (var fileStream = new FileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+                using (var fileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
                 {
                     await fileStream.CopyToAsync(toStream).ConfigureAwait(false);
                     semaphore.Release();
@@ -150,7 +153,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
 
             try
             {
-                using (var fileStream = new FileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
+                using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
                 {
                     // Copy to memory stream to avoid Image locking file
                     using (var memoryStream = new MemoryStream())
@@ -228,7 +231,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
                     Directory.CreateDirectory(parentPath);
 
                     // Save to the cache location
-                    using (var cacheFileStream = new FileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+                    using (var cacheFileStream = _fileSystem.GetFileStream(cacheFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
                     {
                         // Save to the filestream
                         await cacheFileStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
@@ -359,7 +362,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
 
             try
             {
-                using (var fileStream = new FileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
+                using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
                 {
                     // Copy to memory stream to avoid Image locking file
                     using (var memoryStream = new MemoryStream())
@@ -376,7 +379,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
 
                                 Directory.CreateDirectory(parentPath);
 
-                                using (var outputStream = new FileStream(croppedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read))
+                                using (var outputStream = _fileSystem.GetFileStream(croppedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read, false))
                                 {
                                     croppedImage.Save(outputFormat, outputStream, 100);
                                 }
@@ -525,7 +528,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
                     // Cache file doesn't exist no biggie
                 }
 
-                var size = ImageHeader.GetDimensions(path, _logger);
+                var size = ImageHeader.GetDimensions(path, _logger, _fileSystem);
 
                 var parentPath = Path.GetDirectoryName(fullCachePath);
 
@@ -685,7 +688,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
 
             try
             {
-                using (var fileStream = new FileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, true))
+                using (var fileStream = _fileSystem.GetFileStream(originalImagePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
                 {
                     // Copy to memory stream to avoid Image locking file
                     using (var memoryStream = new MemoryStream())
@@ -702,7 +705,7 @@ namespace MediaBrowser.Server.Implementations.Drawing
                                 Directory.CreateDirectory(parentDirectory);
 
                                 //And then save it in the cache
-                                using (var outputStream = new FileStream(enhancedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read))
+                                using (var outputStream = _fileSystem.GetFileStream(enhancedImagePath, FileMode.Create, FileAccess.Write, FileShare.Read, false))
                                 {
                                     newImage.Save(ImageFormat.Png, outputStream, 100);
                                 }

+ 6 - 2
MediaBrowser.Server.Implementations/EntryPoints/Notifications/RemoteNotifications.cs

@@ -1,5 +1,7 @@
 using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Notifications;
 using MediaBrowser.Controller.Plugins;
@@ -26,11 +28,12 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
         private readonly IJsonSerializer _json;
         private readonly INotificationsRepository _notificationsRepo;
         private readonly IUserManager _userManager;
+        private readonly IFileSystem _fileSystem;
 
         private readonly TimeSpan _frequency = TimeSpan.FromHours(6);
         private readonly TimeSpan _maxAge = TimeSpan.FromDays(31);
 
-        public RemoteNotifications(IApplicationPaths appPaths, ILogger logger, IHttpClient httpClient, IJsonSerializer json, INotificationsRepository notificationsRepo, IUserManager userManager)
+        public RemoteNotifications(IApplicationPaths appPaths, ILogger logger, IHttpClient httpClient, IJsonSerializer json, INotificationsRepository notificationsRepo, IUserManager userManager, IFileSystem fileSystem)
         {
             _appPaths = appPaths;
             _logger = logger;
@@ -38,6 +41,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
             _json = json;
             _notificationsRepo = notificationsRepo;
             _userManager = userManager;
+            _fileSystem = fileSystem;
         }
 
         /// <summary>
@@ -56,7 +60,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications
         {
             var dataPath = Path.Combine(_appPaths.DataPath, "remotenotifications.json");
 
-            var lastRunTime = File.Exists(dataPath) ? File.GetLastWriteTimeUtc(dataPath) : DateTime.MinValue;
+            var lastRunTime = File.Exists(dataPath) ? _fileSystem.GetLastWriteTimeUtc(dataPath) : DateTime.MinValue;
 
             try
             {

+ 6 - 3
MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs

@@ -1,6 +1,7 @@
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Model.Logging;
 using ServiceStack.Common;
 using ServiceStack.Common.Web;
@@ -25,13 +26,15 @@ namespace MediaBrowser.Server.Implementations.HttpServer
         /// The _logger
         /// </summary>
         private readonly ILogger _logger;
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="HttpResultFactory"/> class.
         /// </summary>
         /// <param name="logManager">The log manager.</param>
-        public HttpResultFactory(ILogManager logManager)
+        public HttpResultFactory(ILogManager logManager, IFileSystem fileSystem)
         {
+            _fileSystem = fileSystem;
             _logger = logManager.GetLogger("HttpResultFactory");
         }
 
@@ -288,7 +291,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
                 throw new ArgumentException("FileShare must be either Read or ReadWrite");
             }
 
-            var dateModified = File.GetLastWriteTimeUtc(path);
+            var dateModified = _fileSystem.GetLastWriteTimeUtc(path);
 
             var cacheKey = path + dateModified.Ticks;
 
@@ -303,7 +306,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
         /// <returns>Stream.</returns>
         private Stream GetFileStream(string path, FileShare fileShare)
         {
-            return new FileStream(path, FileMode.Open, FileAccess.Read, fileShare, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous);
+            return _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, fileShare, true);
         }
 
         /// <summary>

+ 15 - 2
MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.IO;
@@ -321,6 +322,18 @@ namespace MediaBrowser.Server.Implementations.IO
         /// <param name="sender">The source of the event.</param>
         /// <param name="e">The <see cref="FileSystemEventArgs" /> instance containing the event data.</param>
         void watcher_Changed(object sender, FileSystemEventArgs e)
+        {
+            try
+            {
+                OnWatcherChanged(e);
+            }
+            catch (IOException ex)
+            {
+                Logger.ErrorException("IOException in watcher changed", ex);
+            }
+        }
+
+        private void OnWatcherChanged(FileSystemEventArgs e)
         {
             var name = e.Name;
 
@@ -437,7 +450,7 @@ namespace MediaBrowser.Server.Implementations.IO
 
             try
             {
-                using (new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
+                using (_fileSystem.GetFileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
                 {
                     //file is not locked
                     return false;

+ 2 - 1
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Progress;
 using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Controller.Configuration;
@@ -772,7 +773,7 @@ namespace MediaBrowser.Server.Implementations.Library
                     Name = name,
                     Id = id,
                     DateCreated = _fileSystem.GetCreationTimeUtc(fileInfo),
-                    DateModified = fileInfo.LastWriteTimeUtc,
+                    DateModified = _fileSystem.GetLastWriteTimeUtc(fileInfo),
                     Path = path
                 };
                 isNew = true;

+ 1 - 0
MediaBrowser.Server.Implementations/Library/ResolverHelper.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;

+ 8 - 3
MediaBrowser.Server.Implementations/Localization/LocalizationManager.cs

@@ -1,4 +1,6 @@
-using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Localization;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Globalization;
@@ -30,13 +32,16 @@ namespace MediaBrowser.Server.Implementations.Localization
         private readonly ConcurrentDictionary<string, Dictionary<string, ParentalRating>> _allParentalRatings =
             new ConcurrentDictionary<string, Dictionary<string, ParentalRating>>(StringComparer.OrdinalIgnoreCase);
 
+        private readonly IFileSystem _fileSystem;
+        
         /// <summary>
         /// Initializes a new instance of the <see cref="LocalizationManager"/> class.
         /// </summary>
         /// <param name="configurationManager">The configuration manager.</param>
-        public LocalizationManager(IServerConfigurationManager configurationManager)
+        public LocalizationManager(IServerConfigurationManager configurationManager, IFileSystem fileSystem)
         {
             _configurationManager = configurationManager;
+            _fileSystem = fileSystem;
 
             ExtractAll();
         }
@@ -65,7 +70,7 @@ namespace MediaBrowser.Server.Implementations.Localization
                 {
                     using (var stream = type.Assembly.GetManifestResourceStream(resource))
                     {
-                        using (var fs = new FileStream(Path.Combine(localizationPath, filename), FileMode.Create, FileAccess.Write, FileShare.Read))
+                        using (var fs = _fileSystem.GetFileStream(Path.Combine(localizationPath, filename), FileMode.Create, FileAccess.Write, FileShare.Read))
                         {
                             stream.CopyTo(fs);
                         }

+ 6 - 4
MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs

@@ -1,6 +1,7 @@
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.MediaInfo;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Serialization;
@@ -53,6 +54,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
         /// The FF probe resource pool
         /// </summary>
         private readonly SemaphoreSlim _ffProbeResourcePool = new SemaphoreSlim(1, 1);
+        private readonly IFileSystem _fileSystem;
 
         public string FFMpegPath { get; private set; }
 
@@ -61,12 +63,13 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
         public string Version { get; private set; }
 
         public MediaEncoder(ILogger logger, IApplicationPaths appPaths,
-                            IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, string version)
+                            IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, string version, IFileSystem fileSystem)
         {
             _logger = logger;
             _appPaths = appPaths;
             _jsonSerializer = jsonSerializer;
             Version = version;
+            _fileSystem = fileSystem;
             FFProbePath = ffProbePath;
             FFMpegPath = ffMpegPath;
         }
@@ -458,8 +461,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
 
             var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-sub-convert-" + Guid.NewGuid() + ".txt");
 
-            var logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read,
-                                               StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous);
+            var logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
 
             try
             {
@@ -685,7 +687,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
 
             var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-sub-extract-" + Guid.NewGuid() + ".txt");
 
-            var logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous);
+            var logFileStream = _fileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
 
             try
             {

+ 4 - 2
MediaBrowser.Server.Implementations/Providers/ImageSaver.cs

@@ -35,16 +35,18 @@ namespace MediaBrowser.Server.Implementations.Providers
         /// The _directory watchers
         /// </summary>
         private readonly IDirectoryWatchers _directoryWatchers;
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="ImageSaver"/> class.
         /// </summary>
         /// <param name="config">The config.</param>
         /// <param name="directoryWatchers">The directory watchers.</param>
-        public ImageSaver(IServerConfigurationManager config, IDirectoryWatchers directoryWatchers)
+        public ImageSaver(IServerConfigurationManager config, IDirectoryWatchers directoryWatchers, IFileSystem fileSystem)
         {
             _config = config;
             _directoryWatchers = directoryWatchers;
+            _fileSystem = fileSystem;
             _remoteImageCache = new FileSystemRepository(config.ApplicationPaths.DownloadedImagesDataPath);
         }
 
@@ -176,7 +178,7 @@ namespace MediaBrowser.Server.Implementations.Providers
                     }
                 }
 
-                using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+                using (var fs = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true))
                 {
                     await source.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false);
                 }

+ 5 - 3
MediaBrowser.Server.Implementations/Providers/ProviderManager.cs

@@ -50,6 +50,7 @@ namespace MediaBrowser.Server.Implementations.Providers
         private BaseMetadataProvider[] MetadataProviders { get; set; }
 
         private IImageProvider[] ImageProviders { get; set; }
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="ProviderManager" /> class.
@@ -58,12 +59,13 @@ namespace MediaBrowser.Server.Implementations.Providers
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="directoryWatchers">The directory watchers.</param>
         /// <param name="logManager">The log manager.</param>
-        public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, IDirectoryWatchers directoryWatchers, ILogManager logManager)
+        public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, IDirectoryWatchers directoryWatchers, ILogManager logManager, IFileSystem fileSystem)
         {
             _logger = logManager.GetLogger("ProviderManager");
             _httpClient = httpClient;
             ConfigurationManager = configurationManager;
             _directoryWatchers = directoryWatchers;
+            _fileSystem = fileSystem;
         }
 
         /// <summary>
@@ -293,7 +295,7 @@ namespace MediaBrowser.Server.Implementations.Providers
             {
                 using (dataToSave)
                 {
-                    using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
+                    using (var fs = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true))
                     {
                         await dataToSave.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false);
                     }
@@ -347,7 +349,7 @@ namespace MediaBrowser.Server.Implementations.Providers
         /// <returns>Task.</returns>
         public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, string sourceUrl, CancellationToken cancellationToken)
         {
-            return new ImageSaver(ConfigurationManager, _directoryWatchers).SaveImage(item, source, mimeType, type, imageIndex, sourceUrl, cancellationToken);
+            return new ImageSaver(ConfigurationManager, _directoryWatchers, _fileSystem).SaveImage(item, source, mimeType, type, imageIndex, sourceUrl, cancellationToken);
         }
 
         /// <summary>

+ 21 - 0
MediaBrowser.Server.Mono/IO/FileSystemFactory.cs

@@ -0,0 +1,21 @@
+using MediaBrowser.Common.IO;
+using MediaBrowser.Model.Logging;
+using MediaBrowser.Common.Implementations.IO;
+
+namespace MediaBrowser.ServerApplication.IO
+{
+	/// <summary>
+	/// Class FileSystemFactory
+	/// </summary>
+	public static class FileSystemFactory
+	{
+		/// <summary>
+		/// Creates the file system manager.
+		/// </summary>
+		/// <returns>IFileSystem.</returns>
+		public static IFileSystem CreateFileSystemManager(ILogManager logManager)
+		{
+			return new CommonFileSystem(logManager.GetLogger("FileSystem"), false);
+		}
+	}
+}

+ 2 - 0
MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj

@@ -88,6 +88,7 @@
       <Link>FFMpeg\FFMpegDownloader.cs</Link>
     </Compile>
     <Compile Include="FFMpeg\FFMpegDownloadInfo.cs" />
+    <Compile Include="IO\FileSystemFactory.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
@@ -129,6 +130,7 @@
     <Folder Include="Native\" />
     <Folder Include="FFMpeg\" />
     <Folder Include="Networking\" />
+    <Folder Include="IO\" />
   </ItemGroup>
   <ItemGroup>
     <None Include="app.config" />

+ 33 - 0
MediaBrowser.Server.Mono/Program.cs

@@ -17,6 +17,7 @@ using System.Security.Cryptography.X509Certificates;
 using Gtk;
 using Gdk;
 using System.Threading.Tasks;
+using System.Reflection;
 
 namespace MediaBrowser.Server.Mono
 {
@@ -203,6 +204,8 @@ namespace MediaBrowser.Server.Mono
 
 			logger.Info("Server: {0}", Environment.MachineName);
 			logger.Info("Operating system: {0}", Environment.OSVersion.ToString());
+
+			MonoBug11817WorkAround.Apply ();
 		}
 
 		/// <summary>
@@ -280,4 +283,34 @@ namespace MediaBrowser.Server.Mono
 			return true;
 		}
 	}
+
+	public class MonoBug11817WorkAround
+	{
+		public static void Apply()
+		{
+			var property = typeof(TimeZoneInfo).GetProperty("TimeZoneDirectory", BindingFlags.Static | BindingFlags.NonPublic);
+
+			if (property == null) return;
+
+			var zoneInfo = FindZoneInfoFolder();
+			property.SetValue(null, zoneInfo, new object[0]);
+		}
+
+		public static string FindZoneInfoFolder()
+		{
+			var current = new DirectoryInfo(Directory.GetCurrentDirectory());
+
+			while(current != null)
+			{
+				var zoneinfoTestPath = Path.Combine(current.FullName, "zoneinfo");
+
+				if (Directory.Exists(zoneinfoTestPath))
+					return zoneinfoTestPath;
+
+				current = current.Parent;
+			}
+
+			return null;
+		}
+	}
 }

+ 13 - 12
MediaBrowser.ServerApplication/ApplicationHost.cs

@@ -5,6 +5,7 @@ using MediaBrowser.Common.Constants;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Implementations;
 using MediaBrowser.Common.Implementations.ScheduledTasks;
+using MediaBrowser.Common.IO;
 using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
@@ -170,8 +171,6 @@ namespace MediaBrowser.ServerApplication
 
         private Task<IHttpServer> _httpServerCreationTask;
 
-        private IFileSystem FileSystemManager { get; set; }
-        
         /// <summary>
         /// Initializes a new instance of the <see cref="ApplicationHost"/> class.
         /// </summary>
@@ -237,7 +236,7 @@ namespace MediaBrowser.ServerApplication
 
             await base.RegisterResources().ConfigureAwait(false);
 
-            RegisterSingleInstance<IHttpResultFactory>(new HttpResultFactory(LogManager));
+            RegisterSingleInstance<IHttpResultFactory>(new HttpResultFactory(LogManager, FileSystemManager));
 
             RegisterSingleInstance<IServerApplicationHost>(this);
             RegisterSingleInstance<IServerApplicationPaths>(ApplicationPaths);
@@ -249,9 +248,6 @@ namespace MediaBrowser.ServerApplication
 
             RegisterSingleInstance<IBlurayExaminer>(() => new BdInfoExaminer());
 
-            FileSystemManager = FileSystemFactory.CreateFileSystemManager(LogManager);
-            RegisterSingleInstance(FileSystemManager);
-
             var mediaEncoderTask = RegisterMediaEncoder();
 
             UserDataManager = new UserDataManager(LogManager);
@@ -275,7 +271,7 @@ namespace MediaBrowser.ServerApplication
             DirectoryWatchers = new DirectoryWatchers(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager);
             RegisterSingleInstance(DirectoryWatchers);
 
-            ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, DirectoryWatchers, LogManager);
+            ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, DirectoryWatchers, LogManager, FileSystemManager);
             RegisterSingleInstance(ProviderManager);
 
             RegisterSingleInstance<ILibrarySearchEngine>(() => new LuceneSearchEngine(ApplicationPaths, LogManager, LibraryManager));
@@ -289,10 +285,10 @@ namespace MediaBrowser.ServerApplication
             ServerManager = new ServerManager(this, JsonSerializer, Logger, ServerConfigurationManager);
             RegisterSingleInstance(ServerManager);
 
-            LocalizationManager = new LocalizationManager(ServerConfigurationManager);
+            LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager);
             RegisterSingleInstance(LocalizationManager);
 
-            ImageProcessor = new ImageProcessor(Logger, ServerConfigurationManager.ApplicationPaths);
+            ImageProcessor = new ImageProcessor(Logger, ServerConfigurationManager.ApplicationPaths, FileSystemManager);
             RegisterSingleInstance(ImageProcessor);
 
             DtoService = new DtoService(Logger, LibraryManager, UserManager, UserDataManager, ItemRepository, ImageProcessor);
@@ -317,15 +313,20 @@ namespace MediaBrowser.ServerApplication
             return new NetworkManager();
         }
 
+        protected override IFileSystem CreateFileSystemManager()
+        {
+            return FileSystemFactory.CreateFileSystemManager(LogManager);
+        }
+
         /// <summary>
         /// Registers the media encoder.
         /// </summary>
         /// <returns>Task.</returns>
         private async Task RegisterMediaEncoder()
         {
-            var info = await new FFMpegDownloader(Logger, ApplicationPaths, HttpClient, ZipClient).GetFFMpegInfo().ConfigureAwait(false);
+            var info = await new FFMpegDownloader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager).GetFFMpegInfo().ConfigureAwait(false);
 
-            MediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"), ApplicationPaths, JsonSerializer, info.Path, info.ProbePath, info.Version);
+            MediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"), ApplicationPaths, JsonSerializer, info.Path, info.ProbePath, info.Version, FileSystemManager);
             RegisterSingleInstance(MediaEncoder);
         }
 
@@ -335,7 +336,7 @@ namespace MediaBrowser.ServerApplication
         private void SetKernelProperties()
         {
             Parallel.Invoke(
-                 () => ServerKernel.FFMpegManager = new FFMpegManager(ApplicationPaths, MediaEncoder, Logger, ItemRepository),
+                 () => ServerKernel.FFMpegManager = new FFMpegManager(ApplicationPaths, MediaEncoder, Logger, ItemRepository, FileSystemManager),
                  () => LocalizedStrings.StringFiles = GetExports<LocalizedStringData>(),
                  SetStaticProperties
                  );

+ 6 - 4
MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloader.cs

@@ -1,6 +1,7 @@
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Net;
@@ -20,18 +21,20 @@ namespace MediaBrowser.ServerApplication.FFMpeg
         private readonly IApplicationPaths _appPaths;
         private readonly ILogger _logger;
         private readonly IZipClient _zipClient;
+        private readonly IFileSystem _fileSystem;
 
         private readonly string[] _fontUrls = new[]
             {
                 "https://www.dropbox.com/s/pj847twf7riq0j7/ARIALUNI.7z?dl=1"
             };
 
-        public FFMpegDownloader(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IZipClient zipClient)
+        public FFMpegDownloader(ILogger logger, IApplicationPaths appPaths, IHttpClient httpClient, IZipClient zipClient, IFileSystem fileSystem)
         {
             _logger = logger;
             _appPaths = appPaths;
             _httpClient = httpClient;
             _zipClient = zipClient;
+            _fileSystem = fileSystem;
         }
 
         public async Task<FFMpegInfo> GetFFMpegInfo()
@@ -272,9 +275,8 @@ namespace MediaBrowser.ServerApplication.FFMpeg
 
                 var bytes = Encoding.UTF8.GetBytes(contents);
 
-                using (var fileStream = new FileStream(fontConfigFile, FileMode.Create, FileAccess.Write,
-                                                    FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize,
-                                                    FileOptions.Asynchronous))
+                using (var fileStream = _fileSystem.GetFileStream(fontConfigFile, FileMode.Create, FileAccess.Write,
+                                                    FileShare.Read, true))
                 {
                     await fileStream.WriteAsync(bytes, 0, bytes.Length);
                 }

+ 2 - 1
MediaBrowser.ServerApplication/IO/FileSystemFactory.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.IO;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Model.Logging;
 
 namespace MediaBrowser.ServerApplication.IO

+ 3 - 2
MediaBrowser.ServerApplication/IO/NativeFileSystem.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Model.Logging;
+using MediaBrowser.Common.Implementations.IO;
+using MediaBrowser.Model.Logging;
 using System;
 using System.IO;
 using System.Runtime.InteropServices;
@@ -10,7 +11,7 @@ namespace MediaBrowser.ServerApplication.IO
     public class NativeFileSystem : CommonFileSystem
     {
         public NativeFileSystem(ILogger logger)
-            : base(logger)
+            : base(logger, true)
         {
         }
 

+ 0 - 1
MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj

@@ -190,7 +190,6 @@
     <Compile Include="FFMpeg\FFMpegInfo.cs" />
     <Compile Include="IO\FileSystemFactory.cs" />
     <Compile Include="Native\Assemblies.cs" />
-    <Compile Include="IO\CommonFileSystem.cs" />
     <Compile Include="Native\HttpClientFactory.cs" />
     <Compile Include="Native\NativeApp.cs" />
     <Compile Include="IO\NativeFileSystem.cs" />

+ 6 - 3
MediaBrowser.WebDashboard/Api/DashboardService.cs

@@ -5,6 +5,7 @@ using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Logging;
@@ -118,6 +119,7 @@ namespace MediaBrowser.WebDashboard.Api
 
         private readonly ISessionManager _sessionManager;
         private readonly IDtoService _dtoService;
+        private readonly IFileSystem _fileSystem;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="DashboardService" /> class.
@@ -126,13 +128,14 @@ namespace MediaBrowser.WebDashboard.Api
         /// <param name="appHost">The app host.</param>
         /// <param name="serverConfigurationManager">The server configuration manager.</param>
         /// <param name="sessionManager">The session manager.</param>
-        public DashboardService(ITaskManager taskManager, IServerApplicationHost appHost, IServerConfigurationManager serverConfigurationManager, ISessionManager sessionManager, IDtoService dtoService)
+        public DashboardService(ITaskManager taskManager, IServerApplicationHost appHost, IServerConfigurationManager serverConfigurationManager, ISessionManager sessionManager, IDtoService dtoService, IFileSystem fileSystem)
         {
             _taskManager = taskManager;
             _appHost = appHost;
             _serverConfigurationManager = serverConfigurationManager;
             _sessionManager = sessionManager;
             _dtoService = dtoService;
+            _fileSystem = fileSystem;
         }
 
         /// <summary>
@@ -324,7 +327,7 @@ namespace MediaBrowser.WebDashboard.Api
         /// <returns>Task{Stream}.</returns>
         private Stream GetRawResourceStream(string path)
         {
-            return new FileStream(GetDashboardResourcePath(path), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, StreamDefaults.DefaultFileStreamBufferSize, true);
+            return _fileSystem.GetFileStream(GetDashboardResourcePath(path), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true);
         }
 
         /// <summary>
@@ -611,7 +614,7 @@ namespace MediaBrowser.WebDashboard.Api
         {
             path = GetDashboardResourcePath(path);
 
-            using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, StreamDefaults.DefaultFileStreamBufferSize, true))
+            using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
             {
                 using (var streamReader = new StreamReader(fs))
                 {

+ 35 - 0
MediaBrowser.sln.GhostDoc.xml

@@ -0,0 +1,35 @@
+<GhostDoc>
+  <SpellChecker>
+    <IncludeExtensions>
+    </IncludeExtensions>
+    <IgnoreExtensions>
+    </IgnoreExtensions>
+    <IgnoreFiles>
+    </IgnoreFiles>
+  </SpellChecker>
+<HelpConfigurations selected="HelpFile">
+  <HelpConfiguration name="HelpFile">
+    <OutputPath>D:\Development\MediaBrowser\Help</OutputPath>
+    <ImageFolderPath />
+    <HtmlFormats>
+      <HtmlHelp>true</HtmlHelp>
+      <MSHelpViewer>false</MSHelpViewer>
+      <MSHelp2>false</MSHelp2>
+      <Website>false</Website>
+    </HtmlFormats>
+    <IncludeScopes>
+      <Public>true</Public>
+      <Internal>false</Internal>
+      <Protected>false</Protected>
+      <Private>false</Private>
+      <Inherited>true</Inherited>
+      <EnableTags>false</EnableTags>
+      <TagList />
+    </IncludeScopes>
+    <ResolveCrefLinks>true</ResolveCrefLinks>
+    <HeaderText />
+    <FooterText />
+    <SelectedProjects />
+  </HelpConfiguration>
+</HelpConfigurations>
+</GhostDoc>