Browse Source

Created ILibraryMonitor to replace IDirectoryWatchers

Luke Pulverenti 11 years ago
parent
commit
7c5b222463

+ 13 - 24
MediaBrowser.Api/Library/LibraryStructureService.cs

@@ -187,7 +187,7 @@ namespace MediaBrowser.Api.Library
         /// </summary>
         /// </summary>
         private readonly ILibraryManager _libraryManager;
         private readonly ILibraryManager _libraryManager;
 
 
-        private readonly IDirectoryWatchers _directoryWatchers;
+        private readonly ILibraryMonitor _libraryMonitor;
 
 
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
         private readonly ILogger _logger;
         private readonly ILogger _logger;
@@ -199,7 +199,7 @@ namespace MediaBrowser.Api.Library
         /// <param name="userManager">The user manager.</param>
         /// <param name="userManager">The user manager.</param>
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="libraryManager">The library manager.</param>
         /// <exception cref="System.ArgumentNullException">appPaths</exception>
         /// <exception cref="System.ArgumentNullException">appPaths</exception>
-        public LibraryStructureService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IDirectoryWatchers directoryWatchers, IFileSystem fileSystem, ILogger logger)
+        public LibraryStructureService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IFileSystem fileSystem, ILogger logger)
         {
         {
             if (appPaths == null)
             if (appPaths == null)
             {
             {
@@ -209,7 +209,7 @@ namespace MediaBrowser.Api.Library
             _userManager = userManager;
             _userManager = userManager;
             _appPaths = appPaths;
             _appPaths = appPaths;
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
-            _directoryWatchers = directoryWatchers;
+            _libraryMonitor = libraryMonitor;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
             _logger = logger;
             _logger = logger;
         }
         }
@@ -270,8 +270,7 @@ namespace MediaBrowser.Api.Library
                 throw new ArgumentException("There is already a media collection with the name " + name + ".");
                 throw new ArgumentException("There is already a media collection with the name " + name + ".");
             }
             }
 
 
-            _directoryWatchers.Stop();
-            _directoryWatchers.TemporarilyIgnore(virtualFolderPath);
+            _libraryMonitor.Stop();
 
 
             try
             try
             {
             {
@@ -294,10 +293,8 @@ namespace MediaBrowser.Api.Library
                 // No need to start if scanning the library because it will handle it
                 // No need to start if scanning the library because it will handle it
                 if (!request.RefreshLibrary)
                 if (!request.RefreshLibrary)
                 {
                 {
-                    _directoryWatchers.Start();
+                    _libraryMonitor.Start();
                 }
                 }
-
-                _directoryWatchers.RemoveTempIgnore(virtualFolderPath);
             }
             }
 
 
             if (request.RefreshLibrary)
             if (request.RefreshLibrary)
@@ -348,9 +345,7 @@ namespace MediaBrowser.Api.Library
                 throw new ArgumentException("There is already a media collection with the name " + newPath + ".");
                 throw new ArgumentException("There is already a media collection with the name " + newPath + ".");
             }
             }
 
 
-            _directoryWatchers.Stop();
-            _directoryWatchers.TemporarilyIgnore(currentPath);
-            _directoryWatchers.TemporarilyIgnore(newPath);
+            _libraryMonitor.Stop();
 
 
             try
             try
             {
             {
@@ -376,11 +371,8 @@ namespace MediaBrowser.Api.Library
                 // No need to start if scanning the library because it will handle it
                 // No need to start if scanning the library because it will handle it
                 if (!request.RefreshLibrary)
                 if (!request.RefreshLibrary)
                 {
                 {
-                    _directoryWatchers.Start();
+                    _libraryMonitor.Start();
                 }
                 }
-
-                _directoryWatchers.RemoveTempIgnore(currentPath);
-                _directoryWatchers.RemoveTempIgnore(newPath);
             }
             }
 
 
             if (request.RefreshLibrary)
             if (request.RefreshLibrary)
@@ -420,8 +412,7 @@ namespace MediaBrowser.Api.Library
                 throw new DirectoryNotFoundException("The media folder does not exist");
                 throw new DirectoryNotFoundException("The media folder does not exist");
             }
             }
 
 
-            _directoryWatchers.Stop();
-            _directoryWatchers.TemporarilyIgnore(path);
+            _libraryMonitor.Stop();
 
 
             try
             try
             {
             {
@@ -437,10 +428,8 @@ namespace MediaBrowser.Api.Library
                 // No need to start if scanning the library because it will handle it
                 // No need to start if scanning the library because it will handle it
                 if (!request.RefreshLibrary)
                 if (!request.RefreshLibrary)
                 {
                 {
-                    _directoryWatchers.Start();
+                    _libraryMonitor.Start();
                 }
                 }
-
-                _directoryWatchers.RemoveTempIgnore(path);
             }
             }
 
 
             if (request.RefreshLibrary)
             if (request.RefreshLibrary)
@@ -460,7 +449,7 @@ namespace MediaBrowser.Api.Library
                 throw new ArgumentNullException("request");
                 throw new ArgumentNullException("request");
             }
             }
 
 
-            _directoryWatchers.Stop();
+            _libraryMonitor.Stop();
 
 
             try
             try
             {
             {
@@ -485,7 +474,7 @@ namespace MediaBrowser.Api.Library
                 // No need to start if scanning the library because it will handle it
                 // No need to start if scanning the library because it will handle it
                 if (!request.RefreshLibrary)
                 if (!request.RefreshLibrary)
                 {
                 {
-                    _directoryWatchers.Start();
+                    _libraryMonitor.Start();
                 }
                 }
             }
             }
 
 
@@ -506,7 +495,7 @@ namespace MediaBrowser.Api.Library
                 throw new ArgumentNullException("request");
                 throw new ArgumentNullException("request");
             }
             }
 
 
-            _directoryWatchers.Stop();
+            _libraryMonitor.Stop();
 
 
             try
             try
             {
             {
@@ -531,7 +520,7 @@ namespace MediaBrowser.Api.Library
                 // No need to start if scanning the library because it will handle it
                 // No need to start if scanning the library because it will handle it
                 if (!request.RefreshLibrary)
                 if (!request.RefreshLibrary)
                 {
                 {
-                    _directoryWatchers.Start();
+                    _libraryMonitor.Start();
                 }
                 }
             }
             }
 
 

