瀏覽代碼

Backport pull request #12025 from jellyfin/release-10.9.z

Fix empty image folder removal for legacy locations

Original-merge: 476dc01f4d5bf0fdf391935ef0759b0583bf7026

Merged-by: Bond-009 <bond.009@outlook.com>

Backported-by: Joshua M. Boniface <joshua@boniface.me>
Shadowghost 11 月之前
父節點
當前提交
6734450d40

+ 3 - 3
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;
             }

+ 1 - 1
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)
                     {

+ 3 - 41
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);
-            }
-        }
     }
 }

+ 3 - 42
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);
-            }
-        }
     }
 }

+ 4 - 3
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);
         }
 

+ 64 - 0
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;
+
+/// <summary>
+/// Helper methods for file system management.
+/// </summary>
+public static class FileSystemHelper
+{
+    /// <summary>
+    /// Deletes the file.
+    /// </summary>
+    /// <param name="fileSystem">The fileSystem.</param>
+    /// <param name="path">The path.</param>
+    /// <param name="logger">The logger.</param>
+    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);
+        }
+    }
+
+    /// <summary>
+    /// Recursively delete empty folders.
+    /// </summary>
+    /// <param name="fileSystem">The fileSystem.</param>
+    /// <param name="path">The path.</param>
+    /// <param name="logger">The logger.</param>
+    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);
+                }
+            }
+        }
+    }
+}

+ 21 - 4
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;
@@ -188,11 +189,27 @@ namespace MediaBrowser.Providers.Manager
                 {
                     _fileSystem.DeleteFile(currentPath);
 
-                    // Remove containing directory if empty
-                    var folder = Path.GetDirectoryName(currentPath);
-                    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.DirectoryExists(parentDirectoryPath) && !_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)

+ 13 - 13
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.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.Providers;
@@ -96,7 +97,7 @@ namespace MediaBrowser.Providers.Manager
         public bool ValidateImages(BaseItem item, IEnumerable<IImageProvider> providers, ImageRefreshOptions refreshOptions)
         {
             var hasChanges = false;
-            IDirectoryService directoryService = refreshOptions?.DirectoryService;
+            var directoryService = refreshOptions?.DirectoryService;
 
             if (item is not Photo)
             {
@@ -359,10 +360,8 @@ namespace MediaBrowser.Providers.Manager
 
         private void PruneImages(BaseItem item, IReadOnlyList<ItemImageInfo> images)
         {
-            for (var i = 0; i < images.Count; i++)
+            foreach (var image in images)
             {
-                var image = images[i];
-
                 if (image.IsLocalFile)
                 {
                     try
@@ -377,19 +376,20 @@ 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);
-                        if (Directory.Exists(folder) && !_fileSystem.GetFiles(folder).Any())
-                        {
-                            Directory.Delete(folder);
-                        }
-                    }
                 }
             }
 
             item.RemoveImages(images);
+
+            // Cleanup old metadata directory for episodes if empty
+            if (item is Episode)
+            {
+                var oldLocalMetadataDirectory = Path.Combine(item.ContainingFolderPath, "metadata");
+                if (_fileSystem.DirectoryExists(oldLocalMetadataDirectory) && !_fileSystem.GetFiles(oldLocalMetadataDirectory).Any())
+                {
+                    Directory.Delete(oldLocalMetadataDirectory);
+                }
+            }
         }
 
         /// <summary>

+ 6 - 11
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.
@@ -813,19 +811,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);