| 
					
				 | 
			
			
				@@ -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; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 |