+ 0 - 29
MediaBrowser.Controller/IO/IDirectoryWatchers.cs

@@ -1,29 +0,0 @@
-using System;
-
-namespace MediaBrowser.Controller.IO
-{
-    public interface IDirectoryWatchers : IDisposable
-    {
-        /// <summary>
-        /// Add the path to our temporary ignore list.  Use when writing to a path within our listening scope.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        void TemporarilyIgnore(string path);
-
-        /// <summary>
-        /// Removes the temp ignore.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        void RemoveTempIgnore(string path);
-
-        /// <summary>
-        /// Starts this instance.
-        /// </summary>
-        void Start();
-
-        /// <summary>
-        /// Stops this instance.
-        /// </summary>
-        void Stop();
-    }
-}

+ 36 - 0
MediaBrowser.Controller/Library/ILibraryMonitor.cs

@@ -0,0 +1,36 @@
+using System;
+
+namespace MediaBrowser.Controller.Library
+{
+    public interface ILibraryMonitor : IDisposable
+    {
+        /// <summary>
+        /// Starts this instance.
+        /// </summary>
+        void Start();
+
+        /// <summary>
+        /// Stops this instance.
+        /// </summary>
+        void Stop();
+
+        /// <summary>
+        /// Reports the file system change beginning.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        void ReportFileSystemChangeBeginning(string path);
+
+        /// <summary>
+        /// Reports the file system change complete.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <param name="refreshPath">if set to <c>true</c> [refresh path].</param>
+        void ReportFileSystemChangeComplete(string path, bool refreshPath);
+
+        /// <summary>
+        /// Reports the file system changed.
+        /// </summary>
+        /// <param name="path">The path.</param>
+        void ReportFileSystemChanged(string path);
+    }
+}

+ 1 - 1
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -182,7 +182,7 @@
     <Compile Include="Entities\Video.cs" />
     <Compile Include="Entities\Video.cs" />
     <Compile Include="Entities\CollectionFolder.cs" />
     <Compile Include="Entities\CollectionFolder.cs" />
     <Compile Include="Entities\Year.cs" />
     <Compile Include="Entities\Year.cs" />
-    <Compile Include="IO\IDirectoryWatchers.cs" />
+    <Compile Include="Library\ILibraryMonitor.cs" />
     <Compile Include="IServerApplicationHost.cs" />
     <Compile Include="IServerApplicationHost.cs" />
     <Compile Include="IServerApplicationPaths.cs" />
     <Compile Include="IServerApplicationPaths.cs" />
     <Compile Include="Library\SearchHintInfo.cs" />
     <Compile Include="Library\SearchHintInfo.cs" />

+ 2 - 2
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -165,7 +165,7 @@ namespace MediaBrowser.Model.Configuration
         /// different directories and files.
         /// different directories and files.
         /// </summary>
         /// </summary>
         /// <value>The file watcher delay.</value>
         /// <value>The file watcher delay.</value>
-        public int FileWatcherDelay { get; set; }
+        public int RealtimeWatcherDelay { get; set; }
 
 
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether [enable dashboard response caching].
         /// Gets or sets a value indicating whether [enable dashboard response caching].
@@ -250,7 +250,7 @@ namespace MediaBrowser.Model.Configuration
             MaxResumePct = 90;
             MaxResumePct = 90;
             MinResumeDurationSeconds = Convert.ToInt32(TimeSpan.FromMinutes(5).TotalSeconds);
             MinResumeDurationSeconds = Convert.ToInt32(TimeSpan.FromMinutes(5).TotalSeconds);
 
 
-            FileWatcherDelay = 8;
+            RealtimeWatcherDelay = 20;
 
 
             RecentItemDays = 10;
             RecentItemDays = 10;
 
 

+ 11 - 11
MediaBrowser.Providers/Manager/ImageSaver.cs

@@ -3,7 +3,7 @@ using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.IO;
+using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
@@ -36,7 +36,7 @@ namespace MediaBrowser.Providers.Manager
         /// <summary>
         /// <summary>
         /// The _directory watchers
         /// The _directory watchers
         /// </summary>
         /// </summary>
-        private readonly IDirectoryWatchers _directoryWatchers;
+        private readonly ILibraryMonitor _libraryMonitor;
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
         private readonly ILogger _logger;
         private readonly ILogger _logger;
 
 
@@ -44,11 +44,11 @@ namespace MediaBrowser.Providers.Manager
         /// Initializes a new instance of the <see cref="ImageSaver"/> class.
         /// Initializes a new instance of the <see cref="ImageSaver"/> class.
         /// </summary>
         /// </summary>
         /// <param name="config">The config.</param>
         /// <param name="config">The config.</param>
-        /// <param name="directoryWatchers">The directory watchers.</param>
-        public ImageSaver(IServerConfigurationManager config, IDirectoryWatchers directoryWatchers, IFileSystem fileSystem, ILogger logger)
+        /// <param name="libraryMonitor">The directory watchers.</param>
+        public ImageSaver(IServerConfigurationManager config, ILibraryMonitor libraryMonitor, IFileSystem fileSystem, ILogger logger)
         {
         {
             _config = config;
             _config = config;
-            _directoryWatchers = directoryWatchers;
+            _libraryMonitor = libraryMonitor;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
             _logger = logger;
             _logger = logger;
             _remoteImageCache = new FileSystemRepository(config.ApplicationPaths.DownloadedImagesDataPath);
             _remoteImageCache = new FileSystemRepository(config.ApplicationPaths.DownloadedImagesDataPath);
@@ -160,7 +160,7 @@ namespace MediaBrowser.Providers.Manager
             // Delete the current path
             // Delete the current path
             if (!string.IsNullOrEmpty(currentPath) && !paths.Contains(currentPath, StringComparer.OrdinalIgnoreCase))
             if (!string.IsNullOrEmpty(currentPath) && !paths.Contains(currentPath, StringComparer.OrdinalIgnoreCase))
             {
             {
-                _directoryWatchers.TemporarilyIgnore(currentPath);
+                _libraryMonitor.ReportFileSystemChangeBeginning(currentPath);
 
 
                 try
                 try
                 {
                 {
@@ -179,7 +179,7 @@ namespace MediaBrowser.Providers.Manager
                 }
                 }
                 finally
                 finally
                 {
                 {
-                    _directoryWatchers.RemoveTempIgnore(currentPath);
+                    _libraryMonitor.ReportFileSystemChangeComplete(currentPath, false);
                 }
                 }
             }
             }
         }
         }
