diff --git a/Jellyfin.Api/Controllers/SplashscreenController.cs b/Jellyfin.Api/Controllers/SplashscreenController.cs new file mode 100644 index 0000000000..0fc9af60bb --- /dev/null +++ b/Jellyfin.Api/Controllers/SplashscreenController.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Jellyfin.Api.Attributes; +using Jellyfin.Data.Enums; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.Querying; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Api.Controllers +{ + /// + /// Splashscreen controller. + /// + [Route("Splashscreen")] + public class SplashscreenController : BaseJellyfinApiController + { + private readonly IImageEncoder _imageEncoder; + private readonly IItemRepository _itemRepository; + private readonly IApplicationPaths _appPaths; + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public SplashscreenController( + IImageEncoder imageEncoder, + IItemRepository itemRepository, + IApplicationPaths applicationPaths, + ILogger logger) + { + _imageEncoder = imageEncoder; + _itemRepository = itemRepository; + _appPaths = applicationPaths; + _logger = logger; + } + + /// + /// Generates or gets the splashscreen. + /// + /// Darken the generated image. + /// The image width. + /// The image height. + /// Whether to regenerate the image, regardless if one already exists. + /// The splashscreen. + [HttpGet] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + [ProducesImageFile] + public ActionResult GetSplashscreen( + [FromQuery] bool? darken = false, + [FromQuery] int? width = 1920, + [FromQuery] int? height = 1080, + [FromQuery] bool? regenerate = false) + { + var outputPath = Path.Combine(_appPaths.DataPath, $"splashscreen-{width}x{height}-{darken}.jpg"); + + if (!System.IO.File.Exists(outputPath) || (regenerate ?? false)) + { + var posters = GetItemsWithImageType(ImageType.Primary).Select(x => x.GetImages(ImageType.Primary).First().Path).ToList(); + var landscape = GetItemsWithImageType(ImageType.Thumb).Select(x => x.GetImages(ImageType.Thumb).First().Path).ToList(); + if (landscape.Count == 0) + { + _logger.LogDebug("No thumb images found. Using backdrops to generate splashscreen."); + landscape = GetItemsWithImageType(ImageType.Backdrop).Select(x => x.GetImages(ImageType.Backdrop).First().Path).ToList(); + } + + _imageEncoder.CreateSplashscreen(new SplashscreenOptions(posters, landscape, outputPath, width!.Value, height!.Value, darken!.Value)); + } + + return PhysicalFile(outputPath, MimeTypes.GetMimeType(outputPath)); + } + + private IReadOnlyList GetItemsWithImageType(ImageType imageType) + { + return _itemRepository.GetItemList(new InternalItemsQuery + { + CollapseBoxSetItems = false, + Recursive = true, + DtoOptions = new DtoOptions(false), + ImageTypes = new ImageType[] { imageType }, + Limit = 8, + OrderBy = new ValueTuple[] + { + new ValueTuple(ItemSortBy.Random, SortOrder.Ascending) + }, + IncludeItemTypes = new string[] { "Movie", "Series" } + }); + } + } +}