diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs index 7fe2f64af3..56b07ebae7 100644 --- a/MediaBrowser.Controller/Providers/DirectoryService.cs +++ b/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 GetDirectories(string path) + { + var list = new List(); + 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 GetFiles(string path) { var list = new List(); diff --git a/MediaBrowser.Controller/Providers/IDirectoryService.cs b/MediaBrowser.Controller/Providers/IDirectoryService.cs index 6d7550ab53..a3c06cde53 100644 --- a/MediaBrowser.Controller/Providers/IDirectoryService.cs +++ b/MediaBrowser.Controller/Providers/IDirectoryService.cs @@ -9,6 +9,8 @@ namespace MediaBrowser.Controller.Providers { FileSystemMetadata[] GetFileSystemEntries(string path); + List GetDirectories(string path); + List GetFiles(string path); FileSystemMetadata? GetFile(string path); diff --git a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs index a8e2946f18..6a5e3bf04a 100644 --- a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs +++ b/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 GetFilesFromParentFolder(ReadOnlySpan filenameWithoutExtension, List parentPathFiles) + private List GetImageFilesFromFolder(ReadOnlySpan filenameWithoutExtension, List filePaths) { var thumbName = string.Concat(filenameWithoutExtension, "-thumb"); var list = new List(1); - foreach (var i in parentPathFiles) + foreach (var i in filePaths) { if (i.IsDirectory) { diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index d827168314..3704b22764 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/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) { diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 961671a141..bee420d952 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/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); + } + } } }