@@ -197,8 +197,8 @@ namespace MediaBrowser.Providers.Manager
 
 
             var parentFolder = Path.GetDirectoryName(path);
             var parentFolder = Path.GetDirectoryName(path);
 
 
-            _directoryWatchers.TemporarilyIgnore(path);
-            _directoryWatchers.TemporarilyIgnore(parentFolder);
+            _libraryMonitor.ReportFileSystemChangeBeginning(path);
+            _libraryMonitor.ReportFileSystemChangeBeginning(parentFolder);
 
 
             try
             try
             {
             {
@@ -223,8 +223,8 @@ namespace MediaBrowser.Providers.Manager
             }
             }
             finally
             finally
             {
             {
-                _directoryWatchers.RemoveTempIgnore(path);
-                _directoryWatchers.RemoveTempIgnore(parentFolder);
+                _libraryMonitor.ReportFileSystemChangeComplete(path, false);
+                _libraryMonitor.ReportFileSystemChangeComplete(parentFolder, false);
             }
             }
         }
         }
 
 

+ 1 - 17
MediaBrowser.Providers/Manager/MetadataService.cs

@@ -38,7 +38,6 @@ namespace MediaBrowser.Providers.Manager
         public void AddParts(IEnumerable<IMetadataProvider> providers, IEnumerable<IImageProvider> imageProviders)
         public void AddParts(IEnumerable<IMetadataProvider> providers, IEnumerable<IImageProvider> imageProviders)
         {
         {
             _providers = providers.OfType<IMetadataProvider<TItemType>>()
             _providers = providers.OfType<IMetadataProvider<TItemType>>()
-                .OrderBy(GetSortOrder)
                 .ToArray();
                 .ToArray();
 
 
             _imageProviders = imageProviders.OrderBy(i => i.Order).ToArray();
             _imageProviders = imageProviders.OrderBy(i => i.Order).ToArray();
@@ -179,21 +178,6 @@ namespace MediaBrowser.Providers.Manager
             return providers;
             return providers;
         }
         }
 
 
-        /// <summary>
-        /// Gets the sort order.
-        /// </summary>
-        /// <param name="provider">The provider.</param>
-        /// <returns>System.Int32.</returns>
-        protected virtual int GetSortOrder(IMetadataProvider<TItemType> provider)
-        {
-            if (provider is IRemoteMetadataProvider)
-            {
-                return 1;
-            }
-
-            return 0;
-        }
-
         /// <summary>
         /// <summary>
         /// Determines whether this instance can refresh the specified provider.
         /// Determines whether this instance can refresh the specified provider.
         /// </summary>
         /// </summary>
@@ -217,7 +201,7 @@ namespace MediaBrowser.Providers.Manager
 
 
         protected abstract Task SaveItem(TItemType item, ItemUpdateType reason, CancellationToken cancellationToken);
         protected abstract Task SaveItem(TItemType item, ItemUpdateType reason, CancellationToken cancellationToken);
 
 
-        protected virtual ItemId GetId(TItemType item)
+        protected virtual ItemId GetId(IHasMetadata item)
         {
         {
             return new ItemId
             return new ItemId
             {
             {

+ 8 - 8
MediaBrowser.Providers/Manager/ProviderManager.cs

@@ -36,7 +36,7 @@ namespace MediaBrowser.Providers.Manager
         /// <summary>
         /// <summary>
         /// The _directory watchers
         /// The _directory watchers
         /// </summary>
         /// </summary>
-        private readonly IDirectoryWatchers _directoryWatchers;
+        private readonly ILibraryMonitor _libraryMonitor;
 
 
         /// <summary>
         /// <summary>
         /// Gets or sets the configuration manager.
         /// Gets or sets the configuration manager.
@@ -57,23 +57,23 @@ namespace MediaBrowser.Providers.Manager
 
 
         private readonly IItemRepository _itemRepo;
         private readonly IItemRepository _itemRepo;
 
 
-        private IMetadataService[] _metadataServices = {};
+        private IMetadataService[] _metadataServices = { };
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="ProviderManager" /> class.
         /// Initializes a new instance of the <see cref="ProviderManager" /> class.
         /// </summary>
         /// </summary>
         /// <param name="httpClient">The HTTP client.</param>
         /// <param name="httpClient">The HTTP client.</param>
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="configurationManager">The configuration manager.</param>
-        /// <param name="directoryWatchers">The directory watchers.</param>
+        /// <param name="libraryMonitor">The directory watchers.</param>
         /// <param name="logManager">The log manager.</param>
         /// <param name="logManager">The log manager.</param>
         /// <param name="fileSystem">The file system.</param>
         /// <param name="fileSystem">The file system.</param>
         /// <param name="itemRepo">The item repo.</param>
         /// <param name="itemRepo">The item repo.</param>
-        public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, IDirectoryWatchers directoryWatchers, ILogManager logManager, IFileSystem fileSystem, IItemRepository itemRepo)
+        public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem, IItemRepository itemRepo)
         {
         {
             _logger = logManager.GetLogger("ProviderManager");
             _logger = logManager.GetLogger("ProviderManager");
             _httpClient = httpClient;
             _httpClient = httpClient;
             ConfigurationManager = configurationManager;
             ConfigurationManager = configurationManager;
-            _directoryWatchers = directoryWatchers;
+            _libraryMonitor = libraryMonitor;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
             _itemRepo = itemRepo;
             _itemRepo = itemRepo;
         }
         }
@@ -315,7 +315,7 @@ namespace MediaBrowser.Providers.Manager
             }
             }
 
 
             //Tell the watchers to ignore
             //Tell the watchers to ignore
-            _directoryWatchers.TemporarilyIgnore(path);
+            _libraryMonitor.ReportFileSystemChangeBeginning(path);
 
 
             if (dataToSave.CanSeek)
             if (dataToSave.CanSeek)
             {
             {
@@ -338,7 +338,7 @@ namespace MediaBrowser.Providers.Manager
             finally
             finally
             {
             {
                 //Remove the ignore
                 //Remove the ignore
-                _directoryWatchers.RemoveTempIgnore(path);
+                _libraryMonitor.ReportFileSystemChangeComplete(path, false);
             }
             }
         }
         }
 
 
