Refactor Channel endpoints and data models: replace jingle functionality with bumper templates, update related commands and handlers, and enhance API routes for managing bumper templates. Remove obsolete jingle-related code and adjust channel data structures to support new bumper template features.

This commit is contained in:
Leonid Pershin
2026-07-25 11:02:16 +03:00
parent 27571a4ab6
commit 84c2867062
60 changed files with 2805 additions and 1045 deletions
@@ -0,0 +1,116 @@
namespace TeleWave.Domain.Broadcast;
/// <summary>
/// Блок ТВ-заставки канала: свой звук + своё оформление (цвета, опциональная фон-картинка). На
/// переходе между шоу генератор рендерит «Сейчас/Далее» стилем блока поверх его звука; длительность
/// заставки определяется длиной звука (выравнивается на сегмент при рендере). Общие для канала шрифт,
/// подписи и правила показа живут на <see cref="Channel"/>.
///
/// Первый блок (<see cref="Position"/> == 0) — дефолтный, не удаляется; если звук в нём не загружен,
/// рендер синтезирует джингл по умолчанию.
/// </summary>
public class BumperTemplate
{
public Guid Id { get; private set; }
public Guid ChannelId { get; private set; }
/// <summary>Порядковый номер (0 — дефолтный блок). Используется ротацией и как признак дефолта.</summary>
public int Position { get; private set; }
public string Name { get; private set; } = string.Empty;
// ── Оформление блока (цвета — в нотации ffmpeg: 0xRRGGBB или имя) ──
public string BackgroundColor { get; private set; } = DefaultBackgroundColor;
public string BackgroundColor2 { get; private set; } = DefaultBackgroundColor2;
public string AccentColor { get; private set; } = DefaultAccentColor;
public string TextColor { get; private set; } = DefaultTextColor;
/// <summary>Расширение загруженной фон-картинки (с точкой) или null — тогда фон градиент/постер.</summary>
public string? BackgroundImageExtension { get; private set; }
/// <summary>Расширение загруженного звука (с точкой) или null — тогда синтезируется джингл.</summary>
public string? AudioExtension { get; private set; }
/// <summary>Длина загруженного звука в секундах (замер ffprobe) или null, если звука нет.</summary>
public double? AudioDurationSeconds { get; private set; }
/// <summary>Версия файлов блока (звук/фон). Входит в кэш-ключ рендера — замена файла пересобирает заставки.</summary>
public int Revision { get; private set; }
public DateTimeOffset CreatedAt { get; private set; }
public const string DefaultBackgroundColor = "0x0b1020";
public const string DefaultBackgroundColor2 = "0x1e293b";
public const string DefaultAccentColor = "0x38bdf8";
public const string DefaultTextColor = "white";
public bool IsDefault => Position == 0;
private BumperTemplate() { }
internal static BumperTemplate Create(Guid channelId, int position, string name) =>
new()
{
Id = Guid.NewGuid(),
ChannelId = channelId,
Position = position,
Name = name,
BackgroundColor = DefaultBackgroundColor,
BackgroundColor2 = DefaultBackgroundColor2,
AccentColor = DefaultAccentColor,
TextColor = DefaultTextColor,
BackgroundImageExtension = null,
AudioExtension = null,
AudioDurationSeconds = null,
Revision = 0,
CreatedAt = DateTimeOffset.UtcNow,
};
/// <summary>Обновить имя и цвета блока. Цвета — в нотации ffmpeg (0xRRGGBB или имя).</summary>
public void UpdateStyle(
string name,
string backgroundColor,
string backgroundColor2,
string accentColor,
string textColor
)
{
Name = name;
BackgroundColor = backgroundColor;
BackgroundColor2 = backgroundColor2;
AccentColor = accentColor;
TextColor = textColor;
}
/// <summary>Отметить загруженный звук (extension — с точкой, нижний регистр) и его длину. Меняет ревизию.</summary>
public void SetAudio(string extension, double durationSeconds)
{
AudioExtension = extension;
AudioDurationSeconds = durationSeconds > 0 ? durationSeconds : null;
Revision++;
}
public void ClearAudio()
{
if (AudioExtension is null && AudioDurationSeconds is null)
return;
AudioExtension = null;
AudioDurationSeconds = null;
Revision++;
}
/// <summary>Отметить загруженную фон-картинку (extension — с точкой, нижний регистр). Меняет ревизию.</summary>
public void SetBackgroundImage(string extension)
{
BackgroundImageExtension = extension;
Revision++;
}
public void ClearBackgroundImage()
{
if (BackgroundImageExtension is null)
return;
BackgroundImageExtension = null;
Revision++;
}
}