diff --git a/Emby.Drawing/NullImageEncoder.cs b/Emby.Drawing/NullImageEncoder.cs
index ed12f6acb2..1c05aa9161 100644
--- a/Emby.Drawing/NullImageEncoder.cs
+++ b/Emby.Drawing/NullImageEncoder.cs
@@ -43,12 +43,6 @@ namespace Emby.Drawing
throw new NotImplementedException();
}
- ///
- public void CreateSplashscreen(SplashscreenOptions options)
- {
- throw new NotImplementedException();
- }
-
///
public string GetImageBlurHash(int xComp, int yComp, string path)
{
diff --git a/Jellyfin.Api/Controllers/SplashscreenController.cs b/Jellyfin.Api/Controllers/SplashscreenController.cs
deleted file mode 100644
index 48a559b281..0000000000
--- a/Jellyfin.Api/Controllers/SplashscreenController.cs
+++ /dev/null
@@ -1,105 +0,0 @@
-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.
- /// 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] bool? regenerate = false)
- {
- var outputPath = Path.Combine(_appPaths.DataPath, $"splashscreen-{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)
- {
- // Thumb images fit better because they include the title in the image but are not provided with TMDb.
- // Using backdrops as a fallback to generate an image at all
- _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, darken!.Value));
- }
-
- return PhysicalFile(outputPath, MimeTypes.GetMimeType(outputPath));
- }
-
- private IReadOnlyList GetItemsWithImageType(ImageType imageType)
- {
- // todo make included libraries configurable
- return _itemRepository.GetItemList(new InternalItemsQuery
- {
- CollapseBoxSetItems = false,
- Recursive = true,
- DtoOptions = new DtoOptions(false),
- ImageTypes = new ImageType[] { imageType },
- Limit = 30,
- // todo max parental rating configurable
- MaxParentalRating = 10,
- OrderBy = new ValueTuple[]
- {
- new ValueTuple(ItemSortBy.Random, SortOrder.Ascending)
- },
- IncludeItemTypes = new string[] { "Movie", "Series" }
- });
- }
- }
-}
diff --git a/Jellyfin.Drawing.Skia/DefaultImageGenerator.cs b/Jellyfin.Drawing.Skia/DefaultImageGenerator.cs
new file mode 100644
index 0000000000..780d0b060c
--- /dev/null
+++ b/Jellyfin.Drawing.Skia/DefaultImageGenerator.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Jellyfin.Data.Enums;
+using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
+using Microsoft.Extensions.Logging;
+
+namespace Jellyfin.Drawing.Skia
+{
+ ///
+ /// The default image generator.
+ ///
+ public class DefaultImageGenerator : IImageGenerator
+ {
+ private readonly IImageEncoder _imageEncoder;
+ private readonly IItemRepository _itemRepository;
+ private readonly ILogger _logger;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ public DefaultImageGenerator(
+ IImageEncoder imageEncoder,
+ IItemRepository itemRepository,
+ ILogger logger)
+ {
+ _imageEncoder = imageEncoder;
+ _itemRepository = itemRepository;
+ _logger = logger;
+ }
+
+ ///
+ public GeneratedImages[] GetSupportedImages()
+ {
+ return new[] { GeneratedImages.Splashscreen };
+ }
+
+ ///
+ public void GenerateSplashscreen(SplashscreenOptions generationOptions)
+ {
+ 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)
+ {
+ // Thumb images fit better because they include the title in the image but are not provided with TMDb.
+ // Using backdrops as a fallback to generate an image at all
+ _logger.LogDebug("No thumb images found. Using backdrops to generate splashscreen.");
+ landscape = GetItemsWithImageType(ImageType.Backdrop).Select(x => x.GetImages(ImageType.Backdrop).First().Path).ToList();
+ }
+
+ var splashBuilder = new SplashscreenBuilder((SkiaEncoder)_imageEncoder);
+ splashBuilder.GenerateSplash(posters, landscape, generationOptions.OutputPath, generationOptions.ApplyFilter);
+ }
+
+ private IReadOnlyList GetItemsWithImageType(ImageType imageType)
+ {
+ // todo make included libraries configurable
+ return _itemRepository.GetItemList(new InternalItemsQuery
+ {
+ CollapseBoxSetItems = false,
+ Recursive = true,
+ DtoOptions = new DtoOptions(false),
+ ImageTypes = new ImageType[] { imageType },
+ Limit = 30,
+ // todo max parental rating configurable
+ MaxParentalRating = 10,
+ OrderBy = new ValueTuple[]
+ {
+ new ValueTuple(ItemSortBy.Random, SortOrder.Ascending)
+ },
+ IncludeItemTypes = new string[] { "Movie", "Series" }
+ });
+ }
+ }
+}
diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs
index 16de5d7fde..6d0a5ac2b9 100644
--- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs
+++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs
@@ -492,13 +492,6 @@ namespace Jellyfin.Drawing.Skia
}
}
- ///
- public void CreateSplashscreen(SplashscreenOptions options)
- {
- var splashBuilder = new SplashscreenBuilder(this);
- splashBuilder.GenerateSplash(options);
- }
-
private void DrawIndicator(SKCanvas canvas, int imageWidth, int imageHeight, ImageProcessingOptions options)
{
try
diff --git a/Jellyfin.Drawing.Skia/SplashscreenBuilder.cs b/Jellyfin.Drawing.Skia/SplashscreenBuilder.cs
index 4773464b43..7cb10bfeef 100644
--- a/Jellyfin.Drawing.Skia/SplashscreenBuilder.cs
+++ b/Jellyfin.Drawing.Skia/SplashscreenBuilder.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using MediaBrowser.Controller.Drawing;
using SkiaSharp;
namespace Jellyfin.Drawing.Skia
@@ -34,25 +33,28 @@ namespace Jellyfin.Drawing.Skia
///
/// Generate a splashscreen.
///
- /// The options to generate the splashscreen.
- public void GenerateSplash(SplashscreenOptions options)
+ /// The poster paths.
+ /// The landscape paths.
+ /// The output path.
+ /// Whether to apply the darkening filter.
+ public void GenerateSplash(IReadOnlyList posters, IReadOnlyList backdrop, string outputPath, bool applyFilter)
{
- var wall = GenerateCollage(options.PortraitInputPaths, options.LandscapeInputPaths, options.ApplyFilter);
+ var wall = GenerateCollage(posters, backdrop, applyFilter);
var transformed = Transform3D(wall);
- using var outputStream = new SKFileWStream(options.OutputPath);
+ using var outputStream = new SKFileWStream(outputPath);
using var pixmap = new SKPixmap(new SKImageInfo(FinalWidth, FinalHeight), transformed.GetPixels());
- pixmap.Encode(outputStream, StripCollageBuilder.GetEncodedFormat(options.OutputPath), 90);
+ pixmap.Encode(outputStream, StripCollageBuilder.GetEncodedFormat(outputPath), 90);
}
///
/// Generates a collage of posters and landscape pictures.
///
- /// The poster paths.
+ /// The poster paths.
/// The landscape paths.
/// Whether to apply the darkening filter.
/// The created collage as a bitmap.
- private SKBitmap GenerateCollage(IReadOnlyList poster, IReadOnlyList backdrop, bool applyFilter)
+ private SKBitmap GenerateCollage(IReadOnlyList posters, IReadOnlyList backdrop, bool applyFilter)
{
_random = new Random();
@@ -80,7 +82,7 @@ namespace Jellyfin.Drawing.Skia
case 0:
case 2:
case 3:
- currentImage = SkiaHelper.GetNextValidImage(_skiaEncoder, poster, posterIndex, out int newPosterIndex);
+ currentImage = SkiaHelper.GetNextValidImage(_skiaEncoder, posters, posterIndex, out int newPosterIndex);
posterIndex = newPosterIndex;
break;
default:
diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs
index 67e50b92d9..ac7ab2dee0 100644
--- a/Jellyfin.Server/CoreAppHost.cs
+++ b/Jellyfin.Server/CoreAppHost.cs
@@ -85,6 +85,9 @@ namespace Jellyfin.Server
serviceCollection.AddSingleton();
serviceCollection.AddSingleton();
+ // TODO search plugins
+ ServiceCollection.AddSingleton();
+
// TODO search the assemblies instead of adding them manually?
serviceCollection.AddSingleton();
serviceCollection.AddSingleton();
diff --git a/MediaBrowser.Controller/Drawing/GeneratedImages.cs b/MediaBrowser.Controller/Drawing/GeneratedImages.cs
new file mode 100644
index 0000000000..47b60979b2
--- /dev/null
+++ b/MediaBrowser.Controller/Drawing/GeneratedImages.cs
@@ -0,0 +1,13 @@
+namespace MediaBrowser.Controller.Drawing
+{
+ ///
+ /// Which generated images an supports.
+ ///
+ public enum GeneratedImages
+ {
+ ///
+ /// The splashscreen.
+ ///
+ Splashscreen
+ }
+}
diff --git a/MediaBrowser.Controller/Drawing/IImageEncoder.cs b/MediaBrowser.Controller/Drawing/IImageEncoder.cs
index 57d73699f6..4e67cfee4f 100644
--- a/MediaBrowser.Controller/Drawing/IImageEncoder.cs
+++ b/MediaBrowser.Controller/Drawing/IImageEncoder.cs
@@ -74,11 +74,5 @@ namespace MediaBrowser.Controller.Drawing
/// The options to use when creating the collage.
/// Optional.
void CreateImageCollage(ImageCollageOptions options, string? libraryName);
-
- ///
- /// Creates a splashscreen image.
- ///
- /// The options to use when creating the splashscreen.
- void CreateSplashscreen(SplashscreenOptions options);
}
}
diff --git a/MediaBrowser.Controller/Drawing/IImageGenerator.cs b/MediaBrowser.Controller/Drawing/IImageGenerator.cs
new file mode 100644
index 0000000000..21699c3f0b
--- /dev/null
+++ b/MediaBrowser.Controller/Drawing/IImageGenerator.cs
@@ -0,0 +1,17 @@
+namespace MediaBrowser.Controller.Drawing
+{
+ public interface IImageGenerator
+ {
+ ///
+ /// Gets the supported generated images of the image generator.
+ ///
+ /// The supported images.
+ GeneratedImages[] GetSupportedImages();
+
+ ///
+ /// Generates a splashscreen.
+ ///
+ /// The options used to generate the splashscreen.
+ void GenerateSplashscreen(SplashscreenOptions generationOptions);
+ }
+}
diff --git a/MediaBrowser.Controller/Drawing/SplashscreenOptions.cs b/MediaBrowser.Controller/Drawing/SplashscreenOptions.cs
index 0534d60b69..ba268b8eb7 100644
--- a/MediaBrowser.Controller/Drawing/SplashscreenOptions.cs
+++ b/MediaBrowser.Controller/Drawing/SplashscreenOptions.cs
@@ -1,5 +1,3 @@
-using System.Collections.Generic;
-
namespace MediaBrowser.Controller.Drawing
{
///
@@ -10,30 +8,14 @@ namespace MediaBrowser.Controller.Drawing
///
/// Initializes a new instance of the class.
///
- /// The portrait input paths.
- /// The landscape input paths.
/// The output path.
- /// Optional. The image width.
- /// Optional. The image height.
/// Optional. Apply a darkening filter.
- public SplashscreenOptions(IReadOnlyList portraitInputPaths, IReadOnlyList landscapeInputPaths, string outputPath, bool applyFilter = false)
+ public SplashscreenOptions(string outputPath, bool applyFilter = false)
{
- PortraitInputPaths = portraitInputPaths;
- LandscapeInputPaths = landscapeInputPaths;
OutputPath = outputPath;
ApplyFilter = applyFilter;
}
- ///
- /// Gets or sets the poster input paths.
- ///
- public IReadOnlyList PortraitInputPaths { get; set; }
-
- ///
- /// Gets or sets the landscape input paths.
- ///
- public IReadOnlyList LandscapeInputPaths { get; set; }
-
///
/// Gets or sets the output path.
///