@@ -380,7 +380,7 @@ namespace MediaBrowser.Providers.Manager
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, string sourceUrl, CancellationToken cancellationToken)
         public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, string sourceUrl, CancellationToken cancellationToken)
         {
         {
-            return new ImageSaver(ConfigurationManager, _directoryWatchers, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, sourceUrl, cancellationToken);
+            return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, sourceUrl, cancellationToken);
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 11 - 5
MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs

@@ -22,7 +22,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
 {
 {
     public class EpisodeFileOrganizer
     public class EpisodeFileOrganizer
     {
     {
-        private readonly IDirectoryWatchers _directoryWatchers;
+        private readonly ILibraryMonitor _libraryMonitor;
         private readonly ILibraryManager _libraryManager;
         private readonly ILibraryManager _libraryManager;
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
@@ -31,14 +31,14 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
 
 
         private readonly CultureInfo _usCulture = new CultureInfo("en-US");
         private readonly CultureInfo _usCulture = new CultureInfo("en-US");
 
 
-        public EpisodeFileOrganizer(IFileOrganizationService organizationService, IServerConfigurationManager config, IFileSystem fileSystem, ILogger logger, ILibraryManager libraryManager, IDirectoryWatchers directoryWatchers)
+        public EpisodeFileOrganizer(IFileOrganizationService organizationService, IServerConfigurationManager config, IFileSystem fileSystem, ILogger logger, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor)
         {
         {
             _organizationService = organizationService;
             _organizationService = organizationService;
             _config = config;
             _config = config;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
             _logger = logger;
             _logger = logger;
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
-            _directoryWatchers = directoryWatchers;
+            _libraryMonitor = libraryMonitor;
         }
         }
 
 
         public async Task<FileOrganizationResult> OrganizeEpisodeFile(string path, TvFileOrganizationOptions options, bool overwriteExisting)
         public async Task<FileOrganizationResult> OrganizeEpisodeFile(string path, TvFileOrganizationOptions options, bool overwriteExisting)
@@ -174,6 +174,8 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
                 {
                 {
                     _logger.Debug("Removing duplicate episode {0}", path);
                     _logger.Debug("Removing duplicate episode {0}", path);
 
 
+                    _libraryMonitor.ReportFileSystemChangeBeginning(path);
+
                     try
                     try
                     {
                     {
                         File.Delete(path);
                         File.Delete(path);
@@ -182,6 +184,10 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
                     {
                     {
                         _logger.ErrorException("Error removing duplicate episode", ex, path);
                         _logger.ErrorException("Error removing duplicate episode", ex, path);
                     }
                     }
+                    finally
+                    {
+                        _libraryMonitor.ReportFileSystemChangeComplete(path, true);
+                    }
                 }
                 }
             }
             }
         }
         }
@@ -232,7 +238,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
 
 
         private void PerformFileSorting(TvFileOrganizationOptions options, FileOrganizationResult result)
         private void PerformFileSorting(TvFileOrganizationOptions options, FileOrganizationResult result)
         {
         {
-            _directoryWatchers.TemporarilyIgnore(result.TargetPath);
+            _libraryMonitor.ReportFileSystemChangeBeginning(result.TargetPath);
 
 
             Directory.CreateDirectory(Path.GetDirectoryName(result.TargetPath));
             Directory.CreateDirectory(Path.GetDirectoryName(result.TargetPath));
 
 
@@ -264,7 +270,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
             }
             }
             finally
             finally
             {
             {
-                _directoryWatchers.RemoveTempIgnore(result.TargetPath);
+                _libraryMonitor.ReportFileSystemChangeComplete(result.TargetPath, true);
             }
             }
 
 
             if (copy)
             if (copy)

+ 5 - 11
MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs

@@ -21,17 +21,17 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
         private readonly ITaskManager _taskManager;
         private readonly ITaskManager _taskManager;
         private readonly IFileOrganizationRepository _repo;
         private readonly IFileOrganizationRepository _repo;
         private readonly ILogger _logger;
         private readonly ILogger _logger;
-        private readonly IDirectoryWatchers _directoryWatchers;
+        private readonly ILibraryMonitor _libraryMonitor;
         private readonly ILibraryManager _libraryManager;
         private readonly ILibraryManager _libraryManager;
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
 
 
-        public FileOrganizationService(ITaskManager taskManager, IFileOrganizationRepository repo, ILogger logger, IDirectoryWatchers directoryWatchers, ILibraryManager libraryManager, IServerConfigurationManager config, IFileSystem fileSystem)
+        public FileOrganizationService(ITaskManager taskManager, IFileOrganizationRepository repo, ILogger logger, ILibraryMonitor libraryMonitor, ILibraryManager libraryManager, IServerConfigurationManager config, IFileSystem fileSystem)
         {
         {
             _taskManager = taskManager;
             _taskManager = taskManager;
             _repo = repo;
             _repo = repo;
             _logger = logger;
             _logger = logger;
-            _directoryWatchers = directoryWatchers;
+            _libraryMonitor = libraryMonitor;
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
             _config = config;
             _config = config;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
@@ -91,13 +91,10 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
             }
             }
 
 
             var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
             var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
-                _directoryWatchers);
+                _libraryMonitor);
 
 
             await organizer.OrganizeEpisodeFile(result.OriginalPath, _config.Configuration.TvFileOrganizationOptions, true)
             await organizer.OrganizeEpisodeFile(result.OriginalPath, _config.Configuration.TvFileOrganizationOptions, true)
                     .ConfigureAwait(false);
                     .ConfigureAwait(false);
-
-            await _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None)
-                    .ConfigureAwait(false);
         }
         }
 
 
         public Task ClearLog()
         public Task ClearLog()
@@ -108,12 +105,9 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
         public async Task PerformEpisodeOrganization(EpisodeFileOrganizationRequest request)
         public async Task PerformEpisodeOrganization(EpisodeFileOrganizationRequest request)
         {
         {
             var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
             var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
-                _directoryWatchers);
+                _libraryMonitor);
 
 
             await organizer.OrganizeWithCorrection(request, _config.Configuration.TvFileOrganizationOptions).ConfigureAwait(false);
             await organizer.OrganizeWithCorrection(request, _config.Configuration.TvFileOrganizationOptions).ConfigureAwait(false);
