From b76a1abda578b8ff64bad2997b036b0fc43e264f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 3 Nov 2016 03:14:14 -0400 Subject: move classes to portable server lib --- .../Images/BaseDynamicImageProvider.cs | 361 +++++++++++++++++++++ 1 file changed, 361 insertions(+) create mode 100644 Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs (limited to 'Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs') diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs new file mode 100644 index 000000000..224cd056a --- /dev/null +++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs @@ -0,0 +1,361 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Playlists; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Common.IO; +using MediaBrowser.Model.IO; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.IO; +using MediaBrowser.Model.Configuration; + +namespace Emby.Server.Implementations.Images +{ + public abstract class BaseDynamicImageProvider : IHasItemChangeMonitor, IForcedProvider, ICustomMetadataProvider, IHasOrder + where T : IHasMetadata + { + protected IFileSystem FileSystem { get; private set; } + protected IProviderManager ProviderManager { get; private set; } + protected IApplicationPaths ApplicationPaths { get; private set; } + protected IImageProcessor ImageProcessor { get; set; } + + protected BaseDynamicImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor) + { + ApplicationPaths = applicationPaths; + ProviderManager = providerManager; + FileSystem = fileSystem; + ImageProcessor = imageProcessor; + } + + protected virtual bool Supports(IHasImages item) + { + return true; + } + + public virtual IEnumerable GetSupportedImages(IHasImages item) + { + return new List + { + ImageType.Primary, + ImageType.Thumb + }; + } + + private IEnumerable GetEnabledImages(IHasImages item) + { + //var options = ProviderManager.GetMetadataOptions(item); + + return GetSupportedImages(item); + //return GetSupportedImages(item).Where(i => IsEnabled(options, i, item)).ToList(); + } + + private bool IsEnabled(MetadataOptions options, ImageType type, IHasImages item) + { + if (type == ImageType.Backdrop) + { + if (item.LockedFields.Contains(MetadataFields.Backdrops)) + { + return false; + } + } + else if (type == ImageType.Screenshot) + { + if (item.LockedFields.Contains(MetadataFields.Screenshots)) + { + return false; + } + } + else + { + if (item.LockedFields.Contains(MetadataFields.Images)) + { + return false; + } + } + + return options.IsEnabled(type); + } + + public async Task FetchAsync(T item, MetadataRefreshOptions options, CancellationToken cancellationToken) + { + if (!Supports(item)) + { + return ItemUpdateType.None; + } + + var updateType = ItemUpdateType.None; + var supportedImages = GetEnabledImages(item).ToList(); + + if (supportedImages.Contains(ImageType.Primary)) + { + var primaryResult = await FetchAsync(item, ImageType.Primary, options, cancellationToken).ConfigureAwait(false); + updateType = updateType | primaryResult; + } + + if (supportedImages.Contains(ImageType.Thumb)) + { + var thumbResult = await FetchAsync(item, ImageType.Thumb, options, cancellationToken).ConfigureAwait(false); + updateType = updateType | thumbResult; + } + + return updateType; + } + + protected async Task FetchAsync(IHasImages item, ImageType imageType, MetadataRefreshOptions options, CancellationToken cancellationToken) + { + var image = item.GetImageInfo(imageType, 0); + + if (image != null) + { + if (!image.IsLocalFile) + { + return ItemUpdateType.None; + } + + if (!FileSystem.ContainsSubPath(item.GetInternalMetadataPath(), image.Path)) + { + return ItemUpdateType.None; + } + } + + var items = await GetItemsWithImages(item).ConfigureAwait(false); + + return await FetchToFileInternal(item, items, imageType, cancellationToken).ConfigureAwait(false); + } + + protected async Task FetchToFileInternal(IHasImages item, + List itemsWithImages, + ImageType imageType, + CancellationToken cancellationToken) + { + var outputPathWithoutExtension = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid().ToString("N")); + FileSystem.CreateDirectory(Path.GetDirectoryName(outputPathWithoutExtension)); + string outputPath = await CreateImage(item, itemsWithImages, outputPathWithoutExtension, imageType, 0).ConfigureAwait(false); + + if (string.IsNullOrWhiteSpace(outputPath)) + { + return ItemUpdateType.None; + } + + await ProviderManager.SaveImage(item, outputPath, "image/png", imageType, null, false, cancellationToken).ConfigureAwait(false); + + return ItemUpdateType.ImageUpdate; + } + + protected abstract Task> GetItemsWithImages(IHasImages item); + + protected Task CreateThumbCollage(IHasImages primaryItem, List items, string outputPath) + { + return CreateCollage(primaryItem, items, outputPath, 640, 360); + } + + protected virtual IEnumerable GetStripCollageImagePaths(IHasImages primaryItem, IEnumerable items) + { + return items + .Select(i => + { + var image = i.GetImageInfo(ImageType.Primary, 0); + + if (image != null && image.IsLocalFile) + { + return image.Path; + } + image = i.GetImageInfo(ImageType.Thumb, 0); + + if (image != null && image.IsLocalFile) + { + return image.Path; + } + return null; + }) + .Where(i => !string.IsNullOrWhiteSpace(i)); + } + + protected Task CreatePosterCollage(IHasImages primaryItem, List items, string outputPath) + { + return CreateCollage(primaryItem, items, outputPath, 400, 600); + } + + protected Task CreateSquareCollage(IHasImages primaryItem, List items, string outputPath) + { + return CreateCollage(primaryItem, items, outputPath, 600, 600); + } + + protected Task CreateThumbCollage(IHasImages primaryItem, List items, string outputPath, int width, int height) + { + return CreateCollage(primaryItem, items, outputPath, width, height); + } + + private async Task CreateCollage(IHasImages primaryItem, List items, string outputPath, int width, int height) + { + FileSystem.CreateDirectory(Path.GetDirectoryName(outputPath)); + + var options = new ImageCollageOptions + { + Height = height, + Width = width, + OutputPath = outputPath, + InputPaths = GetStripCollageImagePaths(primaryItem, items).ToArray() + }; + + if (options.InputPaths.Length == 0) + { + return null; + } + + if (!ImageProcessor.SupportsImageCollageCreation) + { + return null; + } + + await ImageProcessor.CreateImageCollage(options).ConfigureAwait(false); + return outputPath; + } + + public string Name + { + get { return "Dynamic Image Provider"; } + } + + protected virtual async Task CreateImage(IHasImages item, + List itemsWithImages, + string outputPathWithoutExtension, + ImageType imageType, + int imageIndex) + { + if (itemsWithImages.Count == 0) + { + return null; + } + + string outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png"); + + if (imageType == ImageType.Thumb) + { + return await CreateThumbCollage(item, itemsWithImages, outputPath).ConfigureAwait(false); + } + + if (imageType == ImageType.Primary) + { + if (item is UserView) + { + return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false); + } + if (item is Playlist || item is MusicGenre) + { + return await CreateSquareCollage(item, itemsWithImages, outputPath).ConfigureAwait(false); + } + return await CreatePosterCollage(item, itemsWithImages, outputPath).ConfigureAwait(false); + } + + throw new ArgumentException("Unexpected image type"); + } + + protected virtual int MaxImageAgeDays + { + get { return 7; } + } + + public bool HasChanged(IHasMetadata item, IDirectoryService directoryServicee) + { + if (!Supports(item)) + { + return false; + } + + var supportedImages = GetEnabledImages(item).ToList(); + + if (supportedImages.Contains(ImageType.Primary) && HasChanged(item, ImageType.Primary)) + { + return true; + } + if (supportedImages.Contains(ImageType.Thumb) && HasChanged(item, ImageType.Thumb)) + { + return true; + } + + return false; + } + + protected bool HasChanged(IHasImages item, ImageType type) + { + var image = item.GetImageInfo(type, 0); + + if (image != null) + { + if (!image.IsLocalFile) + { + return false; + } + + if (!FileSystem.ContainsSubPath(item.GetInternalMetadataPath(), image.Path)) + { + return false; + } + + var age = DateTime.UtcNow - image.DateModified; + if (age.TotalDays <= MaxImageAgeDays) + { + return false; + } + } + + return true; + } + + protected List GetFinalItems(List items) + { + return GetFinalItems(items, 4); + } + + protected virtual List GetFinalItems(List items, int limit) + { + // Rotate the images once every x days + var random = DateTime.Now.DayOfYear % MaxImageAgeDays; + + return items + .OrderBy(i => (random + string.Empty + items.IndexOf(i)).GetMD5()) + .Take(limit) + .OrderBy(i => i.Name) + .ToList(); + } + + public int Order + { + get + { + // Run before the default image provider which will download placeholders + return 0; + } + } + + protected async Task CreateSingleImage(List itemsWithImages, string outputPathWithoutExtension, ImageType imageType) + { + var image = itemsWithImages + .Where(i => i.HasImage(imageType) && i.GetImageInfo(imageType, 0).IsLocalFile && Path.HasExtension(i.GetImagePath(imageType))) + .Select(i => i.GetImagePath(imageType)) + .FirstOrDefault(); + + if (string.IsNullOrWhiteSpace(image)) + { + return null; + } + + var ext = Path.GetExtension(image); + + var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ext); + FileSystem.CopyFile(image, outputPath, true); + + return outputPath; + } + } +} -- cgit v1.2.3 From fa24cd65af30e50a5da206804eb14dc7ba834e46 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 11 Nov 2016 23:02:35 -0500 Subject: fix dynamic image extension --- Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs') diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs index 224cd056a..5a8be5a49 100644 --- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs +++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs @@ -17,6 +17,7 @@ using MediaBrowser.Model.IO; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.IO; using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Net; namespace Emby.Server.Implementations.Images { @@ -146,7 +147,9 @@ namespace Emby.Server.Implementations.Images return ItemUpdateType.None; } - await ProviderManager.SaveImage(item, outputPath, "image/png", imageType, null, false, cancellationToken).ConfigureAwait(false); + var mimeType = MimeTypes.GetMimeType(outputPath); + + await ProviderManager.SaveImage(item, outputPath, mimeType, imageType, null, false, cancellationToken).ConfigureAwait(false); return ItemUpdateType.ImageUpdate; } -- cgit v1.2.3 From 4a9c77c32713ed0a52597f9abb7313062ef1872f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 2 Dec 2016 15:45:11 -0500 Subject: update backdrops --- .../Images/BaseDynamicImageProvider.cs | 5 +++++ .../UserViews/DynamicImageProvider.cs | 16 +++++----------- 2 files changed, 10 insertions(+), 11 deletions(-) (limited to 'Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs') diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs index 5a8be5a49..7a36691df 100644 --- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs +++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs @@ -149,6 +149,11 @@ namespace Emby.Server.Implementations.Images var mimeType = MimeTypes.GetMimeType(outputPath); + if (string.Equals(mimeType, "application/octet-stream", StringComparison.OrdinalIgnoreCase)) + { + mimeType = "image/png"; + } + await ProviderManager.SaveImage(item, outputPath, mimeType, imageType, null, false, cancellationToken).ConfigureAwait(false); return ItemUpdateType.ImageUpdate; diff --git a/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs b/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs index 245fe8ebe..bef964c6f 100644 --- a/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs +++ b/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs @@ -159,20 +159,14 @@ namespace Emby.Server.Implementations.UserViews protected override async Task CreateImage(IHasImages item, List itemsWithImages, string outputPathWithoutExtension, ImageType imageType, int imageIndex) { - var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png"); - - var view = (UserView)item; - if (imageType == ImageType.Primary && IsUsingCollectionStrip(view)) + if (itemsWithImages.Count == 0) { - if (itemsWithImages.Count == 0) - { - return null; - } - - return await CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540).ConfigureAwait(false); + return null; } - return await base.CreateImage(item, itemsWithImages, outputPath, imageType, imageIndex).ConfigureAwait(false); + var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ".png"); + + return await CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540).ConfigureAwait(false); } } } -- cgit v1.2.3