Refactor RenderBumperPreviewCommandHandler to streamline background path resolution and rendering specification. Introduce helper methods for improved readability and maintainability. Update FindMissingEpisodesQueryHandler and RefreshShowEpisodesMetadataCommandHandler to encapsulate episode number resolution logic. Enhance CopyTemplateCommandHandler by modularizing junction copying and slot handling for better clarity. Improve FfmpegMediaProcessor by separating duration and stream parsing into dedicated methods. Refactor MediaClaimingBackgroundService to simplify idle waiting logic. Update GenreSeeder to modularize alias addition logic, enhancing code organization.
ci / build-backend (push) Successful in 1m29s
ci / build-frontend (push) Successful in 1m4s
ci / tests (push) Successful in 1m58s
ci / sonar (push) Successful in 3m34s

This commit is contained in:
Leonid Pershin
2026-07-26 23:31:56 +03:00
parent 69d1319564
commit 59cc453026
11 changed files with 544 additions and 362 deletions
@@ -46,19 +46,7 @@ public sealed class RenderBumperPreviewCommandHandler(
var fontFile =
channel.BumperFont == BumperFont.Serif ? _bumper.FontFileSerif : _bumper.FontFileSans;
// Фон блока — из общего реестра по id (общий для всех подблоков).
string? backgroundPath = null;
if (template.BackgroundImageId is { } bgId)
{
var bgExt = await dbContext
.Images.AsNoTracking()
.Where(i => i.Id == bgId)
.Select(i => i.FileExtension)
.FirstOrDefaultAsync(cancellationToken);
if (bgExt is not null)
backgroundPath = imageStore.ResolvePath(bgId, bgExt);
}
var backgroundPath = await ResolveBackgroundPathAsync(template, cancellationToken);
var seconds = template.AudioDurationSeconds is { } d and > 0
? d
: DefaultBumperDurationSeconds;
@@ -70,27 +58,15 @@ public sealed class RenderBumperPreviewCommandHandler(
// Рендерим каждый подблок в свой ассет-превью (id по подблоку).
foreach (var variant in template.Variants.OrderBy(v => v.Position))
{
var free = variant.Kind == BumperTextKind.Free;
var spec = new BumperRenderSpec(
var spec = BuildSpec(
variant,
template,
aligned,
_bumper.Width,
_bumper.Height,
template.BackgroundColor,
template.BackgroundColor2,
template.AccentColor,
template.TextColor,
fontFile,
free ? "" : variant.NowLabel,
free ? "" : fromName,
free ? "" : variant.NextLabel,
free ? "" : toName,
backgroundPath,
audioPath,
// Постер зависит от конкретного «следующего» шоу — в превью не подставляем.
null,
free,
variant.Line1,
variant.Line2
fromName,
toName
);
await renderer.RenderAsync(BumperPreview.AssetId(variant.Id), spec, cancellationToken);
}
@@ -98,6 +74,63 @@ public sealed class RenderBumperPreviewCommandHandler(
return Result.Success();
}
/// <summary>Путь к фон-картинке блока в общем реестре или null, если она не привязана.</summary>
private async Task<string?> ResolveBackgroundPathAsync(
BumperTemplate template,
CancellationToken cancellationToken
)
{
if (template.BackgroundImageId is not { } imageId)
return null;
var extension = await dbContext
.Images.AsNoTracking()
.Where(i => i.Id == imageId)
.Select(i => i.FileExtension)
.FirstOrDefaultAsync(cancellationToken);
return extension is null ? null : imageStore.ResolvePath(imageId, extension);
}
/// <summary>
/// Спецификация рендера одного подблока. В режиме <see cref="BumperTextKind.Free"/> подписи и
/// названия шоу гасятся: там на экране произвольные строки, а не «Сейчас/Далее».
/// </summary>
private BumperRenderSpec BuildSpec(
BumperTextVariant variant,
BumperTemplate template,
int alignedSeconds,
string fontFile,
string? backgroundPath,
string? audioPath,
string fromName,
string toName
)
{
var free = variant.Kind == BumperTextKind.Free;
return new BumperRenderSpec(
alignedSeconds,
_bumper.Width,
_bumper.Height,
template.BackgroundColor,
template.BackgroundColor2,
template.AccentColor,
template.TextColor,
fontFile,
free ? "" : variant.NowLabel,
free ? "" : fromName,
free ? "" : variant.NextLabel,
free ? "" : toName,
backgroundPath,
audioPath,
// Постер зависит от конкретного «следующего» шоу — в превью не подставляем.
null,
free,
variant.Line1,
variant.Line2
);
}
/// <summary>
/// Примерные названия «из/в» для превью. Берём шоу из групп, на которые ссылаются слоты канала:
/// так превью показывает реальные названия этого канала, а не случайные из библиотеки.