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

7
ErsatzTV.Core/Images/ChannelLogoGenerator.cs

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

18
ErsatzTV/Controllers/ArtworkController.cs

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

Loading…
Cancel
Save