Updated the GridScheduleGenerator to support rebuilding future schedules while correctly managing aired positions. Introduced a new AiredPosition record to track the last aired state of slots, ensuring that the cursor rewinds to the correct position during rebuilds. Refactored the BuildInputAsync method to accept aired positions, and modified the LoadAiredPositionsAsync method for accurate retrieval of past entries. Enhanced the SchedulePlanner to utilize shared cursor states between main and background loops, preventing duplicate series plays. Updated documentation to reflect these changes and added integration tests to verify the correct behavior of the new functionality.
58 lines
2.6 KiB
C#
58 lines
2.6 KiB
C#
namespace TeleWave.Domain.Programming.Planning;
|
|
|
|
/// <summary>
|
|
/// Показы, добавленные этим же прогоном. Остывание и потолок повторов считаются по ленте, а она на
|
|
/// момент сборки входа содержит только прошлое: горизонт в неделю строится одним прогоном, и без
|
|
/// этого счётчика оба правила не видели бы ничего из того, что сами же и поставили.
|
|
///
|
|
/// Ключ — шоу, как и в снимке из базы: у коллекции остывание общее по всем частям, поэтому элемент
|
|
/// спрашивает историю сразу по всем своим шоу.
|
|
/// </summary>
|
|
public sealed class RunPlayHistory
|
|
{
|
|
private readonly Dictionary<Guid, List<DateTimeOffset>> _byShow = [];
|
|
|
|
public void Record(Guid showId, DateTimeOffset startsAtUtc)
|
|
{
|
|
if (!_byShow.TryGetValue(showId, out var plays))
|
|
_byShow[showId] = plays = [];
|
|
|
|
plays.Add(startsAtUtc);
|
|
}
|
|
|
|
/// <summary>Когда элемент последний раз выходил в этом прогоне; null — ещё не выходил.</summary>
|
|
public DateTimeOffset? LastPlayed(PlanningElement element)
|
|
{
|
|
DateTimeOffset? last = null;
|
|
foreach (var showId in ShowsOf(element))
|
|
{
|
|
if (!_byShow.TryGetValue(showId, out var plays))
|
|
continue;
|
|
|
|
foreach (var play in plays)
|
|
if (last is null || play > last)
|
|
last = play;
|
|
}
|
|
|
|
return last;
|
|
}
|
|
|
|
/// <summary>Сколько раз элемент выходил в этом прогоне начиная с момента.</summary>
|
|
public int CountSince(PlanningElement element, DateTimeOffset from)
|
|
{
|
|
var count = 0;
|
|
foreach (var showId in ShowsOf(element))
|
|
if (_byShow.TryGetValue(showId, out var plays))
|
|
count += plays.Count(play => play >= from);
|
|
|
|
return count;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Шоу элемента берутся из его единиц: у коллекции их столько же, сколько частей, и это ровно
|
|
/// тот набор, по которому историю собирает и оркестратор.
|
|
/// </summary>
|
|
private static IEnumerable<Guid> ShowsOf(PlanningElement element) =>
|
|
element.Units.Select(unit => unit.ShowId).Distinct();
|
|
}
|