From 7c1f0d6dbde731433c5565d238621696632293b9 Mon Sep 17 00:00:00 2001 From: Jason Dove <1695733+jasongdove@users.noreply.github.com> Date: Tue, 21 May 2024 15:51:35 -0500 Subject: [PATCH] treat mid-roll as post-roll when chapter markers are missing (#1722) --- CHANGELOG.md | 2 + .../Scheduling/PlayoutModeSchedulerBase.cs | 41 +++++++++++++++++-- .../PlayoutModeSchedulerDuration.cs | 30 +++++++++++++- 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bdaf022..065e7bef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -86,6 +86,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fix block playout random seeds - Different blocks within a single playout will now correctly use different random seeds (shuffles) - Erasing block playout history will also generate new random seeds for the playout +- Fix building playouts that use mid-roll filler and have content without chapter markers + - When this happens, mid-roll will be treated as post-roll ### Changed - Use ffmpeg 7 in all docker images diff --git a/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs b/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs index 55afccac..c30fd69f 100644 --- a/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs +++ b/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs @@ -243,7 +243,41 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe List effectiveChapters = chapters; if (allFiller.All(fp => fp.FillerKind != FillerKind.MidRoll) || effectiveChapters.Count <= 1) { - effectiveChapters = new List(); + effectiveChapters = []; + } + + // convert mid-roll to post-roll if we have no chapters + if (allFiller.Any(f => f.FillerKind is FillerKind.MidRoll) && effectiveChapters.Count == 0) + { + Logger.LogInformation( + "Converting mid-roll filler preset to post-roll for content that has no chapter markers"); + + var toRemove = allFiller.Filter(f => f.FillerKind is FillerKind.MidRoll).ToList(); + allFiller.RemoveAll(toRemove.Contains); + + foreach (FillerPreset midRollFiller in toRemove) + { + var clone = new FillerPreset + { + FillerKind = FillerKind.PostRoll, + FillerMode = midRollFiller.FillerMode, + Duration = midRollFiller.Duration, + Count = midRollFiller.Count, + PadToNearestMinute = midRollFiller.PadToNearestMinute, + AllowWatermarks = midRollFiller.AllowWatermarks, + CollectionType = midRollFiller.CollectionType, + CollectionId = midRollFiller.CollectionId, + Collection = midRollFiller.Collection, + MediaItemId = midRollFiller.MediaItemId, + MediaItem = midRollFiller.MediaItem, + MultiCollectionId = midRollFiller.MultiCollectionId, + MultiCollection = midRollFiller.MultiCollection, + SmartCollectionId = midRollFiller.SmartCollectionId, + SmartCollection = midRollFiller.SmartCollection + }; + + allFiller.Add(clone); + } } foreach (FillerPreset filler in allFiller.Filter( @@ -395,10 +429,11 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe TimeSpan remainingToFill = targetTime - totalDuration - playoutItem.StartOffset; - // _logger.LogInformation( - // "Total duration {TotalDuration}; need to fill {TimeSpan} to pad properly to {TargetTime}", + // Logger.LogInformation( + // "Total duration {TotalDuration}; need to fill {TimeSpan} to pad properly from {StartTime} to {TargetTime}", // totalDuration, // remainingToFill, + // playoutItem.StartOffset, // targetTime); switch (padFiller.FillerKind) diff --git a/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerDuration.cs b/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerDuration.cs index dd7a28ed..cbb65fd6 100644 --- a/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerDuration.cs +++ b/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerDuration.cs @@ -20,6 +20,13 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase(); PlayoutBuilderState nextState = playoutBuilderState; @@ -30,8 +37,16 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase pi.StartOffset)) + // { + // Logger.LogDebug( + // " - PI Start: {Start} - {Id} - {FillerKind}", + // pi.StartOffset, + // pi.MediaItemId, + // pi.FillerKind); + // } + DateTimeOffset itemEndTimeWithFiller = maybePlayoutItems.Max(pi => pi.FinishOffset); willFinishInTime = itemStartTime > durationFinish || @@ -256,7 +282,7 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase pi.FinishOffset); - // if we've finished the duration or are in offline tail mode with no fallback, keep guide finish on the last item + // if we've finished the duration or are in offline tail mode with no fallback, keep guide finish on the last item if (nextState.DurationFinish.IsNone && (scheduleItem.TailMode != TailMode.Offline || hasFallback)) { playoutItemsToClear.Remove(lastItem);