< Summary - Jellyfin

Information
Class: MediaBrowser.Providers.Manager.ImageSaver
Assembly: MediaBrowser.Providers
File(s): /srv/git/jellyfin/MediaBrowser.Providers/Manager/ImageSaver.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 164
Coverable lines: 164
Total lines: 718
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 140
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
get_EnableExtraThumbsDuplication()100%210%
SaveImage(...)100%210%
SetHidden(...)100%210%
GetSavePaths(...)0%2040%
GetCurrentImage(...)100%210%
SetImagePath(...)100%210%
GetStandardSavePath(...)0%8556920%
GetBackdropSaveFilename(...)0%4260%
GetCompatibleSavePaths(...)0%1332360%
GetSavePathForItemInMixedFolder(...)0%620%

File(s)

/srv/git/jellyfin/MediaBrowser.Providers/Manager/ImageSaver.cs

#LineLine coverage
 1#nullable disable
 2
 3#pragma warning disable CS1591
 4
 5using System;
 6using System.Collections.Generic;
 7using System.Globalization;
 8using System.IO;
 9using System.Linq;
 10using System.Threading;
 11using System.Threading.Tasks;
 12using Jellyfin.Extensions;
 13using MediaBrowser.Common.Configuration;
 14using MediaBrowser.Controller.Configuration;
 15using MediaBrowser.Controller.Entities;
 16using MediaBrowser.Controller.Entities.Audio;
 17using MediaBrowser.Controller.IO;
 18using MediaBrowser.Controller.Library;
 19using MediaBrowser.Model.Configuration;
 20using MediaBrowser.Model.Entities;
 21using MediaBrowser.Model.IO;
 22using MediaBrowser.Model.Net;
 23using Microsoft.Extensions.Logging;
 24using Episode = MediaBrowser.Controller.Entities.TV.Episode;
 25using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
 26using Person = MediaBrowser.Controller.Entities.Person;
 27using Season = MediaBrowser.Controller.Entities.TV.Season;
 28
 29namespace MediaBrowser.Providers.Manager
 30{
 31    /// <summary>
 32    /// Class ImageSaver.
 33    /// </summary>
 34    public class ImageSaver
 35    {
 36        /// <summary>
 37        /// The _config.
 38        /// </summary>
 39        private readonly IServerConfigurationManager _config;
 40
 41        /// <summary>
 42        /// The _directory watchers.
 43        /// </summary>
 44        private readonly ILibraryMonitor _libraryMonitor;
 45        private readonly IFileSystem _fileSystem;
 46        private readonly ILogger _logger;
 47
 48        /// <summary>
 49        /// Initializes a new instance of the <see cref="ImageSaver" /> class.
 50        /// </summary>
 51        /// <param name="config">The config.</param>
 52        /// <param name="libraryMonitor">The directory watchers.</param>
 53        /// <param name="fileSystem">The file system.</param>
 54        /// <param name="logger">The logger.</param>
 55        public ImageSaver(IServerConfigurationManager config, ILibraryMonitor libraryMonitor, IFileSystem fileSystem, IL
 56        {
 057            _config = config;
 058            _libraryMonitor = libraryMonitor;
 059            _fileSystem = fileSystem;
 060            _logger = logger;
 061        }
 62
 63        private bool EnableExtraThumbsDuplication
 64        {
 65            get
 66            {
 067                var config = _config.GetConfiguration<XbmcMetadataOptions>("xbmcmetadata");
 68
 069                return config.EnableExtraThumbsDuplication;
 70            }
 71        }
 72
 73        /// <summary>
 74        /// Saves the image.
 75        /// </summary>
 76        /// <param name="item">The item.</param>
 77        /// <param name="source">The source.</param>
 78        /// <param name="mimeType">Type of the MIME.</param>
 79        /// <param name="type">The type.</param>
 80        /// <param name="imageIndex">Index of the image.</param>
 81        /// <param name="cancellationToken">The cancellation token.</param>
 82        /// <returns>Task.</returns>
 83        /// <exception cref="ArgumentNullException">mimeType.</exception>
 84        public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, Cancellati
 85        {
 086            return SaveImage(item, source, mimeType, type, imageIndex, null, cancellationToken);
 87        }
 88
 89        public async Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, bool
 90        {
 91            ArgumentException.ThrowIfNullOrEmpty(mimeType);
 92
 93            var saveLocally = item.SupportsLocalMetadata && item.IsSaveLocalMetadataEnabled() && !item.ExtraType.HasValu
 94
 95            if (type != ImageType.Primary && item is Episode)
 96            {
 97                saveLocally = false;
 98            }
 99
 100            if (!item.IsFileProtocol)
 101            {
 102                saveLocally = false;
 103
 104                // If season is virtual under a physical series, save locally
 105                if (item is Season season)
 106                {
 107                    var series = season.Series;
 108
 109                    if (series is not null && series.SupportsLocalMetadata && series.IsSaveLocalMetadataEnabled())
 110                    {
 111                        saveLocally = true;
 112                    }
 113                }
 114            }
 115
 116            if (saveLocallyWithMedia.HasValue && !saveLocallyWithMedia.Value)
 117            {
 118                saveLocally = saveLocallyWithMedia.Value;
 119            }
 120
 121            if (!imageIndex.HasValue && item.AllowsMultipleImages(type))
 122            {
 123                imageIndex = item.GetImages(type).Count();
 124            }
 125
 126            var index = imageIndex ?? 0;
 127
 128            var paths = GetSavePaths(item, type, imageIndex, mimeType, saveLocally);
 129
 130            string[] retryPaths = [];
 131            if (saveLocally)
 132            {
 133                retryPaths = GetSavePaths(item, type, imageIndex, mimeType, false);
 134            }
 135
 136            // If there are more than one output paths, the stream will need to be seekable
 137            if (paths.Length > 1 && !source.CanSeek)
 138            {
 139                var memoryStream = new MemoryStream();
 140                await using (source.ConfigureAwait(false))
 141                {
 142                    await source.CopyToAsync(memoryStream, cancellationToken).ConfigureAwait(false);
 143                }
 144
 145                source = memoryStream;
 146            }
 147
 148            var currentImage = GetCurrentImage(item, type, index);
 149            var currentImageIsLocalFile = currentImage is not null && currentImage.IsLocalFile;
 150            var currentImagePath = currentImage?.Path;
 151
 152            var savedPaths = new List<string>();
 153
 154            await using (source.ConfigureAwait(false))
 155            {
 156                for (int i = 0; i < paths.Length; i++)
 157                {
 158                    if (i != 0)
 159                    {
 160                        source.Position = 0;
 161                    }
 162
 163                    string retryPath = null;
 164                    if (paths.Length == retryPaths.Length)
 165                    {
 166                        retryPath = retryPaths[i];
 167                    }
 168
 169                    var savedPath = await SaveImageToLocation(source, paths[i], retryPath, cancellationToken).ConfigureA
 170                    savedPaths.Add(savedPath);
 171                }
 172            }
 173
 174            // Set the path into the item
 175            SetImagePath(item, type, imageIndex, savedPaths[0]);
 176
 177            // Delete the current path
 178            if (currentImageIsLocalFile
 179                && !savedPaths.Contains(currentImagePath, StringComparison.OrdinalIgnoreCase)
 180                && (saveLocally || currentImagePath.Contains(_config.ApplicationPaths.InternalMetadataPath, StringCompar
 181            {
 182                var currentPath = currentImagePath;
 183
 184                _logger.LogInformation("Deleting previous image {0}", currentPath);
 185
 186                _libraryMonitor.ReportFileSystemChangeBeginning(currentPath);
 187
 188                try
 189                {
 190                    _fileSystem.DeleteFile(currentPath);
 191
 192                    // Remove local episode metadata directory if it exists and is empty
 193                    var directory = Path.GetDirectoryName(currentPath);
 194                    if (item is Episode && directory.Equals("metadata", StringComparison.Ordinal))
 195                    {
 196                        var parentDirectoryPath = Directory.GetParent(currentPath).FullName;
 197                        if (_fileSystem.DirectoryExists(parentDirectoryPath) && !_fileSystem.GetFiles(parentDirectoryPat
 198                        {
 199                            try
 200                            {
 201                                _logger.LogInformation("Deleting empty local metadata folder {Folder}", parentDirectoryP
 202                                Directory.Delete(parentDirectoryPath);
 203                            }
 204                            catch (UnauthorizedAccessException ex)
 205                            {
 206                                _logger.LogError(ex, "Error deleting directory {Path}", parentDirectoryPath);
 207                            }
 208                            catch (IOException ex)
 209                            {
 210                                _logger.LogError(ex, "Error deleting directory {Path}", parentDirectoryPath);
 211                            }
 212                        }
 213                    }
 214                }
 215                catch (FileNotFoundException)
 216                {
 217                }
 218                finally
 219                {
 220                    _libraryMonitor.ReportFileSystemChangeComplete(currentPath, false);
 221                }
 222            }
 223        }
 224
 225        public async Task SaveImage(Stream source, string path)
 226        {
 227            await SaveImageToLocation(source, path, path, CancellationToken.None).ConfigureAwait(false);
 228        }
 229
 230        private async Task<string> SaveImageToLocation(Stream source, string path, string retryPath, CancellationToken c
 231        {
 232            try
 233            {
 234                await SaveImageToLocation(source, path, cancellationToken).ConfigureAwait(false);
 235                return path;
 236            }
 237            catch (UnauthorizedAccessException)
 238            {
 239                var retry = !string.IsNullOrWhiteSpace(retryPath) &&
 240                    !string.Equals(path, retryPath, StringComparison.OrdinalIgnoreCase);
 241
 242                if (retry)
 243                {
 244                    _logger.LogError("UnauthorizedAccessException - Access to path {0} is denied. Will retry saving to {
 245                }
 246                else
 247                {
 248                    throw;
 249                }
 250            }
 251            catch (IOException ex)
 252            {
 253                var retry = !string.IsNullOrWhiteSpace(retryPath) &&
 254                    !string.Equals(path, retryPath, StringComparison.OrdinalIgnoreCase);
 255
 256                if (retry)
 257                {
 258                    _logger.LogError(ex, "IOException saving to {0}. Will retry saving to {1}", path, retryPath);
 259                }
 260                else
 261                {
 262                    throw;
 263                }
 264            }
 265
 266            await SaveImageToLocation(source, retryPath, cancellationToken).ConfigureAwait(false);
 267            return retryPath;
 268        }
 269
 270        /// <summary>
 271        /// Saves the image to location.
 272        /// </summary>
 273        /// <param name="source">The source.</param>
 274        /// <param name="path">The path.</param>
 275        /// <param name="cancellationToken">The cancellation token.</param>
 276        /// <returns>Task.</returns>
 277        private async Task SaveImageToLocation(Stream source, string path, CancellationToken cancellationToken)
 278        {
 279            _logger.LogDebug("Saving image to {0}", path);
 280
 281            var parentFolder = Path.GetDirectoryName(path);
 282
 283            try
 284            {
 285                _libraryMonitor.ReportFileSystemChangeBeginning(path);
 286                _libraryMonitor.ReportFileSystemChangeBeginning(parentFolder);
 287
 288                Directory.CreateDirectory(Path.GetDirectoryName(path));
 289
 290                _fileSystem.SetAttributes(path, false, false);
 291
 292                var fileStreamOptions = AsyncFile.WriteOptions;
 293                fileStreamOptions.Mode = FileMode.Create;
 294                fileStreamOptions.Options = FileOptions.WriteThrough;
 295                if (source.CanSeek)
 296                {
 297                    fileStreamOptions.PreallocationSize = source.Length;
 298                }
 299
 300                var fs = new FileStream(path, fileStreamOptions);
 301                await using (fs.ConfigureAwait(false))
 302                {
 303                    await source.CopyToAsync(fs, cancellationToken).ConfigureAwait(false);
 304                }
 305
 306                if (_config.Configuration.SaveMetadataHidden)
 307                {
 308                    SetHidden(path, true);
 309                }
 310            }
 311            finally
 312            {
 313                _libraryMonitor.ReportFileSystemChangeComplete(path, false);
 314                _libraryMonitor.ReportFileSystemChangeComplete(parentFolder, false);
 315            }
 316        }
 317
 318        private void SetHidden(string path, bool hidden)
 319        {
 320            try
 321            {
 0322                _fileSystem.SetHidden(path, hidden);
 0323            }
 0324            catch (Exception ex)
 325            {
 0326                _logger.LogError(ex, "Error setting hidden attribute on {0}", path);
 0327            }
 0328        }
 329
 330        /// <summary>
 331        /// Gets the save paths.
 332        /// </summary>
 333        /// <param name="item">The item.</param>
 334        /// <param name="type">The type.</param>
 335        /// <param name="imageIndex">Index of the image.</param>
 336        /// <param name="mimeType">Type of the MIME.</param>
 337        /// <param name="saveLocally">if set to <c>true</c> [save locally].</param>
 338        /// <returns>IEnumerable{System.String}.</returns>
 339        private string[] GetSavePaths(BaseItem item, ImageType type, int? imageIndex, string mimeType, bool saveLocally)
 340        {
 0341            if (!saveLocally || (_config.Configuration.ImageSavingConvention == ImageSavingConvention.Legacy))
 342            {
 0343                return new[] { GetStandardSavePath(item, type, imageIndex, mimeType, saveLocally) };
 344            }
 345
 0346            return GetCompatibleSavePaths(item, type, imageIndex, mimeType);
 347        }
 348
 349        /// <summary>
 350        /// Gets the current image path.
 351        /// </summary>
 352        /// <param name="item">The item.</param>
 353        /// <param name="type">The type.</param>
 354        /// <param name="imageIndex">Index of the image.</param>
 355        /// <returns>System.String.</returns>
 356        /// <exception cref="ArgumentNullException">
 357        /// imageIndex
 358        /// or
 359        /// imageIndex.
 360        /// </exception>
 361        private ItemImageInfo GetCurrentImage(BaseItem item, ImageType type, int imageIndex)
 362        {
 0363            return item.GetImageInfo(type, imageIndex);
 364        }
 365
 366        /// <summary>
 367        /// Sets the image path.
 368        /// </summary>
 369        /// <param name="item">The item.</param>
 370        /// <param name="type">The type.</param>
 371        /// <param name="imageIndex">Index of the image.</param>
 372        /// <param name="path">The path.</param>
 373        /// <exception cref="ArgumentNullException">imageIndex
 374        /// or
 375        /// imageIndex.
 376        /// </exception>
 377        private void SetImagePath(BaseItem item, ImageType type, int? imageIndex, string path)
 378        {
 0379            item.SetImagePath(type, imageIndex ?? 0, _fileSystem.GetFileInfo(path));
 0380        }
 381
 382        /// <summary>
 383        /// Gets the save path.
 384        /// </summary>
 385        /// <param name="item">The item.</param>
 386        /// <param name="type">The type.</param>
 387        /// <param name="imageIndex">Index of the image.</param>
 388        /// <param name="mimeType">Type of the MIME.</param>
 389        /// <param name="saveLocally">if set to <c>true</c> [save locally].</param>
 390        /// <returns>System.String.</returns>
 391        /// <exception cref="ArgumentNullException">
 392        /// imageIndex
 393        /// or
 394        /// imageIndex.
 395        /// </exception>
 396        private string GetStandardSavePath(BaseItem item, ImageType type, int? imageIndex, string mimeType, bool saveLoc
 397        {
 0398            var season = item as Season;
 0399            var extension = MimeTypes.ToExtension(mimeType);
 400
 0401            if (string.IsNullOrWhiteSpace(extension))
 402            {
 0403                throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Unable to determine image file 
 404            }
 405
 0406            if (string.Equals(extension, ".jpeg", StringComparison.OrdinalIgnoreCase))
 407            {
 0408                extension = ".jpg";
 409            }
 410
 0411            extension = extension.ToLowerInvariant();
 412
 0413            if (type == ImageType.Primary && saveLocally)
 414            {
 0415                if (season is not null && season.IndexNumber.HasValue)
 416                {
 0417                    var seriesFolder = season.SeriesPath;
 418
 0419                    var seasonMarker = season.IndexNumber.Value == 0
 0420                                           ? "-specials"
 0421                                           : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture);
 422
 0423                    var imageFilename = "season" + seasonMarker + "-poster" + extension;
 424
 0425                    return Path.Combine(seriesFolder, imageFilename);
 426                }
 427            }
 428
 0429            if (type == ImageType.Backdrop && saveLocally)
 430            {
 0431                if (season is not null
 0432                    && season.IndexNumber.HasValue
 0433                    && (imageIndex is null || imageIndex == 0))
 434                {
 0435                    var seriesFolder = season.SeriesPath;
 436
 0437                    var seasonMarker = season.IndexNumber.Value == 0
 0438                                        ? "-specials"
 0439                                        : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture);
 440
 0441                    var imageFilename = "season" + seasonMarker + "-fanart" + extension;
 442
 0443                    return Path.Combine(seriesFolder, imageFilename);
 444                }
 445            }
 446
 0447            if (type == ImageType.Thumb && saveLocally)
 448            {
 0449                if (season is not null && season.IndexNumber.HasValue)
 450                {
 0451                    var seriesFolder = season.SeriesPath;
 452
 0453                    var seasonMarker = season.IndexNumber.Value == 0
 0454                                           ? "-specials"
 0455                                           : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture);
 456
 0457                    var imageFilename = "season" + seasonMarker + "-landscape" + extension;
 458
 0459                    return Path.Combine(seriesFolder, imageFilename);
 460                }
 461
 0462                if (item.IsInMixedFolder)
 463                {
 0464                    return GetSavePathForItemInMixedFolder(item, type, "landscape", extension);
 465                }
 466
 0467                return Path.Combine(item.ContainingFolderPath, "landscape" + extension);
 468            }
 469
 0470            if (type == ImageType.Banner && saveLocally)
 471            {
 0472                if (season is not null && season.IndexNumber.HasValue)
 473                {
 0474                    var seriesFolder = season.SeriesPath;
 475
 0476                    var seasonMarker = season.IndexNumber.Value == 0
 0477                                           ? "-specials"
 0478                                           : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture);
 479
 0480                    var imageFilename = "season" + seasonMarker + "-banner" + extension;
 481
 0482                    return Path.Combine(seriesFolder, imageFilename);
 483                }
 484            }
 485
 0486            if (type == ImageType.Logo && saveLocally)
 487            {
 0488                if (season is not null && season.IndexNumber.HasValue)
 489                {
 0490                    var seriesFolder = season.SeriesPath;
 491
 0492                    var seasonMarker = season.IndexNumber.Value == 0
 0493                                        ? "-specials"
 0494                                        : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture);
 495
 0496                    var imageFilename = "season" + seasonMarker + "-logo" + extension;
 497
 0498                    return Path.Combine(seriesFolder, imageFilename);
 499                }
 500            }
 501
 502            string filename;
 0503            var folderName = item is MusicAlbum ||
 0504                item is MusicArtist ||
 0505                item is PhotoAlbum ||
 0506                item is Person ||
 0507                (saveLocally && _config.Configuration.ImageSavingConvention == ImageSavingConvention.Legacy) ?
 0508                "folder" :
 0509                "poster";
 510
 511            switch (type)
 512            {
 513                case ImageType.Art:
 0514                    filename = "clearart";
 0515                    break;
 516                case ImageType.BoxRear:
 0517                    filename = "back";
 0518                    break;
 519                case ImageType.Thumb:
 0520                    filename = "landscape";
 0521                    break;
 522                case ImageType.Disc:
 0523                    filename = item is MusicAlbum ? "cdart" : "disc";
 0524                    break;
 525                case ImageType.Primary:
 0526                    filename = saveLocally && item is Episode ? Path.GetFileNameWithoutExtension(item.Path) : folderName
 0527                    break;
 528                case ImageType.Backdrop:
 0529                    filename = GetBackdropSaveFilename(item.GetImages(type), "backdrop", "backdrop", imageIndex);
 0530                    break;
 531                default:
 0532                    filename = type.ToString().ToLowerInvariant();
 533                    break;
 534            }
 535
 0536            string path = null;
 0537            if (saveLocally)
 538            {
 0539                if (type == ImageType.Primary && item is Episode)
 540                {
 0541                    path = Path.Combine(Path.GetDirectoryName(item.Path), filename + "-thumb" + extension);
 542                }
 0543                else if (item.IsInMixedFolder)
 544                {
 0545                    path = GetSavePathForItemInMixedFolder(item, type, filename, extension);
 546                }
 547
 0548                if (string.IsNullOrEmpty(path))
 549                {
 0550                    path = Path.Combine(item.ContainingFolderPath, filename + extension);
 551                }
 552            }
 553
 554            // None of the save local conditions passed, so store it in our internal folders
 0555            if (string.IsNullOrEmpty(path))
 556            {
 0557                if (string.IsNullOrEmpty(filename))
 558                {
 0559                    filename = folderName;
 560                }
 561
 0562                path = Path.Combine(item.GetInternalMetadataPath(), filename + extension);
 563            }
 564
 0565            return path;
 566        }
 567
 568        private string GetBackdropSaveFilename(IEnumerable<ItemImageInfo> images, string zeroIndexFilename, string numbe
 569        {
 0570            if (index.HasValue && index.Value == 0)
 571            {
 0572                return zeroIndexFilename;
 573            }
 574
 0575            var filenames = images.Select(i => Path.GetFileNameWithoutExtension(i.Path)).ToList();
 576
 0577            var current = 1;
 0578            while (filenames.Contains(numberedIndexPrefix + current.ToString(CultureInfo.InvariantCulture), StringCompar
 579            {
 0580                current++;
 581            }
 582
 0583            return numberedIndexPrefix + current.ToString(CultureInfo.InvariantCulture);
 584        }
 585
 586        /// <summary>
 587        /// Gets the compatible save paths.
 588        /// </summary>
 589        /// <param name="item">The item.</param>
 590        /// <param name="type">The type.</param>
 591        /// <param name="imageIndex">Index of the image.</param>
 592        /// <param name="mimeType">Type of the MIME.</param>
 593        /// <returns>IEnumerable{System.String}.</returns>
 594        /// <exception cref="ArgumentNullException">imageIndex.</exception>
 595        private string[] GetCompatibleSavePaths(BaseItem item, ImageType type, int? imageIndex, string mimeType)
 596        {
 0597            var season = item as Season;
 598
 0599            var extension = MimeTypes.ToExtension(mimeType);
 600
 601            // Backdrop paths
 0602            if (type == ImageType.Backdrop)
 603            {
 0604                if (!imageIndex.HasValue)
 605                {
 0606                    throw new ArgumentNullException(nameof(imageIndex));
 607                }
 608
 0609                if (imageIndex.Value == 0)
 610                {
 0611                    if (item.IsInMixedFolder)
 612                    {
 0613                        return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart", extension) };
 614                    }
 615
 0616                    if (season is not null && season.IndexNumber.HasValue)
 617                    {
 0618                        var seriesFolder = season.SeriesPath;
 619
 0620                        var seasonMarker = season.IndexNumber.Value == 0
 0621                                               ? "-specials"
 0622                                               : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture);
 623
 0624                        var imageFilename = "season" + seasonMarker + "-fanart" + extension;
 625
 0626                        return new[] { Path.Combine(seriesFolder, imageFilename) };
 627                    }
 628
 0629                    return new[]
 0630                        {
 0631                            Path.Combine(item.ContainingFolderPath, "fanart" + extension)
 0632                        };
 633                }
 634
 0635                var outputIndex = imageIndex.Value;
 636
 0637                if (item.IsInMixedFolder)
 638                {
 0639                    return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart" + outputIndex.ToString(CultureIn
 640                }
 641
 0642                var extraFanartFilename = GetBackdropSaveFilename(item.GetImages(ImageType.Backdrop), "fanart", "fanart"
 643
 0644                var list = new List<string>
 0645                {
 0646                    Path.Combine(item.ContainingFolderPath, "extrafanart", extraFanartFilename + extension)
 0647                };
 648
 0649                if (EnableExtraThumbsDuplication)
 650                {
 0651                    list.Add(Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + outputIndex.ToString(Cultu
 652                }
 653
 0654                return list.ToArray();
 655            }
 656
 0657            if (type == ImageType.Primary)
 658            {
 0659                if (season is not null && season.IndexNumber.HasValue)
 660                {
 0661                    var seriesFolder = season.SeriesPath;
 662
 0663                    var seasonMarker = season.IndexNumber.Value == 0
 0664                                           ? "-specials"
 0665                                           : season.IndexNumber.Value.ToString("00", CultureInfo.InvariantCulture);
 666
 0667                    var imageFilename = "season" + seasonMarker + "-poster" + extension;
 668
 0669                    return new[] { Path.Combine(seriesFolder, imageFilename) };
 670                }
 671
 0672                if (item is Episode)
 673                {
 0674                    var seasonFolder = Path.GetDirectoryName(item.Path);
 675
 0676                    var imageFilename = Path.GetFileNameWithoutExtension(item.Path) + "-thumb" + extension;
 677
 0678                    return new[] { Path.Combine(seasonFolder, imageFilename) };
 679                }
 680
 0681                if (item.IsInMixedFolder || item is MusicVideo)
 682                {
 0683                    return new[] { GetSavePathForItemInMixedFolder(item, type, string.Empty, extension) };
 684                }
 685
 0686                if (item is MusicAlbum || item is MusicArtist)
 687                {
 0688                    return new[] { Path.Combine(item.ContainingFolderPath, "folder" + extension) };
 689                }
 690
 0691                return new[] { Path.Combine(item.ContainingFolderPath, "poster" + extension) };
 692            }
 693
 694            // All other paths are the same
 0695            return new[] { GetStandardSavePath(item, type, imageIndex, mimeType, true) };
 696        }
 697
 698        /// <summary>
 699        /// Gets the save path for item in mixed folder.
 700        /// </summary>
 701        /// <param name="item">The item.</param>
 702        /// <param name="type">The type.</param>
 703        /// <param name="imageFilename">The image filename.</param>
 704        /// <param name="extension">The extension.</param>
 705        /// <returns>System.String.</returns>
 706        private string GetSavePathForItemInMixedFolder(BaseItem item, ImageType type, string imageFilename, string exten
 707        {
 0708            if (type == ImageType.Primary)
 709            {
 0710                imageFilename = "poster";
 711            }
 712
 0713            var folder = Path.GetDirectoryName(item.Path);
 714
 0715            return Path.Combine(folder, Path.GetFileNameWithoutExtension(item.Path) + "-" + imageFilename + extension);
 716        }
 717    }
 718}

Methods/Properties

.ctor(MediaBrowser.Controller.Configuration.IServerConfigurationManager,MediaBrowser.Controller.Library.ILibraryMonitor,MediaBrowser.Model.IO.IFileSystem,Microsoft.Extensions.Logging.ILogger)
get_EnableExtraThumbsDuplication()
SaveImage(MediaBrowser.Controller.Entities.BaseItem,System.IO.Stream,System.String,MediaBrowser.Model.Entities.ImageType,System.Nullable`1<System.Int32>,System.Threading.CancellationToken)
SetHidden(System.String,System.Boolean)
GetSavePaths(MediaBrowser.Controller.Entities.BaseItem,MediaBrowser.Model.Entities.ImageType,System.Nullable`1<System.Int32>,System.String,System.Boolean)
GetCurrentImage(MediaBrowser.Controller.Entities.BaseItem,MediaBrowser.Model.Entities.ImageType,System.Int32)
SetImagePath(MediaBrowser.Controller.Entities.BaseItem,MediaBrowser.Model.Entities.ImageType,System.Nullable`1<System.Int32>,System.String)
GetStandardSavePath(MediaBrowser.Controller.Entities.BaseItem,MediaBrowser.Model.Entities.ImageType,System.Nullable`1<System.Int32>,System.String,System.Boolean)
GetBackdropSaveFilename(System.Collections.Generic.IEnumerable`1<MediaBrowser.Controller.Entities.ItemImageInfo>,System.String,System.String,System.Nullable`1<System.Int32>)
GetCompatibleSavePaths(MediaBrowser.Controller.Entities.BaseItem,MediaBrowser.Model.Entities.ImageType,System.Nullable`1<System.Int32>,System.String)
GetSavePathForItemInMixedFolder(MediaBrowser.Controller.Entities.BaseItem,MediaBrowser.Model.Entities.ImageType,System.String,System.String)