< 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
21%
Covered lines: 23
Uncovered lines: 85
Coverable lines: 108
Total lines: 319
Line coverage: 21.2%
Branch coverage
15%
Covered branches: 8
Total branches: 52
Branch coverage: 15.3%
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_MaxImageAgeDays()100%210%
get_Order()100%11100%
Supports(...)100%210%
FetchAsync(...)33.33%10.5650%
CreateThumbCollage(...)100%210%
GetStripCollageImagePaths(...)0%2040%
CreatePosterCollage(...)100%210%
CreateSquareCollage(...)100%210%
CreateThumbCollage(...)100%210%
CreateCollage(...)0%2040%
CreateImage(...)0%342180%
HasChanged(...)30%28.671042.85%
HasChanged(...)25%26.97833.33%
HasChangedByDate(...)100%210%
CreateSingleImage(...)50%2.26260%

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.Threading;
 11using System.Threading.Tasks;
 12using MediaBrowser.Common.Configuration;
 13using MediaBrowser.Controller.Drawing;
 14using MediaBrowser.Controller.Entities;
 15using MediaBrowser.Controller.Entities.Audio;
 16using MediaBrowser.Controller.Library;
 17using MediaBrowser.Controller.Playlists;
 18using MediaBrowser.Controller.Providers;
 19using MediaBrowser.Model.Entities;
 20using MediaBrowser.Model.IO;
 21using MediaBrowser.Model.Net;
 22
 23namespace Emby.Server.Implementations.Images
 24{
 25    public abstract class BaseDynamicImageProvider<T> : IHasItemChangeMonitor, IForcedProvider, ICustomMetadataProvider<
 26        where T : BaseItem
 27    {
 28        protected BaseDynamicImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths a
 29        {
 22030            ApplicationPaths = applicationPaths;
 22031            ProviderManager = providerManager;
 22032            FileSystem = fileSystem;
 22033            ImageProcessor = imageProcessor;
 22034        }
 35
 36        protected IFileSystem FileSystem { get; }
 37
 38        protected IProviderManager ProviderManager { get; }
 39
 40        protected IApplicationPaths ApplicationPaths { get; }
 41
 42        protected IImageProcessor ImageProcessor { get; set; }
 43
 44        protected virtual IReadOnlyCollection<ImageType> SupportedImages { get; }
 22045            = new ImageType[] { ImageType.Primary };
 46
 47        /// <inheritdoc />
 048        public string Name => "Dynamic Image Provider";
 49
 050        protected virtual int MaxImageAgeDays => 7;
 51
 4652        public int Order => 0;
 53
 054        protected virtual bool Supports(BaseItem item) => true;
 55
 56        public async Task<ItemUpdateType> FetchAsync(T item, MetadataRefreshOptions options, CancellationToken cancellat
 57        {
 58            if (!Supports(item))
 59            {
 60                return ItemUpdateType.None;
 61            }
 62
 63            var updateType = ItemUpdateType.None;
 64
 65            if (SupportedImages.Contains(ImageType.Primary))
 66            {
 67                var primaryResult = await FetchAsync(item, ImageType.Primary, options, cancellationToken).ConfigureAwait
 68                updateType |= primaryResult;
 69            }
 70
 71            if (SupportedImages.Contains(ImageType.Thumb))
 72            {
 73                var thumbResult = await FetchAsync(item, ImageType.Thumb, options, cancellationToken).ConfigureAwait(fal
 74                updateType |= thumbResult;
 75            }
 76
 77            return updateType;
 78        }
 79
 80        protected Task<ItemUpdateType> FetchAsync(BaseItem item, ImageType imageType, MetadataRefreshOptions options, Ca
 81        {
 4682            var image = item.GetImageInfo(imageType, 0);
 83
 4684            if (image is not null)
 85            {
 086                if (!image.IsLocalFile)
 87                {
 088                    return Task.FromResult(ItemUpdateType.None);
 89                }
 90
 091                if (!FileSystem.ContainsSubPath(item.GetInternalMetadataPath(), image.Path))
 92                {
 093                    return Task.FromResult(ItemUpdateType.None);
 94                }
 95            }
 96
 4697            var items = GetItemsWithImages(item);
 98
 4699            return FetchToFileInternal(item, items, imageType, cancellationToken);
 100        }
 101
 102        protected async Task<ItemUpdateType> FetchToFileInternal(
 103            BaseItem item,
 104            IReadOnlyList<BaseItem> itemsWithImages,
 105            ImageType imageType,
 106            CancellationToken cancellationToken)
 107        {
 108            var outputPathWithoutExtension = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid().ToString("N", C
 109            Directory.CreateDirectory(Path.GetDirectoryName(outputPathWithoutExtension));
 110            string outputPath = CreateImage(item, itemsWithImages, outputPathWithoutExtension, imageType, 0);
 111
 112            if (string.IsNullOrEmpty(outputPath))
 113            {
 114                return ItemUpdateType.None;
 115            }
 116
 117            var mimeType = MimeTypes.GetMimeType(outputPath);
 118
 119            if (string.Equals(mimeType, "application/octet-stream", StringComparison.OrdinalIgnoreCase))
 120            {
 121                mimeType = "image/png";
 122            }
 123
 124            await ProviderManager.SaveImage(item, outputPath, mimeType, imageType, null, false, cancellationToken).Confi
 125            File.Delete(outputPath);
 126
 127            return ItemUpdateType.ImageUpdate;
 128        }
 129
 130        protected abstract IReadOnlyList<BaseItem> GetItemsWithImages(BaseItem item);
 131
 132        protected string CreateThumbCollage(BaseItem primaryItem, IEnumerable<BaseItem> items, string outputPath)
 133        {
 0134            return CreateCollage(primaryItem, items, outputPath, 640, 360);
 135        }
 136
 137        protected virtual IEnumerable<string> GetStripCollageImagePaths(BaseItem primaryItem, IEnumerable<BaseItem> item
 138        {
 0139            var useBackdrop = primaryItem is CollectionFolder || primaryItem is UserView;
 0140            return items
 0141                .Select(i =>
 0142                {
 0143                    // Use Backdrop instead of Primary image for Library images.
 0144                    if (useBackdrop)
 0145                    {
 0146                        var backdrop = i.GetImageInfo(ImageType.Backdrop, 0);
 0147                        if (backdrop is not null && backdrop.IsLocalFile)
 0148                        {
 0149                            return backdrop.Path;
 0150                        }
 0151                    }
 0152
 0153                    var image = i.GetImageInfo(ImageType.Primary, 0);
 0154                    if (image is not null && image.IsLocalFile)
 0155                    {
 0156                        return image.Path;
 0157                    }
 0158
 0159                    image = i.GetImageInfo(ImageType.Thumb, 0);
 0160                    if (image is not null && image.IsLocalFile)
 0161                    {
 0162                        return image.Path;
 0163                    }
 0164
 0165                    return null;
 0166                })
 0167                .Where(i => !string.IsNullOrEmpty(i));
 168        }
 169
 170        protected string CreatePosterCollage(BaseItem primaryItem, IEnumerable<BaseItem> items, string outputPath)
 171        {
 0172            return CreateCollage(primaryItem, items, outputPath, 400, 600);
 173        }
 174
 175        protected string CreateSquareCollage(BaseItem primaryItem, IEnumerable<BaseItem> items, string outputPath)
 176        {
 0177            return CreateCollage(primaryItem, items, outputPath, 600, 600);
 178        }
 179
 180        protected string CreateThumbCollage(BaseItem primaryItem, IEnumerable<BaseItem> items, string outputPath, int wi
 181        {
 0182            return CreateCollage(primaryItem, items, outputPath, width, height);
 183        }
 184
 185        private string CreateCollage(BaseItem primaryItem, IEnumerable<BaseItem> items, string outputPath, int width, in
 186        {
 0187            Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
 188
 0189            var options = new ImageCollageOptions
 0190            {
 0191                Height = height,
 0192                Width = width,
 0193                OutputPath = outputPath,
 0194                InputPaths = GetStripCollageImagePaths(primaryItem, items).ToArray()
 0195            };
 196
 0197            if (options.InputPaths.Count == 0)
 198            {
 0199                return null;
 200            }
 201
 0202            if (!ImageProcessor.SupportsImageCollageCreation)
 203            {
 0204                return null;
 205            }
 206
 0207            ImageProcessor.CreateImageCollage(options, primaryItem.Name);
 0208            return outputPath;
 209        }
 210
 211        protected virtual string CreateImage(
 212            BaseItem item,
 213            IReadOnlyCollection<BaseItem> itemsWithImages,
 214            string outputPathWithoutExtension,
 215            ImageType imageType,
 216            int imageIndex)
 217        {
 0218            if (itemsWithImages.Count == 0)
 219            {
 0220                return null;
 221            }
 222
 0223            string outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png");
 224
 0225            if (imageType == ImageType.Thumb)
 226            {
 0227                return CreateThumbCollage(item, itemsWithImages, outputPath);
 228            }
 229
 0230            if (imageType == ImageType.Primary)
 231            {
 0232                if (item is UserView
 0233                    || item is Playlist
 0234                    || item is MusicGenre
 0235                    || item is Genre
 0236                    || item is PhotoAlbum
 0237                    || item is MusicArtist)
 238                {
 0239                    return CreateSquareCollage(item, itemsWithImages, outputPath);
 240                }
 241
 0242                return CreatePosterCollage(item, itemsWithImages, outputPath);
 243            }
 244
 0245            throw new ArgumentException("Unexpected image type", nameof(imageType));
 246        }
 247
 248        public bool HasChanged(BaseItem item, IDirectoryService directoryService)
 249        {
 10250            if (!Supports(item))
 251            {
 0252                return false;
 253            }
 254
 10255            if (SupportedImages.Contains(ImageType.Primary) && HasChanged(item, ImageType.Primary))
 256            {
 10257                return true;
 258            }
 259
 0260            if (SupportedImages.Contains(ImageType.Thumb) && HasChanged(item, ImageType.Thumb))
 261            {
 0262                return true;
 263            }
 264
 0265            return false;
 266        }
 267
 268        protected bool HasChanged(BaseItem item, ImageType type)
 269        {
 10270            var image = item.GetImageInfo(type, 0);
 271
 10272            if (image is not null)
 273            {
 0274                if (!image.IsLocalFile)
 275                {
 0276                    return false;
 277                }
 278
 0279                if (!FileSystem.ContainsSubPath(item.GetInternalMetadataPath(), image.Path))
 280                {
 0281                    return false;
 282                }
 283
 0284                if (!HasChangedByDate(item, image))
 285                {
 0286                    return false;
 287                }
 288            }
 289
 10290            return true;
 291        }
 292
 293        protected virtual bool HasChangedByDate(BaseItem item, ItemImageInfo image)
 294        {
 0295            var age = DateTime.UtcNow - image.DateModified;
 0296            return age.TotalDays > MaxImageAgeDays;
 297        }
 298
 299        protected string CreateSingleImage(IEnumerable<BaseItem> itemsWithImages, string outputPathWithoutExtension, Ima
 300        {
 42301            var image = itemsWithImages
 42302                .Where(i => i.HasImage(imageType) && i.GetImageInfo(imageType, 0).IsLocalFile && Path.HasExtension(i.Get
 42303                .Select(i => i.GetImagePath(imageType))
 42304                .FirstOrDefault();
 305
 42306            if (string.IsNullOrEmpty(image))
 307            {
 42308                return null;
 309            }
 310
 0311            var ext = Path.GetExtension(image);
 312
 0313            var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ext);
 0314            File.Copy(image, outputPath, true);
 315
 0316            return outputPath;
 317        }
 318    }
 319}

Methods/Properties

.ctor(MediaBrowser.Model.IO.IFileSystem,MediaBrowser.Controller.Providers.IProviderManager,MediaBrowser.Common.Configuration.IApplicationPaths,MediaBrowser.Controller.Drawing.IImageProcessor)
get_Name()
get_MaxImageAgeDays()
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)