Browse Source

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

Fix local image saving

Original-merge: b0bb22b65080a21ad1ce27fa2937a6b439e157da

Merged-by: crobibero <cody@robibe.ro>

Backported-by: Joshua M. Boniface <joshua@boniface.me>
Shadowghost 1 year ago
parent
commit
18dd6b2875

+ 16 - 0
MediaBrowser.Controller/Providers/DirectoryService.cs

@@ -28,6 +28,22 @@ namespace MediaBrowser.Controller.Providers
             return _cache.GetOrAdd(path, static (p, fileSystem) => fileSystem.GetFileSystemEntries(p).ToArray(), _fileSystem);
         }
 
+        public List<FileSystemMetadata> GetDirectories(string path)
+        {
+            var list = new List<FileSystemMetadata>();
+            var items = GetFileSystemEntries(path);
+            for (var i = 0; i < items.Length; i++)
+            {
+                var item = items[i];
+                if (item.IsDirectory)
+                {
+                    list.Add(item);
+                }
+            }
+
+            return list;
+        }
+
         public List<FileSystemMetadata> GetFiles(string path)
         {
             var list = new List<FileSystemMetadata>();

+ 2 - 0
MediaBrowser.Controller/Providers/IDirectoryService.cs

@@ -9,6 +9,8 @@ namespace MediaBrowser.Controller.Providers
     {
         FileSystemMetadata[] GetFileSystemEntries(string path);
 
+        List<FileSystemMetadata> GetDirectories(string path);
+
         List<FileSystemMetadata> GetFiles(string path);
 
         FileSystemMetadata? GetFile(string path);

+ 13 - 4
MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs

@@ -38,19 +38,28 @@ namespace MediaBrowser.LocalMetadata.Images
             }
 
             var parentPathFiles = directoryService.GetFiles(parentPath);
+            var nameWithoutExtension = Path.GetFileNameWithoutExtension(item.Path.AsSpan()).ToString();
 
-            var nameWithoutExtension = Path.GetFileNameWithoutExtension(item.Path.AsSpan());
+            var thumbName = string.Concat(nameWithoutExtension, "-thumb");
+            var images = GetImageFilesFromFolder(thumbName, parentPathFiles);
 
-            return GetFilesFromParentFolder(nameWithoutExtension, parentPathFiles);
+            var metadataSubPath = directoryService.GetDirectories(parentPath).Where(d => d.Name.EndsWith("metadata", StringComparison.OrdinalIgnoreCase)).ToList();
+            foreach (var path in metadataSubPath)
+            {
+                var files = directoryService.GetFiles(path.FullName);
+                images.AddRange(GetImageFilesFromFolder(nameWithoutExtension, files));
+            }
+
+            return images;
         }
 
-        private List<LocalImageInfo> GetFilesFromParentFolder(ReadOnlySpan<char> filenameWithoutExtension, List<FileSystemMetadata> parentPathFiles)
+        private List<LocalImageInfo> GetImageFilesFromFolder(ReadOnlySpan<char> filenameWithoutExtension, List<FileSystemMetadata> filePaths)
         {
             var thumbName = string.Concat(filenameWithoutExtension, "-thumb");
 
             var list = new List<LocalImageInfo>(1);
 
-            foreach (var i in parentPathFiles)
+            foreach (var i in filePaths)
             {
                 if (i.IsDirectory)
                 {

+ 50 - 12
MediaBrowser.Providers/Manager/ImageSaver.cs

@@ -100,8 +100,8 @@ namespace MediaBrowser.Providers.Manager
             {
                 saveLocally = false;
 
-                // If season is virtual under a physical series, save locally if using compatible convention
-                if (item is Season season && _config.Configuration.ImageSavingConvention == ImageSavingConvention.Compatible)
+                // If season is virtual under a physical series, save locally
+                if (item is Season season)
                 {
                     var series = season.Series;
 
@@ -126,7 +126,7 @@ namespace MediaBrowser.Providers.Manager
 
             var paths = GetSavePaths(item, type, imageIndex, mimeType, saveLocally);
 
-            var retryPaths = GetSavePaths(item, type, imageIndex, mimeType, false);
+            var retryPaths = GetSavePaths(item, type, imageIndex, mimeType, !saveLocally);
 
             // If there are more than one output paths, the stream will need to be seekable
             if (paths.Length > 1 && !source.CanSeek)
@@ -183,6 +183,13 @@ namespace MediaBrowser.Providers.Manager
                 try
                 {
                     _fileSystem.DeleteFile(currentPath);
+
+                    // Remove containing directory if empty
+                    var folder = Path.GetDirectoryName(currentPath);
+                    if (!_fileSystem.GetFiles(folder).Any())
+                    {
+                        Directory.Delete(folder);
+                    }
                 }
                 catch (FileNotFoundException)
                 {
@@ -374,6 +381,45 @@ namespace MediaBrowser.Providers.Manager
                 throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Unable to determine image file extension from mime type {0}", mimeType));
             }
 
+            if (string.Equals(extension, ".jpeg", StringComparison.OrdinalIgnoreCase))
+            {
+                extension = ".jpg";
+            }
+
+            extension = extension.ToLowerInvariant();
+
+            if (type == ImageType.Primary && saveLocally)
+            {
+                if (season is not null && season.IndexNumber.HasValue)
+                {
+                    var seriesFolder = season.SeriesPath;
+
+                    var seasonMarker = season.IndexNumber.Value == 0
+                                           ? "-specials"
+                                           : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture);
+
+                    var imageFilename = "season" + seasonMarker + "-poster" + extension;
+
+                    return Path.Combine(seriesFolder, imageFilename);
+                }
+            }
+
+            if (type == ImageType.Backdrop && saveLocally)
+            {
+                if (season is not null && season.IndexNumber.HasValue)
+                {
+                    var seriesFolder = season.SeriesPath;
+
+                    var seasonMarker = season.IndexNumber.Value == 0
+                                           ? "-specials"
+                                           : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture);
+
+                    var imageFilename = "season" + seasonMarker + "-fanart" + extension;
+
+                    return Path.Combine(seriesFolder, imageFilename);
+                }
+            }
+
             if (type == ImageType.Thumb && saveLocally)
             {
                 if (season is not null && season.IndexNumber.HasValue)
@@ -447,20 +493,12 @@ namespace MediaBrowser.Providers.Manager
                     break;
             }
 
-            if (string.Equals(extension, ".jpeg", StringComparison.OrdinalIgnoreCase))
-            {
-                extension = ".jpg";
-            }
-
-            extension = extension.ToLowerInvariant();
-
             string path = null;
-
             if (saveLocally)
             {
                 if (type == ImageType.Primary && item is Episode)
                 {
-                    path = Path.Combine(Path.GetDirectoryName(item.Path), "metadata", filename + extension);
+                    path = Path.Combine(Path.GetDirectoryName(item.Path), filename + "-thumb" + extension);
                 }
                 else if (item.IsInMixedFolder)
                 {

+ 10 - 1
MediaBrowser.Providers/Manager/ItemImageProvider.cs

@@ -371,12 +371,21 @@ namespace MediaBrowser.Providers.Manager
                     }
                     catch (FileNotFoundException)
                     {
-                        // nothing to do, already gone
+                        // Nothing to do, already gone
                     }
                     catch (UnauthorizedAccessException ex)
                     {
                         _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);
+                        }
+                    }
                 }
             }