From 763862cbd879aceed9277d79c5e38e851403cfe6 Mon Sep 17 00:00:00 2001 From: cvium Date: Sat, 3 Oct 2020 13:36:53 +0200 Subject: Defer image pre-fetching until the end of a refresh/scan --- .../Library/ImageFetcherPostScanTask.cs | 118 +++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs (limited to 'Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs') diff --git a/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs b/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs new file mode 100644 index 000000000..94d7f3cd6 --- /dev/null +++ b/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Concurrent; +using System.Globalization; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Data.Events; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Providers; +using Microsoft.Extensions.Logging; + +namespace Emby.Server.Implementations.Library +{ + /// + /// Test. + /// + public class ImageFetcherPostScanTask : ILibraryPostScanTask + { + private readonly ILibraryManager _libraryManager; + private readonly IProviderManager _providerManager; + private readonly ILogger _logger; + private readonly SemaphoreSlim _imageFetcherLock; + + private ConcurrentDictionary _queuedItems; + + /// + /// Initializes a new instance of the class. + /// + /// Some stuff. + public ImageFetcherPostScanTask( + ILibraryManager libraryManager, + IProviderManager providerManager, + ILogger logger) + { + _libraryManager = libraryManager; + _providerManager = providerManager; + _logger = logger; + _queuedItems = new ConcurrentDictionary(); + _imageFetcherLock = new SemaphoreSlim(1, 1); + _libraryManager.ItemAdded += OnLibraryManagerItemAddedOrUpdated; + _libraryManager.ItemUpdated += OnLibraryManagerItemAddedOrUpdated; + _providerManager.RefreshCompleted += OnProviderManagerRefreshCompleted; + } + + /// + public async Task Run(IProgress progress, CancellationToken cancellationToken) + { + // Sometimes a library scan will cause this to run twice if there's an item refresh going on. + await _imageFetcherLock.WaitAsync(cancellationToken).ConfigureAwait(false); + + try + { + var now = DateTime.UtcNow; + var itemGuids = _queuedItems.Keys.ToList(); + + for (var i = 0; i < itemGuids.Count; i++) + { + if (!_queuedItems.TryGetValue(itemGuids[i], out var queuedItem)) + { + continue; + } + + _logger.LogDebug( + "Updating remote images for item {ItemId} with media type {ItemMediaType}", + queuedItem.item.Id.ToString("N", CultureInfo.InvariantCulture), + queuedItem.item.GetType()); + await _libraryManager.UpdateImagesAsync(queuedItem.item, queuedItem.updateReason >= ItemUpdateType.ImageUpdate).ConfigureAwait(false); + + _queuedItems.TryRemove(queuedItem.item.Id, out _); + } + + if (itemGuids.Count > 0) + { + _logger.LogInformation( + "Finished updating/pre-fetching {NumberOfImages} images. Elapsed time: {TimeElapsed}s.", + itemGuids.Count.ToString(CultureInfo.InvariantCulture), + (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture)); + } + else + { + _logger.LogDebug("No images were updated."); + } + } + finally + { + _imageFetcherLock.Release(); + } + } + + private void OnLibraryManagerItemAddedOrUpdated(object sender, ItemChangeEventArgs itemChangeEventArgs) + { + if (!_queuedItems.ContainsKey(itemChangeEventArgs.Item.Id) && itemChangeEventArgs.Item.ImageInfos.Length > 0) + { + _queuedItems.AddOrUpdate( + itemChangeEventArgs.Item.Id, + (itemChangeEventArgs.Item, itemChangeEventArgs.UpdateReason), + (key, existingValue) => existingValue); + } + } + + private void OnProviderManagerRefreshCompleted(object sender, GenericEventArgs e) + { + if (!_queuedItems.ContainsKey(e.Argument.Id) && e.Argument.ImageInfos.Length > 0) + { + _queuedItems.AddOrUpdate( + e.Argument.Id, + (e.Argument, ItemUpdateType.None), + (key, existingValue) => existingValue); + } + + // The RefreshCompleted event is a bit awkward in that it seems to _only_ be fired on + // the item that was refreshed regardless of children refreshes. So we take it as a signal + // that the refresh is entirely completed. + Run(null, CancellationToken.None).GetAwaiter().GetResult(); + } + } +} -- cgit v1.2.3 From 5d3449e9dc8c43efa16669a390870c52676bcba5 Mon Sep 17 00:00:00 2001 From: cvium Date: Sat, 3 Oct 2020 13:39:39 +0200 Subject: Fix xml doc comment --- Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs') diff --git a/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs b/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs index 94d7f3cd6..49f920eda 100644 --- a/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs +++ b/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs @@ -13,7 +13,7 @@ using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Library { /// - /// Test. + /// A library post scan/refresh task for pre-fetching remote images. /// public class ImageFetcherPostScanTask : ILibraryPostScanTask { -- cgit v1.2.3 From 1b18f86c8b92eb0c75ee6db27eaffce918afa988 Mon Sep 17 00:00:00 2001 From: cvium Date: Sat, 3 Oct 2020 13:52:51 +0200 Subject: Add missing parameter comments. --- Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs') diff --git a/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs b/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs index 49f920eda..66540b4d4 100644 --- a/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs +++ b/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs @@ -27,7 +27,9 @@ namespace Emby.Server.Implementations.Library /// /// Initializes a new instance of the class. /// - /// Some stuff. + /// An instance of . + /// An instance of . + /// An instance of . public ImageFetcherPostScanTask( ILibraryManager libraryManager, IProviderManager providerManager, -- cgit v1.2.3 From 4a81ee43dc7aed94012c312a8262a1426be9b6d9 Mon Sep 17 00:00:00 2001 From: cvium Date: Tue, 6 Oct 2020 23:36:48 +0200 Subject: Add try-catch to avoid crashing the whole thing --- .../Library/ImageFetcherPostScanTask.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs') diff --git a/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs b/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs index 66540b4d4..b18a0c1a8 100644 --- a/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs +++ b/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs @@ -8,6 +8,7 @@ using Jellyfin.Data.Events; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Net; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Library @@ -63,11 +64,20 @@ namespace Emby.Server.Implementations.Library continue; } + var itemId = queuedItem.item.Id.ToString("N", CultureInfo.InvariantCulture); + var itemType = queuedItem.item.GetType(); _logger.LogDebug( "Updating remote images for item {ItemId} with media type {ItemMediaType}", - queuedItem.item.Id.ToString("N", CultureInfo.InvariantCulture), - queuedItem.item.GetType()); - await _libraryManager.UpdateImagesAsync(queuedItem.item, queuedItem.updateReason >= ItemUpdateType.ImageUpdate).ConfigureAwait(false); + itemId, + itemType); + try + { + await _libraryManager.UpdateImagesAsync(queuedItem.item, queuedItem.updateReason >= ItemUpdateType.ImageUpdate).ConfigureAwait(false); + } + catch (HttpException ex) + { + _logger.LogError(ex, "Failed to fetch images for {Type} item with id {ItemId}", itemType, itemId); + } _queuedItems.TryRemove(queuedItem.item.Id, out _); } -- cgit v1.2.3 From 969b9e2a18aa76fd0b2915960ea799a12a9605a0 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Sat, 21 Nov 2020 23:33:41 +0000 Subject: Update ImageFetcherPostScanTask.cs --- Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs') diff --git a/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs b/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs index b18a0c1a8..d4e790c9a 100644 --- a/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs +++ b/Emby.Server.Implementations/Library/ImageFetcherPostScanTask.cs @@ -74,7 +74,7 @@ namespace Emby.Server.Implementations.Library { await _libraryManager.UpdateImagesAsync(queuedItem.item, queuedItem.updateReason >= ItemUpdateType.ImageUpdate).ConfigureAwait(false); } - catch (HttpException ex) + catch (Exception ex) { _logger.LogError(ex, "Failed to fetch images for {Type} item with id {ItemId}", itemType, itemId); } -- cgit v1.2.3