Browse Source

replace file system calls with IFileSystem when needed

Luke Pulverenti 11 năm trước cách đây
mục cha
commit
6c8d919298
80 tập tin đã thay đổi với 570 bổ sung302 xóa
  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>