From f7720e7c99e0e0f84f6492670dc1bcf83fa0f2fb Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sat, 16 Sep 2023 15:08:45 +0200 Subject: [PATCH 1/6] Extend collections cleanup task to include playlists too --- .../Playlists/PlaylistManager.cs | 5 + .../CleanupCollectionAndPlaylistPathsTask.cs | 147 ++++++++++++++++++ .../Tasks/CleanupCollectionPathsTask.cs | 119 -------------- .../Playlists/IPlaylistManager.cs | 6 + 4 files changed, 158 insertions(+), 119 deletions(-) create mode 100644 Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs delete mode 100644 Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionPathsTask.cs diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index 702f8d45bc..0cb450cdf3 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -518,6 +518,11 @@ namespace Emby.Server.Implementations.Playlists return relativePath; } + public Folder GetPlaylistsFolder() + { + return GetPlaylistsFolder(Guid.Empty); + } + public Folder GetPlaylistsFolder(Guid userId) { const string TypeName = "PlaylistsFolder"; diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs new file mode 100644 index 0000000000..3daa2b6d0a --- /dev/null +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Collections; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Playlists; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Tasks; +using Microsoft.Extensions.Logging; + +namespace Emby.Server.Implementations.ScheduledTasks.Tasks; + +/// +/// Deletes path references from collections and playlists that no longer exists. +/// +public class CleanupCollectionAndPlaylistPathsTask : IScheduledTask +{ + private readonly ILocalizationManager _localization; + private readonly ICollectionManager _collectionManager; + private readonly IPlaylistManager _playlistManager; + private readonly ILogger _logger; + private readonly IProviderManager _providerManager; + private readonly IFileSystem _fileSystem; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// The logger. + /// The provider manager. + /// The filesystem. + public CleanupCollectionAndPlaylistPathsTask( + ILocalizationManager localization, + ICollectionManager collectionManager, + IPlaylistManager playlistManager, + ILogger logger, + IProviderManager providerManager, + IFileSystem fileSystem) + { + _localization = localization; + _collectionManager = collectionManager; + _playlistManager = playlistManager; + _logger = logger; + _providerManager = providerManager; + _fileSystem = fileSystem; + } + + /// + public string Name => _localization.GetLocalizedString("TaskCleanCollectionsAndPlaylists"); + + /// + public string Key => "CleanCollectionsAndPlaylists"; + + /// + public string Description => _localization.GetLocalizedString("TaskCleanCollectionsAndPlaylistsDescription"); + + /// + public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory"); + + /// + public async Task ExecuteAsync(IProgress progress, CancellationToken cancellationToken) + { + var collectionsFolder = await _collectionManager.GetCollectionsFolder(false).ConfigureAwait(false); + if (collectionsFolder is null) + { + _logger.LogDebug("There is no collection folder to be found"); + } + else + { + var collections = collectionsFolder.Children.OfType().ToArray(); + _logger.LogDebug("Found {CollectionLength} boxsets", collections.Length); + + for (var index = 0; index < collections.Length; index++) + { + var collection = collections[index]; + _logger.LogDebug("Checking boxset {CollectionName}", collection.Name); + + CleanupLinkedChildren(collection, cancellationToken); + progress.Report(50D / collections.Length * (index + 1)); + } + } + + var playlistsFolder = _playlistManager.GetPlaylistsFolder(); + if (playlistsFolder is null) + { + _logger.LogDebug("There is no collection folder to be found"); + return; + } + + var playlists = playlistsFolder.Children.OfType().ToArray(); + _logger.LogDebug("Found {PlaylistLength} boxsets", playlists.Length); + + for (var index = 0; index < playlists.Length; index++) + { + var playlist = playlists[index]; + _logger.LogDebug("Checking playlist {PlaylistName}", playlist.Name); + + CleanupLinkedChildren(playlist, cancellationToken); + progress.Report(50D / playlists.Length * (index + 1)); + } + } + + private void CleanupLinkedChildren(T folder, CancellationToken cancellationToken) where T : Folder + { + var itemsToRemove = new List(); + foreach (var linkedChild in folder.LinkedChildren) + { + if (!File.Exists(folder.Path)) + { + _logger.LogInformation("Item in {FolderName} cannot be found at {ItemPath}", folder.Name, linkedChild.Path); + itemsToRemove.Add(linkedChild); + } + } + + if (itemsToRemove.Count != 0) + { + _logger.LogDebug("Updating {FolderName}", folder.Name); + folder.LinkedChildren = folder.LinkedChildren.Except(itemsToRemove).ToArray(); + folder.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, cancellationToken); + + _providerManager.QueueRefresh( + folder.Id, + new MetadataRefreshOptions(new DirectoryService(_fileSystem)) + { + ForceSave = true + }, + RefreshPriority.High); + + itemsToRemove.Clear(); + } + } + + /// + public IEnumerable GetDefaultTriggers() + { + return new[] { new TaskTriggerInfo() { Type = TaskTriggerInfo.TriggerStartup } }; + } +} diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionPathsTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionPathsTask.cs deleted file mode 100644 index f78fc6f970..0000000000 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionPathsTask.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Controller.Collections; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Movies; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Tasks; -using Microsoft.Extensions.Logging; - -namespace Emby.Server.Implementations.ScheduledTasks.Tasks; - -/// -/// Deletes Path references from collections that no longer exists. -/// -public class CleanupCollectionPathsTask : IScheduledTask -{ - private readonly ILocalizationManager _localization; - private readonly ICollectionManager _collectionManager; - private readonly ILogger _logger; - private readonly IProviderManager _providerManager; - private readonly IFileSystem _fileSystem; - - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - /// The logger. - /// The provider manager. - /// The filesystem. - public CleanupCollectionPathsTask( - ILocalizationManager localization, - ICollectionManager collectionManager, - ILogger logger, - IProviderManager providerManager, - IFileSystem fileSystem) - { - _localization = localization; - _collectionManager = collectionManager; - _logger = logger; - _providerManager = providerManager; - _fileSystem = fileSystem; - } - - /// - public string Name => _localization.GetLocalizedString("TaskCleanCollections"); - - /// - public string Key => "CleanCollections"; - - /// - public string Description => _localization.GetLocalizedString("TaskCleanCollectionsDescription"); - - /// - public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory"); - - /// - public async Task ExecuteAsync(IProgress progress, CancellationToken cancellationToken) - { - var collectionsFolder = await _collectionManager.GetCollectionsFolder(false).ConfigureAwait(false); - if (collectionsFolder is null) - { - _logger.LogDebug("There is no collection folder to be found"); - return; - } - - var collections = collectionsFolder.Children.OfType().ToArray(); - _logger.LogDebug("Found {CollectionLength} Boxsets", collections.Length); - - var itemsToRemove = new List(); - for (var index = 0; index < collections.Length; index++) - { - var collection = collections[index]; - _logger.LogDebug("Check Boxset {CollectionName}", collection.Name); - - foreach (var collectionLinkedChild in collection.LinkedChildren) - { - if (!File.Exists(collectionLinkedChild.Path)) - { - _logger.LogInformation("Item in boxset {CollectionName} cannot be found at {ItemPath}", collection.Name, collectionLinkedChild.Path); - itemsToRemove.Add(collectionLinkedChild); - } - } - - if (itemsToRemove.Count != 0) - { - _logger.LogDebug("Update Boxset {CollectionName}", collection.Name); - collection.LinkedChildren = collection.LinkedChildren.Except(itemsToRemove).ToArray(); - await collection.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, cancellationToken) - .ConfigureAwait(false); - - _providerManager.QueueRefresh( - collection.Id, - new MetadataRefreshOptions(new DirectoryService(_fileSystem)) - { - ForceSave = true - }, - RefreshPriority.High); - - itemsToRemove.Clear(); - } - - progress.Report(100D / collections.Length * (index + 1)); - } - } - - /// - public IEnumerable GetDefaultTriggers() - { - return new[] { new TaskTriggerInfo() { Type = TaskTriggerInfo.TriggerStartup } }; - } -} diff --git a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs index d1a51c2cf6..bb68a3b6dd 100644 --- a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs +++ b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs @@ -44,6 +44,12 @@ namespace MediaBrowser.Controller.Playlists /// /// Gets the playlists folder. /// + /// Folder. + Folder GetPlaylistsFolder(); + + /// + /// Gets the playlists folder for a user. + /// /// The user identifier. /// Folder. Folder GetPlaylistsFolder(Guid userId); From 783bb8a8cbd2b105e64d5e33891fd754c5c83182 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sat, 16 Sep 2023 17:05:54 +0200 Subject: [PATCH 2/6] Apply review suggestions --- .../Tasks/CleanupCollectionAndPlaylistPathsTask.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs index 3daa2b6d0a..f30a26863d 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs @@ -72,7 +72,7 @@ public class CleanupCollectionAndPlaylistPathsTask : IScheduledTask var collectionsFolder = await _collectionManager.GetCollectionsFolder(false).ConfigureAwait(false); if (collectionsFolder is null) { - _logger.LogDebug("There is no collection folder to be found"); + _logger.LogDebug("There is no collections folder to be found"); } else { @@ -92,12 +92,12 @@ public class CleanupCollectionAndPlaylistPathsTask : IScheduledTask var playlistsFolder = _playlistManager.GetPlaylistsFolder(); if (playlistsFolder is null) { - _logger.LogDebug("There is no collection folder to be found"); + _logger.LogDebug("There is no playlists folder to be found"); return; } var playlists = playlistsFolder.Children.OfType().ToArray(); - _logger.LogDebug("Found {PlaylistLength} boxsets", playlists.Length); + _logger.LogDebug("Found {PlaylistLength} playlists", playlists.Length); for (var index = 0; index < playlists.Length; index++) { @@ -109,7 +109,8 @@ public class CleanupCollectionAndPlaylistPathsTask : IScheduledTask } } - private void CleanupLinkedChildren(T folder, CancellationToken cancellationToken) where T : Folder + private void CleanupLinkedChildren(T folder, CancellationToken cancellationToken) + where T : Folder { var itemsToRemove = new List(); foreach (var linkedChild in folder.LinkedChildren) From fccea4625d29feb1b91345c6b944e5dc6f062a85 Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Sun, 17 Sep 2023 14:13:19 +0200 Subject: [PATCH 3/6] Update Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs Co-authored-by: Bond-009 --- .../Tasks/CleanupCollectionAndPlaylistPathsTask.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs index f30a26863d..e5af22b319 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs @@ -112,17 +112,17 @@ public class CleanupCollectionAndPlaylistPathsTask : IScheduledTask private void CleanupLinkedChildren(T folder, CancellationToken cancellationToken) where T : Folder { - var itemsToRemove = new List(); + List itemsToRemove = null; foreach (var linkedChild in folder.LinkedChildren) { if (!File.Exists(folder.Path)) { _logger.LogInformation("Item in {FolderName} cannot be found at {ItemPath}", folder.Name, linkedChild.Path); - itemsToRemove.Add(linkedChild); + (itemsToRemove ??= new List()).Add(linkedChild); } } - if (itemsToRemove.Count != 0) + if (itemsToRemove is not null) { _logger.LogDebug("Updating {FolderName}", folder.Name); folder.LinkedChildren = folder.LinkedChildren.Except(itemsToRemove).ToArray(); From 61a49e94c4753eb8dbc421530656962f4a7a33c8 Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Sun, 17 Sep 2023 14:13:25 +0200 Subject: [PATCH 4/6] Update Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs Co-authored-by: Bond-009 --- .../Tasks/CleanupCollectionAndPlaylistPathsTask.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs index e5af22b319..91f3c435c1 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs @@ -136,7 +136,6 @@ public class CleanupCollectionAndPlaylistPathsTask : IScheduledTask }, RefreshPriority.High); - itemsToRemove.Clear(); } } From bce45992d9fa5fd121cbc35af00d2512dbe912fa Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Sun, 17 Sep 2023 16:35:41 +0200 Subject: [PATCH 5/6] Update Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs Co-authored-by: Bond-009 --- .../Tasks/CleanupCollectionAndPlaylistPathsTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs index 91f3c435c1..ef2d1942a5 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs @@ -112,7 +112,7 @@ public class CleanupCollectionAndPlaylistPathsTask : IScheduledTask private void CleanupLinkedChildren(T folder, CancellationToken cancellationToken) where T : Folder { - List itemsToRemove = null; + List? itemsToRemove = null; foreach (var linkedChild in folder.LinkedChildren) { if (!File.Exists(folder.Path)) From 151d678b0ea344ec589f7ce478911b8e079e4f84 Mon Sep 17 00:00:00 2001 From: Tim Eisele Date: Mon, 18 Sep 2023 19:13:33 +0200 Subject: [PATCH 6/6] Update Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs Co-authored-by: Bond-009 --- .../Tasks/CleanupCollectionAndPlaylistPathsTask.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs index ef2d1942a5..acd4bf9056 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs @@ -135,7 +135,6 @@ public class CleanupCollectionAndPlaylistPathsTask : IScheduledTask ForceSave = true }, RefreshPriority.High); - } }