|
|
@ -1,5 +1,3 @@
|
|
|
|
#pragma warning disable CS1591
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using System;
|
|
|
|
using System.Collections.Concurrent;
|
|
|
|
using System.Collections.Concurrent;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Collections.Generic;
|
|
|
@ -11,11 +9,13 @@ using MediaBrowser.Controller.Configuration;
|
|
|
|
using MediaBrowser.Controller.Entities;
|
|
|
|
using MediaBrowser.Controller.Entities;
|
|
|
|
using MediaBrowser.Controller.Library;
|
|
|
|
using MediaBrowser.Controller.Library;
|
|
|
|
using MediaBrowser.Model.IO;
|
|
|
|
using MediaBrowser.Model.IO;
|
|
|
|
|
|
|
|
using Microsoft.Extensions.Hosting;
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Emby.Server.Implementations.IO
|
|
|
|
namespace Emby.Server.Implementations.IO
|
|
|
|
{
|
|
|
|
{
|
|
|
|
public class LibraryMonitor : ILibraryMonitor
|
|
|
|
/// <inheritdoc cref="ILibraryMonitor" />
|
|
|
|
|
|
|
|
public sealed class LibraryMonitor : ILibraryMonitor, IDisposable
|
|
|
|
{
|
|
|
|
{
|
|
|
|
private readonly ILogger<LibraryMonitor> _logger;
|
|
|
|
private readonly ILogger<LibraryMonitor> _logger;
|
|
|
|
private readonly ILibraryManager _libraryManager;
|
|
|
|
private readonly ILibraryManager _libraryManager;
|
|
|
@ -25,19 +25,19 @@ namespace Emby.Server.Implementations.IO
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// The file system watchers.
|
|
|
|
/// The file system watchers.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
private readonly ConcurrentDictionary<string, FileSystemWatcher> _fileSystemWatchers = new ConcurrentDictionary<string, FileSystemWatcher>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
private readonly ConcurrentDictionary<string, FileSystemWatcher> _fileSystemWatchers = new(StringComparer.OrdinalIgnoreCase);
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// The affected paths.
|
|
|
|
/// The affected paths.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
private readonly List<FileRefresher> _activeRefreshers = new List<FileRefresher>();
|
|
|
|
private readonly List<FileRefresher> _activeRefreshers = [];
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// A dynamic list of paths that should be ignored. Added to during our own file system modifications.
|
|
|
|
/// A dynamic list of paths that should be ignored. Added to during our own file system modifications.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
private readonly ConcurrentDictionary<string, string> _tempIgnoredPaths = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
private readonly ConcurrentDictionary<string, string> _tempIgnoredPaths = new(StringComparer.OrdinalIgnoreCase);
|
|
|
|
|
|
|
|
|
|
|
|
private bool _disposed = false;
|
|
|
|
private bool _disposed;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// Initializes a new instance of the <see cref="LibraryMonitor" /> class.
|
|
|
|
/// Initializes a new instance of the <see cref="LibraryMonitor" /> class.
|
|
|
@ -46,34 +46,31 @@ namespace Emby.Server.Implementations.IO
|
|
|
|
/// <param name="libraryManager">The library manager.</param>
|
|
|
|
/// <param name="libraryManager">The library manager.</param>
|
|
|
|
/// <param name="configurationManager">The configuration manager.</param>
|
|
|
|
/// <param name="configurationManager">The configuration manager.</param>
|
|
|
|
/// <param name="fileSystem">The filesystem.</param>
|
|
|
|
/// <param name="fileSystem">The filesystem.</param>
|
|
|
|
|
|
|
|
/// <param name="appLifetime">The <see cref="IHostApplicationLifetime"/>.</param>
|
|
|
|
public LibraryMonitor(
|
|
|
|
public LibraryMonitor(
|
|
|
|
ILogger<LibraryMonitor> logger,
|
|
|
|
ILogger<LibraryMonitor> logger,
|
|
|
|
ILibraryManager libraryManager,
|
|
|
|
ILibraryManager libraryManager,
|
|
|
|
IServerConfigurationManager configurationManager,
|
|
|
|
IServerConfigurationManager configurationManager,
|
|
|
|
IFileSystem fileSystem)
|
|
|
|
IFileSystem fileSystem,
|
|
|
|
|
|
|
|
IHostApplicationLifetime appLifetime)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
_libraryManager = libraryManager;
|
|
|
|
_libraryManager = libraryManager;
|
|
|
|
_logger = logger;
|
|
|
|
_logger = logger;
|
|
|
|
_configurationManager = configurationManager;
|
|
|
|
_configurationManager = configurationManager;
|
|
|
|
_fileSystem = fileSystem;
|
|
|
|
_fileSystem = fileSystem;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
appLifetime.ApplicationStarted.Register(Start);
|
|
|
|
/// 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>
|
|
|
|
|
|
|
|
private void TemporarilyIgnore(string path)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
_tempIgnoredPaths[path] = path;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
public void ReportFileSystemChangeBeginning(string path)
|
|
|
|
public void ReportFileSystemChangeBeginning(string path)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
ArgumentException.ThrowIfNullOrEmpty(path);
|
|
|
|
ArgumentException.ThrowIfNullOrEmpty(path);
|
|
|
|
|
|
|
|
|
|
|
|
TemporarilyIgnore(path);
|
|
|
|
_tempIgnoredPaths[path] = path;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
public async void ReportFileSystemChangeComplete(string path, bool refreshPath)
|
|
|
|
public async void ReportFileSystemChangeComplete(string path, bool refreshPath)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
ArgumentException.ThrowIfNullOrEmpty(path);
|
|
|
|
ArgumentException.ThrowIfNullOrEmpty(path);
|
|
|
@ -107,14 +104,10 @@ namespace Emby.Server.Implementations.IO
|
|
|
|
|
|
|
|
|
|
|
|
var options = _libraryManager.GetLibraryOptions(item);
|
|
|
|
var options = _libraryManager.GetLibraryOptions(item);
|
|
|
|
|
|
|
|
|
|
|
|
if (options is not null)
|
|
|
|
return options is not null && options.EnableRealtimeMonitor;
|
|
|
|
{
|
|
|
|
|
|
|
|
return options.EnableRealtimeMonitor;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
public void Start()
|
|
|
|
public void Start()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
_libraryManager.ItemAdded += OnLibraryManagerItemAdded;
|
|
|
|
_libraryManager.ItemAdded += OnLibraryManagerItemAdded;
|
|
|
@ -306,20 +299,11 @@ namespace Emby.Server.Implementations.IO
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (removeFromList)
|
|
|
|
if (removeFromList)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
RemoveWatcherFromList(watcher);
|
|
|
|
_fileSystemWatchers.TryRemove(watcher.Path, out _);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Removes the watcher from list.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
/// <param name="watcher">The watcher.</param>
|
|
|
|
|
|
|
|
private void RemoveWatcherFromList(FileSystemWatcher watcher)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
_fileSystemWatchers.TryRemove(watcher.Path, out _);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// Handles the Error event of the watcher control.
|
|
|
|
/// Handles the Error event of the watcher control.
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
@ -352,6 +336,7 @@ namespace Emby.Server.Implementations.IO
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
public void ReportFileSystemChanged(string path)
|
|
|
|
public void ReportFileSystemChanged(string path)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
ArgumentException.ThrowIfNullOrEmpty(path);
|
|
|
|
ArgumentException.ThrowIfNullOrEmpty(path);
|
|
|
@ -479,31 +464,15 @@ namespace Emby.Server.Implementations.IO
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <inheritdoc />
|
|
|
|
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
public void Dispose()
|
|
|
|
{
|
|
|
|
|
|
|
|
Dispose(true);
|
|
|
|
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Releases unmanaged and - optionally - managed resources.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
|
|
|
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (_disposed)
|
|
|
|
if (_disposed)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (disposing)
|
|
|
|
Stop();
|
|
|
|
{
|
|
|
|
|
|
|
|
Stop();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_disposed = true;
|
|
|
|
_disposed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|