diff --git a/CHANGELOG.md b/CHANGELOG.md index 56df7ea33..b8f0670ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - POST `/api/libraries/{libraryId}/scan` - Add Deco setting to `Use Watermark During Filler` - This setting is turned OFF by default, meaning filler will NOT use the configured watermark unless this is manually turned on +- Add `Random Count` filler mode by @embolon + - This mode will randomly schedule between zero and the provided count number of items + - e.g. random count 3 will schedule between 0 and 3 filler items ### Fixed - Add basic cache busting to XMLTV image URLs diff --git a/ErsatzTV.Core/Domain/Filler/FillerMode.cs b/ErsatzTV.Core/Domain/Filler/FillerMode.cs index 3fe6c6d7b..c26d3fde4 100644 --- a/ErsatzTV.Core/Domain/Filler/FillerMode.cs +++ b/ErsatzTV.Core/Domain/Filler/FillerMode.cs @@ -5,5 +5,6 @@ public enum FillerMode None = 0, Duration = 1, Count = 2, - Pad = 3 + Pad = 3, + RandomCount = 4 } diff --git a/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs b/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs index 20a7f170b..a1e9cfcaf 100644 --- a/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs +++ b/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs @@ -11,6 +11,8 @@ namespace ErsatzTV.Core.Scheduling; [SuppressMessage("Design", "CA1000:Do not declare static members on generic types")] public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler where T : ProgramScheduleItem { + private readonly Random _random = new(); + protected PlayoutModeSchedulerBase(ILogger logger) => Logger = logger; protected ILogger Logger { get; } @@ -308,6 +310,17 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe filler.AllowWatermarks, cancellationToken)); break; + case FillerMode.RandomCount when filler.Count.HasValue: + IMediaCollectionEnumerator e3 = enumerators[CollectionKey.ForFillerPreset(filler)]; + result.AddRange( + AddRandomCountFiller( + playoutBuilderState, + e3, + filler.Count.Value, + FillerKind.PreRoll, + filler.AllowWatermarks, + cancellationToken)); + break; } } @@ -360,6 +373,25 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe } } + break; + case FillerMode.RandomCount when filler.Count.HasValue: + IMediaCollectionEnumerator e3 = enumerators[CollectionKey.ForFillerPreset(filler)]; + for (var i = 0; i < effectiveChapters.Count; i++) + { + result.Add(playoutItem.ForChapter(effectiveChapters[i])); + if (i < effectiveChapters.Count - 1) + { + result.AddRange( + AddRandomCountFiller( + playoutBuilderState, + e3, + filler.Count.Value, + FillerKind.MidRoll, + filler.AllowWatermarks, + cancellationToken)); + } + } + break; } } @@ -393,6 +425,17 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe filler.AllowWatermarks, cancellationToken)); break; + case FillerMode.RandomCount when filler.Count.HasValue: + IMediaCollectionEnumerator e3 = enumerators[CollectionKey.ForFillerPreset(filler)]; + result.AddRange( + AddRandomCountFiller( + playoutBuilderState, + e3, + filler.Count.Value, + FillerKind.PostRoll, + filler.AllowWatermarks, + cancellationToken)); + break; } } @@ -699,4 +742,30 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe return None; } + + private List AddRandomCountFiller( + PlayoutBuilderState playoutBuilderState, + IMediaCollectionEnumerator enumerator, + int count, + FillerKind fillerKind, + bool allowWatermarks, + CancellationToken cancellationToken) + { + var result = new List(); + // randomCount is from 0 to count. + int randomCount = _random.Next(count + 1); + + if (randomCount != 0) + { + result = AddCountFiller( + playoutBuilderState, + enumerator, + randomCount, + fillerKind, + allowWatermarks, + cancellationToken); + } + + return result; + } } diff --git a/ErsatzTV/Pages/FillerPresetEditor.razor b/ErsatzTV/Pages/FillerPresetEditor.razor index 5c2fd4f07..4904bce8d 100644 --- a/ErsatzTV/Pages/FillerPresetEditor.razor +++ b/ErsatzTV/Pages/FillerPresetEditor.razor @@ -35,9 +35,10 @@ Duration Count Pad + Random Count - + 5 (:00, :05, :10, :15, :20, etc) 10 (:00, :10, :20, :30, :40, :50) diff --git a/ErsatzTV/ViewModels/FillerPresetEditViewModel.cs b/ErsatzTV/ViewModels/FillerPresetEditViewModel.cs index 88c75edfc..8176de369 100644 --- a/ErsatzTV/ViewModels/FillerPresetEditViewModel.cs +++ b/ErsatzTV/ViewModels/FillerPresetEditViewModel.cs @@ -47,7 +47,7 @@ public class FillerPresetEditViewModel public int? Count { - get => FillerMode == FillerMode.Count ? _count : null; + get => FillerMode is FillerMode.Count or FillerMode.RandomCount ? _count : null; set => _count = value; }