diff options
| author | softworkz <softworkz@hotmail.com> | 2016-08-19 03:00:04 +0200 |
|---|---|---|
| committer | softworkz <softworkz@hotmail.com> | 2016-08-20 01:03:30 +0200 |
| commit | 751febc1de65c9f2811deca66d093503968dd514 (patch) | |
| tree | 37474c3c4822f2a112b13b2c5cd46dd5164d94f6 /MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs | |
| parent | d1da8f4449580dd642ae71580e9c40cab8aedbe3 (diff) | |
Auto-Organize: Async operation and instant feedback UI (reworked)
This commit includes changes to enable and stabilize asyncronous
operation in the auto-organize area. Here are the key points:
- The auto-organize correction dialog is now closed (almost) instantly.
This means that the user does not have to wait until the file copy/move
operation is completed in order to continue. (even with local HDs the
copy/move process can take several minutes or even much longer with
network destination).
- This commit also implements locking of files to be organized in order
to prevent parallel processing of the same item. In effect, there can be
2 or more manual organization operations active even while the normal
auto-organization task is running without causing any problems
- The items that are currently being processed are indicated as such in
the log with an orange color and a spinner graphic
- The client display is refreshed through websocket messages
- A side effect of this is that other clients showing the auto-organize
log at the same time are always up-to-date as well
Diffstat (limited to 'MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs')
| -rw-r--r-- | MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs | 100 |
1 files changed, 94 insertions, 6 deletions
diff --git a/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs b/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs index 9e16613e6..a42eba6ca 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/FileOrganizationService.cs @@ -3,16 +3,21 @@ using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.FileOrganization; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.FileOrganization; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Querying; using System; +using System.Collections.Concurrent; using System.Linq; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Events; +using MediaBrowser.Common.Events; namespace MediaBrowser.Server.Implementations.FileOrganization { @@ -26,6 +31,12 @@ namespace MediaBrowser.Server.Implementations.FileOrganization private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; private readonly IProviderManager _providerManager; + private readonly ConcurrentDictionary<string, bool> _inProgressItemIds = new ConcurrentDictionary<string, bool>(); + + public event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemAdded; + public event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemUpdated; + public event EventHandler<GenericEventArgs<FileOrganizationResult>> ItemRemoved; + public event EventHandler LogReset; public FileOrganizationService(ITaskManager taskManager, IFileOrganizationRepository repo, ILogger logger, ILibraryMonitor libraryMonitor, ILibraryManager libraryManager, IServerConfigurationManager config, IFileSystem fileSystem, IProviderManager providerManager) { @@ -58,12 +69,26 @@ namespace MediaBrowser.Server.Implementations.FileOrganization public QueryResult<FileOrganizationResult> GetResults(FileOrganizationResultQuery query) { - return _repo.GetResults(query); + var results = _repo.GetResults(query); + + foreach (var result in results.Items) + { + result.IsInProgress = _inProgressItemIds.ContainsKey(result.Id); + } + + return results; } public FileOrganizationResult GetResult(string id) { - return _repo.GetResult(id); + var result = _repo.GetResult(id); + + if (result != null) + { + result.IsInProgress = _inProgressItemIds.ContainsKey(result.Id); + } + + return result; } public FileOrganizationResult GetResultBySourcePath(string path) @@ -78,11 +103,17 @@ namespace MediaBrowser.Server.Implementations.FileOrganization return GetResult(id); } - public Task DeleteOriginalFile(string resultId) + public async Task DeleteOriginalFile(string resultId) { var result = _repo.GetResult(resultId); _logger.Info("Requested to delete {0}", result.OriginalPath); + + if (!AddToInProgressList(result, false)) + { + throw new Exception("Path is currently processed otherwise. Please try again later."); + } + try { _fileSystem.DeleteFile(result.OriginalPath); @@ -91,8 +122,14 @@ namespace MediaBrowser.Server.Implementations.FileOrganization { _logger.ErrorException("Error deleting {0}", ex, result.OriginalPath); } + finally + { + RemoveFromInprogressList(result); + } - return _repo.Delete(resultId); + await _repo.Delete(resultId); + + EventHelper.FireEventIfNotNull(ItemRemoved, this, new GenericEventArgs<FileOrganizationResult>(result), _logger); } private AutoOrganizeOptions GetAutoOrganizeOptions() @@ -121,9 +158,10 @@ namespace MediaBrowser.Server.Implementations.FileOrganization } } - public Task ClearLog() + public async Task ClearLog() { - return _repo.DeleteAll(); + await _repo.DeleteAll(); + EventHelper.FireEventIfNotNull(LogReset, this, EventArgs.Empty, _logger); } public async Task PerformEpisodeOrganization(EpisodeFileOrganizationRequest request) @@ -189,5 +227,55 @@ namespace MediaBrowser.Server.Implementations.FileOrganization _config.SaveAutoOrganizeOptions(options); } } + + /// <summary> + /// Attempts to add a an item to the list of currently processed items. + /// </summary> + /// <param name="result">The result item.</param> + /// <param name="isNewItem">Passing true will notify the client to reload all items, otherwise only a single item will be refreshed.</param> + /// <returns>True if the item was added, False if the item is already contained in the list.</returns> + public bool AddToInProgressList(FileOrganizationResult result, bool isNewItem) + { + if (string.IsNullOrWhiteSpace(result.Id)) + { + result.Id = result.OriginalPath.GetMD5().ToString("N"); + } + + if (!_inProgressItemIds.TryAdd(result.Id, false)) + { + return false; + } + + result.IsInProgress = true; + + if (isNewItem) + { + EventHelper.FireEventIfNotNull(ItemAdded, this, new GenericEventArgs<FileOrganizationResult>(result), _logger); + } + else + { + EventHelper.FireEventIfNotNull(ItemUpdated, this, new GenericEventArgs<FileOrganizationResult>(result), _logger); + } + + return true; + } + + /// <summary> + /// Removes an item from the list of currently processed items. + /// </summary> + /// <param name="result">The result item.</param> + /// <returns>True if the item was removed, False if the item was not contained in the list.</returns> + public bool RemoveFromInprogressList(FileOrganizationResult result) + { + bool itemValue; + var retval = _inProgressItemIds.TryRemove(result.Id, out itemValue); + + result.IsInProgress = false; + + EventHelper.FireEventIfNotNull(ItemUpdated, this, new GenericEventArgs<FileOrganizationResult>(result), _logger); + + return retval; + } + } } |