-
-            await _libraryManager.ValidateMediaLibrary(new Progress<double>(), CancellationToken.None)
-                    .ConfigureAwait(false);
         }
         }
     }
     }
 }
 }

+ 4 - 4
MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs

@@ -14,16 +14,16 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
 {
 {
     public class OrganizerScheduledTask : IScheduledTask, IConfigurableScheduledTask
     public class OrganizerScheduledTask : IScheduledTask, IConfigurableScheduledTask
     {
     {
-        private readonly IDirectoryWatchers _directoryWatchers;
+        private readonly ILibraryMonitor _libraryMonitor;
         private readonly ILibraryManager _libraryManager;
         private readonly ILibraryManager _libraryManager;
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
         private readonly IFileOrganizationService _organizationService;
         private readonly IFileOrganizationService _organizationService;
 
 
-        public OrganizerScheduledTask(IDirectoryWatchers directoryWatchers, ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, IServerConfigurationManager config, IFileOrganizationService organizationService)
+        public OrganizerScheduledTask(ILibraryMonitor libraryMonitor, ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, IServerConfigurationManager config, IFileOrganizationService organizationService)
         {
         {
-            _directoryWatchers = directoryWatchers;
+            _libraryMonitor = libraryMonitor;
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
             _logger = logger;
             _logger = logger;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
@@ -48,7 +48,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
 
 
         public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
         public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
         {
         {
-            return new TvFolderOrganizer(_libraryManager, _logger, _fileSystem, _directoryWatchers, _organizationService, _config)
+            return new TvFolderOrganizer(_libraryManager, _logger, _fileSystem, _libraryMonitor, _organizationService, _config)
                 .Organize(_config.Configuration.TvFileOrganizationOptions, cancellationToken, progress);
                 .Organize(_config.Configuration.TvFileOrganizationOptions, cancellationToken, progress);
         }
         }
 
 

+ 4 - 4
MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs

@@ -18,19 +18,19 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
 {
 {
     public class TvFolderOrganizer
     public class TvFolderOrganizer
     {
     {
-        private readonly IDirectoryWatchers _directoryWatchers;
+        private readonly ILibraryMonitor _libraryMonitor;
         private readonly ILibraryManager _libraryManager;
         private readonly ILibraryManager _libraryManager;
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
         private readonly IFileOrganizationService _organizationService;
         private readonly IFileOrganizationService _organizationService;
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
 
 
-        public TvFolderOrganizer(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, IDirectoryWatchers directoryWatchers, IFileOrganizationService organizationService, IServerConfigurationManager config)
+        public TvFolderOrganizer(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem, ILibraryMonitor libraryMonitor, IFileOrganizationService organizationService, IServerConfigurationManager config)
         {
         {
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
             _logger = logger;
             _logger = logger;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
-            _directoryWatchers = directoryWatchers;
+            _libraryMonitor = libraryMonitor;
             _organizationService = organizationService;
             _organizationService = organizationService;
             _config = config;
             _config = config;
         }
         }
@@ -57,7 +57,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
                 foreach (var file in eligibleFiles)
                 foreach (var file in eligibleFiles)
                 {
                 {
                     var organizer = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager,
                     var organizer = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager,
-                        _directoryWatchers);
+                        _libraryMonitor);
 
 
                     var result = await organizer.OrganizeEpisodeFile(file.FullName, options, false).ConfigureAwait(false);
                     var result = await organizer.OrganizeEpisodeFile(file.FullName, options, false).ConfigureAwait(false);
 
 

+ 54 - 121
MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs → MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs

@@ -1,8 +1,6 @@
-using MediaBrowser.Common.IO;
-using MediaBrowser.Common.ScheduledTasks;
+using MediaBrowser.Common.ScheduledTasks;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.IO;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
@@ -18,10 +16,7 @@ using System.Threading.Tasks;
 
 
 namespace MediaBrowser.Server.Implementations.IO
 namespace MediaBrowser.Server.Implementations.IO
 {
 {
-    /// <summary>
-    /// Class DirectoryWatchers
-    /// </summary>
-    public class DirectoryWatchers : IDirectoryWatchers
+    public class LibraryMonitor : ILibraryMonitor
     {
     {
         /// <summary>
         /// <summary>
         /// The file system watchers
         /// The file system watchers
@@ -55,7 +50,7 @@ namespace MediaBrowser.Server.Implementations.IO
         /// Add the path to our temporary ignore list.  Use when writing to a path within our listening scope.
         /// Add the path to our temporary ignore list.  Use when writing to a path within our listening scope.
         /// </summary>
         /// </summary>
         /// <param name="path">The path.</param>
         /// <param name="path">The path.</param>
-        public void TemporarilyIgnore(string path)
+        private void TemporarilyIgnore(string path)
         {
         {
             _tempIgnoredPaths[path] = path;
             _tempIgnoredPaths[path] = path;
         }
         }
@@ -64,7 +59,7 @@ namespace MediaBrowser.Server.Implementations.IO
         /// Removes the temp ignore.
         /// Removes the temp ignore.
         /// </summary>
         /// </summary>
         /// <param name="path">The path.</param>
         /// <param name="path">The path.</param>
-        public async void RemoveTempIgnore(string path)
+        private async void RemoveTempIgnore(string path)
         {
         {
             // This is an arbitraty amount of time, but delay it because file system writes often trigger events after RemoveTempIgnore has been called. 
             // This is an arbitraty amount of time, but delay it because file system writes often trigger events after RemoveTempIgnore has been called. 
             // Seeing long delays in some situations, especially over the network.
             // Seeing long delays in some situations, especially over the network.
@@ -75,6 +70,21 @@ namespace MediaBrowser.Server.Implementations.IO
             _tempIgnoredPaths.TryRemove(path, out val);
             _tempIgnoredPaths.TryRemove(path, out val);
         }
         }
 
 
+        public void ReportFileSystemChangeBeginning(string path)
+        {
+            TemporarilyIgnore(path);
+        }
+
+        public void ReportFileSystemChangeComplete(string path, bool refreshPath)
+        {
+            RemoveTempIgnore(path);
+
+            if (refreshPath)
+            {
+                ReportFileSystemChanged(path);
+            }
+        }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the logger.
         /// Gets or sets the logger.
         /// </summary>
         /// </summary>
@@ -90,12 +100,10 @@ namespace MediaBrowser.Server.Implementations.IO
         private ILibraryManager LibraryManager { get; set; }
         private ILibraryManager LibraryManager { get; set; }
         private IServerConfigurationManager ConfigurationManager { get; set; }
         private IServerConfigurationManager ConfigurationManager { get; set; }
 
 
-        private readonly IFileSystem _fileSystem;
-        
         /// <summary>
         /// <summary>
-        /// Initializes a new instance of the <see cref="DirectoryWatchers" /> class.
+        /// Initializes a new instance of the <see cref="LibraryMonitor" /> class.
         /// </summary>
         /// </summary>
-        public DirectoryWatchers(ILogManager logManager, ITaskManager taskManager, ILibraryManager libraryManager, IServerConfigurationManager configurationManager, IFileSystem fileSystem)
+        public LibraryMonitor(ILogManager logManager, ITaskManager taskManager, ILibraryManager libraryManager, IServerConfigurationManager configurationManager)
         {
         {
             if (taskManager == null)
             if (taskManager == null)
             {
             {
@@ -104,9 +112,8 @@ namespace MediaBrowser.Server.Implementations.IO
 
 
             LibraryManager = libraryManager;
             LibraryManager = libraryManager;
             TaskManager = taskManager;
             TaskManager = taskManager;
-            Logger = logManager.GetLogger("DirectoryWatchers");
+            Logger = logManager.GetLogger(GetType().Name);
             ConfigurationManager = configurationManager;
             ConfigurationManager = configurationManager;
-            _fileSystem = fileSystem;
 
 
             SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
             SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
         }
         }
@@ -328,31 +335,25 @@ namespace MediaBrowser.Server.Implementations.IO
             {
             {
                 OnWatcherChanged(e);
                 OnWatcherChanged(e);
             }
             }
-            catch (IOException ex)
+            catch (Exception ex)
             {
             {
-                Logger.ErrorException("IOException in watcher changed. Path: {0}", ex, e.FullPath);
+                Logger.ErrorException("Exception in watcher changed. Path: {0}", ex, e.FullPath);
             }
             }
         }
         }
 
 
         private void OnWatcherChanged(FileSystemEventArgs e)
         private void OnWatcherChanged(FileSystemEventArgs e)
         {
         {
-            var name = e.Name;
+            Logger.Debug("Watcher sees change of type " + e.ChangeType + " to " + e.FullPath);
 
 
-            // Ignore certain files
-            if (_alwaysIgnoreFiles.Contains(name, StringComparer.OrdinalIgnoreCase))
-            {
-                return;
-            }
+            ReportFileSystemChanged(e.FullPath);
+        }
 
 
-            var nameFromFullPath = Path.GetFileName(e.FullPath);
-            // Ignore certain files
-            if (!string.IsNullOrEmpty(nameFromFullPath) && _alwaysIgnoreFiles.Contains(nameFromFullPath, StringComparer.OrdinalIgnoreCase))
-            {
-                return;
-            }
+        public void ReportFileSystemChanged(string path)
+        {
+            var filename = Path.GetFileName(path);
 
 
-            // Ignore when someone manually creates a new folder
-            if (e.ChangeType == WatcherChangeTypes.Created && name == "New folder")
+            // Ignore certain files
+            if (!string.IsNullOrEmpty(filename) && _alwaysIgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase))
             {
             {
                 return;
                 return;
             }
             }
@@ -362,17 +363,17 @@ namespace MediaBrowser.Server.Implementations.IO
             // If the parent of an ignored path has a change event, ignore that too
             // If the parent of an ignored path has a change event, ignore that too
             if (tempIgnorePaths.Any(i =>
             if (tempIgnorePaths.Any(i =>
             {
             {
-                if (string.Equals(i, e.FullPath, StringComparison.OrdinalIgnoreCase))
+                if (string.Equals(i, path, StringComparison.OrdinalIgnoreCase))
                 {
                 {
-                    Logger.Debug("Watcher ignoring change to {0}", e.FullPath);
+                    Logger.Debug("Ignoring change to {0}", path);
                     return true;
                     return true;
                 }
                 }
 
 
                 // Go up a level
                 // Go up a level
                 var parent = Path.GetDirectoryName(i);
                 var parent = Path.GetDirectoryName(i);
-                if (string.Equals(parent, e.FullPath, StringComparison.OrdinalIgnoreCase))
+                if (string.Equals(parent, path, StringComparison.OrdinalIgnoreCase))
                 {
                 {
-                    Logger.Debug("Watcher ignoring change to {0}", e.FullPath);
+                    Logger.Debug("Ignoring change to {0}", path);
                     return true;
                     return true;
                 }
                 }
 
 
@@ -380,17 +381,17 @@ namespace MediaBrowser.Server.Implementations.IO
                 if (!string.IsNullOrEmpty(parent))
                 if (!string.IsNullOrEmpty(parent))
                 {
                 {
                     parent = Path.GetDirectoryName(i);
                     parent = Path.GetDirectoryName(i);
-                    if (string.Equals(parent, e.FullPath, StringComparison.OrdinalIgnoreCase))
+                    if (string.Equals(parent, path, StringComparison.OrdinalIgnoreCase))
                     {
                     {
-                        Logger.Debug("Watcher ignoring change to {0}", e.FullPath);
+                        Logger.Debug("Ignoring change to {0}", path);
                         return true;
                         return true;
                     }
                     }
                 }
                 }
 
 
-                if (i.StartsWith(e.FullPath, StringComparison.OrdinalIgnoreCase) || 
-                    e.FullPath.StartsWith(i, StringComparison.OrdinalIgnoreCase))
+                if (i.StartsWith(path, StringComparison.OrdinalIgnoreCase) ||
+                    path.StartsWith(i, StringComparison.OrdinalIgnoreCase))
                 {
                 {
-                    Logger.Debug("Watcher ignoring change to {0}", e.FullPath);
+                    Logger.Debug("Ignoring change to {0}", path);
                     return true;
                     return true;
                 }
                 }
 
 
@@ -401,22 +402,19 @@ namespace MediaBrowser.Server.Implementations.IO
                 return;
                 return;
             }
             }
 
 
-            Logger.Info("Watcher sees change of type " + e.ChangeType + " to " + e.FullPath);
-
-            //Since we're watching created, deleted and renamed we always want the parent of the item to be the affected path
-            var affectedPath = e.FullPath;
-
-            _affectedPaths.AddOrUpdate(affectedPath, affectedPath, (key, oldValue) => affectedPath);
+            // Avoid implicitly captured closure
+            var affectedPath = path;
+            _affectedPaths.AddOrUpdate(path, path, (key, oldValue) => affectedPath);
 
 
             lock (_timerLock)
             lock (_timerLock)
             {
             {
                 if (_updateTimer == null)
                 if (_updateTimer == null)
                 {
                 {
-                    _updateTimer = new Timer(TimerStopped, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.FileWatcherDelay), TimeSpan.FromMilliseconds(-1));
+                    _updateTimer = new Timer(TimerStopped, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeWatcherDelay), TimeSpan.FromMilliseconds(-1));
                 }
                 }
                 else
                 else
                 {
                 {
-                    _updateTimer.Change(TimeSpan.FromSeconds(ConfigurationManager.Configuration.FileWatcherDelay), TimeSpan.FromMilliseconds(-1));
+                    _updateTimer.Change(TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeWatcherDelay), TimeSpan.FromMilliseconds(-1));
                 }
                 }
             }
             }
         }
         }
@@ -427,24 +425,9 @@ namespace MediaBrowser.Server.Implementations.IO
         /// <param name="stateInfo">The state info.</param>
         /// <param name="stateInfo">The state info.</param>
         private async void TimerStopped(object stateInfo)
         private async void TimerStopped(object stateInfo)
         {
         {
-            lock (_timerLock)
-            {
-                // Extend the timer as long as any of the paths are still being written to.
-                if (_affectedPaths.Any(p => IsFileLocked(p.Key)))
-                {
-                    Logger.Info("Timer extended.");
-                    _updateTimer.Change(TimeSpan.FromSeconds(ConfigurationManager.Configuration.FileWatcherDelay), TimeSpan.FromMilliseconds(-1));
-                    return;
-                }
+            Logger.Debug("Timer stopped.");
 
 
-                Logger.Info("Timer stopped.");
-
-                if (_updateTimer != null)
-                {
-                    _updateTimer.Dispose();
-                    _updateTimer = null;
-                }
-            }
+            DisposeTimer();
 
 
             var paths = _affectedPaths.Keys.ToList();
             var paths = _affectedPaths.Keys.ToList();
             _affectedPaths.Clear();
             _affectedPaths.Clear();
@@ -452,59 +435,16 @@ namespace MediaBrowser.Server.Implementations.IO
             await ProcessPathChanges(paths).ConfigureAwait(false);
             await ProcessPathChanges(paths).ConfigureAwait(false);
         }
         }
 
 
-        /// <summary>
-        /// Try and determine if a file is locked
-        /// This is not perfect, and is subject to race conditions, so I'd rather not make this a re-usable library method.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <returns><c>true</c> if [is file locked] [the specified path]; otherwise, <c>false</c>.</returns>
-        private bool IsFileLocked(string path)
+        private void DisposeTimer()
         {
         {
-            try
-            {
-                var data = _fileSystem.GetFileSystemInfo(path);
-
-                if (!data.Exists
-                    || data.Attributes.HasFlag(FileAttributes.Directory)
-                    || data.Attributes.HasFlag(FileAttributes.ReadOnly))
-                {
-                    return false;
-                }
-            }
-            catch (IOException)
-            {
-                return false;
-            }
-
-            try
+            lock (_timerLock)
             {
             {
-                using (_fileSystem.GetFileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
+                if (_updateTimer != null)
                 {
                 {
-                    //file is not locked
-                    return false;
+                    _updateTimer.Dispose();
+                    _updateTimer = null;
                 }
                 }
             }
             }
-            catch (DirectoryNotFoundException)
-            {
-                return false;
-            }
-            catch (FileNotFoundException)
-            {
-                return false;
-            }
-            catch (IOException)
-            {
-                //the file is unavailable because it is:
-                //still being written to
-                //or being processed by another thread
-                //or does not exist (has already been processed)
-                Logger.Debug("{0} is locked.", path);
-                return true;
-            }
-            catch
-            {
-                return false;
-            }
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -599,14 +539,7 @@ namespace MediaBrowser.Server.Implementations.IO
                 watcher.Dispose();
                 watcher.Dispose();
             }
             }
 
 
-            lock (_timerLock)
-            {
-                if (_updateTimer != null)
-                {
-                    _updateTimer.Dispose();
-                    _updateTimer = null;
-                }
-            }
+            DisposeTimer();
 
 
             _fileSystemWatchers.Clear();
             _fileSystemWatchers.Clear();
             _affectedPaths.Clear();
             _affectedPaths.Clear();

+ 8 - 8
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -137,7 +137,7 @@ namespace MediaBrowser.Server.Implementations.Library
 
 
         private IEnumerable<IMetadataSaver> _savers;
         private IEnumerable<IMetadataSaver> _savers;
 
 
-        private readonly Func<IDirectoryWatchers> _directoryWatchersFactory;
+        private readonly Func<ILibraryMonitor> _libraryMonitorFactory;
 
 
         /// <summary>
         /// <summary>
         /// The _library items cache
         /// The _library items cache
@@ -180,14 +180,14 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <param name="userManager">The user manager.</param>
         /// <param name="userManager">The user manager.</param>
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="configurationManager">The configuration manager.</param>
         /// <param name="userDataRepository">The user data repository.</param>
         /// <param name="userDataRepository">The user data repository.</param>
-        public LibraryManager(ILogger logger, ITaskManager taskManager, IUserManager userManager, IServerConfigurationManager configurationManager, IUserDataManager userDataRepository, Func<IDirectoryWatchers> directoryWatchersFactory, IFileSystem fileSystem)
+        public LibraryManager(ILogger logger, ITaskManager taskManager, IUserManager userManager, IServerConfigurationManager configurationManager, IUserDataManager userDataRepository, Func<ILibraryMonitor> libraryMonitorFactory, IFileSystem fileSystem)
         {
         {
             _logger = logger;
             _logger = logger;
             _taskManager = taskManager;
             _taskManager = taskManager;
             _userManager = userManager;
             _userManager = userManager;
             ConfigurationManager = configurationManager;
             ConfigurationManager = configurationManager;
             _userDataRepository = userDataRepository;
             _userDataRepository = userDataRepository;
-            _directoryWatchersFactory = directoryWatchersFactory;
+            _libraryMonitorFactory = libraryMonitorFactory;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
             ByReferenceItems = new ConcurrentDictionary<Guid, BaseItem>();
             ByReferenceItems = new ConcurrentDictionary<Guid, BaseItem>();
 
 
@@ -934,7 +934,7 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         public async Task ValidateMediaLibraryInternal(IProgress<double> progress, CancellationToken cancellationToken)
         public async Task ValidateMediaLibraryInternal(IProgress<double> progress, CancellationToken cancellationToken)
         {
         {
-            _directoryWatchersFactory().Stop();
+            _libraryMonitorFactory().Stop();
 
 
             try
             try
             {
             {
@@ -942,7 +942,7 @@ namespace MediaBrowser.Server.Implementations.Library
             }
             }
             finally
             finally
             {
             {
-                _directoryWatchersFactory().Start();
+                _libraryMonitorFactory().Start();
             }
             }
         }
         }
 
 
@@ -1462,13 +1462,13 @@ namespace MediaBrowser.Server.Implementations.Library
 
 
                 var semaphore = _fileLocks.GetOrAdd(path, key => new SemaphoreSlim(1, 1));
                 var semaphore = _fileLocks.GetOrAdd(path, key => new SemaphoreSlim(1, 1));
 
 
-                var directoryWatchers = _directoryWatchersFactory();
+                var directoryWatchers = _libraryMonitorFactory();
 
 
                 await semaphore.WaitAsync().ConfigureAwait(false);
                 await semaphore.WaitAsync().ConfigureAwait(false);
 
 
                 try
                 try
                 {
                 {
-                    directoryWatchers.TemporarilyIgnore(path);
+                    directoryWatchers.ReportFileSystemChangeBeginning(path);
                     saver.Save(item, CancellationToken.None);
                     saver.Save(item, CancellationToken.None);
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
@@ -1477,7 +1477,7 @@ namespace MediaBrowser.Server.Implementations.Library
                 }
                 }
                 finally
                 finally
                 {
                 {
-                    directoryWatchers.RemoveTempIgnore(path);
+                    directoryWatchers.ReportFileSystemChangeComplete(path, false);
                     semaphore.Release();
                     semaphore.Release();
                 }
                 }
             }
             }

+ 1 - 1
MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -137,7 +137,7 @@
     <Compile Include="HttpServer\StreamWriter.cs" />
     <Compile Include="HttpServer\StreamWriter.cs" />
     <Compile Include="HttpServer\SwaggerService.cs" />
     <Compile Include="HttpServer\SwaggerService.cs" />
     <Compile Include="Drawing\ImageProcessor.cs" />
     <Compile Include="Drawing\ImageProcessor.cs" />
-    <Compile Include="IO\DirectoryWatchers.cs" />
+    <Compile Include="IO\LibraryMonitor.cs" />
     <Compile Include="Library\CoreResolutionIgnoreRule.cs" />
     <Compile Include="Library\CoreResolutionIgnoreRule.cs" />
     <Compile Include="Library\LibraryManager.cs" />
     <Compile Include="Library\LibraryManager.cs" />
     <Compile Include="Library\SearchEngine.cs" />
     <Compile Include="Library\SearchEngine.cs" />

+ 6 - 6
MediaBrowser.ServerApplication/ApplicationHost.cs

@@ -137,7 +137,7 @@ namespace MediaBrowser.ServerApplication
         /// Gets or sets the directory watchers.
         /// Gets or sets the directory watchers.
         /// </summary>
         /// </summary>
         /// <value>The directory watchers.</value>
         /// <value>The directory watchers.</value>
-        private IDirectoryWatchers DirectoryWatchers { get; set; }
+        private ILibraryMonitor LibraryMonitor { get; set; }
         /// <summary>
         /// <summary>
         /// Gets or sets the provider manager.
         /// Gets or sets the provider manager.
         /// </summary>
         /// </summary>
@@ -273,13 +273,13 @@ namespace MediaBrowser.ServerApplication
             UserManager = new UserManager(Logger, ServerConfigurationManager, UserRepository);
             UserManager = new UserManager(Logger, ServerConfigurationManager, UserRepository);
             RegisterSingleInstance(UserManager);
             RegisterSingleInstance(UserManager);
 
 
-            LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => DirectoryWatchers, FileSystemManager);
+            LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager);
             RegisterSingleInstance(LibraryManager);
             RegisterSingleInstance(LibraryManager);
 
 
-            DirectoryWatchers = new DirectoryWatchers(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager);
-            RegisterSingleInstance(DirectoryWatchers);
+            LibraryMonitor = new LibraryMonitor(LogManager, TaskManager, LibraryManager, ServerConfigurationManager);
+            RegisterSingleInstance(LibraryMonitor);
 
 
-            ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, DirectoryWatchers, LogManager, FileSystemManager, ItemRepository);
+            ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager, ItemRepository);
             RegisterSingleInstance(ProviderManager);
             RegisterSingleInstance(ProviderManager);
 
 
             RegisterSingleInstance<ISearchEngine>(() => new SearchEngine(LogManager, LibraryManager, UserManager));
             RegisterSingleInstance<ISearchEngine>(() => new SearchEngine(LogManager, LibraryManager, UserManager));
@@ -306,7 +306,7 @@ namespace MediaBrowser.ServerApplication
             var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
             var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
             RegisterSingleInstance<INewsService>(newsService);
             RegisterSingleInstance<INewsService>(newsService);
 
 
-            var fileOrganizationService = new FileOrganizationService(TaskManager, FileOrganizationRepository, Logger, DirectoryWatchers, LibraryManager, ServerConfigurationManager, FileSystemManager);
+            var fileOrganizationService = new FileOrganizationService(TaskManager, FileOrganizationRepository, Logger, LibraryMonitor, LibraryManager, ServerConfigurationManager, FileSystemManager);
             RegisterSingleInstance<IFileOrganizationService>(fileOrganizationService);
             RegisterSingleInstance<IFileOrganizationService>(fileOrganizationService);
 
 
             progress.Report(15);
             progress.Report(15);