< Summary - Jellyfin

Information
Class: Emby.Server.Implementations.Images.BaseDynamicImageProvider<T>
Assembly: Emby.Server.Implementations
File(s): /srv/git/jellyfin/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs
Line coverage
20%
Covered lines: 22
Uncovered lines: 88
Coverable lines: 110
Total lines: 323
Line coverage: 20%
Branch coverage
14%
Covered branches: 8
Total branches: 54
Branch coverage: 14.8%
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%11100%
get_Name()100%210%
get_Order()100%210%
Supports(...)100%210%
FetchAsync(...)33.33%11650%
CreateThumbCollage(...)100%210%
GetStripCollageImagePaths(...)0%2040%
CreatePosterCollage(...)100%210%
CreateSquareCollage(...)100%210%
CreateThumbCollage(...)100%210%
CreateCollage(...)0%2040%
CreateImage(...)0%342180%
HasChanged(...)30%291042.85%
HasChanged(...)25%27833.33%
HasChangedByDate(...)0%620%
CreateSingleImage(...)50%2260%

File(s)

/srv/git/jellyfin/Emby.Server.Implementations/Images/BaseDynamicImageProvider.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.Net.Mime;
 11using System.Threading;
 12using System.Threading.Tasks;
 13using MediaBrowser.Common.Configuration;
 14using MediaBrowser.Controller.Drawing;
 15using MediaBrowser.Controller.Entities;
 16using MediaBrowser.Controller.Entities.Audio;
 17using MediaBrowser.Controller.Library;
 18using MediaBrowser.Controller.Playlists;
 19using MediaBrowser.Controller.Providers;
 20using MediaBrowser.Model.Entities;
 21using MediaBrowser.Model.IO;
 22using MediaBrowser.Model.Net;
 23
 24namespace Emby.Server.Implementations.Images
 25{
 26    public abstract class BaseDynamicImageProvider<T> : IHasItemChangeMonitor, IForcedProvider, ICustomMetadataProvider<
 27        where T : BaseItem
 28    {
 29        protected BaseDynamicImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths a
 30        {
 21031            ApplicationPaths = applicationPaths;
 21032            ProviderManager = providerManager;
 21033            FileSystem = fileSystem;
 21034            ImageProcessor = imageProcessor;
 21035        }
 36
 37        protected IFileSystem FileSystem { get; }
 38
 39        protected IProviderManager ProviderManager { get; }
 40
 41        protected IApplicationPaths ApplicationPaths { get; }
 42
 43        protected IImageProcessor ImageProcessor { get; set; }
 44
 45        protected virtual IReadOnlyCollection<ImageType> SupportedImages { get; }
 21046            = [ImageType.Primary];
 47
 48        /// <inheritdoc />
 049        public string Name => "Dynamic Image Provider";
 50
 051        public int Order => 0;
 52
 053        protected virtual bool Supports(BaseItem item) => true;
 54
 55        public async Task<ItemUpdateType> FetchAsync(T item, MetadataRefreshOptions options, CancellationToken cancellat
 56        {
 57            if (!Supports(item))
 58            {
 59                return ItemUpdateType.None;
 60            }
 61
 62            var updateType = ItemUpdateType.None;
 63
 64            if (SupportedImages.Contains(ImageType.Primary))
 65            {
 66                var primaryResult = await FetchAsync(item, ImageType.Primary, options, cancellationToken).ConfigureAwait
 67                updateType |= primaryResult;
 68            }
 69
 70            if (SupportedImages.Contains(ImageType.Thumb))
 71            {
 72                var thumbResult = await FetchAsync(item, ImageType.Thumb, options, cancellationToken).ConfigureAwait(fal
 73                updateType |= thumbResult;
 74            }
 75
 76            return updateType;
 77        }
 78
 79        protected Task<ItemUpdateType> FetchAsync(BaseItem item, ImageType imageType, MetadataRefreshOptions options, Ca
 80        {
 5381            var image = item.GetImageInfo(imageType, 0);
 82
 5383            if (image is not null)
 84            {
 085                if (!image.IsLocalFile)
 86                {
 087                    return Task.FromResult(ItemUpdateType.None);
 88                }
 89
 090                if (!FileSystem.ContainsSubPath(item.GetInternalMetadataPath(), image.Path))
 91                {
 092                    return Task.FromResult(ItemUpdateType.None);
 93                }
 94            }
 95
 5396            var items = GetItemsWithImages(item);
 97
 5398            return FetchToFileInternal(item, items, imageType, cancellationToken);
 99        }
 100
 101        protected async Task<ItemUpdateType> FetchToFileInternal(
 102            BaseItem item,
 103            IReadOnlyList<BaseItem> itemsWithImages,
 104            ImageType imageType,
 105            CancellationToken cancellationToken)
 106        {
 107            var outputPathWithoutExtension = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid().ToString("N", C
 108            Directory.CreateDirectory(Path.GetDirectoryName(outputPathWithoutExtension));
 109            string outputPath = CreateImage(item, itemsWithImages, outputPathWithoutExtension, imageType, 0);
 110
 111            if (string.IsNullOrEmpty(outputPath))
 112            {
 113                return ItemUpdateType.None;
 114            }
 115
 116            var mimeType = MimeTypes.GetMimeType(outputPath);
 117
 118            if (string.Equals(mimeType, MediaTypeNames.Application.Octet, StringComparison.OrdinalIgnoreCase))
 119            {
 120                mimeType = MediaTypeNames.Image.Png;
 121            }
 122
 123            await ProviderManager.SaveImage(item, outputPath, mimeType, imageType, null, false, cancellationToken).Confi
 124
 125            return ItemUpdateType.ImageUpdate;
 126        }
 127
 128        protected abstract IReadOnlyList<BaseItem> GetItemsWithImages(BaseItem item);
 129
 130        protected string CreateThumbCollage(BaseItem primaryItem, IEnumerable<BaseItem> items, string outputPath)
 131        {
 0132            return CreateCollage(primaryItem, items, outputPath, 640, 360);
 133        }
 134
 135        protected virtual IEnumerable<string> GetStripCollageImagePaths(BaseItem primaryItem, IEnumerable<BaseItem> item
 136        {
 0137            var useBackdrop = primaryItem is CollectionFolder || primaryItem is UserView;
 0138            return items
 0139                .Select(i =>
 0140                {
 0141                    // Use Backdrop instead of Primary image for Library images.
 0142                    if (useBackdrop)
 0143                    {
 0144                        var backdrop = i.GetImageInfo(ImageType.Backdrop, 0);
 0145                        if (backdrop is not null && backdrop.IsLocalFile)
 0146                        {
 0147                            return backdrop.Path;
 0148                        }
 0149                    }
 0150
 0151                    var image = i.GetImageInfo(ImageType.Primary, 0);
 0152                    if (image is not null && image.IsLocalFile)
 0153                    {
 0154                        return image.Path;
 0155                    }
 0156
 0157                    image = i.GetImageInfo(ImageType.Thumb, 0);
 0158                    if (image is not null && image.IsLocalFile)
 0159                    {
 0160                        return image.Path;
 0161                    }
 0162
 0163                    return null;
 0164                })
 0165                .Where(i => !string.IsNullOrEmpty(i));
 166        }
 167
 168        protected string CreatePosterCollage(BaseItem primaryItem, IEnumerable<BaseItem> items, string outputPath)
 169        {
 0170            return CreateCollage(primaryItem, items, outputPath, 400, 600);
 171        }
 172
 173        protected string CreateSquareCollage(BaseItem primaryItem, IEnumerable<BaseItem> items, string outputPath)
 174        {
 0175            return CreateCollage(primaryItem, items, outputPath, 600, 600);
 176        }
 177
 178        protected string CreateThumbCollage(BaseItem primaryItem, IEnumerable<BaseItem> items, string outputPath, int wi
 179        {
 0180            return CreateCollage(primaryItem, items, outputPath, width, height);
 181        }
 182
 183        private string CreateCollage(BaseItem primaryItem, IEnumerable<BaseItem> items, string outputPath, int width, in
 184        {
 0185            Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
 186
 0187            var options = new ImageCollageOptions
 0188            {
 0189                Height = height,
 0190                Width = width,
 0191                OutputPath = outputPath,
 0192                InputPaths = GetStripCollageImagePaths(primaryItem, items).ToArray()
 0193            };
 194
 0195            if (options.InputPaths.Count == 0)
 196            {
 0197                return null;
 198            }
 199
 0200            if (!ImageProcessor.SupportsImageCollageCreation)
 201            {
 0202                return null;
 203            }
 204
 0205            ImageProcessor.CreateImageCollage(options, primaryItem.Name);
 0206            return outputPath;
 207        }
 208
 209        protected virtual string CreateImage(
 210            BaseItem item,
 211            IReadOnlyCollection<BaseItem> itemsWithImages,
 212            string outputPathWithoutExtension,
 213            ImageType imageType,
 214            int imageIndex)
 215        {
 0216            if (itemsWithImages.Count == 0)
 217            {
 0218                return null;
 219            }
 220
 0221            string outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png");
 222
 0223            if (imageType == ImageType.Thumb)
 224            {
 0225                return CreateThumbCollage(item, itemsWithImages, outputPath);
 226            }
 227
 0228            if (imageType == ImageType.Primary)
 229            {
 0230                if (item is UserView
 0231                    || item is Playlist
 0232                    || item is MusicGenre
 0233                    || item is Genre
 0234                    || item is PhotoAlbum
 0235                    || item is MusicArtist)
 236                {
 0237                    return CreateSquareCollage(item, itemsWithImages, outputPath);
 238                }
 239
 0240                return CreatePosterCollage(item, itemsWithImages, outputPath);
 241            }
 242
 0243            throw new ArgumentException("Unexpected image type", nameof(imageType));
 244        }
 245
 246        public bool HasChanged(BaseItem item, IDirectoryService directoryService)
 247        {
 22248            if (!Supports(item))
 249            {
 0250                return false;
 251            }
 252
 22253            if (SupportedImages.Contains(ImageType.Primary) && HasChanged(item, ImageType.Primary))
 254            {
 22255                return true;
 256            }
 257
 0258            if (SupportedImages.Contains(ImageType.Thumb) && HasChanged(item, ImageType.Thumb))
 259            {
 0260                return true;
 261            }
 262
 0263            return false;
 264        }
 265
 266        protected bool HasChanged(BaseItem item, ImageType type)
 267        {
 22268            var image = item.GetImageInfo(type, 0);
 269
 22270            if (image is not null)
 271            {
 0272                if (!image.IsLocalFile)
 273                {
 0274                    return false;
 275                }
 276
 0277                if (!FileSystem.ContainsSubPath(item.GetInternalMetadataPath(), image.Path))
 278                {
 0279                    return false;
 280                }
 281
 0282                if (!HasChangedByDate(item, image))
 283                {
 0284                    return false;
 285                }
 286            }
 287
 22288            return true;
 289        }
 290
 291        protected virtual bool HasChangedByDate(BaseItem item, ItemImageInfo image)
 292        {
 0293            var path = image.Path;
 0294            if (!string.IsNullOrEmpty(path))
 295            {
 0296                var modificationDate = FileSystem.GetLastWriteTimeUtc(path);
 0297                return image.DateModified != modificationDate;
 298            }
 299
 0300            return false;
 301        }
 302
 303        protected string CreateSingleImage(IEnumerable<BaseItem> itemsWithImages, string outputPathWithoutExtension, Ima
 304        {
 38305            var image = itemsWithImages
 38306                .Where(i => i.HasImage(imageType) && i.GetImageInfo(imageType, 0).IsLocalFile && Path.HasExtension(i.Get
 38307                .Select(i => i.GetImagePath(imageType))
 38308                .FirstOrDefault();
 309
 38310            if (string.IsNullOrEmpty(image))
 311            {
 38312                return null;
 313            }
 314
 0315            var ext = Path.GetExtension(image);
 316
 0317            var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ext);
 0318            File.Copy(image, outputPath, true);
 319
 0320            return outputPath;
 321        }
 322    }
 323}

Methods/Properties

.ctor(MediaBrowser.Model.IO.IFileSystem,MediaBrowser.Controller.Providers.IProviderManager,MediaBrowser.Common.Configuration.IApplicationPaths,MediaBrowser.Controller.Drawing.IImageProcessor)
get_Name()
get_Order()
Supports(MediaBrowser.Controller.Entities.BaseItem)
FetchAsync(MediaBrowser.Controller.Entities.BaseItem,MediaBrowser.Model.Entities.ImageType,MediaBrowser.Controller.Providers.MetadataRefreshOptions,System.Threading.CancellationToken)
CreateThumbCollage(MediaBrowser.Controller.Entities.BaseItem,System.Collections.Generic.IEnumerable`1<MediaBrowser.Controller.Entities.BaseItem>,System.String)
GetStripCollageImagePaths(MediaBrowser.Controller.Entities.BaseItem,System.Collections.Generic.IEnumerable`1<MediaBrowser.Controller.Entities.BaseItem>)
CreatePosterCollage(MediaBrowser.Controller.Entities.BaseItem,System.Collections.Generic.IEnumerable`1<MediaBrowser.Controller.Entities.BaseItem>,System.String)
CreateSquareCollage(MediaBrowser.Controller.Entities.BaseItem,System.Collections.Generic.IEnumerable`1<MediaBrowser.Controller.Entities.BaseItem>,System.String)
CreateThumbCollage(MediaBrowser.Controller.Entities.BaseItem,System.Collections.Generic.IEnumerable`1<MediaBrowser.Controller.Entities.BaseItem>,System.String,System.Int32,System.Int32)
CreateCollage(MediaBrowser.Controller.Entities.BaseItem,System.Collections.Generic.IEnumerable`1<MediaBrowser.Controller.Entities.BaseItem>,System.String,System.Int32,System.Int32)
CreateImage(MediaBrowser.Controller.Entities.BaseItem,System.Collections.Generic.IReadOnlyCollection`1<MediaBrowser.Controller.Entities.BaseItem>,System.String,MediaBrowser.Model.Entities.ImageType,System.Int32)
HasChanged(MediaBrowser.Controller.Entities.BaseItem,MediaBrowser.Controller.Providers.IDirectoryService)
HasChanged(MediaBrowser.Controller.Entities.BaseItem,MediaBrowser.Model.Entities.ImageType)
HasChangedByDate(MediaBrowser.Controller.Entities.BaseItem,MediaBrowser.Controller.Entities.ItemImageInfo)
CreateSingleImage(System.Collections.Generic.IEnumerable`1<MediaBrowser.Controller.Entities.BaseItem>,System.String,MediaBrowser.Model.Entities.ImageType)