Implement template export/import endpoints and enhance grid generation logic
Added new endpoints for exporting and importing grid configurations in TemplateEndpoints, allowing for better management of template data. Enhanced the GenerateGridCommandHandler to support seasonal layers in grid generation, improving scheduling accuracy during holiday periods. Updated related classes and records to accommodate these changes, ensuring a cohesive integration of new features. Improved documentation for clarity and maintainability.
This commit is contained in:
@@ -454,7 +454,8 @@ JunctionElement
|
||||
"minMinutesBetween": 30,
|
||||
"dayparts": ["prime", "day"],
|
||||
"timeWindow": { "from": "20:00", "to": "23:00" },
|
||||
"chance": 40
|
||||
"chance": 40,
|
||||
"nearHourMinutes": 2
|
||||
}
|
||||
```
|
||||
|
||||
@@ -465,6 +466,10 @@ JunctionElement
|
||||
стыков ставим анонс». `minMinutesBetween` считается **по конкретной врезке**, а не по её виду:
|
||||
две рекламные врезки в разных стыках — это разные ограничения, общий счётчик на вид склеил бы их.
|
||||
|
||||
`nearHourMinutes` — допуск от круглого часа по времени канала. Сигнал точного времени и джингл тем
|
||||
и узнаются, что звучат в :00; врезка с допуском ставится только в его окрестности, а не «когда-нибудь
|
||||
в этом часе». Ноль — привязки нет.
|
||||
|
||||
**Развилка** (`choiceKey`) — несколько врезок с одной меткой, из которых играет одна, выбранная по
|
||||
весам: «иногда заставка, иногда короткий рекламный блок». Врезки одной развилки обязаны занимать
|
||||
непрерывный отрезок позиций (иначе неясно, куда встаёт выбранная), обязательность и условия
|
||||
@@ -565,11 +570,20 @@ BumperLine
|
||||
| `{now.episode}` `{next.episode}` | «с5э12» либо название серии |
|
||||
| `{next.year}` `{next.genre}` | из метаданных |
|
||||
| `{next.time}` | во сколько начнётся следующая программа |
|
||||
| `{tonight.title}` `{tonight.time}` | первая программа прайма этих вещательных суток |
|
||||
| `{tomorrow.title}` `{tomorrow.time}` | то же для следующих суток |
|
||||
| `{time}` `{date}` `{weekday}` | момент показа заставки во времени канала |
|
||||
| `{slot}` | название слота — «Вечернее кино» |
|
||||
|
||||
Неизвестное значение подставляется пустым, строка со схлопнувшимися пробелами не рисуется.
|
||||
Неизвестный плейсхолдер — **ошибка валидации при сохранении**, а не сюрприз в эфире.
|
||||
Анонсы смотрят **вперёд по собранной ленте** и только на программы, которые ещё не начались:
|
||||
«сегодня в 20:00 — Терминатор», сказанное в девять вечера, хуже, чем молчание. Ночь до
|
||||
`dayStartTime` относится к предыдущим вещательным суткам, иначе «сегодня вечером» в час ночи
|
||||
означало бы уже следующий вечер.
|
||||
|
||||
Неизвестное значение подставляется пустым. Строка, в которой **не подставился ни один**
|
||||
плейсхолдер, не рисуется целиком: она писалась ради данных, и «ДАЛЕЕ В» без времени — это не
|
||||
подпись, а мусор в кадре. Постоянного текста без плейсхолдеров это не касается. Неизвестный
|
||||
плейсхолдер — **ошибка валидации при сохранении**, а не сюрприз в эфире.
|
||||
|
||||
Цена гибкости — кэш: `{time}` и `{date}` делают каждый показ уникальным, а рендер это ffmpeg
|
||||
на несколько секунд, помноженный на недельный горизонт. Запрещать нечего, но редактор обязан
|
||||
@@ -1034,6 +1048,15 @@ seed = hash(channelId, date, slotId, occurrenceInDay)
|
||||
не лучшего кандидата, а следующего по кругу: иначе неделя выглядит одним повторяющимся днём.
|
||||
Остальные полосы остаются слотами «каждый день» — сетка должна читаться.
|
||||
|
||||
**Праздничная сетка — сезонный слой.** В режиме «с нуля» генератор строит ещё один слой поверх
|
||||
основного и выходных, с ежегодной применимостью (25 декабря — 8 января): днём марафон, вечером кино.
|
||||
Он один и тот же у всех профилей намеренно — в праздники каналы сходятся к одному ритму, и различает
|
||||
их библиотека, а не сетка. Слоты слоя идут «каждый день»: период занимает несколько дат подряд, и
|
||||
расписывать их по дням недели значило бы получить сетку, зависящую от того, на какой день выпало
|
||||
31 декабря. Свой разбор и свой бюджет: праздничная неделя идёт **вместо** обычной, а не вдобавок,
|
||||
и обеднять ради неё обычную нельзя. Даты и содержимое слоя дальше правятся как у любого другого —
|
||||
повторная генерация применимость уже созданного слоя не переписывает.
|
||||
|
||||
**Жанр не занимает две полосы подряд**, а при заданном `MaxGenreSharePercent` — и больше своей
|
||||
доли суток. Это тот же потолок, который потом проверяет пост-проверка из 3.8, но соблюдаемый
|
||||
на раскладке, а не констатируемый после.
|
||||
@@ -1045,6 +1068,32 @@ seed = hash(channelId, date, slotId, occurrenceInDay)
|
||||
с тем, что потом скажут проверки сетки. Эфир генерация не двигает — как любая правка сетки, она
|
||||
только поднимает ревизию шаблона, а хвост пересобирает кнопка применения.
|
||||
|
||||
### 6.10. Обмен конфигурацией сетки
|
||||
|
||||
Сетка переносится файлом: выгрузка, загрузка и запрос к ИИ — три вкладки одного диалога.
|
||||
|
||||
**Ссылки в файле именные.** Группа, стык и аварийная группа записываются названиями, а не
|
||||
идентификаторами: файл едет на другой канал и на другую установку, где тех же GUID нет, а сетку для
|
||||
импорта пишет в том числе языковая модель — идентификаторы она может только выдумать. Импорт
|
||||
разрешает имена сам; незнакомое имя не валит загрузку, а становится замечанием, и админ видит
|
||||
списком, чего в библиотеке не нашлось. Тем же способом пропускаются слоты, которые не проходят
|
||||
проверки (перекрытие, нет группы у содержательного слота).
|
||||
|
||||
Слой берётся по имени, поэтому повторная загрузка того же файла даёт ту же сетку, а не
|
||||
«Основная сетка (2)». Режим «снести существующие слоты» работает как пересборка из 6.9. Эфир
|
||||
импорт не двигает: он помечает шаблон изменённым, а хвост пересобирает кнопка применения.
|
||||
|
||||
**Запрос к ИИ собирается на сервере и никуда не отправляется.** Ключей внешних сервисов проект
|
||||
не хранит, и заводить их ради одной кнопки не нужно: админ вводит референс-каналы («как у 2×2»)
|
||||
и пожелания своими словами, получает готовый текст, копирует его в ту модель, которой пользуется,
|
||||
и приносит ответ назад вкладкой импорта.
|
||||
|
||||
В запрос входят параметры канала, доступные группы с их ёмкостью и средней длиной единицы (те же
|
||||
числа, по которым раскладывает автосборка, — считает их общий `GroupCatalog`), библиотека справкой,
|
||||
имена стыков и заставок, правила раскладки и схема ответа. Схема лежит рядом с форматом
|
||||
(`GridPromptText` в одной папке с `GridConfig`), а не в шаблоне на фронте: разойдись она с импортом
|
||||
— ответ модели пришлось бы чинить руками.
|
||||
|
||||
---
|
||||
|
||||
## 7. Порядок реализации
|
||||
|
||||
Reference in New Issue
Block a user