From fa20c5e01e9da6eb284130f024ecfe6d4904b319 Mon Sep 17 00:00:00 2001 From: Jason Dove <1695733+jasongdove@users.noreply.github.com> Date: Fri, 26 Jul 2024 14:33:55 -0500 Subject: [PATCH] template playout => yaml playout (#1813) --- CHANGELOG.md | 5 +- .../Playouts/Commands/BuildPlayoutHandler.cs | 10 +-- .../Playouts/Commands/CreatePlayout.cs | 4 +- ...Handler.cs => CreateYamlPlayoutHandler.cs} | 28 +++---- .../Commands/UpdateTemplatePlayoutHandler.cs | 10 +-- ...emplatePlayout.cs => UpdateYamlPlayout.cs} | 2 +- .../Domain/ProgramSchedulePlayoutType.cs | 2 +- ...ayoutBuilder.cs => IYamlPlayoutBuilder.cs} | 2 +- .../TemplateScheduling/PlayoutTemplate.cs | 7 -- .../PlayoutTemplateContentGuid.cs | 7 -- .../PlayoutTemplateContentItem.cs | 7 -- .../PlayoutTemplateContentSearchItem.cs | 7 -- .../PlayoutTemplateContentShowItem.cs | 7 -- .../PlayoutTemplateCountItem.cs | 6 -- .../TemplateScheduling/PlayoutTemplateItem.cs | 6 -- .../PlayoutTemplatePlayout.cs | 5 -- .../PlayoutTemplateRepeatItem.cs | 6 -- .../YamlPlayoutBuilder.cs} | 76 +++++++++---------- .../YamlScheduling/YamlPlayoutContentGuid.cs | 7 ++ .../YamlScheduling/YamlPlayoutContentItem.cs | 7 ++ .../YamlPlayoutContentSearchItem.cs | 7 ++ .../YamlPlayoutContentShowItem.cs | 7 ++ .../YamlPlayoutCountInstruction.cs | 6 ++ .../YamlScheduling/YamlPlayoutDefinition.cs | 7 ++ .../YamlPlayoutDurationInstruction.cs} | 4 +- .../YamlScheduling/YamlPlayoutInstruction.cs | 6 ++ .../YamlPlayoutPadToNextInstruction.cs} | 4 +- .../YamlPlayoutRepeatInstruction.cs | 6 ++ .../YamlPlayoutScheduler.cs} | 4 +- .../YamlPlayoutSchedulerCount.cs} | 6 +- .../YamlPlayoutSchedulerDuration.cs} | 6 +- .../YamlPlayoutSchedulerPadToNext.cs} | 6 +- ErsatzTV/Pages/PlayoutEditor.razor | 8 +- ErsatzTV/Pages/Playouts.razor | 26 +++---- ErsatzTV/PlayoutKind.cs | 2 +- ...eDialog.razor => EditYamlFileDialog.razor} | 14 ++-- ErsatzTV/Startup.cs | 4 +- ErsatzTV/ViewModels/PlayoutEditViewModel.cs | 4 +- 38 files changed, 167 insertions(+), 171 deletions(-) rename ErsatzTV.Application/Playouts/Commands/{CreateTemplatePlayoutHandler.cs => CreateYamlPlayoutHandler.cs} (78%) rename ErsatzTV.Application/Playouts/Commands/{UpdateTemplatePlayout.cs => UpdateYamlPlayout.cs} (63%) rename ErsatzTV.Core/Interfaces/Scheduling/{ITemplatePlayoutBuilder.cs => IYamlPlayoutBuilder.cs} (83%) delete mode 100644 ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplate.cs delete mode 100644 ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentGuid.cs delete mode 100644 ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentItem.cs delete mode 100644 ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentSearchItem.cs delete mode 100644 ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentShowItem.cs delete mode 100644 ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateCountItem.cs delete mode 100644 ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateItem.cs delete mode 100644 ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplatePlayout.cs delete mode 100644 ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateRepeatItem.cs rename ErsatzTV.Core/Scheduling/{TemplateScheduling/TemplatePlayoutBuilder.cs => YamlScheduling/YamlPlayoutBuilder.cs} (72%) create mode 100644 ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentGuid.cs create mode 100644 ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentItem.cs create mode 100644 ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentSearchItem.cs create mode 100644 ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentShowItem.cs create mode 100644 ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutCountInstruction.cs create mode 100644 ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutDefinition.cs rename ErsatzTV.Core/Scheduling/{TemplateScheduling/PlayoutTemplateDurationItem.cs => YamlScheduling/YamlPlayoutDurationInstruction.cs} (70%) create mode 100644 ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutInstruction.cs rename ErsatzTV.Core/Scheduling/{TemplateScheduling/PlayoutTemplatePadToNextItem.cs => YamlScheduling/YamlPlayoutPadToNextInstruction.cs} (74%) create mode 100644 ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutRepeatInstruction.cs rename ErsatzTV.Core/Scheduling/{TemplateScheduling/PlayoutTemplateScheduler.cs => YamlScheduling/YamlPlayoutScheduler.cs} (80%) rename ErsatzTV.Core/Scheduling/{TemplateScheduling/PlayoutTemplateSchedulerCount.cs => YamlScheduling/YamlPlayoutSchedulerCount.cs} (92%) rename ErsatzTV.Core/Scheduling/{TemplateScheduling/PlayoutTemplateSchedulerDuration.cs => YamlScheduling/YamlPlayoutSchedulerDuration.cs} (95%) rename ErsatzTV.Core/Scheduling/{TemplateScheduling/PlayoutTemplateSchedulerPadToNext.cs => YamlScheduling/YamlPlayoutSchedulerPadToNext.cs} (87%) rename ErsatzTV/Shared/{EditTemplateFileDialog.razor => EditYamlFileDialog.razor} (62%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26450e118..4b2838dfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,13 +22,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Default filler will stop scheduling when the next item would extend into primary content - Alternatively, default filler can be configured to `Trim To Fit` - In this case, the last item that would extend into primary content is trimmed to end exactly when the primary content starts -- Add **experimental** playout type `Template` +- Add **experimental** playout type `YAML` - This playout type uses a YAML file to declare content and describe how the playout should be built - Content currently supports search queries - Playout instructions currently include `count`, `pad to next`, and `repeat` - `count`: add the specified number of items (from the referenced content) to the playout + - `duration`: play the referenced content for the specified duration - `pad to next`: add items from the referenced content until the wall clock is a multiple of the specified minutes value - - `repeat`: continue building the playout from the first instruction in the template + - `repeat`: continue building the playout from the first instruction in the YAML file ### Fixed - Add basic cache busting to XMLTV image URLs diff --git a/ErsatzTV.Application/Playouts/Commands/BuildPlayoutHandler.cs b/ErsatzTV.Application/Playouts/Commands/BuildPlayoutHandler.cs index 96a574535..d63db3862 100644 --- a/ErsatzTV.Application/Playouts/Commands/BuildPlayoutHandler.cs +++ b/ErsatzTV.Application/Playouts/Commands/BuildPlayoutHandler.cs @@ -19,7 +19,7 @@ public class BuildPlayoutHandler : IRequestHandler _dbContextFactory; private readonly IEntityLocker _entityLocker; @@ -34,7 +34,7 @@ public class BuildPlayoutHandler : IRequestHandler> +public class CreateYamlPlayoutHandler + : IRequestHandler> { private readonly ChannelWriter _channel; private readonly IDbContextFactory _dbContextFactory; private readonly ILocalFileSystem _localFileSystem; - public CreateTemplatePlayoutHandler( + public CreateYamlPlayoutHandler( ILocalFileSystem localFileSystem, ChannelWriter channel, IDbContextFactory dbContextFactory) @@ -29,7 +29,7 @@ public class CreateTemplatePlayoutHandler } public async Task> Handle( - CreateTemplatePlayout request, + CreateYamlPlayout request, CancellationToken cancellationToken) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); @@ -48,8 +48,8 @@ public class CreateTemplatePlayoutHandler private async Task> Validate( TvContext dbContext, - CreateTemplatePlayout request) => - (await ValidateChannel(dbContext, request), ValidateTemplateFile(request), ValidatePlayoutType(request)) + CreateYamlPlayout request) => + (await ValidateChannel(dbContext, request), ValidateYamlFile(request), ValidatePlayoutType(request)) .Apply( (channel, externalJsonFile, playoutType) => new Playout { @@ -60,10 +60,10 @@ public class CreateTemplatePlayoutHandler private static Task> ValidateChannel( TvContext dbContext, - CreateTemplatePlayout createTemplatePlayout) => + CreateYamlPlayout createYamlPlayout) => dbContext.Channels .Include(c => c.Playouts) - .SelectOneAsync(c => c.Id, c => c.Id == createTemplatePlayout.ChannelId) + .SelectOneAsync(c => c.Id, c => c.Id == createYamlPlayout.ChannelId) .Map(o => o.ToValidation("Channel does not exist")) .BindT(ChannelMustNotHavePlayouts); @@ -73,19 +73,19 @@ public class CreateTemplatePlayoutHandler .Map(_ => channel) .ToValidation("Channel already has one playout"); - private Validation ValidateTemplateFile(CreateTemplatePlayout request) + private Validation ValidateYamlFile(CreateYamlPlayout request) { if (!_localFileSystem.FileExists(request.TemplateFile)) { - return BaseError.New("Template file does not exist!"); + return BaseError.New("YAML file does not exist!"); } return request.TemplateFile; } private static Validation ValidatePlayoutType( - CreateTemplatePlayout createTemplatePlayout) => - Optional(createTemplatePlayout.ProgramSchedulePlayoutType) - .Filter(playoutType => playoutType == ProgramSchedulePlayoutType.Template) - .ToValidation("[ProgramSchedulePlayoutType] must be Template"); + CreateYamlPlayout createYamlPlayout) => + Optional(createYamlPlayout.ProgramSchedulePlayoutType) + .Filter(playoutType => playoutType == ProgramSchedulePlayoutType.Yaml) + .ToValidation("[ProgramSchedulePlayoutType] must be YAML"); } diff --git a/ErsatzTV.Application/Playouts/Commands/UpdateTemplatePlayoutHandler.cs b/ErsatzTV.Application/Playouts/Commands/UpdateTemplatePlayoutHandler.cs index ad9f57f3b..095bda4ca 100644 --- a/ErsatzTV.Application/Playouts/Commands/UpdateTemplatePlayoutHandler.cs +++ b/ErsatzTV.Application/Playouts/Commands/UpdateTemplatePlayoutHandler.cs @@ -9,7 +9,7 @@ using Microsoft.EntityFrameworkCore; namespace ErsatzTV.Application.Playouts; public class - UpdateTemplatePlayoutHandler : IRequestHandler> { private readonly IDbContextFactory _dbContextFactory; @@ -24,7 +24,7 @@ public class } public async Task> Handle( - UpdateTemplatePlayout request, + UpdateYamlPlayout request, CancellationToken cancellationToken) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); @@ -34,7 +34,7 @@ public class private async Task ApplyUpdateRequest( TvContext dbContext, - UpdateTemplatePlayout request, + UpdateYamlPlayout request, Playout playout) { playout.TemplateFile = request.TemplateFile; @@ -58,12 +58,12 @@ public class private static Task> Validate( TvContext dbContext, - UpdateTemplatePlayout request) => + UpdateYamlPlayout request) => PlayoutMustExist(dbContext, request); private static Task> PlayoutMustExist( TvContext dbContext, - UpdateTemplatePlayout updatePlayout) => + UpdateYamlPlayout updatePlayout) => dbContext.Playouts .Include(p => p.Channel) .SelectOneAsync(p => p.Id, p => p.Id == updatePlayout.PlayoutId) diff --git a/ErsatzTV.Application/Playouts/Commands/UpdateTemplatePlayout.cs b/ErsatzTV.Application/Playouts/Commands/UpdateYamlPlayout.cs similarity index 63% rename from ErsatzTV.Application/Playouts/Commands/UpdateTemplatePlayout.cs rename to ErsatzTV.Application/Playouts/Commands/UpdateYamlPlayout.cs index fe7bfa5d4..e85876ea3 100644 --- a/ErsatzTV.Application/Playouts/Commands/UpdateTemplatePlayout.cs +++ b/ErsatzTV.Application/Playouts/Commands/UpdateYamlPlayout.cs @@ -2,5 +2,5 @@ namespace ErsatzTV.Application.Playouts; -public record UpdateTemplatePlayout(int PlayoutId, string TemplateFile) +public record UpdateYamlPlayout(int PlayoutId, string TemplateFile) : IRequest>; diff --git a/ErsatzTV.Core/Domain/ProgramSchedulePlayoutType.cs b/ErsatzTV.Core/Domain/ProgramSchedulePlayoutType.cs index 4733a41c6..9c555ad71 100644 --- a/ErsatzTV.Core/Domain/ProgramSchedulePlayoutType.cs +++ b/ErsatzTV.Core/Domain/ProgramSchedulePlayoutType.cs @@ -5,7 +5,7 @@ public enum ProgramSchedulePlayoutType None = 0, Flood = 1, Block = 2, - Template = 3, + Yaml = 3, ExternalJson = 20 } diff --git a/ErsatzTV.Core/Interfaces/Scheduling/ITemplatePlayoutBuilder.cs b/ErsatzTV.Core/Interfaces/Scheduling/IYamlPlayoutBuilder.cs similarity index 83% rename from ErsatzTV.Core/Interfaces/Scheduling/ITemplatePlayoutBuilder.cs rename to ErsatzTV.Core/Interfaces/Scheduling/IYamlPlayoutBuilder.cs index 6d8170697..830a6839f 100644 --- a/ErsatzTV.Core/Interfaces/Scheduling/ITemplatePlayoutBuilder.cs +++ b/ErsatzTV.Core/Interfaces/Scheduling/IYamlPlayoutBuilder.cs @@ -3,7 +3,7 @@ using ErsatzTV.Core.Scheduling; namespace ErsatzTV.Core.Interfaces.Scheduling; -public interface ITemplatePlayoutBuilder +public interface IYamlPlayoutBuilder { Task Build(Playout playout, PlayoutBuildMode mode, CancellationToken cancellationToken); } diff --git a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplate.cs b/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplate.cs deleted file mode 100644 index 0879e8261..000000000 --- a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplate.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ErsatzTV.Core.Scheduling.TemplateScheduling; - -public class PlayoutTemplate -{ - public List Content { get; set; } = []; - public List Playout { get; set; } = []; -} diff --git a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentGuid.cs b/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentGuid.cs deleted file mode 100644 index d2aca377d..000000000 --- a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentGuid.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ErsatzTV.Core.Scheduling.TemplateScheduling; - -public class PlayoutTemplateContentGuid -{ - public string Source { get; set; } - public string Value { get; set; } -} diff --git a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentItem.cs b/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentItem.cs deleted file mode 100644 index 9e4bc53ad..000000000 --- a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentItem.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ErsatzTV.Core.Scheduling.TemplateScheduling; - -public class PlayoutTemplateContentItem -{ - public string Key { get; set; } - public string Order { get; set; } -} diff --git a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentSearchItem.cs b/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentSearchItem.cs deleted file mode 100644 index 07b44d1c3..000000000 --- a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentSearchItem.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ErsatzTV.Core.Scheduling.TemplateScheduling; - -public class PlayoutTemplateContentSearchItem : PlayoutTemplateContentItem -{ - public string Search { get; set; } - public string Query { get; set; } -} diff --git a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentShowItem.cs b/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentShowItem.cs deleted file mode 100644 index cc2a8f606..000000000 --- a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentShowItem.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ErsatzTV.Core.Scheduling.TemplateScheduling; - -public class PlayoutTemplateContentShowItem : PlayoutTemplateContentItem -{ - public string Show { get; set; } - public List Guids { get; set; } = []; -} diff --git a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateCountItem.cs b/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateCountItem.cs deleted file mode 100644 index 7f34d6984..000000000 --- a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateCountItem.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ErsatzTV.Core.Scheduling.TemplateScheduling; - -public class PlayoutTemplateCountItem : PlayoutTemplateItem -{ - public int Count { get; set; } -} diff --git a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateItem.cs b/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateItem.cs deleted file mode 100644 index 67e4afb80..000000000 --- a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateItem.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ErsatzTV.Core.Scheduling.TemplateScheduling; - -public class PlayoutTemplateItem -{ - public string Content { get; set; } -} diff --git a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplatePlayout.cs b/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplatePlayout.cs deleted file mode 100644 index 55f0f8b7b..000000000 --- a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplatePlayout.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace ErsatzTV.Core.Scheduling.TemplateScheduling; - -public class PlayoutTemplatePlayout -{ -} diff --git a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateRepeatItem.cs b/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateRepeatItem.cs deleted file mode 100644 index 3e7669092..000000000 --- a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateRepeatItem.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ErsatzTV.Core.Scheduling.TemplateScheduling; - -public class PlayoutTemplateRepeatItem : PlayoutTemplateItem -{ - public bool Repeat { get; set; } -} diff --git a/ErsatzTV.Core/Scheduling/TemplateScheduling/TemplatePlayoutBuilder.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutBuilder.cs similarity index 72% rename from ErsatzTV.Core/Scheduling/TemplateScheduling/TemplatePlayoutBuilder.cs rename to ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutBuilder.cs index b691a48f2..884e2734d 100644 --- a/ErsatzTV.Core/Scheduling/TemplateScheduling/TemplatePlayoutBuilder.cs +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutBuilder.cs @@ -7,24 +7,24 @@ using Microsoft.Extensions.Logging; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; -namespace ErsatzTV.Core.Scheduling.TemplateScheduling; +namespace ErsatzTV.Core.Scheduling.YamlScheduling; -public class TemplatePlayoutBuilder( +public class YamlPlayoutBuilder( ILocalFileSystem localFileSystem, IConfigElementRepository configElementRepository, IMediaCollectionRepository mediaCollectionRepository, - ILogger logger) - : ITemplatePlayoutBuilder + ILogger logger) + : IYamlPlayoutBuilder { public async Task Build(Playout playout, PlayoutBuildMode mode, CancellationToken cancellationToken) { if (!localFileSystem.FileExists(playout.TemplateFile)) { - logger.LogWarning("Playout template file {File} does not exist; aborting.", playout.TemplateFile); + logger.LogWarning("YAML playout file {File} does not exist; aborting.", playout.TemplateFile); return playout; } - PlayoutTemplate playoutTemplate = await LoadTemplate(playout, cancellationToken); + YamlPlayoutDefinition playoutDefinition = await LoadYamlDefinition(playout, cancellationToken); DateTimeOffset start = DateTimeOffset.Now; int daysToBuild = await GetDaysToBuild(); @@ -32,7 +32,7 @@ public class TemplatePlayoutBuilder( if (mode is not PlayoutBuildMode.Reset) { - logger.LogWarning("Template playouts can only be reset; ignoring build mode {Mode}", mode.ToString()); + logger.LogWarning("YAML playouts can only be reset; ignoring build mode {Mode}", mode.ToString()); return playout; } @@ -50,16 +50,16 @@ public class TemplatePlayoutBuilder( var index = 0; while (currentTime < finish) { - if (index >= playoutTemplate.Playout.Count) + if (index >= playoutDefinition.Playout.Count) { - logger.LogInformation("Reached the end of the playout template; stopping"); + logger.LogInformation("Reached the end of the YAML playout definition; stopping"); break; } - PlayoutTemplateItem playoutItem = playoutTemplate.Playout[index]; + YamlPlayoutInstruction playoutItem = playoutDefinition.Playout[index]; - // repeat resets index into template playout - if (playoutItem is PlayoutTemplateRepeatItem) + // repeat resets index into YAML playout + if (playoutItem is YamlPlayoutRepeatInstruction) { index = 0; if (playout.Items.Count == itemsAfterRepeat) @@ -74,7 +74,7 @@ public class TemplatePlayoutBuilder( Option maybeEnumerator = await GetCachedEnumeratorForContent( playout, - playoutTemplate, + playoutDefinition, enumerators, playoutItem.Content, cancellationToken); @@ -92,31 +92,31 @@ public class TemplatePlayoutBuilder( { switch (playoutItem) { - case PlayoutTemplateCountItem count: - currentTime = PlayoutTemplateSchedulerCount.Schedule(playout, currentTime, count, enumerator); + case YamlPlayoutCountInstruction count: + currentTime = YamlPlayoutSchedulerCount.Schedule(playout, currentTime, count, enumerator); break; - case PlayoutTemplateDurationItem duration: + case YamlPlayoutDurationInstruction duration: Option durationFallbackEnumerator = await GetCachedEnumeratorForContent( playout, - playoutTemplate, + playoutDefinition, enumerators, duration.Fallback, cancellationToken); - currentTime = PlayoutTemplateSchedulerDuration.Schedule( + currentTime = YamlPlayoutSchedulerDuration.Schedule( playout, currentTime, duration, enumerator, durationFallbackEnumerator); break; - case PlayoutTemplatePadToNextItem padToNext: + case YamlPlayoutPadToNextInstruction padToNext: Option fallbackEnumerator = await GetCachedEnumeratorForContent( playout, - playoutTemplate, + playoutDefinition, enumerators, padToNext.Fallback, cancellationToken); - currentTime = PlayoutTemplateSchedulerPadToNext.Schedule( + currentTime = YamlPlayoutSchedulerPadToNext.Schedule( playout, currentTime, padToNext, @@ -139,7 +139,7 @@ public class TemplatePlayoutBuilder( private async Task> GetCachedEnumeratorForContent( Playout playout, - PlayoutTemplate playoutTemplate, + YamlPlayoutDefinition playoutDefinition, Dictionary enumerators, string contentKey, CancellationToken cancellationToken) @@ -152,7 +152,7 @@ public class TemplatePlayoutBuilder( if (!enumerators.TryGetValue(contentKey, out IMediaCollectionEnumerator enumerator)) { Option maybeEnumerator = - await GetEnumeratorForContent(playout, contentKey, playoutTemplate, cancellationToken); + await GetEnumeratorForContent(playout, contentKey, playoutDefinition, cancellationToken); if (maybeEnumerator.IsNone) { @@ -172,10 +172,10 @@ public class TemplatePlayoutBuilder( private async Task> GetEnumeratorForContent( Playout playout, string contentKey, - PlayoutTemplate playoutTemplate, + YamlPlayoutDefinition playoutDefinition, CancellationToken cancellationToken) { - int index = playoutTemplate.Content.FindIndex(c => c.Key == contentKey); + int index = playoutDefinition.Content.FindIndex(c => c.Key == contentKey); if (index < 0) { return Option.None; @@ -183,13 +183,13 @@ public class TemplatePlayoutBuilder( List items = []; - PlayoutTemplateContentItem content = playoutTemplate.Content[index]; + YamlPlayoutContentItem content = playoutDefinition.Content[index]; switch (content) { - case PlayoutTemplateContentSearchItem search: + case YamlPlayoutContentSearchItem search: items = await mediaCollectionRepository.GetSmartCollectionItems(search.Query); break; - case PlayoutTemplateContentShowItem show: + case YamlPlayoutContentShowItem show: items = await mediaCollectionRepository.GetShowItemsByShowGuids( show.Guids.Map(g => $"{g.Source}://{g.Value}").ToList()); break; @@ -209,7 +209,7 @@ public class TemplatePlayoutBuilder( return Option.None; } - private static async Task LoadTemplate(Playout playout, CancellationToken cancellationToken) + private static async Task LoadYamlDefinition(Playout playout, CancellationToken cancellationToken) { string yaml = await File.ReadAllTextAsync(playout.TemplateFile, cancellationToken); @@ -220,24 +220,24 @@ public class TemplatePlayoutBuilder( { var contentKeyMappings = new Dictionary { - { "search", typeof(PlayoutTemplateContentSearchItem) }, - { "show", typeof(PlayoutTemplateContentShowItem) } + { "search", typeof(YamlPlayoutContentSearchItem) }, + { "show", typeof(YamlPlayoutContentShowItem) } }; - o.AddUniqueKeyTypeDiscriminator(contentKeyMappings); + o.AddUniqueKeyTypeDiscriminator(contentKeyMappings); var instructionKeyMappings = new Dictionary { - { "count", typeof(PlayoutTemplateCountItem) }, - { "duration", typeof(PlayoutTemplateDurationItem) }, - { "pad_to_next", typeof(PlayoutTemplatePadToNextItem) }, - { "repeat", typeof(PlayoutTemplateRepeatItem) } + { "count", typeof(YamlPlayoutCountInstruction) }, + { "duration", typeof(YamlPlayoutDurationInstruction) }, + { "pad_to_next", typeof(YamlPlayoutPadToNextInstruction) }, + { "repeat", typeof(YamlPlayoutRepeatInstruction) } }; - o.AddUniqueKeyTypeDiscriminator(instructionKeyMappings); + o.AddUniqueKeyTypeDiscriminator(instructionKeyMappings); }) .Build(); - return deserializer.Deserialize(yaml); + return deserializer.Deserialize(yaml); } } diff --git a/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentGuid.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentGuid.cs new file mode 100644 index 000000000..5579ae9b6 --- /dev/null +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentGuid.cs @@ -0,0 +1,7 @@ +namespace ErsatzTV.Core.Scheduling.YamlScheduling; + +public class YamlPlayoutContentGuid +{ + public string Source { get; set; } + public string Value { get; set; } +} diff --git a/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentItem.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentItem.cs new file mode 100644 index 000000000..48a967475 --- /dev/null +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentItem.cs @@ -0,0 +1,7 @@ +namespace ErsatzTV.Core.Scheduling.YamlScheduling; + +public class YamlPlayoutContentItem +{ + public string Key { get; set; } + public string Order { get; set; } +} diff --git a/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentSearchItem.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentSearchItem.cs new file mode 100644 index 000000000..ddee1ac5e --- /dev/null +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentSearchItem.cs @@ -0,0 +1,7 @@ +namespace ErsatzTV.Core.Scheduling.YamlScheduling; + +public class YamlPlayoutContentSearchItem : YamlPlayoutContentItem +{ + public string Search { get; set; } + public string Query { get; set; } +} diff --git a/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentShowItem.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentShowItem.cs new file mode 100644 index 000000000..9c0e3eacc --- /dev/null +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentShowItem.cs @@ -0,0 +1,7 @@ +namespace ErsatzTV.Core.Scheduling.YamlScheduling; + +public class YamlPlayoutContentShowItem : YamlPlayoutContentItem +{ + public string Show { get; set; } + public List Guids { get; set; } = []; +} diff --git a/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutCountInstruction.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutCountInstruction.cs new file mode 100644 index 000000000..89353c989 --- /dev/null +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutCountInstruction.cs @@ -0,0 +1,6 @@ +namespace ErsatzTV.Core.Scheduling.YamlScheduling; + +public class YamlPlayoutCountInstruction : YamlPlayoutInstruction +{ + public int Count { get; set; } +} diff --git a/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutDefinition.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutDefinition.cs new file mode 100644 index 000000000..29f8fff07 --- /dev/null +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutDefinition.cs @@ -0,0 +1,7 @@ +namespace ErsatzTV.Core.Scheduling.YamlScheduling; + +public class YamlPlayoutDefinition +{ + public List Content { get; set; } = []; + public List Playout { get; set; } = []; +} diff --git a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateDurationItem.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutDurationInstruction.cs similarity index 70% rename from ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateDurationItem.cs rename to ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutDurationInstruction.cs index ca7282474..d250e74ae 100644 --- a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateDurationItem.cs +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutDurationInstruction.cs @@ -1,8 +1,8 @@ using YamlDotNet.Serialization; -namespace ErsatzTV.Core.Scheduling.TemplateScheduling; +namespace ErsatzTV.Core.Scheduling.YamlScheduling; -public class PlayoutTemplateDurationItem : PlayoutTemplateItem +public class YamlPlayoutDurationInstruction : YamlPlayoutInstruction { public string Duration { get; set; } diff --git a/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutInstruction.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutInstruction.cs new file mode 100644 index 000000000..e9ee07aa8 --- /dev/null +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutInstruction.cs @@ -0,0 +1,6 @@ +namespace ErsatzTV.Core.Scheduling.YamlScheduling; + +public class YamlPlayoutInstruction +{ + public string Content { get; set; } +} diff --git a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplatePadToNextItem.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutPadToNextInstruction.cs similarity index 74% rename from ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplatePadToNextItem.cs rename to ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutPadToNextInstruction.cs index a2b9cfbe5..1ce0a613b 100644 --- a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplatePadToNextItem.cs +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutPadToNextInstruction.cs @@ -1,8 +1,8 @@ using YamlDotNet.Serialization; -namespace ErsatzTV.Core.Scheduling.TemplateScheduling; +namespace ErsatzTV.Core.Scheduling.YamlScheduling; -public class PlayoutTemplatePadToNextItem : PlayoutTemplateItem +public class YamlPlayoutPadToNextInstruction : YamlPlayoutInstruction { [YamlMember(Alias = "pad_to_next", ApplyNamingConventions = false)] public int PadToNext { get; set; } diff --git a/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutRepeatInstruction.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutRepeatInstruction.cs new file mode 100644 index 000000000..89c2675b6 --- /dev/null +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutRepeatInstruction.cs @@ -0,0 +1,6 @@ +namespace ErsatzTV.Core.Scheduling.YamlScheduling; + +public class YamlPlayoutRepeatInstruction : YamlPlayoutInstruction +{ + public bool Repeat { get; set; } +} diff --git a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateScheduler.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutScheduler.cs similarity index 80% rename from ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateScheduler.cs rename to ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutScheduler.cs index c8d938b0e..a08023bcb 100644 --- a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateScheduler.cs +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutScheduler.cs @@ -1,9 +1,9 @@ using ErsatzTV.Core.Domain; using ErsatzTV.Core.Extensions; -namespace ErsatzTV.Core.Scheduling.TemplateScheduling; +namespace ErsatzTV.Core.Scheduling.YamlScheduling; -public abstract class PlayoutTemplateScheduler +public abstract class YamlPlayoutScheduler { protected static TimeSpan DurationForMediaItem(MediaItem mediaItem) { diff --git a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateSchedulerCount.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutSchedulerCount.cs similarity index 92% rename from ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateSchedulerCount.cs rename to ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutSchedulerCount.cs index 7519627ff..8092e0493 100644 --- a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateSchedulerCount.cs +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutSchedulerCount.cs @@ -2,14 +2,14 @@ using ErsatzTV.Core.Domain; using ErsatzTV.Core.Domain.Filler; using ErsatzTV.Core.Interfaces.Scheduling; -namespace ErsatzTV.Core.Scheduling.TemplateScheduling; +namespace ErsatzTV.Core.Scheduling.YamlScheduling; -public class PlayoutTemplateSchedulerCount : PlayoutTemplateScheduler +public class YamlPlayoutSchedulerCount : YamlPlayoutScheduler { public static DateTimeOffset Schedule( Playout playout, DateTimeOffset currentTime, - PlayoutTemplateCountItem count, + YamlPlayoutCountInstruction count, IMediaCollectionEnumerator enumerator) { for (int i = 0; i < count.Count; i++) diff --git a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateSchedulerDuration.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutSchedulerDuration.cs similarity index 95% rename from ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateSchedulerDuration.cs rename to ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutSchedulerDuration.cs index eced7c73d..f515e424e 100644 --- a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateSchedulerDuration.cs +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutSchedulerDuration.cs @@ -3,14 +3,14 @@ using ErsatzTV.Core.Domain.Filler; using ErsatzTV.Core.Interfaces.Scheduling; using TimeSpanParserUtil; -namespace ErsatzTV.Core.Scheduling.TemplateScheduling; +namespace ErsatzTV.Core.Scheduling.YamlScheduling; -public class PlayoutTemplateSchedulerDuration : PlayoutTemplateScheduler +public class YamlPlayoutSchedulerDuration : YamlPlayoutScheduler { public static DateTimeOffset Schedule( Playout playout, DateTimeOffset currentTime, - PlayoutTemplateDurationItem duration, + YamlPlayoutDurationInstruction duration, IMediaCollectionEnumerator enumerator, Option fallbackEnumerator) { diff --git a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateSchedulerPadToNext.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutSchedulerPadToNext.cs similarity index 87% rename from ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateSchedulerPadToNext.cs rename to ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutSchedulerPadToNext.cs index a8f16225d..b7f4bc787 100644 --- a/ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateSchedulerPadToNext.cs +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutSchedulerPadToNext.cs @@ -1,14 +1,14 @@ using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Scheduling; -namespace ErsatzTV.Core.Scheduling.TemplateScheduling; +namespace ErsatzTV.Core.Scheduling.YamlScheduling; -public class PlayoutTemplateSchedulerPadToNext : PlayoutTemplateSchedulerDuration +public class YamlPlayoutSchedulerPadToNext : YamlPlayoutSchedulerDuration { public static DateTimeOffset Schedule( Playout playout, DateTimeOffset currentTime, - PlayoutTemplatePadToNextItem padToNext, + YamlPlayoutPadToNextInstruction padToNext, IMediaCollectionEnumerator enumerator, Option fallbackEnumerator) { diff --git a/ErsatzTV/Pages/PlayoutEditor.razor b/ErsatzTV/Pages/PlayoutEditor.razor index 277ede4c1..772d0d90d 100644 --- a/ErsatzTV/Pages/PlayoutEditor.razor +++ b/ErsatzTV/Pages/PlayoutEditor.razor @@ -15,8 +15,8 @@ case PlayoutKind.ExternalJson: Add External Json Playout break; - case PlayoutKind.Template: - Add Template Playout + case PlayoutKind.Yaml: + Add YAML Playout break; case PlayoutKind.Block: Add Block Playout @@ -47,8 +47,8 @@ case PlayoutKind.ExternalJson: break; - case PlayoutKind.Template: - + case PlayoutKind.Yaml: + break; default: - - Add Template Playout + + Add YAML Playout @@ -68,8 +68,8 @@ case ProgramSchedulePlayoutType.Block: Block break; - case ProgramSchedulePlayoutType.Template: - Template + case ProgramSchedulePlayoutType.Yaml: + YAML break; case ProgramSchedulePlayoutType.ExternalJson: External Json @@ -131,12 +131,12 @@
} - else if (context.PlayoutType == ProgramSchedulePlayoutType.Template) + else if (context.PlayoutType == ProgramSchedulePlayoutType.Yaml) { - + + OnClick="@(_ => EditYamlFile(context))"> @@ -256,8 +256,8 @@ private async Task PlayoutSelected(PlayoutNameViewModel playout) { - // only show details for flood, block and template playouts - _selectedPlayoutId = playout.PlayoutType is ProgramSchedulePlayoutType.Flood or ProgramSchedulePlayoutType.Block or ProgramSchedulePlayoutType.Template + // only show details for flood, block and YAML playouts + _selectedPlayoutId = playout.PlayoutType is ProgramSchedulePlayoutType.Flood or ProgramSchedulePlayoutType.Block or ProgramSchedulePlayoutType.Yaml ? playout.PlayoutId : null; @@ -286,16 +286,16 @@ } } - private async Task EditTemplateFile(PlayoutNameViewModel playout) + private async Task EditYamlFile(PlayoutNameViewModel playout) { - var parameters = new DialogParameters { { "TemplateFile", $"{playout.TemplateFile}" } }; + var parameters = new DialogParameters { { "YamlFile", $"{playout.TemplateFile}" } }; var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraLarge }; - IDialogReference dialog = await Dialog.ShowAsync("Edit Template File", parameters, options); + IDialogReference dialog = await Dialog.ShowAsync("Edit YAML File", parameters, options); DialogResult result = await dialog.Result; if (!result.Canceled) { - await Mediator.Send(new UpdateTemplatePlayout(playout.PlayoutId, result.Data as string ?? playout.TemplateFile), _cts.Token); + await Mediator.Send(new UpdateYamlPlayout(playout.PlayoutId, result.Data as string ?? playout.TemplateFile), _cts.Token); if (_table != null) { await _table.ReloadServerData(); diff --git a/ErsatzTV/PlayoutKind.cs b/ErsatzTV/PlayoutKind.cs index 9b0896ea4..e247b00cb 100644 --- a/ErsatzTV/PlayoutKind.cs +++ b/ErsatzTV/PlayoutKind.cs @@ -3,6 +3,6 @@ namespace ErsatzTV; public static class PlayoutKind { public const string ExternalJson = "externaljson"; - public const string Template = "template"; + public const string Yaml = "yaml"; public const string Block = "block"; } diff --git a/ErsatzTV/Shared/EditTemplateFileDialog.razor b/ErsatzTV/Shared/EditYamlFileDialog.razor similarity index 62% rename from ErsatzTV/Shared/EditTemplateFileDialog.razor rename to ErsatzTV/Shared/EditYamlFileDialog.razor index 92f14bd9c..6d92bbe67 100644 --- a/ErsatzTV/Shared/EditTemplateFileDialog.razor +++ b/ErsatzTV/Shared/EditYamlFileDialog.razor @@ -4,14 +4,14 @@ - Edit the playout's template file + Edit the playout's YAML file - + Cancel - + Save Changes @@ -21,12 +21,12 @@ private readonly CancellationTokenSource _cts = new(); [Parameter] - public string TemplateFile { get; set; } + public string YamlFile { get; set; } [CascadingParameter] MudDialogInstance MudDialog { get; set; } - private string _templateFile; + private string _yamlFile; public void Dispose() { @@ -34,9 +34,9 @@ _cts.Dispose(); } - protected override void OnParametersSet() => _templateFile = TemplateFile; + protected override void OnParametersSet() => _yamlFile = YamlFile; - private void Submit() => MudDialog.Close(DialogResult.Ok(_templateFile)); + private void Submit() => MudDialog.Close(DialogResult.Ok(_yamlFile)); private void Cancel() => MudDialog.Cancel(); } \ No newline at end of file diff --git a/ErsatzTV/Startup.cs b/ErsatzTV/Startup.cs index 74f8f4e97..f3d726a6f 100644 --- a/ErsatzTV/Startup.cs +++ b/ErsatzTV/Startup.cs @@ -36,7 +36,7 @@ using ErsatzTV.Core.Metadata; using ErsatzTV.Core.Plex; using ErsatzTV.Core.Scheduling; using ErsatzTV.Core.Scheduling.BlockScheduling; -using ErsatzTV.Core.Scheduling.TemplateScheduling; +using ErsatzTV.Core.Scheduling.YamlScheduling; using ErsatzTV.Core.Trakt; using ErsatzTV.FFmpeg.Capabilities; using ErsatzTV.FFmpeg.Pipeline; @@ -656,7 +656,7 @@ public class Startup services.AddScoped(); services.AddScoped(); services.AddScoped(); - services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); diff --git a/ErsatzTV/ViewModels/PlayoutEditViewModel.cs b/ErsatzTV/ViewModels/PlayoutEditViewModel.cs index 0663f14ad..b292f523a 100644 --- a/ErsatzTV/ViewModels/PlayoutEditViewModel.cs +++ b/ErsatzTV/ViewModels/PlayoutEditViewModel.cs @@ -10,13 +10,13 @@ public class PlayoutEditViewModel public ChannelViewModel Channel { get; set; } public ProgramScheduleViewModel ProgramSchedule { get; set; } public string ExternalJsonFile { get; set; } - public string TemplateFile { get; set; } + public string YamlFile { get; set; } public CreatePlayout ToCreate() => Kind switch { PlayoutKind.ExternalJson => new CreateExternalJsonPlayout(Channel.Id, ExternalJsonFile), - PlayoutKind.Template => new CreateTemplatePlayout(Channel.Id, TemplateFile), + PlayoutKind.Yaml => new CreateYamlPlayout(Channel.Id, YamlFile), PlayoutKind.Block => new CreateBlockPlayout(Channel.Id), _ => new CreateFloodPlayout(Channel.Id, ProgramSchedule.Id) };