aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Api/Library/LibraryStructureService.cs37
-rw-r--r--MediaBrowser.Controller/IO/IDirectoryWatchers.cs29
-rw-r--r--MediaBrowser.Controller/Library/ILibraryMonitor.cs36
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj2
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs4
-rw-r--r--MediaBrowser.Providers/Manager/ImageSaver.cs22
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs18
-rw-r--r--MediaBrowser.Providers/Manager/ProviderManager.cs16
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs16
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs16
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/OrganizerScheduledTask.cs8
-rw-r--r--MediaBrowser.Server.Implementations/FileOrganization/TvFolderOrganizer.cs8
-rw-r--r--MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs (renamed from MediaBrowser.Server.Implementations/IO/DirectoryWatchers.cs)175
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs16
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj2
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs12
16 files changed, 165 insertions, 252 deletions
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
/// </summary>
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
/// <param name="userManager">The user manager.</param>
/// <param name="libraryManager">The library manager.</param>
/// <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)
{
@@ -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
- {
- /// <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();
- }
-} \ 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
+ {
+ /// <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);
+ }
+} \ 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 @@
<Compile Include="Entities\Video.cs" />
<Compile Include="Entities\CollectionFolder.cs" />
<Compile Include="Entities\Year.cs" />
- <Compile Include="IO\IDirectoryWatchers.cs" />
+ <Compile Include="Library\ILibraryMonitor.cs" />
<Compile Include="IServerApplicationHost.cs" />
<Compile Include="IServerApplicationPaths.cs" />
<Compile Include="Library\SearchHintInfo.cs" />
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.
/// </summary>
/// <value>The file watcher delay.</value>
- public int FileWatcherDelay { get; set; }
+ public int RealtimeWatcherDelay { get; set; }
/// <summary>
/// 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
/// <summary>
/// The _directory watchers
/// </summary>
- 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 <see cref="ImageSaver"/> class.
/// </summary>
/// <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;
- _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<IMetadataProvider> providers, IEnumerable<IImageProvider> imageProviders)
{
_providers = providers.OfType<IMetadataProvider<TItemType>>()
- .OrderBy(GetSortOrder)
.ToArray();
_imageProviders = imageProviders.OrderBy(i => i.Order).ToArray();
@@ -180,21 +179,6 @@ namespace MediaBrowser.Providers.Manager
}
/// <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>
/// Determines whether this instance can refresh the specified provider.
/// </summary>
/// <param name="provider">The provider.</param>
@@ -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
/// <summary>
/// The _directory watchers
/// </summary>
- private readonly IDirectoryWatchers _directoryWatchers;
+ private readonly ILibraryMonitor _libraryMonitor;
/// <summary>
/// Gets or sets the configuration manager.
@@ -57,23 +57,23 @@ namespace MediaBrowser.Providers.Manager
private readonly IItemRepository _itemRepo;
- private IMetadataService[] _metadataServices = {};
+ private IMetadataService[] _metadataServices = { };
/// <summary>
/// Initializes a new instance of the <see cref="ProviderManager" /> class.
/// </summary>
/// <param name="httpClient">The HTTP client.</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="fileSystem">The file system.</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");
_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
/// <returns>Task.</returns>
public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, string sourceUrl, CancellationToken cancellationToken)
{
- return new ImageSaver(ConfigurationManager, _directoryWatchers, _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>
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<FileOrganizationResult> 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<double>(), 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<double>(), 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<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);
}
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
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
{
- /// <summary>
- /// Class DirectoryWatchers
- /// </summary>
- public class DirectoryWatchers : IDirectoryWatchers
+ public class LibraryMonitor : ILibraryMonitor
{
/// <summary>
/// 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.
/// </summary>
/// <param name="path">The path.</param>
- 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.
/// </summary>
/// <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.
// 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);
+ }
+ }
+
/// <summary>
/// Gets or sets the logger.
/// </summary>
@@ -90,12 +100,10 @@ namespace MediaBrowser.Server.Implementations.IO
private ILibraryManager LibraryManager { get; set; }
private IServerConfigurationManager ConfigurationManager { get; set; }
- private readonly IFileSystem _fileSystem;
-
/// <summary>
- /// Initializes a new instance of the <see cref="DirectoryWatchers" /> class.
+ /// Initializes a new instance of the <see cref="LibraryMonitor" /> class.
/// </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)
{
@@ -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);
- // 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;
}
@@ -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
/// <param name="stateInfo">The state info.</param>
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);
}
- /// <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>
@@ -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<IMetadataSaver> _savers;
- private readonly Func<IDirectoryWatchers> _directoryWatchersFactory;
+ private readonly Func<ILibraryMonitor> _libraryMonitorFactory;
/// <summary>
/// The _library items cache
@@ -180,14 +180,14 @@ namespace MediaBrowser.Server.Implementations.Library
/// <param name="userManager">The user manager.</param>
/// <param name="configurationManager">The configuration manager.</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;
_taskManager = taskManager;
_userManager = userManager;
ConfigurationManager = configurationManager;
_userDataRepository = userDataRepository;
- _directoryWatchersFactory = directoryWatchersFactory;
+ _libraryMonitorFactory = libraryMonitorFactory;
_fileSystem = fileSystem;
ByReferenceItems = new ConcurrentDictionary<Guid, BaseItem>();
@@ -934,7 +934,7 @@ namespace MediaBrowser.Server.Implementations.Library
/// <returns>Task.</returns>
public async Task ValidateMediaLibraryInternal(IProgress<double> 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 @@
<Compile Include="HttpServer\StreamWriter.cs" />
<Compile Include="HttpServer\SwaggerService.cs" />
<Compile Include="Drawing\ImageProcessor.cs" />
- <Compile Include="IO\DirectoryWatchers.cs" />
+ <Compile Include="IO\LibraryMonitor.cs" />
<Compile Include="Library\CoreResolutionIgnoreRule.cs" />
<Compile Include="Library\LibraryManager.cs" />
<Compile Include="Library\SearchEngine.cs" />
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.
/// </summary>
/// <value>The directory watchers.</value>
- private IDirectoryWatchers DirectoryWatchers { get; set; }
+ private ILibraryMonitor LibraryMonitor { get; set; }
/// <summary>
/// Gets or sets the provider manager.
/// </summary>
@@ -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<ISearchEngine>(() => new SearchEngine(LogManager, LibraryManager, UserManager));
@@ -306,7 +306,7 @@ namespace MediaBrowser.ServerApplication
var newsService = new Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
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);
progress.Report(15);