diff --git a/MediaBrowser.Api/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs
index 775907379..56b0e01c3 100644
--- a/MediaBrowser.Api/Library/LibraryStructureService.cs
+++ b/MediaBrowser.Api/Library/LibraryStructureService.cs
@@ -187,7 +187,7 @@ namespace MediaBrowser.Api.Library
///
private readonly ILibraryManager _libraryManager;
- private readonly IDirectoryWatchers _directoryWatchers;
+ private readonly ILibraryMonitor _libraryMonitor;
private readonly IFileSystem _fileSystem;
private readonly ILogger _logger;
@@ -199,7 +199,7 @@ namespace MediaBrowser.Api.Library
/// The user manager.
/// The library manager.
/// appPaths
- 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)
{
@@ -209,7 +209,7 @@ namespace MediaBrowser.Api.Library
_userManager = userManager;
_appPaths = appPaths;
_libraryManager = libraryManager;
- _directoryWatchers = directoryWatchers;
+ _libraryMonitor = libraryMonitor;
_fileSystem = fileSystem;
_logger = logger;
}
@@ -270,8 +270,7 @@ namespace MediaBrowser.Api.Library
throw new ArgumentException("There is already a media collection with the name " + name + ".");
}
- _directoryWatchers.Stop();
- _directoryWatchers.TemporarilyIgnore(virtualFolderPath);
+ _libraryMonitor.Stop();
try
{
@@ -294,10 +293,8 @@ namespace MediaBrowser.Api.Library
// No need to start if scanning the library because it will handle it
if (!request.RefreshLibrary)
{
- _directoryWatchers.Start();
+ _libraryMonitor.Start();
}
-
- _directoryWatchers.RemoveTempIgnore(virtualFolderPath);
}
if (request.RefreshLibrary)
@@ -348,9 +345,7 @@ namespace MediaBrowser.Api.Library
throw new ArgumentException("There is already a media collection with the name " + newPath + ".");
}
- _directoryWatchers.Stop();
- _directoryWatchers.TemporarilyIgnore(currentPath);
- _directoryWatchers.TemporarilyIgnore(newPath);
+ _libraryMonitor.Stop();
try
{
@@ -376,11 +371,8 @@ namespace MediaBrowser.Api.Library
// No need to start if scanning the library because it will handle it
if (!request.RefreshLibrary)
{
- _directoryWatchers.Start();
+ _libraryMonitor.Start();
}
-
- _directoryWatchers.RemoveTempIgnore(currentPath);
- _directoryWatchers.RemoveTempIgnore(newPath);
}
if (request.RefreshLibrary)
@@ -420,8 +412,7 @@ namespace MediaBrowser.Api.Library
throw new DirectoryNotFoundException("The media folder does not exist");
}
- _directoryWatchers.Stop();
- _directoryWatchers.TemporarilyIgnore(path);
+ _libraryMonitor.Stop();
try
{
@@ -437,10 +428,8 @@ namespace MediaBrowser.Api.Library
// No need to start if scanning the library because it will handle it
if (!request.RefreshLibrary)
{
- _directoryWatchers.Start();
+ _libraryMonitor.Start();
}
-
- _directoryWatchers.RemoveTempIgnore(path);
}
if (request.RefreshLibrary)
@@ -460,7 +449,7 @@ namespace MediaBrowser.Api.Library
throw new ArgumentNullException("request");
}
- _directoryWatchers.Stop();
+ _libraryMonitor.Stop();
try
{
@@ -485,7 +474,7 @@ namespace MediaBrowser.Api.Library
// No need to start if scanning the library because it will handle it
if (!request.RefreshLibrary)
{
- _directoryWatchers.Start();
+ _libraryMonitor.Start();
}
}
@@ -506,7 +495,7 @@ namespace MediaBrowser.Api.Library
throw new ArgumentNullException("request");
}
- _directoryWatchers.Stop();
+ _libraryMonitor.Stop();
try
{
@@ -531,7 +520,7 @@ namespace MediaBrowser.Api.Library
// No need to start if scanning the library because it will handle it
if (!request.RefreshLibrary)
{
- _directoryWatchers.Start();
+ _libraryMonitor.Start();
}
}
diff --git a/MediaBrowser.Controller/IO/IDirectoryWatchers.cs b/MediaBrowser.Controller/IO/IDirectoryWatchers.cs
deleted file mode 100644
index 9a43ee8ac..000000000
--- a/MediaBrowser.Controller/IO/IDirectoryWatchers.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System;
-
-namespace MediaBrowser.Controller.IO
-{
- public interface IDirectoryWatchers : IDisposable
- {
- ///
- /// Add the path to our temporary ignore list. Use when writing to a path within our listening scope.
- ///
- /// The path.
- void TemporarilyIgnore(string path);
-
- ///
- /// Removes the temp ignore.
- ///
- /// The path.
- void RemoveTempIgnore(string path);
-
- ///
- /// Starts this instance.
- ///
- void Start();
-
- ///
- /// Stops this instance.
- ///
- void Stop();
- }
-}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/Library/ILibraryMonitor.cs b/MediaBrowser.Controller/Library/ILibraryMonitor.cs
new file mode 100644
index 000000000..918382f04
--- /dev/null
+++ b/MediaBrowser.Controller/Library/ILibraryMonitor.cs
@@ -0,0 +1,36 @@
+using System;
+
+namespace MediaBrowser.Controller.Library
+{
+ public interface ILibraryMonitor : IDisposable
+ {
+ ///
+ /// Starts this instance.
+ ///
+ void Start();
+
+ ///
+ /// Stops this instance.
+ ///
+ void Stop();
+
+ ///
+ /// Reports the file system change beginning.
+ ///
+ /// The path.
+ void ReportFileSystemChangeBeginning(string path);
+
+ ///
+ /// Reports the file system change complete.
+ ///
+ /// The path.
+ /// if set to true [refresh path].
+ void ReportFileSystemChangeComplete(string path, bool refreshPath);
+
+ ///
+ /// Reports the file system changed.
+ ///
+ /// The path.
+ void ReportFileSystemChanged(string path);
+ }
+}
\ No newline at end of file
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index ef87c30c7..45297ef3d 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -182,7 +182,7 @@
-
+
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index f017fdf16..923c5ab74 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -165,7 +165,7 @@ namespace MediaBrowser.Model.Configuration
/// different directories and files.
///
/// The file watcher delay.
- public int FileWatcherDelay { get; set; }
+ public int RealtimeWatcherDelay { get; set; }
///
/// Gets or sets a value indicating whether [enable dashboard response caching].
@@ -250,7 +250,7 @@ namespace MediaBrowser.Model.Configuration
MaxResumePct = 90;
MinResumeDurationSeconds = Convert.ToInt32(TimeSpan.FromMinutes(5).TotalSeconds);
- FileWatcherDelay = 8;
+ RealtimeWatcherDelay = 20;
RecentItemDays = 10;
diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs
index a75ce88ae..56a1a9d4f 100644
--- a/MediaBrowser.Providers/Manager/ImageSaver.cs
+++ b/MediaBrowser.Providers/Manager/ImageSaver.cs
@@ -3,7 +3,7 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Controller.IO;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
@@ -36,7 +36,7 @@ namespace MediaBrowser.Providers.Manager
///
/// The _directory watchers
///
- private readonly IDirectoryWatchers _directoryWatchers;
+ private readonly ILibraryMonitor _libraryMonitor;
private readonly IFileSystem _fileSystem;
private readonly ILogger _logger;
@@ -44,11 +44,11 @@ namespace MediaBrowser.Providers.Manager
/// Initializes a new instance of the class.
///
/// The config.
- /// The directory watchers.
- public ImageSaver(IServerConfigurationManager config, IDirectoryWatchers directoryWatchers, IFileSystem fileSystem, ILogger logger)
+ /// The directory watchers.
+ public ImageSaver(IServerConfigurationManager config, ILibraryMonitor libraryMonitor, IFileSystem fileSystem, ILogger logger)
{
_config = config;
- _directoryWatchers = directoryWatchers;
+ _libraryMonitor = libraryMonitor;
_fileSystem = fileSystem;
_logger = logger;
_remoteImageCache = new FileSystemRepository(config.ApplicationPaths.DownloadedImagesDataPath);
@@ -160,7 +160,7 @@ namespace MediaBrowser.Providers.Manager
// Delete the current path
if (!string.IsNullOrEmpty(currentPath) && !paths.Contains(currentPath, StringComparer.OrdinalIgnoreCase))
{
- _directoryWatchers.TemporarilyIgnore(currentPath);
+ _libraryMonitor.ReportFileSystemChangeBeginning(currentPath);
try
{
@@ -179,7 +179,7 @@ namespace MediaBrowser.Providers.Manager
}
finally
{
- _directoryWatchers.RemoveTempIgnore(currentPath);
+ _libraryMonitor.ReportFileSystemChangeComplete(currentPath, false);
}
}
}
@@ -197,8 +197,8 @@ namespace MediaBrowser.Providers.Manager
var parentFolder = Path.GetDirectoryName(path);
- _directoryWatchers.TemporarilyIgnore(path);
- _directoryWatchers.TemporarilyIgnore(parentFolder);
+ _libraryMonitor.ReportFileSystemChangeBeginning(path);
+ _libraryMonitor.ReportFileSystemChangeBeginning(parentFolder);
try
{
@@ -223,8 +223,8 @@ namespace MediaBrowser.Providers.Manager
}
finally
{
- _directoryWatchers.RemoveTempIgnore(path);
- _directoryWatchers.RemoveTempIgnore(parentFolder);
+ _libraryMonitor.ReportFileSystemChangeComplete(path, false);
+ _libraryMonitor.ReportFileSystemChangeComplete(parentFolder, false);
}
}
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index dbe70b93d..5dde3098a 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -38,7 +38,6 @@ namespace MediaBrowser.Providers.Manager
public void AddParts(IEnumerable providers, IEnumerable imageProviders)
{
_providers = providers.OfType>()
- .OrderBy(GetSortOrder)
.ToArray();
_imageProviders = imageProviders.OrderBy(i => i.Order).ToArray();
@@ -179,21 +178,6 @@ namespace MediaBrowser.Providers.Manager
return providers;
}
- ///
- /// Gets the sort order.
- ///
- /// The provider.
- /// System.Int32.
- protected virtual int GetSortOrder(IMetadataProvider provider)
- {
- if (provider is IRemoteMetadataProvider)
- {
- return 1;
- }
-
- return 0;
- }
-
///
/// Determines whether this instance can refresh the specified provider.
///
@@ -217,7 +201,7 @@ namespace MediaBrowser.Providers.Manager
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
{
diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs
index ebad2e6e0..faad15669 100644
--- a/MediaBrowser.Providers/Manager/ProviderManager.cs
+++ b/MediaBrowser.Providers/Manager/ProviderManager.cs
@@ -36,7 +36,7 @@ namespace MediaBrowser.Providers.Manager
///
/// The _directory watchers
///
- private readonly IDirectoryWatchers _directoryWatchers;
+ private readonly ILibraryMonitor _libraryMonitor;
///
/// Gets or sets the configuration manager.
@@ -57,23 +57,23 @@ namespace MediaBrowser.Providers.Manager
private readonly IItemRepository _itemRepo;
- private IMetadataService[] _metadataServices = {};
+ private IMetadataService[] _metadataServices = { };
///
/// Initializes a new instance of the class.
///
/// The HTTP client.
/// The configuration manager.
- /// The directory watchers.
+ /// The directory watchers.
/// The log manager.
/// The file system.
/// The item repo.
- 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");
_httpClient = httpClient;
ConfigurationManager = configurationManager;
- _directoryWatchers = directoryWatchers;
+ _libraryMonitor = libraryMonitor;
_fileSystem = fileSystem;
_itemRepo = itemRepo;
}
@@ -315,7 +315,7 @@ namespace MediaBrowser.Providers.Manager
}
//Tell the watchers to ignore
- _directoryWatchers.TemporarilyIgnore(path);
+ _libraryMonitor.ReportFileSystemChangeBeginning(path);
if (dataToSave.CanSeek)
{
@@ -338,7 +338,7 @@ namespace MediaBrowser.Providers.Manager
finally
{
//Remove the ignore
- _directoryWatchers.RemoveTempIgnore(path);
+ _libraryMonitor.ReportFileSystemChangeComplete(path, false);
}
}
@@ -380,7 +380,7 @@ namespace MediaBrowser.Providers.Manager
/// Task.
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);
}
///
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
index 0a2dd5ae0..a2e094e9a 100644
--- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
+++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
@@ -22,7 +22,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
public class EpisodeFileOrganizer
{
- private readonly IDirectoryWatchers _directoryWatchers;
+ private readonly ILibraryMonitor _libraryMonitor;
private readonly ILibraryManager _libraryManager;
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
@@ -31,14 +31,14 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
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;
_config = config;
_fileSystem = fileSystem;
_logger = logger;
_libraryManager = libraryManager;
- _directoryWatchers = directoryWatchers;
+ _libraryMonitor = libraryMonitor;
}
public async Task OrganizeEpisodeFile(string path, TvFileOrganizationOptions options, bool overwriteExisting)
@@ -174,6 +174,8 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
_logger.Debug("Removing duplicate episode {0}", path);
+ _libraryMonitor.ReportFileSystemChangeBeginning(path);
+
try
{
File.Delete(path);
@@ -182,6 +184,10 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
_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)
{
- _directoryWatchers.TemporarilyIgnore(result.TargetPath);
+ _libraryMonitor.ReportFileSystemChangeBeginning(result.TargetPath);
Directory.CreateDirectory(Path.GetDirectoryName(result.TargetPath));
@@ -264,7 +270,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
}
finally
{
- _directoryWatchers.RemoveTempIgnore(result.TargetPath);
+ _libraryMonitor.ReportFileSystemChangeComplete(result.TargetPath, true);
}
if (copy)
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs b/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs
index bbd0f74e5..518a7bb48 100644
--- a/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs
+++ b/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs
@@ -21,17 +21,17 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
private readonly ITaskManager _taskManager;
private readonly IFileOrganizationRepository _repo;
private readonly ILogger _logger;
- private readonly IDirectoryWatchers _directoryWatchers;
+ private readonly ILibraryMonitor _libraryMonitor;
private readonly ILibraryManager _libraryManager;
private readonly IServerConfigurationManager _config;
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;
_repo = repo;
_logger = logger;
- _directoryWatchers = directoryWatchers;
+ _libraryMonitor = libraryMonitor;
_libraryManager = libraryManager;
_config = config;
_fileSystem = fileSystem;
@@ -91,13 +91,10 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
}
var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
- _directoryWatchers);
+ _libraryMonitor);
await organizer.OrganizeEpisodeFile(result.OriginalPath, _config.Configuration.TvFileOrganizationOptions, true)
.ConfigureAwait(false);
-
- await _libraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None)
- .ConfigureAwait(false);
}
public Task ClearLog()
@@ -108,12 +105,9 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
public async Task PerformEpisodeOrganization(EpisodeFileOrganizationRequest request)
{
var organizer = new EpisodeFileOrganizer(this, _config, _fileSystem, _logger, _libraryManager,
- _directoryWatchers);
+ _libraryMonitor);
await organizer.OrganizeWithCorrection(request, _config.Configuration.TvFileOrganizationOptions).ConfigureAwait(false);
-
- await _libraryManager.ValidateMediaLibrary(new Progress(), CancellationToken.None)
- .ConfigureAwait(false);
}
}
}
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs b/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs
index 340038e4b..3c5e1ed0e 100644
--- a/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs
@@ -14,16 +14,16 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
public class OrganizerScheduledTask : IScheduledTask, IConfigurableScheduledTask
{
- private readonly IDirectoryWatchers _directoryWatchers;
+ private readonly ILibraryMonitor _libraryMonitor;
private readonly ILibraryManager _libraryManager;
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
private readonly IServerConfigurationManager _config;
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;
_logger = logger;
_fileSystem = fileSystem;
@@ -48,7 +48,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
public Task Execute(CancellationToken cancellationToken, IProgress 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);
}
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
index 6a413f2f0..24f21e339 100644
--- a/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
+++ b/MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs
@@ -18,19 +18,19 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
{
public class TvFolderOrganizer
{
- private readonly IDirectoryWatchers _directoryWatchers;
+ private readonly ILibraryMonitor _libraryMonitor;
private readonly ILibraryManager _libraryManager;
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;
private readonly IFileOrganizationService _organizationService;
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;
_logger = logger;
_fileSystem = fileSystem;
- _directoryWatchers = directoryWatchers;
+ _libraryMonitor = libraryMonitor;
_organizationService = organizationService;
_config = config;
}
@@ -57,7 +57,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
foreach (var file in eligibleFiles)
{
var organizer = new EpisodeFileOrganizer(_organizationService, _config, _fileSystem, _logger, _libraryManager,
- _directoryWatchers);
+ _libraryMonitor);
var result = await organizer.OrganizeEpisodeFile(file.FullName, options, false).ConfigureAwait(false);
diff --git a/MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs b/MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
similarity index 77%
rename from MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs
rename to MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
index 1efc3bc70..e09e66765 100644
--- a/MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs
+++ b/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.Entities;
-using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
@@ -18,10 +16,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.IO
{
- ///
- /// Class DirectoryWatchers
- ///
- public class DirectoryWatchers : IDirectoryWatchers
+ public class LibraryMonitor : ILibraryMonitor
{
///
/// 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.
///
/// The path.
- public void TemporarilyIgnore(string path)
+ private void TemporarilyIgnore(string path)
{
_tempIgnoredPaths[path] = path;
}
@@ -64,7 +59,7 @@ namespace MediaBrowser.Server.Implementations.IO
/// Removes the temp ignore.
///
/// The path.
- 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.
// Seeing long delays in some situations, especially over the network.
@@ -75,6 +70,21 @@ namespace MediaBrowser.Server.Implementations.IO
_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);
+ }
+ }
+
///
/// Gets or sets the logger.
///
@@ -90,12 +100,10 @@ namespace MediaBrowser.Server.Implementations.IO
private ILibraryManager LibraryManager { get; set; }
private IServerConfigurationManager ConfigurationManager { get; set; }
- private readonly IFileSystem _fileSystem;
-
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
- 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)
{
@@ -104,9 +112,8 @@ namespace MediaBrowser.Server.Implementations.IO
LibraryManager = libraryManager;
TaskManager = taskManager;
- Logger = logManager.GetLogger("DirectoryWatchers");
+ Logger = logManager.GetLogger(GetType().Name);
ConfigurationManager = configurationManager;
- _fileSystem = fileSystem;
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
}
@@ -328,31 +335,25 @@ namespace MediaBrowser.Server.Implementations.IO
{
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)
{
- var name = e.Name;
+ Logger.Debug("Watcher sees change of type " + e.ChangeType + " to " + e.FullPath);
+
+ ReportFileSystemChanged(e.FullPath);
+ }
+
+ public void ReportFileSystemChanged(string path)
+ {
+ var filename = Path.GetFileName(path);
// Ignore certain files
- if (_alwaysIgnoreFiles.Contains(name, StringComparer.OrdinalIgnoreCase))
- {
- return;
- }
-
- var nameFromFullPath = Path.GetFileName(e.FullPath);
- // Ignore certain files
- if (!string.IsNullOrEmpty(nameFromFullPath) && _alwaysIgnoreFiles.Contains(nameFromFullPath, StringComparer.OrdinalIgnoreCase))
- {
- return;
- }
-
- // Ignore when someone manually creates a new folder
- if (e.ChangeType == WatcherChangeTypes.Created && name == "New folder")
+ if (!string.IsNullOrEmpty(filename) && _alwaysIgnoreFiles.Contains(filename, StringComparer.OrdinalIgnoreCase))
{
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 (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;
}
// Go up a level
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;
}
@@ -380,17 +381,17 @@ namespace MediaBrowser.Server.Implementations.IO
if (!string.IsNullOrEmpty(parent))
{
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;
}
}
- 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;
}
@@ -401,22 +402,19 @@ namespace MediaBrowser.Server.Implementations.IO
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)
{
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
{
- _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
/// The state info.
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();
_affectedPaths.Clear();
@@ -452,59 +435,16 @@ namespace MediaBrowser.Server.Implementations.IO
await ProcessPathChanges(paths).ConfigureAwait(false);
}
- ///
- /// 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.
- ///
- /// The path.
- /// true if [is file locked] [the specified path]; otherwise, false.
- private bool IsFileLocked(string path)
+ private void DisposeTimer()
{
- try
+ lock (_timerLock)
{
- var data = _fileSystem.GetFileSystemInfo(path);
-
- if (!data.Exists
- || data.Attributes.HasFlag(FileAttributes.Directory)
- || data.Attributes.HasFlag(FileAttributes.ReadOnly))
+ if (_updateTimer != null)
{
- return false;
+ _updateTimer.Dispose();
+ _updateTimer = null;
}
}
- catch (IOException)
- {
- return false;
- }
-
- try
- {
- using (_fileSystem.GetFileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
- {
- //file is not locked
- return false;
- }
- }
- 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;
- }
}
///
@@ -599,14 +539,7 @@ namespace MediaBrowser.Server.Implementations.IO
watcher.Dispose();
}
- lock (_timerLock)
- {
- if (_updateTimer != null)
- {
- _updateTimer.Dispose();
- _updateTimer = null;
- }
- }
+ DisposeTimer();
_fileSystemWatchers.Clear();
_affectedPaths.Clear();
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index 736c70ad5..04344553f 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -137,7 +137,7 @@ namespace MediaBrowser.Server.Implementations.Library
private IEnumerable _savers;
- private readonly Func _directoryWatchersFactory;
+ private readonly Func _libraryMonitorFactory;
///
/// The _library items cache
@@ -180,14 +180,14 @@ namespace MediaBrowser.Server.Implementations.Library
/// The user manager.
/// The configuration manager.
/// The user data repository.
- public LibraryManager(ILogger logger, ITaskManager taskManager, IUserManager userManager, IServerConfigurationManager configurationManager, IUserDataManager userDataRepository, Func directoryWatchersFactory, IFileSystem fileSystem)
+ public LibraryManager(ILogger logger, ITaskManager taskManager, IUserManager userManager, IServerConfigurationManager configurationManager, IUserDataManager userDataRepository, Func libraryMonitorFactory, IFileSystem fileSystem)
{
_logger = logger;
_taskManager = taskManager;
_userManager = userManager;
ConfigurationManager = configurationManager;
_userDataRepository = userDataRepository;
- _directoryWatchersFactory = directoryWatchersFactory;
+ _libraryMonitorFactory = libraryMonitorFactory;
_fileSystem = fileSystem;
ByReferenceItems = new ConcurrentDictionary();
@@ -934,7 +934,7 @@ namespace MediaBrowser.Server.Implementations.Library
/// Task.
public async Task ValidateMediaLibraryInternal(IProgress progress, CancellationToken cancellationToken)
{
- _directoryWatchersFactory().Stop();
+ _libraryMonitorFactory().Stop();
try
{
@@ -942,7 +942,7 @@ namespace MediaBrowser.Server.Implementations.Library
}
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 directoryWatchers = _directoryWatchersFactory();
+ var directoryWatchers = _libraryMonitorFactory();
await semaphore.WaitAsync().ConfigureAwait(false);
try
{
- directoryWatchers.TemporarilyIgnore(path);
+ directoryWatchers.ReportFileSystemChangeBeginning(path);
saver.Save(item, CancellationToken.None);
}
catch (Exception ex)
@@ -1477,7 +1477,7 @@ namespace MediaBrowser.Server.Implementations.Library
}
finally
{
- directoryWatchers.RemoveTempIgnore(path);
+ directoryWatchers.ReportFileSystemChangeComplete(path, false);
semaphore.Release();
}
}
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index a92ec29d5..fe4283368 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -137,7 +137,7 @@
-
+
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index 3553996b0..0c8a6b923 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -137,7 +137,7 @@ namespace MediaBrowser.ServerApplication
/// Gets or sets the directory watchers.
///
/// The directory watchers.
- private IDirectoryWatchers DirectoryWatchers { get; set; }
+ private ILibraryMonitor LibraryMonitor { get; set; }
///
/// Gets or sets the provider manager.
///
@@ -273,13 +273,13 @@ namespace MediaBrowser.ServerApplication
UserManager = new UserManager(Logger, ServerConfigurationManager, UserRepository);
RegisterSingleInstance(UserManager);
- LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => DirectoryWatchers, FileSystemManager);
+ LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager);
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(() => new SearchEngine(LogManager, LibraryManager, UserManager));
@@ -306,7 +306,7 @@ namespace MediaBrowser.ServerApplication
var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
RegisterSingleInstance(newsService);
- var fileOrganizationService = new FileOrganizationService(TaskManager, FileOrganizationRepository, Logger, DirectoryWatchers, LibraryManager, ServerConfigurationManager, FileSystemManager);
+ var fileOrganizationService = new FileOrganizationService(TaskManager, FileOrganizationRepository, Logger, LibraryMonitor, LibraryManager, ServerConfigurationManager, FileSystemManager);
RegisterSingleInstance(fileOrganizationService);
progress.Report(15);