dependencies and code cleanup (#2117)

* fix validation in new form layout

* pin mediatr to last oss version

* update dependencies

* cleanup code in core

* cleanup code in ffmpeg

* cleanup code in infra

* cleanup code in scanner

* cleanup code in application

* cleanup main code

* cleanup test code

* solution-wide code cleanup
This commit is contained in:
Jason Dove
2025-07-06 15:56:17 +00:00
committed by GitHub
parent fa6a31b4fc
commit 7e30444857
313 changed files with 4207 additions and 4202 deletions
@@ -8,10 +8,8 @@ namespace ErsatzTV.Controllers.Api;
public class LibrariesController(IMediator mediator)
{
[HttpPost("/api/libraries/{id:int}/scan")]
public async Task<IActionResult> ResetPlayout(int id)
{
return await mediator.Send(new QueueLibraryScanByLibraryId(id))
public async Task<IActionResult> ResetPlayout(int id) =>
await mediator.Send(new QueueLibraryScanByLibraryId(id))
? new OkResult()
: new NotFoundResult();
}
}
+28 -17
View File
@@ -20,9 +20,9 @@ namespace ErsatzTV.Controllers;
[ApiExplorerSettings(IgnoreApi = true)]
public class ArtworkController : ControllerBase
{
private readonly IChannelLogoGenerator _channelLogoGenerator;
private readonly IHttpClientFactory _httpClientFactory;
private readonly IMediator _mediator;
private readonly IChannelLogoGenerator _channelLogoGenerator;
public ArtworkController(
IMediator mediator,
@@ -37,22 +37,23 @@ public class ArtworkController : ControllerBase
[HttpHead("/artwork/{id}")]
[HttpGet("/artwork/{id}")]
// This route redirect to the proper artwork from its Id
public async Task<IActionResult> RedirectArtwork(int id, CancellationToken cancellationToken) {
public async Task<IActionResult> RedirectArtwork(int id, CancellationToken cancellationToken)
{
Either<BaseError, Artwork> artwork =
await _mediator.Send(new GetArtwork(id), cancellationToken);
return artwork.Match<IActionResult>(
Left: _ => new NotFoundResult(),
Right: r => r.ArtworkKind switch
{
ArtworkKind.Poster => new RedirectResult("/artwork/posters/" + r.Path),
ArtworkKind.Thumbnail => new RedirectResult("/artwork/thumbnails/" + r.Path),
ArtworkKind.Logo => new RedirectResult("/iptv/logos/" + r.Path),
ArtworkKind.FanArt => new RedirectResult("/artwork/fanart/" + r.Path),
ArtworkKind.Watermark => new RedirectResult("/artwork/watermarks/" + r.Path),
_ => new NotFoundResult()
}
);
{
ArtworkKind.Poster => new RedirectResult("/artwork/posters/" + r.Path),
ArtworkKind.Thumbnail => new RedirectResult("/artwork/thumbnails/" + r.Path),
ArtworkKind.Logo => new RedirectResult("/iptv/logos/" + r.Path),
ArtworkKind.FanArt => new RedirectResult("/artwork/fanart/" + r.Path),
ArtworkKind.Watermark => new RedirectResult("/artwork/watermarks/" + r.Path),
_ => new NotFoundResult()
}
);
}
[HttpHead("/iptv/artwork/posters/{fileName}")]
@@ -63,17 +64,25 @@ public class ArtworkController : ControllerBase
public async Task<IActionResult> GetPoster(string fileName, CancellationToken cancellationToken)
{
Either<BaseError, CachedImagePathViewModel> cachedImagePath =
await _mediator.Send(new GetCachedImagePath(fileName, ArtworkKind.Poster, string.Empty, 440), cancellationToken);
await _mediator.Send(
new GetCachedImagePath(fileName, ArtworkKind.Poster, string.Empty, 440),
cancellationToken);
return cachedImagePath.Match<IActionResult>(
Left: _ => new NotFoundResult(),
Right: r => new PhysicalFileResult(r.FileName, r.MimeType));
}
[HttpGet("/artwork/watermarks/{fileName}")]
public async Task<IActionResult> GetWatermark(string fileName, [FromQuery] string contentType, CancellationToken cancellationToken)
public async Task<IActionResult> GetWatermark(
string fileName,
[FromQuery]
string contentType,
CancellationToken cancellationToken)
{
Either<BaseError, CachedImagePathViewModel> cachedImagePath =
await _mediator.Send(new GetCachedImagePath(fileName, ArtworkKind.Watermark, contentType), cancellationToken);
await _mediator.Send(
new GetCachedImagePath(fileName, ArtworkKind.Watermark, contentType),
cancellationToken);
return cachedImagePath.Match<IActionResult>(
Left: _ => new NotFoundResult(),
Right: r => new PhysicalFileResult(r.FileName, r.MimeType));
@@ -155,7 +164,9 @@ public class ArtworkController : ControllerBase
public async Task<IActionResult> GetThumbnail(string fileName, CancellationToken cancellationToken)
{
Either<BaseError, CachedImagePathViewModel> cachedImagePath =
await _mediator.Send(new GetCachedImagePath(fileName, ArtworkKind.Thumbnail, string.Empty, 220), cancellationToken);
await _mediator.Send(
new GetCachedImagePath(fileName, ArtworkKind.Thumbnail, string.Empty, 220),
cancellationToken);
return cachedImagePath.Match<IActionResult>(
Left: _ => new NotFoundResult(),
Right: r => new PhysicalFileResult(r.FileName, r.MimeType));
@@ -263,8 +274,8 @@ public class ArtworkController : ControllerBase
[HttpGet(ChannelLogoGenerator.GetRoute)]
public IActionResult GenerateChannelLogo(
string text, // param name = ChannelLogoGenerator.GetRouteQueryParamName
CancellationToken cancellationToken) =>
string text, // param name = ChannelLogoGenerator.GetRouteQueryParamName
CancellationToken cancellationToken) =>
_channelLogoGenerator
.GenerateChannelLogo(text, 100, 200, cancellationToken).Match<IActionResult>(
Left: _ => new RedirectResult("/iptv/images/ersatztv-500.png"),
+41 -36
View File
@@ -84,7 +84,9 @@ public class IptvController : ControllerBase
string mode = null)
{
Option<ChannelViewModel> maybeChannel = await _mediator.Send(new GetChannelByNumber(channelNumber));
if (maybeChannel.IsNone || await maybeChannel.Map(c => c.ActiveMode).IfNoneAsync(ChannelActiveMode.Inactive) is ChannelActiveMode.Inactive)
if (maybeChannel.IsNone ||
await maybeChannel.Map(c => c.ActiveMode).IfNoneAsync(ChannelActiveMode.Inactive) is ChannelActiveMode
.Inactive)
{
return NotFound();
}
@@ -119,37 +121,36 @@ public class IptvController : ControllerBase
};
return await _mediator.Send(request)
.Map(
result => result.Match<IActionResult>(
processModel =>
.Map(result => result.Match<IActionResult>(
processModel =>
{
Command command = processModel.Process;
_logger.LogInformation("Starting ts stream for channel {ChannelNumber}", channelNumber);
_logger.LogDebug("ffmpeg arguments {FFmpegArguments}", command.Arguments);
var process = new FFmpegProcess
{
Command command = processModel.Process;
_logger.LogInformation("Starting ts stream for channel {ChannelNumber}", channelNumber);
_logger.LogDebug("ffmpeg arguments {FFmpegArguments}", command.Arguments);
var process = new FFmpegProcess
StartInfo = new ProcessStartInfo
{
StartInfo = new ProcessStartInfo
{
FileName = command.TargetFilePath,
Arguments = command.Arguments,
RedirectStandardOutput = true,
RedirectStandardError = false,
UseShellExecute = false,
CreateNoWindow = true
}
};
HttpContext.Response.RegisterForDispose(process);
foreach ((string key, string value) in command.EnvironmentVariables)
{
process.StartInfo.Environment[key] = value;
FileName = command.TargetFilePath,
Arguments = command.Arguments,
RedirectStandardOutput = true,
RedirectStandardError = false,
UseShellExecute = false,
CreateNoWindow = true
}
};
HttpContext.Response.RegisterForDispose(process);
process.Start();
return new FileStreamResult(process.StandardOutput.BaseStream, "video/mp2t");
},
error => BadRequest(error.Value)));
foreach ((string key, string value) in command.EnvironmentVariables)
{
process.StartInfo.Environment[key] = value;
}
process.Start();
return new FileStreamResult(process.StandardOutput.BaseStream, "video/mp2t");
},
error => BadRequest(error.Value)));
}
[HttpHead("iptv/session/{channelNumber}/hls.m3u8")]
@@ -174,7 +175,9 @@ public class IptvController : ControllerBase
return NotFound();
}
_logger.LogWarning("Unable to locate session worker for channel {Channel}; will redirect to start session", channelNumber);
_logger.LogWarning(
"Unable to locate session worker for channel {Channel}; will redirect to start session",
channelNumber);
return RedirectToAction(nameof(GetHttpLiveStreamingVideo), new { channelNumber });
}
@@ -186,7 +189,9 @@ public class IptvController : ControllerBase
string mode = "mixed")
{
Option<ChannelViewModel> maybeChannel = await _mediator.Send(new GetChannelByNumber(channelNumber));
if (maybeChannel.IsNone || await maybeChannel.Map(c => c.ActiveMode).IfNoneAsync(ChannelActiveMode.Inactive) is ChannelActiveMode.Inactive)
if (maybeChannel.IsNone ||
await maybeChannel.Map(c => c.ActiveMode).IfNoneAsync(ChannelActiveMode.Inactive) is ChannelActiveMode
.Inactive)
{
return NotFound();
}
@@ -260,10 +265,9 @@ public class IptvController : ControllerBase
Request.Host.ToString(),
channelNumber,
mode))
.Map(
r => r.Match<IActionResult>(
playlist => Content(playlist, "application/vnd.apple.mpegurl"),
error => BadRequest(error.Value)));
.Map(r => r.Match<IActionResult>(
playlist => Content(playlist, "application/vnd.apple.mpegurl"),
error => BadRequest(error.Value)));
}
}
@@ -312,9 +316,10 @@ public class IptvController : ControllerBase
"Failed to return ffmpeg multi-variant playlist; falling back to generated playlist");
}
Option<ResolutionAndBitrateViewModel> maybeResolutionAndBitrate = await _mediator.Send(new GetChannelResolutionAndBitrate(channelNumber));
Option<ResolutionAndBitrateViewModel> maybeResolutionAndBitrate =
await _mediator.Send(new GetChannelResolutionAndBitrate(channelNumber));
string resolution = string.Empty;
string bitrate = "10000000";
var bitrate = "10000000";
foreach (ResolutionAndBitrateViewModel res in maybeResolutionAndBitrate)
{
resolution = $",RESOLUTION={res.Width}x{res.Height}";