Implement interval intersection and subtraction methods in GridCoverage, update GridPlan and related DTOs for PlanNote integration
ci / build-backend (push) Successful in 2m45s
ci / build-frontend (push) Successful in 1m12s
ci / tests (push) Successful in 2m52s
ci / sonar (push) Successful in 8m13s

Added new methods for intersecting and subtracting time intervals in the GridCoverage class to enhance scheduling capabilities. Updated the GridPlan and GridPlanDto classes to replace string notes with a structured PlanNote type, improving note management. Enhanced the GridPlanner class to utilize these new features, ensuring better handling of scheduling conflicts and notes during grid generation. Adjusted related tests to validate the new functionality.
This commit is contained in:
Leonid Pershin
2026-07-27 11:36:06 +03:00
parent 062f4aa200
commit 96ff2cc7ab
12 changed files with 742 additions and 176 deletions
+27 -2
View File
@@ -860,9 +860,34 @@ seed = hash(channelId, date, slotId, occurrenceInDay)
будни слоем `Основная сетка`, а выходные — слоем `Выходные` поверх: слой имеет смысл, только когда
покрывает день целиком, поэтому отдельные выходные бывают лишь в этом режиме.
**Длину слота задаёт контент, а не профиль.** `BlockMinutes`/`UnitsPerBlock` — замысел полосы;
фактическая длина считается из средней длительности единицы выбранной группы. Иначе двухчасовой
слот с «тремя сериями по 22 минуты» отдаёт 54 минуты фону, а трёхчасовой прайм с одним фильмом на
100 минут — восемьдесят. Остаток, не влезающий под ещё одну единицу, достаётся следующему слоту, и
под него подбирается группа подходящей длины: кандидат, чья единица длиннее оставшегося места,
штрафуется — до ближайшего якоря он всё равно не влезет.
**Ёмкость считается на неделю.** Слот «каждый день» выходит семь раз, поэтому бюджет группы
(`PlanRun`) списывается сразу на все выходы. Исчерпанная группа уступает нетронутой, а когда
свежего контента не остаётся вовсе — полоса закрывается **повтором вечернего блока**
(`SlotKind.Repeat` на начало прайма прошлых суток), как это делают настоящие каналы. Тем же
повтором закрывается полоса, под которую подходящей группы нет вовсе (например ночной блок 18+
на канале без взрослого контента) — это честнее дыры в эфире.
**Прайм чередуется по дням недели.** Полосы с `Rotate` раскладываются поимённо по будням и берут
не лучшего кандидата, а следующего по кругу: иначе неделя выглядит одним повторяющимся днём.
Остальные полосы остаются слотами «каждый день» — сетка должна читаться.
**Жанр не занимает две полосы подряд**, а при заданном `MaxGenreSharePercent` — и больше своей
доли суток. Это тот же потолок, который потом проверяет пост-проверка из 3.8, но соблюдаемый
на раскладке, а не констатируемый после.
**Предпросмотр обязателен**: он считается тем же `GridPlanner`, что и создание, поэтому показанное
и созданное совпадают по построению. Эфир генерация не двигает — как любая правка сетки, она только
поднимает ревизию шаблона, а хвост пересобирает кнопка применения.
и созданное совпадают по построению. Там же показываются замечания — незакрытое время (красным),
нехватка состава с точными числами («84 выхода в неделю при 40 позициях») и конфликты с детским
временем: всё это считается по тому же бюджету, по которому раскладывалось, и потому совпадает
с тем, что потом скажут проверки сетки. Эфир генерация не двигает — как любая правка сетки, она
только поднимает ревизию шаблона, а хвост пересобирает кнопка применения.
---