mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-05-31 20:24:21 -04:00
Created ILibraryMonitor to replace IDirectoryWatchers
This commit is contained in:
parent
2ae17a8d52
commit
7c5b222463
@ -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();
|
_libraryMonitor.Stop();
|
||||||
_directoryWatchers.TemporarilyIgnore(virtualFolderPath);
|
|
||||||
|
|
||||||
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();
|
_libraryMonitor.Stop();
|
||||||
_directoryWatchers.TemporarilyIgnore(currentPath);
|
|
||||||
_directoryWatchers.TemporarilyIgnore(newPath);
|
|
||||||
|
|
||||||
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();
|
_libraryMonitor.Stop();
|
||||||
_directoryWatchers.TemporarilyIgnore(path);
|
|
||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
MediaBrowser.Controller/Library/ILibraryMonitor.cs
Normal file
36
MediaBrowser.Controller/Library/ILibraryMonitor.cs
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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" />
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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>
|
/// <param name="libraryMonitor">The directory watchers.</param>
|
||||||
public ImageSaver(IServerConfigurationManager config, IDirectoryWatchers directoryWatchers, IFileSystem fileSystem, ILogger logger)
|
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);
|
_libraryMonitor.ReportFileSystemChangeBeginning(path);
|
||||||
_directoryWatchers.TemporarilyIgnore(parentFolder);
|
_libraryMonitor.ReportFileSystemChangeBeginning(parentFolder);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -223,8 +223,8 @@ namespace MediaBrowser.Providers.Manager
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_directoryWatchers.RemoveTempIgnore(path);
|
_libraryMonitor.ReportFileSystemChangeComplete(path, false);
|
||||||
_directoryWatchers.RemoveTempIgnore(parentFolder);
|
_libraryMonitor.ReportFileSystemChangeComplete(parentFolder, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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>
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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>
|
public class LibraryMonitor : ILibraryMonitor
|
||||||
/// Class DirectoryWatchers
|
|
||||||
/// </summary>
|
|
||||||
public class DirectoryWatchers : IDirectoryWatchers
|
|
||||||
{
|
{
|
||||||
/// <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);
|
||||||
|
|
||||||
|
ReportFileSystemChanged(e.FullPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReportFileSystemChanged(string path)
|
||||||
|
{
|
||||||
|
var filename = Path.GetFileName(path);
|
||||||
|
|
||||||
// Ignore certain files
|
// Ignore certain files
|
||||||
if (_alwaysIgnoreFiles.Contains(name, StringComparer.OrdinalIgnoreCase))
|
if (!string.IsNullOrEmpty(filename) && _alwaysIgnoreFiles.Contains(filename, 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")
|
|
||||||
{
|
{
|
||||||
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) ||
|
if (i.StartsWith(path, StringComparison.OrdinalIgnoreCase) ||
|
||||||
e.FullPath.StartsWith(i, 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);
|
// Avoid implicitly captured closure
|
||||||
|
var affectedPath = path;
|
||||||
//Since we're watching created, deleted and renamed we always want the parent of the item to be the affected path
|
_affectedPaths.AddOrUpdate(path, path, (key, oldValue) => affectedPath);
|
||||||
var affectedPath = e.FullPath;
|
|
||||||
|
|
||||||
_affectedPaths.AddOrUpdate(affectedPath, affectedPath, (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)
|
Logger.Debug("Timer stopped.");
|
||||||
{
|
|
||||||
// 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.Info("Timer stopped.");
|
DisposeTimer();
|
||||||
|
|
||||||
if (_updateTimer != null)
|
|
||||||
{
|
|
||||||
_updateTimer.Dispose();
|
|
||||||
_updateTimer = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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>
|
private void DisposeTimer()
|
||||||
/// 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)
|
|
||||||
{
|
{
|
||||||
try
|
lock (_timerLock)
|
||||||
{
|
{
|
||||||
var data = _fileSystem.GetFileSystemInfo(path);
|
if (_updateTimer != null)
|
||||||
|
|
||||||
if (!data.Exists
|
|
||||||
|| data.Attributes.HasFlag(FileAttributes.Directory)
|
|
||||||
|| data.Attributes.HasFlag(FileAttributes.ReadOnly))
|
|
||||||
{
|
{
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -599,14 +539,7 @@ namespace MediaBrowser.Server.Implementations.IO
|
|||||||
watcher.Dispose();
|
watcher.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
lock (_timerLock)
|
DisposeTimer();
|
||||||
{
|
|
||||||
if (_updateTimer != null)
|
|
||||||
{
|
|
||||||
_updateTimer.Dispose();
|
|
||||||
_updateTimer = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_fileSystemWatchers.Clear();
|
_fileSystemWatchers.Clear();
|
||||||
_affectedPaths.Clear();
|
_affectedPaths.Clear();
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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" />
|
||||||
|
@ -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);
|
LibraryMonitor = new LibraryMonitor(LogManager, TaskManager, LibraryManager, ServerConfigurationManager);
|
||||||
RegisterSingleInstance(DirectoryWatchers);
|
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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user