From 28274d4c757f1bf10b8280b34577a1ef1aaa8823 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Fri, 7 Jun 2024 22:12:48 +0200 Subject: [PATCH 1/7] Remove empty image folders recursively --- MediaBrowser.Providers/Manager/ImageSaver.cs | 4 ++-- MediaBrowser.Providers/Manager/ItemImageProvider.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index e0677aa9fe..b430561155 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -190,9 +190,9 @@ namespace MediaBrowser.Providers.Manager // Remove containing directory if empty var folder = Path.GetDirectoryName(currentPath); - if (!_fileSystem.GetFiles(folder).Any()) + if (Directory.Exists(folder) && !_fileSystem.GetFiles(folder, true).Any()) { - Directory.Delete(folder); + Directory.Delete(folder, true); } } catch (FileNotFoundException) diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index bee420d952..763e5be968 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -381,9 +381,9 @@ namespace MediaBrowser.Providers.Manager { // Always remove empty parent folder var folder = Path.GetDirectoryName(image.Path); - if (Directory.Exists(folder) && !_fileSystem.GetFiles(folder).Any()) + if (Directory.Exists(folder) && !_fileSystem.GetFiles(folder, true).Any()) { - Directory.Delete(folder); + Directory.Delete(folder, true); } } } From feb20c131ad787286acb96ed606f79ac0b86217c Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Fri, 7 Jun 2024 22:12:48 +0200 Subject: [PATCH 2/7] Use helper --- .../IO/ManagedFileSystem.cs | 6 +- .../Tasks/DeleteCacheFileTask.cs | 44 +------------ .../Tasks/DeleteTranscodeFileTask.cs | 45 +------------ .../IO/FileSystemHelper.cs | 64 +++++++++++++++++++ MediaBrowser.Providers/Manager/ImageSaver.cs | 6 +- .../Manager/ItemImageProvider.cs | 6 +- 6 files changed, 77 insertions(+), 94 deletions(-) create mode 100644 MediaBrowser.Controller/IO/FileSystemHelper.cs diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index d5afac2663..250bec9ea9 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -389,7 +389,7 @@ namespace Emby.Server.Implementations.IO var info = new FileInfo(path); if (info.Exists && - ((info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) != isHidden) + (info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden != isHidden) { if (isHidden) { @@ -417,8 +417,8 @@ namespace Emby.Server.Implementations.IO return; } - if (((info.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) == readOnly - && ((info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) == isHidden) + if ((info.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly == readOnly + && (info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden == isHidden) { return; } diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs index 03935b384c..fc3ad90f6c 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.IO; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.Tasks; @@ -133,53 +134,14 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks cancellationToken.ThrowIfCancellationRequested(); - DeleteFile(file.FullName); + FileSystemHelper.DeleteFile(_fileSystem, file.FullName, _logger); index++; } - DeleteEmptyFolders(directory); + FileSystemHelper.DeleteEmptyFolders(_fileSystem, directory, _logger); progress.Report(100); } - - private void DeleteEmptyFolders(string parent) - { - foreach (var directory in _fileSystem.GetDirectoryPaths(parent)) - { - DeleteEmptyFolders(directory); - if (!_fileSystem.GetFileSystemEntryPaths(directory).Any()) - { - try - { - Directory.Delete(directory, false); - } - catch (UnauthorizedAccessException ex) - { - _logger.LogError(ex, "Error deleting directory {Path}", directory); - } - catch (IOException ex) - { - _logger.LogError(ex, "Error deleting directory {Path}", directory); - } - } - } - } - - private void DeleteFile(string path) - { - try - { - _fileSystem.DeleteFile(path); - } - catch (UnauthorizedAccessException ex) - { - _logger.LogError(ex, "Error deleting file {Path}", path); - } - catch (IOException ex) - { - _logger.LogError(ex, "Error deleting file {Path}", path); - } - } } } diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs index e4e565c642..6cb06d31c0 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.IO; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.Tasks; @@ -113,53 +113,14 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks cancellationToken.ThrowIfCancellationRequested(); - DeleteFile(file.FullName); + FileSystemHelper.DeleteFile(_fileSystem, file.FullName, _logger); index++; } - DeleteEmptyFolders(directory); + FileSystemHelper.DeleteEmptyFolders(_fileSystem, directory, _logger); progress.Report(100); } - - private void DeleteEmptyFolders(string parent) - { - foreach (var directory in _fileSystem.GetDirectoryPaths(parent)) - { - DeleteEmptyFolders(directory); - if (!_fileSystem.GetFileSystemEntryPaths(directory).Any()) - { - try - { - Directory.Delete(directory, false); - } - catch (UnauthorizedAccessException ex) - { - _logger.LogError(ex, "Error deleting directory {Path}", directory); - } - catch (IOException ex) - { - _logger.LogError(ex, "Error deleting directory {Path}", directory); - } - } - } - } - - private void DeleteFile(string path) - { - try - { - _fileSystem.DeleteFile(path); - } - catch (UnauthorizedAccessException ex) - { - _logger.LogError(ex, "Error deleting file {Path}", path); - } - catch (IOException ex) - { - _logger.LogError(ex, "Error deleting file {Path}", path); - } - } } } diff --git a/MediaBrowser.Controller/IO/FileSystemHelper.cs b/MediaBrowser.Controller/IO/FileSystemHelper.cs new file mode 100644 index 0000000000..1a33c3aa8c --- /dev/null +++ b/MediaBrowser.Controller/IO/FileSystemHelper.cs @@ -0,0 +1,64 @@ +using System; +using System.IO; +using System.Linq; +using MediaBrowser.Model.IO; +using Microsoft.Extensions.Logging; + +namespace MediaBrowser.Controller.IO; + +/// +/// Helper methods for file system management. +/// +public static class FileSystemHelper +{ + /// + /// Deletes the file. + /// + /// The fileSystem. + /// The path. + /// The logger. + public static void DeleteFile(IFileSystem fileSystem, string path, ILogger logger) + { + try + { + fileSystem.DeleteFile(path); + } + catch (UnauthorizedAccessException ex) + { + logger.LogError(ex, "Error deleting file {Path}", path); + } + catch (IOException ex) + { + logger.LogError(ex, "Error deleting file {Path}", path); + } + } + + /// + /// Recursively delete empty folders. + /// + /// The fileSystem. + /// The path. + /// The logger. + public static void DeleteEmptyFolders(IFileSystem fileSystem, string path, ILogger logger) + { + foreach (var directory in fileSystem.GetDirectoryPaths(path)) + { + DeleteEmptyFolders(fileSystem, directory, logger); + if (!fileSystem.GetFileSystemEntryPaths(directory).Any()) + { + try + { + Directory.Delete(directory, false); + } + catch (UnauthorizedAccessException ex) + { + logger.LogError(ex, "Error deleting directory {Path}", directory); + } + catch (IOException ex) + { + logger.LogError(ex, "Error deleting directory {Path}", directory); + } + } + } + } +} diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index b430561155..7911f35455 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -14,6 +14,7 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; @@ -190,10 +191,7 @@ namespace MediaBrowser.Providers.Manager // Remove containing directory if empty var folder = Path.GetDirectoryName(currentPath); - if (Directory.Exists(folder) && !_fileSystem.GetFiles(folder, true).Any()) - { - Directory.Delete(folder, true); - } + FileSystemHelper.DeleteEmptyFolders(_fileSystem, folder, _logger); } catch (FileNotFoundException) { diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 763e5be968..c72d4256af 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Providers; @@ -381,10 +382,7 @@ namespace MediaBrowser.Providers.Manager { // Always remove empty parent folder var folder = Path.GetDirectoryName(image.Path); - if (Directory.Exists(folder) && !_fileSystem.GetFiles(folder, true).Any()) - { - Directory.Delete(folder, true); - } + FileSystemHelper.DeleteEmptyFolders(_fileSystem, folder, _logger); } } } From 19a89d5a609c9f7cb14a271714c798dc361c4cb1 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sat, 8 Jun 2024 00:12:36 +0200 Subject: [PATCH 3/7] Remove folder after removing empty subfolders --- MediaBrowser.Providers/Manager/ImageSaver.cs | 4 ++++ MediaBrowser.Providers/Manager/ItemImageProvider.cs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 7911f35455..b9b07da67d 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -192,6 +192,10 @@ namespace MediaBrowser.Providers.Manager // Remove containing directory if empty var folder = Path.GetDirectoryName(currentPath); FileSystemHelper.DeleteEmptyFolders(_fileSystem, folder, _logger); + if (!_fileSystem.GetFiles(folder).Any()) + { + Directory.Delete(folder); + } } catch (FileNotFoundException) { diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index c72d4256af..ad80611261 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -383,6 +383,10 @@ namespace MediaBrowser.Providers.Manager // Always remove empty parent folder var folder = Path.GetDirectoryName(image.Path); FileSystemHelper.DeleteEmptyFolders(_fileSystem, folder, _logger); + if (!_fileSystem.GetFiles(folder).Any()) + { + Directory.Delete(folder); + } } } } From f9e7d5229e8f8c5340134d5c7a5c4ce91208f907 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sun, 9 Jun 2024 00:46:19 +0200 Subject: [PATCH 4/7] Limit removal scope --- .../Library/LibraryManager.cs | 2 +- MediaBrowser.Providers/Manager/ImageSaver.cs | 25 ++++++++++++---- .../Manager/ItemImageProvider.cs | 29 +++++++++---------- .../Manager/MetadataService.cs | 17 ++++------- 4 files changed, 41 insertions(+), 32 deletions(-) diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 953fe19e05..ac2248264d 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1884,7 +1884,7 @@ namespace Emby.Server.Implementations.Library try { var index = item.GetImageIndex(img); - image = await ConvertImageToLocal(item, img, index, removeOnFailure: true).ConfigureAwait(false); + image = await ConvertImageToLocal(item, img, index, true).ConfigureAwait(false); } catch (ArgumentException) { diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index b9b07da67d..7e881cb976 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -189,12 +189,27 @@ namespace MediaBrowser.Providers.Manager { _fileSystem.DeleteFile(currentPath); - // Remove containing directory if empty - var folder = Path.GetDirectoryName(currentPath); - FileSystemHelper.DeleteEmptyFolders(_fileSystem, folder, _logger); - if (!_fileSystem.GetFiles(folder).Any()) + // Remove local episode metadata directory if it exists and is empty + var directory = Path.GetDirectoryName(currentPath); + if (item is Episode && directory.Equals("metadata", StringComparison.Ordinal)) { - Directory.Delete(folder); + var parentDirectoryPath = Directory.GetParent(currentPath).FullName; + if (!_fileSystem.GetFiles(parentDirectoryPath).Any()) + { + try + { + _logger.LogInformation("Deleting empty local metadata folder {Folder}", parentDirectoryPath); + Directory.Delete(parentDirectoryPath); + } + catch (UnauthorizedAccessException ex) + { + _logger.LogError(ex, "Error deleting directory {Path}", parentDirectoryPath); + } + catch (IOException ex) + { + _logger.LogError(ex, "Error deleting directory {Path}", parentDirectoryPath); + } + } } } catch (FileNotFoundException) diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index ad80611261..f89dc51795 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -10,7 +10,7 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.IO; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Providers; @@ -97,7 +97,7 @@ namespace MediaBrowser.Providers.Manager public bool ValidateImages(BaseItem item, IEnumerable providers, ImageRefreshOptions refreshOptions) { var hasChanges = false; - IDirectoryService directoryService = refreshOptions?.DirectoryService; + var directoryService = refreshOptions?.DirectoryService; if (item is not Photo) { @@ -360,10 +360,8 @@ namespace MediaBrowser.Providers.Manager private void PruneImages(BaseItem item, IReadOnlyList images) { - for (var i = 0; i < images.Count; i++) + foreach (var image in images) { - var image = images[i]; - if (image.IsLocalFile) { try @@ -378,16 +376,17 @@ namespace MediaBrowser.Providers.Manager { _logger.LogWarning(ex, "Unable to delete {Image}", image.Path); } - finally - { - // Always remove empty parent folder - var folder = Path.GetDirectoryName(image.Path); - FileSystemHelper.DeleteEmptyFolders(_fileSystem, folder, _logger); - if (!_fileSystem.GetFiles(folder).Any()) - { - Directory.Delete(folder); - } - } + } + } + + // Cleanup old metadata directory for episodes if empty + if (item is Episode) + { + var oldLocalMetadataDirectory = Path.Combine(item.ContainingFolderPath, "metadata"); + var localImages = images.Where(i => i.Path.StartsWith(oldLocalMetadataDirectory, StringComparison.Ordinal)).ToList(); + if (!_fileSystem.GetFiles(oldLocalMetadataDirectory).Any()) + { + Directory.Delete(oldLocalMetadataDirectory); } } diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 61a4d75863..934f88c650 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -92,10 +92,6 @@ namespace MediaBrowser.Providers.Manager } } - var localImagesFailed = false; - - var allImageProviders = ProviderManager.GetImageProviders(item, refreshOptions).ToList(); - if (refreshOptions.RemoveOldMetadata && refreshOptions.ReplaceAllImages) { if (ImageProvider.RemoveImages(item)) @@ -105,6 +101,8 @@ namespace MediaBrowser.Providers.Manager } // Start by validating images + var localImagesFailed = false; + var allImageProviders = ProviderManager.GetImageProviders(item, refreshOptions).ToList(); try { // Always validate images and check for new locally stored ones. @@ -811,19 +809,16 @@ namespace MediaBrowser.Providers.Manager { var refreshResult = new RefreshResult(); - var tmpDataMerged = false; + if (id is not null) + { + MergeNewData(temp.Item, id); + } foreach (var provider in providers) { var providerName = provider.GetType().Name; Logger.LogDebug("Running {Provider} for {Item}", providerName, logName); - if (id is not null && !tmpDataMerged) - { - MergeNewData(temp.Item, id); - tmpDataMerged = true; - } - try { var result = await provider.GetMetadata(id, cancellationToken).ConfigureAwait(false); From b63f7a2bc05c39236b061f2e06862e19f187e894 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sun, 9 Jun 2024 00:46:46 +0200 Subject: [PATCH 5/7] Only remove image from item if file system delete was successful --- MediaBrowser.Controller/Entities/BaseItem.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 184bb4d688..8bd4fb4f38 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1949,14 +1949,15 @@ namespace MediaBrowser.Controller.Entities return; } - // Remove it from the item - RemoveImage(info); - + // Remove from file system if (info.IsLocalFile) { FileSystem.DeleteFile(info.Path); } + // Remove from item + RemoveImage(info); + await UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); } From 8b442a77495fd4788704e521ecbcf172aaa6ef8b Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sun, 9 Jun 2024 08:24:58 +0200 Subject: [PATCH 6/7] Check for existence before trying to delete directory --- MediaBrowser.Providers/Manager/ImageSaver.cs | 2 +- MediaBrowser.Providers/Manager/ItemImageProvider.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 7e881cb976..4b3b0a14d0 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -194,7 +194,7 @@ namespace MediaBrowser.Providers.Manager if (item is Episode && directory.Equals("metadata", StringComparison.Ordinal)) { var parentDirectoryPath = Directory.GetParent(currentPath).FullName; - if (!_fileSystem.GetFiles(parentDirectoryPath).Any()) + if (_fileSystem.DirectoryExists(parentDirectoryPath) && !_fileSystem.GetFiles(parentDirectoryPath).Any()) { try { diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index f89dc51795..245489ea21 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -384,7 +384,7 @@ namespace MediaBrowser.Providers.Manager { var oldLocalMetadataDirectory = Path.Combine(item.ContainingFolderPath, "metadata"); var localImages = images.Where(i => i.Path.StartsWith(oldLocalMetadataDirectory, StringComparison.Ordinal)).ToList(); - if (!_fileSystem.GetFiles(oldLocalMetadataDirectory).Any()) + if (_fileSystem.DirectoryExists(oldLocalMetadataDirectory) && !_fileSystem.GetFiles(oldLocalMetadataDirectory).Any()) { Directory.Delete(oldLocalMetadataDirectory); } From aadd57bc486f85fdded44058c82adfbc64dda0ee Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Mon, 24 Jun 2024 09:16:51 +0200 Subject: [PATCH 7/7] Fix check --- MediaBrowser.Providers/Manager/ItemImageProvider.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 245489ea21..4690845d2a 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -379,18 +379,17 @@ namespace MediaBrowser.Providers.Manager } } + item.RemoveImages(images); + // Cleanup old metadata directory for episodes if empty if (item is Episode) { var oldLocalMetadataDirectory = Path.Combine(item.ContainingFolderPath, "metadata"); - var localImages = images.Where(i => i.Path.StartsWith(oldLocalMetadataDirectory, StringComparison.Ordinal)).ToList(); if (_fileSystem.DirectoryExists(oldLocalMetadataDirectory) && !_fileSystem.GetFiles(oldLocalMetadataDirectory).Any()) { Directory.Delete(oldLocalMetadataDirectory); } } - - item.RemoveImages(images); } ///