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
@@ -22,19 +22,22 @@ public sealed record PlannerOverride(
public sealed record PlannerOverrideShow(Guid ShowId, int Weight);
/// <summary>
/// Политика ТВ-заставок на переходах. <see cref="Duration"/> должна быть кратна длине сегмента
/// (генератор выравнивает). Планировщик резервирует под заставку слот этой длины, а конкретный
/// сгенерированный ассет подставляет уже оркестратор.
/// Политика ТВ-заставок на переходах. Планировщик выбирает блок (<see cref="Templates"/>) по
/// стратегии <see cref="Selection"/> и резервирует слот его длины (<see cref="PlannerBumperTemplate.Duration"/>,
/// уже выровнена генератором на сегмент). Конкретный отрендеренный ассет подставляет оркестратор
/// по паре шоу + выбранному блоку.
/// </summary>
public sealed record PlannerBumperConfig(
bool Enabled,
TimeSpan Duration,
bool OnlyBetweenDifferentShows,
TimeSpan MinInterval,
BumperMode Mode = BumperMode.Dynamic,
IReadOnlyList<Guid>? JinglePool = null
BumperSelection Selection,
IReadOnlyList<PlannerBumperTemplate> Templates
);
/// <summary>Блок заставки в терминах планировщика: id + длительность слота (кратна сегменту).</summary>
public sealed record PlannerBumperTemplate(Guid TemplateId, TimeSpan Duration);
/// <summary>Полный вход планировщика для одного прогона по каналу.</summary>
public sealed record PlannerInput(
Guid ChannelId,
@@ -48,13 +51,14 @@ public sealed record PlannerInput(
DateTimeOffset StartTime,
DateTimeOffset HorizonEnd,
PlannerBumperConfig? Bumpers = null,
int NextJingleIndex = 0
int NextBumperIndex = 0
);
/// <summary>
/// Одна запланированная запись (ещё не доменная сущность). Для заставок (<see cref="Kind"/> ==
/// <see cref="ScheduleEntryKind.Bumper"/>) <see cref="MediaAssetId"/> пуст — его подставит
/// оркестратор после рендера по паре (<see cref="FromShowId"/> → <see cref="ToShowId"/>).
/// оркестратор после рендера по паре (<see cref="FromShowId"/> → <see cref="ToShowId"/>) и выбранному
/// блоку (<see cref="BumperTemplateId"/>).
/// </summary>
public sealed record PlannedEntry(
Guid MediaAssetId,
@@ -64,13 +68,14 @@ public sealed record PlannedEntry(
Guid? ShowId,
int? EpisodeIndex,
Guid? FromShowId = null,
Guid? ToShowId = null
Guid? ToShowId = null,
Guid? BumperTemplateId = null
);
/// <summary>Результат прогона: новые записи + обновлённые курсоры (серий по каждому ChannelShow и рекламы).</summary>
/// <summary>Результат прогона: новые записи + обновлённые курсоры (серий по каждому ChannelShow, рекламы, заставок).</summary>
public sealed record PlannerResult(
IReadOnlyList<PlannedEntry> Entries,
IReadOnlyDictionary<Guid, int> NextEpisodeIndexByChannelShow,
int NextAdIndex,
int NextJingleIndex
int NextBumperIndex
);