diff options
| author | Bond-009 <bond.009@outlook.com> | 2023-11-22 12:57:41 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-11-22 12:57:41 +0100 |
| commit | 547d8c07b3fb20ff18c119bbadb5a74c81703d4f (patch) | |
| tree | b245675270f3cfd961292f9b6f4925c07dae2dc8 | |
| parent | 2f87158e682fc4f7257053d4792bf390c0fe4a0f (diff) | |
| parent | 4e61c2b4ec7ff1a25ac7b8e71bcf6a2833f78e75 (diff) | |
Merge pull request #10592 from barronpm/librarychangednotifier-cleanup
LibraryChangedNotifier Cleanup
| -rw-r--r-- | Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs | 668 |
1 files changed, 285 insertions, 383 deletions
diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs index be36bbd2c..a83d7a410 100644 --- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs @@ -1,7 +1,3 @@ -#nullable disable - -#pragma warning disable CS1591 - using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -23,476 +19,382 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Session; using Microsoft.Extensions.Logging; -namespace Emby.Server.Implementations.EntryPoints +namespace Emby.Server.Implementations.EntryPoints; + +/// <summary> +/// A <see cref="IServerEntryPoint"/> that notifies users when libraries are updated. +/// </summary> +public sealed class LibraryChangedNotifier : IServerEntryPoint { - public class LibraryChangedNotifier : IServerEntryPoint + private readonly ILibraryManager _libraryManager; + private readonly IServerConfigurationManager _configurationManager; + private readonly IProviderManager _providerManager; + private readonly ISessionManager _sessionManager; + private readonly IUserManager _userManager; + private readonly ILogger<LibraryChangedNotifier> _logger; + + private readonly object _libraryChangedSyncLock = new(); + private readonly List<Folder> _foldersAddedTo = new(); + private readonly List<Folder> _foldersRemovedFrom = new(); + private readonly List<BaseItem> _itemsAdded = new(); + private readonly List<BaseItem> _itemsRemoved = new(); + private readonly List<BaseItem> _itemsUpdated = new(); + private readonly ConcurrentDictionary<Guid, DateTime> _lastProgressMessageTimes = new(); + + private Timer? _libraryUpdateTimer; + + /// <summary> + /// Initializes a new instance of the <see cref="LibraryChangedNotifier"/> class. + /// </summary> + /// <param name="libraryManager">The <see cref="ILibraryManager"/>.</param> + /// <param name="configurationManager">The <see cref="IServerConfigurationManager"/>.</param> + /// <param name="sessionManager">The <see cref="ISessionManager"/>.</param> + /// <param name="userManager">The <see cref="IUserManager"/>.</param> + /// <param name="logger">The <see cref="ILogger"/>.</param> + /// <param name="providerManager">The <see cref="IProviderManager"/>.</param> + public LibraryChangedNotifier( + ILibraryManager libraryManager, + IServerConfigurationManager configurationManager, + ISessionManager sessionManager, + IUserManager userManager, + ILogger<LibraryChangedNotifier> logger, + IProviderManager providerManager) { - private readonly ILibraryManager _libraryManager; - private readonly IServerConfigurationManager _configurationManager; - private readonly IProviderManager _providerManager; - private readonly ISessionManager _sessionManager; - private readonly IUserManager _userManager; - private readonly ILogger<LibraryChangedNotifier> _logger; - - /// <summary> - /// The library changed sync lock. - /// </summary> - private readonly object _libraryChangedSyncLock = new object(); - - private readonly List<Folder> _foldersAddedTo = new List<Folder>(); - private readonly List<Folder> _foldersRemovedFrom = new List<Folder>(); - private readonly List<BaseItem> _itemsAdded = new List<BaseItem>(); - private readonly List<BaseItem> _itemsRemoved = new List<BaseItem>(); - private readonly List<BaseItem> _itemsUpdated = new List<BaseItem>(); - private readonly ConcurrentDictionary<Guid, DateTime> _lastProgressMessageTimes = new ConcurrentDictionary<Guid, DateTime>(); - - public LibraryChangedNotifier( - ILibraryManager libraryManager, - IServerConfigurationManager configurationManager, - ISessionManager sessionManager, - IUserManager userManager, - ILogger<LibraryChangedNotifier> logger, - IProviderManager providerManager) - { - _libraryManager = libraryManager; - _configurationManager = configurationManager; - _sessionManager = sessionManager; - _userManager = userManager; - _logger = logger; - _providerManager = providerManager; - } + _libraryManager = libraryManager; + _configurationManager = configurationManager; + _sessionManager = sessionManager; + _userManager = userManager; + _logger = logger; + _providerManager = providerManager; + } - /// <summary> - /// Gets or sets the library update timer. - /// </summary> - /// <value>The library update timer.</value> - private Timer LibraryUpdateTimer { get; set; } + /// <inheritdoc /> + public Task RunAsync() + { + _libraryManager.ItemAdded += OnLibraryItemAdded; + _libraryManager.ItemUpdated += OnLibraryItemUpdated; + _libraryManager.ItemRemoved += OnLibraryItemRemoved; - public Task RunAsync() - { - _libraryManager.ItemAdded += OnLibraryItemAdded; - _libraryManager.ItemUpdated += OnLibraryItemUpdated; - _libraryManager.ItemRemoved += OnLibraryItemRemoved; + _providerManager.RefreshCompleted += OnProviderRefreshCompleted; + _providerManager.RefreshStarted += OnProviderRefreshStarted; + _providerManager.RefreshProgress += OnProviderRefreshProgress; - _providerManager.RefreshCompleted += OnProviderRefreshCompleted; - _providerManager.RefreshStarted += OnProviderRefreshStarted; - _providerManager.RefreshProgress += OnProviderRefreshProgress; + return Task.CompletedTask; + } - return Task.CompletedTask; - } + private void OnProviderRefreshProgress(object? sender, GenericEventArgs<Tuple<BaseItem, double>> e) + { + var item = e.Argument.Item1; - private void OnProviderRefreshProgress(object sender, GenericEventArgs<Tuple<BaseItem, double>> e) + if (!EnableRefreshMessage(item)) { - var item = e.Argument.Item1; + return; + } - if (!EnableRefreshMessage(item)) + var progress = e.Argument.Item2; + + if (_lastProgressMessageTimes.TryGetValue(item.Id, out var lastMessageSendTime)) + { + if (progress > 0 && progress < 100 && (DateTime.UtcNow - lastMessageSendTime).TotalMilliseconds < 1000) { return; } + } - var progress = e.Argument.Item2; + _lastProgressMessageTimes.AddOrUpdate(item.Id, _ => DateTime.UtcNow, (_, _) => DateTime.UtcNow); - if (_lastProgressMessageTimes.TryGetValue(item.Id, out var lastMessageSendTime)) - { - if (progress > 0 && progress < 100 && (DateTime.UtcNow - lastMessageSendTime).TotalMilliseconds < 1000) - { - return; - } - } + var dict = new Dictionary<string, string>(); + dict["ItemId"] = item.Id.ToString("N", CultureInfo.InvariantCulture); + dict["Progress"] = progress.ToString(CultureInfo.InvariantCulture); - _lastProgressMessageTimes.AddOrUpdate(item.Id, _ => DateTime.UtcNow, (_, _) => DateTime.UtcNow); + try + { + _sessionManager.SendMessageToAdminSessions(SessionMessageType.RefreshProgress, dict, CancellationToken.None); + } + catch + { + } - var dict = new Dictionary<string, string>(); - dict["ItemId"] = item.Id.ToString("N", CultureInfo.InvariantCulture); - dict["Progress"] = progress.ToString(CultureInfo.InvariantCulture); + var collectionFolders = _libraryManager.GetCollectionFolders(item); + + foreach (var collectionFolder in collectionFolders) + { + var collectionFolderDict = new Dictionary<string, string> + { + ["ItemId"] = collectionFolder.Id.ToString("N", CultureInfo.InvariantCulture), + ["Progress"] = (collectionFolder.GetRefreshProgress() ?? 0).ToString(CultureInfo.InvariantCulture) + }; try { - _sessionManager.SendMessageToAdminSessions(SessionMessageType.RefreshProgress, dict, CancellationToken.None); + _sessionManager.SendMessageToAdminSessions(SessionMessageType.RefreshProgress, collectionFolderDict, CancellationToken.None); } catch { } + } + } - var collectionFolders = _libraryManager.GetCollectionFolders(item); + private void OnProviderRefreshStarted(object? sender, GenericEventArgs<BaseItem> e) + { + OnProviderRefreshProgress(sender, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(e.Argument, 0))); + } - foreach (var collectionFolder in collectionFolders) - { - var collectionFolderDict = new Dictionary<string, string> - { - ["ItemId"] = collectionFolder.Id.ToString("N", CultureInfo.InvariantCulture), - ["Progress"] = (collectionFolder.GetRefreshProgress() ?? 0).ToString(CultureInfo.InvariantCulture) - }; - - try - { - _sessionManager.SendMessageToAdminSessions(SessionMessageType.RefreshProgress, collectionFolderDict, CancellationToken.None); - } - catch - { - } - } - } + private void OnProviderRefreshCompleted(object? sender, GenericEventArgs<BaseItem> e) + { + OnProviderRefreshProgress(sender, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(e.Argument, 100))); - private void OnProviderRefreshStarted(object sender, GenericEventArgs<BaseItem> e) - { - OnProviderRefreshProgress(sender, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(e.Argument, 0))); - } + _lastProgressMessageTimes.TryRemove(e.Argument.Id, out _); + } - private void OnProviderRefreshCompleted(object sender, GenericEventArgs<BaseItem> e) - { - OnProviderRefreshProgress(sender, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(e.Argument, 100))); + private static bool EnableRefreshMessage(BaseItem item) + => item is Folder { IsRoot: false, IsTopParent: true } + and not (AggregateFolder or UserRootFolder or UserView or Channel); - _lastProgressMessageTimes.TryRemove(e.Argument.Id, out _); - } + private void OnLibraryItemAdded(object? sender, ItemChangeEventArgs e) + => OnLibraryChange(e.Item, e.Parent, _itemsAdded, _foldersAddedTo); - private static bool EnableRefreshMessage(BaseItem item) + private void OnLibraryItemUpdated(object? sender, ItemChangeEventArgs e) + => OnLibraryChange(e.Item, e.Parent, _itemsUpdated, null); + + private void OnLibraryItemRemoved(object? sender, ItemChangeEventArgs e) + => OnLibraryChange(e.Item, e.Parent, _itemsRemoved, _foldersRemovedFrom); + + private void OnLibraryChange(BaseItem item, BaseItem parent, List<BaseItem> itemsList, List<Folder>? foldersList) + { + if (!FilterItem(item)) { - if (item is not Folder folder) - { - return false; - } + return; + } - if (folder.IsRoot) - { - return false; - } + lock (_libraryChangedSyncLock) + { + var updateDuration = TimeSpan.FromSeconds(_configurationManager.Configuration.LibraryUpdateDuration); - if (folder is AggregateFolder || folder is UserRootFolder) + if (_libraryUpdateTimer is null) { - return false; + _libraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, updateDuration, Timeout.InfiniteTimeSpan); } - - if (folder is UserView || folder is Channel) + else { - return false; + _libraryUpdateTimer.Change(updateDuration, Timeout.InfiniteTimeSpan); } - if (!folder.IsTopParent) + if (foldersList is not null && parent is Folder folder) { - return false; + foldersList.Add(folder); } - return true; + itemsList.Add(item); } + } - /// <summary> - /// Handles the ItemAdded event of the libraryManager control. - /// </summary> - /// <param name="sender">The source of the event.</param> - /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param> - private void OnLibraryItemAdded(object sender, ItemChangeEventArgs e) + private async void LibraryUpdateTimerCallback(object? state) + { + List<Folder> foldersAddedTo; + List<Folder> foldersRemovedFrom; + List<BaseItem> itemsUpdated; + List<BaseItem> itemsAdded; + List<BaseItem> itemsRemoved; + lock (_libraryChangedSyncLock) { - if (!FilterItem(e.Item)) - { - return; - } + // Remove dupes in case some were saved multiple times + foldersAddedTo = _foldersAddedTo + .DistinctBy(x => x.Id) + .ToList(); - lock (_libraryChangedSyncLock) + foldersRemovedFrom = _foldersRemovedFrom + .DistinctBy(x => x.Id) + .ToList(); + + itemsUpdated = _itemsUpdated + .Where(i => !_itemsAdded.Contains(i)) + .DistinctBy(x => x.Id) + .ToList(); + + itemsAdded = _itemsAdded.ToList(); + itemsRemoved = _itemsRemoved.ToList(); + + if (_libraryUpdateTimer is not null) { - if (LibraryUpdateTimer is null) - { - LibraryUpdateTimer = new Timer( - LibraryUpdateTimerCallback, - null, - TimeSpan.FromSeconds(_configurationManager.Configuration.LibraryUpdateDuration), - Timeout.InfiniteTimeSpan); - } - else - { - LibraryUpdateTimer.Change(TimeSpan.FromSeconds(_configurationManager.Configuration.LibraryUpdateDuration), Timeout.InfiniteTimeSpan); - } - - if (e.Item.GetParent() is Folder parent) - { - _foldersAddedTo.Add(parent); - } - - _itemsAdded.Add(e.Item); + _libraryUpdateTimer.Dispose(); + _libraryUpdateTimer = null; } + + _itemsAdded.Clear(); + _itemsRemoved.Clear(); + _itemsUpdated.Clear(); + _foldersAddedTo.Clear(); + _foldersRemovedFrom.Clear(); } - /// <summary> - /// Handles the ItemUpdated event of the libraryManager control. - /// </summary> - /// <param name="sender">The source of the event.</param> - /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param> - private void OnLibraryItemUpdated(object sender, ItemChangeEventArgs e) + await SendChangeNotifications(itemsAdded, itemsUpdated, itemsRemoved, foldersAddedTo, foldersRemovedFrom, CancellationToken.None).ConfigureAwait(false); + } + + private async Task SendChangeNotifications( + List<BaseItem> itemsAdded, + List<BaseItem> itemsUpdated, + List<BaseItem> itemsRemoved, + List<Folder> foldersAddedTo, + List<Folder> foldersRemovedFrom, + CancellationToken cancellationToken) + { + var userIds = _sessionManager.Sessions + .Select(i => i.UserId) + .Where(i => !i.Equals(default)) + .Distinct() + .ToArray(); + + foreach (var userId in userIds) { - if (!FilterItem(e.Item)) - { - return; - } + LibraryUpdateInfo info; - lock (_libraryChangedSyncLock) + try { - if (LibraryUpdateTimer is null) - { - LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, TimeSpan.FromSeconds(_configurationManager.Configuration.LibraryUpdateDuration), Timeout.InfiniteTimeSpan); - } - else - { - LibraryUpdateTimer.Change(TimeSpan.FromSeconds(_configurationManager.Configuration.LibraryUpdateDuration), Timeout.InfiniteTimeSpan); - } - - _itemsUpdated.Add(e.Item); + info = GetLibraryUpdateInfo(itemsAdded, itemsUpdated, itemsRemoved, foldersAddedTo, foldersRemovedFrom, userId); } - } - - /// <summary> - /// Handles the ItemRemoved event of the libraryManager control. - /// </summary> - /// <param name="sender">The source of the event.</param> - /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param> - private void OnLibraryItemRemoved(object sender, ItemChangeEventArgs e) - { - if (!FilterItem(e.Item)) + catch (Exception ex) { + _logger.LogError(ex, "Error in GetLibraryUpdateInfo"); return; } - lock (_libraryChangedSyncLock) + if (info.IsEmpty) { - if (LibraryUpdateTimer is null) - { - LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, TimeSpan.FromSeconds(_configurationManager.Configuration.LibraryUpdateDuration), Timeout.InfiniteTimeSpan); - } - else - { - LibraryUpdateTimer.Change(TimeSpan.FromSeconds(_configurationManager.Configuration.LibraryUpdateDuration), Timeout.InfiniteTimeSpan); - } - - if (e.Parent is Folder parent) - { - _foldersRemovedFrom.Add(parent); - } - - _itemsRemoved.Add(e.Item); + continue; } - } - /// <summary> - /// Libraries the update timer callback. - /// </summary> - /// <param name="state">The state.</param> - private async void LibraryUpdateTimerCallback(object state) - { - List<Folder> foldersAddedTo; - List<Folder> foldersRemovedFrom; - List<BaseItem> itemsUpdated; - List<BaseItem> itemsAdded; - List<BaseItem> itemsRemoved; - lock (_libraryChangedSyncLock) + try { - // Remove dupes in case some were saved multiple times - foldersAddedTo = _foldersAddedTo - .DistinctBy(x => x.Id) - .ToList(); - - foldersRemovedFrom = _foldersRemovedFrom - .DistinctBy(x => x.Id) - .ToList(); - - itemsUpdated = _itemsUpdated - .Where(i => !_itemsAdded.Contains(i)) - .DistinctBy(x => x.Id) - .ToList(); - - itemsAdded = _itemsAdded.ToList(); - itemsRemoved = _itemsRemoved.ToList(); - - if (LibraryUpdateTimer is not null) - { - LibraryUpdateTimer.Dispose(); - LibraryUpdateTimer = null; - } - - _itemsAdded.Clear(); - _itemsRemoved.Clear(); - _itemsUpdated.Clear(); - _foldersAddedTo.Clear(); - _foldersRemovedFrom.Clear(); + await _sessionManager.SendMessageToUserSessions( + new List<Guid> { userId }, + SessionMessageType.LibraryChanged, + info, + cancellationToken) + .ConfigureAwait(false); } - - await SendChangeNotifications(itemsAdded, itemsUpdated, itemsRemoved, foldersAddedTo, foldersRemovedFrom, CancellationToken.None).ConfigureAwait(false); - } - - /// <summary> - /// Sends the change notifications. - /// </summary> - /// <param name="itemsAdded">The items added.</param> - /// <param name="itemsUpdated">The items updated.</param> - /// <param name="itemsRemoved">The items removed.</param> - /// <param name="foldersAddedTo">The folders added to.</param> - /// <param name="foldersRemovedFrom">The folders removed from.</param> - /// <param name="cancellationToken">The cancellation token.</param> - private async Task SendChangeNotifications(List<BaseItem> itemsAdded, List<BaseItem> itemsUpdated, List<BaseItem> itemsRemoved, List<Folder> foldersAddedTo, List<Folder> foldersRemovedFrom, CancellationToken cancellationToken) - { - var userIds = _sessionManager.Sessions - .Select(i => i.UserId) - .Where(i => !i.Equals(default)) - .Distinct() - .ToArray(); - - foreach (var userId in userIds) + catch (Exception ex) { - LibraryUpdateInfo info; - - try - { - info = GetLibraryUpdateInfo(itemsAdded, itemsUpdated, itemsRemoved, foldersAddedTo, foldersRemovedFrom, userId); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error in GetLibraryUpdateInfo"); - return; - } - - if (info.IsEmpty) - { - continue; - } - - try - { - await _sessionManager.SendMessageToUserSessions(new List<Guid> { userId }, SessionMessageType.LibraryChanged, info, cancellationToken).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error sending LibraryChanged message"); - } + _logger.LogError(ex, "Error sending LibraryChanged message"); } } + } - /// <summary> - /// Gets the library update info. - /// </summary> - /// <param name="itemsAdded">The items added.</param> - /// <param name="itemsUpdated">The items updated.</param> - /// <param name="itemsRemoved">The items removed.</param> - /// <param name="foldersAddedTo">The folders added to.</param> - /// <param name="foldersRemovedFrom">The folders removed from.</param> - /// <param name="userId">The user id.</param> - /// <returns>LibraryUpdateInfo.</returns> - private LibraryUpdateInfo GetLibraryUpdateInfo(List<BaseItem> itemsAdded, List<BaseItem> itemsUpdated, List<BaseItem> itemsRemoved, List<Folder> foldersAddedTo, List<Folder> foldersRemovedFrom, Guid userId) - { - var user = _userManager.GetUserById(userId); - - var newAndRemoved = new List<BaseItem>(); - newAndRemoved.AddRange(foldersAddedTo); - newAndRemoved.AddRange(foldersRemovedFrom); - - var allUserRootChildren = _libraryManager.GetUserRootFolder().GetChildren(user, true).OfType<Folder>().ToList(); - - return new LibraryUpdateInfo - { - ItemsAdded = itemsAdded.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)).Distinct().ToArray(), - - ItemsUpdated = itemsUpdated.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)).Distinct().ToArray(), - - ItemsRemoved = itemsRemoved.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, true)).Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)).Distinct().ToArray(), + private LibraryUpdateInfo GetLibraryUpdateInfo( + List<BaseItem> itemsAdded, + List<BaseItem> itemsUpdated, + List<BaseItem> itemsRemoved, + List<Folder> foldersAddedTo, + List<Folder> foldersRemovedFrom, + Guid userId) + { + var user = _userManager.GetUserById(userId); + ArgumentNullException.ThrowIfNull(user); - FoldersAddedTo = foldersAddedTo.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)).Distinct().ToArray(), + var newAndRemoved = new List<BaseItem>(); + newAndRemoved.AddRange(foldersAddedTo); + newAndRemoved.AddRange(foldersRemovedFrom); - FoldersRemovedFrom = foldersRemovedFrom.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)).Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)).Distinct().ToArray(), + var allUserRootChildren = _libraryManager.GetUserRootFolder() + .GetChildren(user, true) + .OfType<Folder>() + .ToList(); - CollectionFolders = GetTopParentIds(newAndRemoved, allUserRootChildren).ToArray() - }; - } - - private static bool FilterItem(BaseItem item) + return new LibraryUpdateInfo { - if (!item.IsFolder && !item.HasPathProtocol) - { - return false; - } - - if (item is IItemByName && item is not MusicArtist) - { - return false; - } + ItemsAdded = itemsAdded.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)) + .Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)) + .Distinct() + .ToArray(), + ItemsUpdated = itemsUpdated.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)) + .Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)) + .Distinct() + .ToArray(), + ItemsRemoved = itemsRemoved.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user, true)) + .Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)) + .Distinct() + .ToArray(), + FoldersAddedTo = foldersAddedTo.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)) + .Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)) + .Distinct() + .ToArray(), + FoldersRemovedFrom = foldersRemovedFrom.SelectMany(i => TranslatePhysicalItemToUserLibrary(i, user)) + .Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture)) + .Distinct() + .ToArray(), + CollectionFolders = GetTopParentIds(newAndRemoved, allUserRootChildren).ToArray() + }; + } - return item.SourceType == SourceType.Library; + private static bool FilterItem(BaseItem item) + { + if (!item.IsFolder && !item.HasPathProtocol) + { + return false; } - private IEnumerable<string> GetTopParentIds(List<BaseItem> items, List<Folder> allUserRootChildren) + if (item is IItemByName && item is not MusicArtist) { - var list = new List<string>(); + return false; + } - foreach (var item in items) - { - // If the physical root changed, return the user root - if (item is AggregateFolder) - { - continue; - } - - foreach (var folder in allUserRootChildren) - { - list.Add(folder.Id.ToString("N", CultureInfo.InvariantCulture)); - } - } + return item.SourceType == SourceType.Library; + } - return list.Distinct(StringComparer.Ordinal); - } + private IEnumerable<string> GetTopParentIds(List<BaseItem> items, List<Folder> allUserRootChildren) + { + var list = new List<string>(); - /// <summary> - /// Translates the physical item to user library. - /// </summary> - /// <typeparam name="T">The type of item.</typeparam> - /// <param name="item">The item.</param> - /// <param name="user">The user.</param> - /// <param name="includeIfNotFound">if set to <c>true</c> [include if not found].</param> - /// <returns>IEnumerable{``0}.</returns> - private IEnumerable<T> TranslatePhysicalItemToUserLibrary<T>(T item, User user, bool includeIfNotFound = false) - where T : BaseItem + foreach (var item in items) { // If the physical root changed, return the user root if (item is AggregateFolder) { - return new[] { _libraryManager.GetUserRootFolder() as T }; + continue; } - // Return it only if it's in the user's library - if (includeIfNotFound || item.IsVisibleStandalone(user)) + foreach (var folder in allUserRootChildren) { - return new[] { item }; + list.Add(folder.Id.ToString("N", CultureInfo.InvariantCulture)); } + } - return Array.Empty<T>(); + return list.Distinct(StringComparer.Ordinal); + } + + private IEnumerable<T> TranslatePhysicalItemToUserLibrary<T>(T item, User user, bool includeIfNotFound = false) + where T : BaseItem + { + // If the physical root changed, return the user root + if (item is AggregateFolder) + { + return _libraryManager.GetUserRootFolder() is T t ? new[] { t } : Array.Empty<T>(); } - /// <summary> - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// </summary> - public void Dispose() + // Return it only if it's in the user's library + if (includeIfNotFound || item.IsVisibleStandalone(user)) { - Dispose(true); - GC.SuppressFinalize(this); + return new[] { item }; } - /// <summary> - /// Releases unmanaged and - optionally - managed resources. - /// </summary> - /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> - protected virtual void Dispose(bool dispose) + return Array.Empty<T>(); + } + + /// <inheritdoc /> + public void Dispose() + { + _libraryManager.ItemAdded -= OnLibraryItemAdded; + _libraryManager.ItemUpdated -= OnLibraryItemUpdated; + _libraryManager.ItemRemoved -= OnLibraryItemRemoved; + + _providerManager.RefreshCompleted -= OnProviderRefreshCompleted; + _providerManager.RefreshStarted -= OnProviderRefreshStarted; + _providerManager.RefreshProgress -= OnProviderRefreshProgress; + + if (_libraryUpdateTimer is not null) { - if (dispose) - { - if (LibraryUpdateTimer is not null) - { - LibraryUpdateTimer.Dispose(); - LibraryUpdateTimer = null; - } - - _libraryManager.ItemAdded -= OnLibraryItemAdded; - _libraryManager.ItemUpdated -= OnLibraryItemUpdated; - _libraryManager.ItemRemoved -= OnLibraryItemRemoved; - - _providerManager.RefreshCompleted -= OnProviderRefreshCompleted; - _providerManager.RefreshStarted -= OnProviderRefreshStarted; - _providerManager.RefreshProgress -= OnProviderRefreshProgress; - } + _libraryUpdateTimer.Dispose(); + _libraryUpdateTimer = null; } } } |
