Browse Source

Overlay Generated Channel Logo when active but no artwork is found (#1848)

pull/1849/head
Sylvain 2 years ago committed by GitHub
parent
commit
39ca27cb3d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 41
      ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs
  2. 7
      ErsatzTV.Core/Images/ChannelLogoGenerator.cs
  3. 18
      ErsatzTV/Controllers/ArtworkController.cs

41
ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs

@ -1,9 +1,11 @@
using System.Diagnostics; using System.Diagnostics;
using System.Text; using System.Text;
using System.Text.Encodings.Web;
using Bugsnag; using Bugsnag;
using CliWrap; using CliWrap;
using CliWrap.Buffered; using CliWrap.Buffered;
using ErsatzTV.Core.Domain; using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Images;
using ErsatzTV.Core.Interfaces.FFmpeg; using ErsatzTV.Core.Interfaces.FFmpeg;
using ErsatzTV.Core.Interfaces.Images; using ErsatzTV.Core.Interfaces.Images;
using ErsatzTV.FFmpeg.State; using ErsatzTV.FFmpeg.State;
@ -188,10 +190,15 @@ public class FFmpegProcessService
None, None,
await IsAnimated(ffprobePath, customPath)); await IsAnimated(ffprobePath, customPath));
case ChannelWatermarkImageSource.ChannelLogo: case ChannelWatermarkImageSource.ChannelLogo:
Option<string> maybeChannelPath = channel.Artwork Option<string> maybeChannelPath = (channel.Artwork.Count == 0) ?
.Filter(a => a.ArtworkKind == ArtworkKind.Logo) //We have to generate the logo on the fly and save it to a local temp path
.HeadOrNone() ChannelLogoGenerator.GenerateChannelLogoUrl(channel) :
.Map(a => _imageCache.GetPathForImage(a.Path, ArtworkKind.Logo, Option<int>.None)); //We have an artwork attached to the channel, let's use it :)
channel.Artwork
.Filter(a => a.ArtworkKind == ArtworkKind.Logo)
.HeadOrNone()
.Map(a => _imageCache.GetPathForImage(a.Path, ArtworkKind.Logo, Option<int>.None));
return new WatermarkOptions( return new WatermarkOptions(
await watermarkOverride.IfNoneAsync(watermark), await watermarkOverride.IfNoneAsync(watermark),
maybeChannelPath, maybeChannelPath,
@ -220,10 +227,14 @@ public class FFmpegProcessService
None, None,
await IsAnimated(ffprobePath, customPath)); await IsAnimated(ffprobePath, customPath));
case ChannelWatermarkImageSource.ChannelLogo: case ChannelWatermarkImageSource.ChannelLogo:
Option<string> maybeChannelPath = channel.Artwork Option<string> maybeChannelPath = (channel.Artwork.Count == 0) ?
.Filter(a => a.ArtworkKind == ArtworkKind.Logo) //We have to generate the logo on the fly and save it to a local temp path
.HeadOrNone() ChannelLogoGenerator.GenerateChannelLogoUrl(channel) :
.Map(a => _imageCache.GetPathForImage(a.Path, ArtworkKind.Logo, Option<int>.None)); //We have an artwork attached to the channel, let's use it :)
channel.Artwork
.Filter(a => a.ArtworkKind == ArtworkKind.Logo)
.HeadOrNone()
.Map(a => _imageCache.GetPathForImage(a.Path, ArtworkKind.Logo, Option<int>.None));
return new WatermarkOptions( return new WatermarkOptions(
await watermarkOverride.IfNoneAsync(channel.Watermark), await watermarkOverride.IfNoneAsync(channel.Watermark),
maybeChannelPath, maybeChannelPath,
@ -252,10 +263,14 @@ public class FFmpegProcessService
None, None,
await IsAnimated(ffprobePath, customPath)); await IsAnimated(ffprobePath, customPath));
case ChannelWatermarkImageSource.ChannelLogo: case ChannelWatermarkImageSource.ChannelLogo:
Option<string> maybeChannelPath = channel.Artwork Option<string> maybeChannelPath = (channel.Artwork.Count == 0) ?
.Filter(a => a.ArtworkKind == ArtworkKind.Logo) //We have to generate the logo on the fly and save it to a local temp path
.HeadOrNone() ChannelLogoGenerator.GenerateChannelLogoUrl(channel) :
.Map(a => _imageCache.GetPathForImage(a.Path, ArtworkKind.Logo, Option<int>.None)); //We have an artwork attached to the channel, let's use it :)
channel.Artwork
.Filter(a => a.ArtworkKind == ArtworkKind.Logo)
.HeadOrNone()
.Map(a => _imageCache.GetPathForImage(a.Path, ArtworkKind.Logo, Option<int>.None));
return new WatermarkOptions( return new WatermarkOptions(
await watermarkOverride.IfNoneAsync(watermark), await watermarkOverride.IfNoneAsync(watermark),
maybeChannelPath, maybeChannelPath,

7
ErsatzTV.Core/Images/ChannelLogoGenerator.cs

@ -1,3 +1,4 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Images; using ErsatzTV.Core.Interfaces.Images;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using SkiaSharp; using SkiaSharp;
@ -6,6 +7,9 @@ namespace ErsatzTV.Core.Images;
public class ChannelLogoGenerator : IChannelLogoGenerator public class ChannelLogoGenerator : IChannelLogoGenerator
{ {
public const string GetRoute = "/iptv/logos/gen";
public const string GetRouteQueryParamName = "text";
private readonly ILogger _logger; private readonly ILogger _logger;
public ChannelLogoGenerator( public ChannelLogoGenerator(
@ -14,6 +18,9 @@ public class ChannelLogoGenerator : IChannelLogoGenerator
_logger = logger; _logger = logger;
} }
public static Option<string> GenerateChannelLogoUrl(Channel channel) =>
$"http://localhost:{Settings.ListenPort}{GetRoute}?{GetRouteQueryParamName}={channel.WebEncodedName}";
public Either<BaseError, byte[]> GenerateChannelLogo( public Either<BaseError, byte[]> GenerateChannelLogo(
string text, string text,
int logoHeight, int logoHeight,

18
ErsatzTV/Controllers/ArtworkController.cs

@ -6,6 +6,7 @@ using ErsatzTV.Application.Plex;
using ErsatzTV.Core; using ErsatzTV.Core;
using ErsatzTV.Core.Domain; using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Emby; using ErsatzTV.Core.Emby;
using ErsatzTV.Core.Images;
using ErsatzTV.Core.Interfaces.Images; using ErsatzTV.Core.Interfaces.Images;
using ErsatzTV.Core.Jellyfin; using ErsatzTV.Core.Jellyfin;
using Flurl; using Flurl;
@ -260,14 +261,13 @@ public class ArtworkController : ControllerBase
#endif #endif
} }
[HttpGet("/iptv/logos/gen")] [HttpGet(ChannelLogoGenerator.GetRoute)]
public IActionResult GenerateChannelLogo( public IActionResult GenerateChannelLogo(
string text, string text, // param name = ChannelLogoGenerator.GetRouteQueryParamName
CancellationToken cancellationToken) CancellationToken cancellationToken) =>
{ _channelLogoGenerator
return _channelLogoGenerator.GenerateChannelLogo(text, 100, 200, cancellationToken).Match<IActionResult>( .GenerateChannelLogo(text, 100, 200, cancellationToken).Match<IActionResult>(
Left: _ => new RedirectResult("/iptv/images/ersatztv-500.png"), Left: _ => new RedirectResult("/iptv/images/ersatztv-500.png"),
Right: img => File(img, "image/png") Right: img => File(img, "image/png")
); );
}
} }

Loading…
Cancel
Save