From 7412ac6fc9bf6bc41c52f5a14ff3e3506d24ecc6 Mon Sep 17 00:00:00 2001 From: Jason Dove Date: Tue, 7 Feb 2023 12:25:22 -0600 Subject: [PATCH] fix mid and post roll filler ordering (#1152) --- CHANGELOG.md | 1 + .../PlayoutModeSchedulerBaseTests.cs | 104 ++++++++++++++++++ .../Scheduling/PlayoutModeSchedulerBase.cs | 7 ++ 3 files changed, 112 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d79572a3..79a59755 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fix NVIDIA color normalization with VP9 sources - Fix fallback filler looping - Fix bug where some libraries would never scan +- Fix filler ordering so post-roll is properly scheduled after padded mid-roll ### Changed - Merge generated `Other Video` folder tags with tags from sidecar NFO diff --git a/ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerBaseTests.cs b/ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerBaseTests.cs index 58808345..f402dc10 100644 --- a/ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerBaseTests.cs +++ b/ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerBaseTests.cs @@ -356,6 +356,110 @@ public class PlayoutModeSchedulerBaseTests : SchedulerTestBase playoutItems[2].MediaItemId.Should().Be(1); playoutItems[2].StartOffset.Should().Be(startState.CurrentTime + TimeSpan.FromMinutes(11)); } + + [Test] + public void Should_Schedule_Post_Roll_After_Padded_Mid_Roll() + { + // content 45 min, mid roll pad to 60, post roll 5 min + // content + post = 50 min, mid roll will add two 5 min items + // content + mid + post = 60 min + + Collection collectionOne = TwoItemCollection(1, 2, TimeSpan.FromMinutes(45)); + Collection collectionTwo = TwoItemCollection(3, 4, TimeSpan.FromMinutes(5)); + Collection collectionThree = TwoItemCollection(5, 6, TimeSpan.FromMinutes(5)); + + var scheduleItem = new ProgramScheduleItemOne + { + Id = 1, + Index = 1, + Collection = collectionOne, + CollectionId = collectionOne.Id, + StartTime = null, + PlaybackOrder = PlaybackOrder.Chronological, + TailFiller = null, + FallbackFiller = null, + MidRollFiller = new FillerPreset + { + FillerKind = FillerKind.MidRoll, + FillerMode = FillerMode.Pad, + PadToNearestMinute = 60, + CollectionId = 2, + Collection = collectionTwo + }, + PostRollFiller = new FillerPreset + { + FillerKind = FillerKind.PostRoll, + FillerMode = FillerMode.Count, + Count = 1, + CollectionId = 3, + Collection = collectionThree + } + }; + + var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator( + new List { scheduleItem }, + new CollectionEnumeratorState()); + + var enumerator = new ChronologicalMediaCollectionEnumerator( + collectionOne.MediaItems, + new CollectionEnumeratorState()); + + var midRollFillerEnumerator = new ChronologicalMediaCollectionEnumerator( + collectionTwo.MediaItems, + new CollectionEnumeratorState()); + + var postRollFillerEnumerator = new ChronologicalMediaCollectionEnumerator( + collectionThree.MediaItems, + new CollectionEnumeratorState()); + + PlayoutBuilderState startState = StartState(scheduleItemsEnumerator); + + Dictionary enumerators = CollectionEnumerators( + scheduleItem, + enumerator); + + enumerators.Add(CollectionKey.ForFillerPreset(scheduleItem.MidRollFiller), midRollFillerEnumerator); + enumerators.Add(CollectionKey.ForFillerPreset(scheduleItem.PostRollFiller), postRollFillerEnumerator); + + List playoutItems = Scheduler() + .AddFiller( + startState, + enumerators, + scheduleItem, + new PlayoutItem + { + MediaItemId = 1, + Start = startState.CurrentTime.UtcDateTime, + Finish = startState.CurrentTime.AddHours(1).UtcDateTime + }, + new List + { + new() { StartTime = TimeSpan.Zero, EndTime = TimeSpan.FromMinutes(6) }, + new() { StartTime = TimeSpan.FromMinutes(6), EndTime = TimeSpan.FromMinutes(45) } + }); + + playoutItems.Count.Should().Be(5); + + // content chapter 1 + playoutItems[0].MediaItemId.Should().Be(1); + playoutItems[0].StartOffset.Should().Be(startState.CurrentTime); + + // mid-roll 1 + playoutItems[1].MediaItemId.Should().Be(3); + playoutItems[1].StartOffset.Should().Be(startState.CurrentTime + TimeSpan.FromMinutes(6)); + + // mid-roll 2 + playoutItems[2].MediaItemId.Should().Be(4); + playoutItems[2].StartOffset.Should().Be(startState.CurrentTime + TimeSpan.FromMinutes(11)); + + // content chapter 2 + playoutItems[3].MediaItemId.Should().Be(1); + playoutItems[3].StartOffset.Should().Be(startState.CurrentTime + TimeSpan.FromMinutes(16)); + + // post-roll + playoutItems[4].MediaItemId.Should().Be(5); + playoutItems[4].StartOffset.Should().Be(startState.CurrentTime + TimeSpan.FromMinutes(55)); + } } [TestFixture] diff --git a/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs b/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs index 3db67675..a3b8ee1a 100644 --- a/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs +++ b/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs @@ -533,6 +533,11 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe ? remainingToFill : remainingToFill / (effectiveChapters.Count - 1); TimeSpan filled = TimeSpan.Zero; + + // remove post-roll to add after mid-roll/content + var postRoll = result.Where(i => i.FillerKind == FillerKind.PostRoll).ToList(); + result.RemoveAll(i => i.FillerKind == FillerKind.PostRoll); + for (var i = 0; i < effectiveChapters.Count; i++) { result.Add(playoutItem.ForChapter(effectiveChapters[i])); @@ -573,6 +578,8 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe } } + result.AddRange(postRoll); + break; case FillerKind.PostRoll: IMediaCollectionEnumerator post1 = enumerators[CollectionKey.ForFillerPreset(padFiller)];