From aa3bd3b750a84974fa7efec486e81f25b7e64b7a Mon Sep 17 00:00:00 2001 From: Jason Dove <1695733+jasongdove@users.noreply.github.com> Date: Sun, 3 Aug 2025 13:29:44 +0000 Subject: [PATCH] add yaml playout rewind instruction (#2243) --- .editorconfig | 2 +- CHANGELOG.md | 9 ++++-- .../Handlers/YamlPlayoutRewindHandler.cs | 30 +++++++++++++++++++ .../Models/YamlPlayoutRewindInstruction.cs | 6 ++++ .../YamlScheduling/YamlPlayoutBuilder.cs | 2 ++ ErsatzTV/Resources/yaml-playout.schema.json | 9 ++++++ 6 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutRewindHandler.cs create mode 100644 ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPlayoutRewindInstruction.cs diff --git a/.editorconfig b/.editorconfig index 0b67d50d2..6f357a3e6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -31,7 +31,7 @@ csharp_style_expression_bodied_constructors=true:none csharp_style_expression_bodied_methods=true:none csharp_style_expression_bodied_properties=true:suggestion csharp_style_var_elsewhere=false:suggestion -csharp_style_var_for_built_in_types=false:suggestion +csharp_style_var_for_built_in_types=false:none csharp_style_var_when_type_is_apparent=true:suggestion dotnet_naming_rule.local_constants_rule.severity=warning dotnet_naming_rule.local_constants_rule.style=all_upper_style diff --git a/CHANGELOG.md b/CHANGELOG.md index a4c8b5db3..7cb13c27f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,9 +19,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - With value of `true` and `sequence` property, will enable automatic post-roll for all content in the playout to the sequence with the provided key - With value of `false`, will disable automatic post-roll in the playout - YAML playout: add `mid_roll` instruction to enable and disable a mid-roll sequence - - With value of `true` and `sequence` property, will enable automatic mid-roll for (`count` and `all`) content in the playout to the sequence with the provided key - - With value of `false`, will disable automatic post-roll in the playout - - `expression` can be used to influence which chapters are selected for mid roll (same as in filler preset) + - With value of `true` and `sequence` property, will enable automatic mid-roll for (`count` and `all`) content in the playout to the sequence with the provided key + - With value of `false`, will disable automatic post-roll in the playout + - `expression` can be used to influence which chapters are selected for mid roll (same as in filler preset) +- YAML playout: add `rewind` instruction to set start of playout relative to the current time + - Value should be formatted as `HH:MM:SS` e.g. `00:05:30` for 5 minutes 30 seconds (before now) + - This is instruction is mostly useful for debugging transitions, and can only be used as a reset instruction - Add YAML playout validation (using JSON Schema) - Invalid YAML playout definitions will fail to build and will log validation failures as warnings - `content` is fully validated diff --git a/ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutRewindHandler.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutRewindHandler.cs new file mode 100644 index 000000000..b93e50080 --- /dev/null +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutRewindHandler.cs @@ -0,0 +1,30 @@ +using ErsatzTV.Core.Scheduling.YamlScheduling.Models; +using Microsoft.Extensions.Logging; + +namespace ErsatzTV.Core.Scheduling.YamlScheduling.Handlers; + +public class YamlPlayoutRewindHandler : IYamlPlayoutHandler +{ + public bool Reset => true; + + public Task Handle( + YamlPlayoutContext context, + YamlPlayoutInstruction instruction, + PlayoutBuildMode mode, + Func executeSequence, + ILogger logger, + CancellationToken cancellationToken) + { + if (instruction is not YamlPlayoutRewindInstruction rewind) + { + return Task.FromResult(false); + } + + if (TimeSpan.TryParse(rewind.Rewind ?? string.Empty, out TimeSpan amount)) + { + context.CurrentTime -= amount; + } + + return Task.FromResult(true); + } +} \ No newline at end of file diff --git a/ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPlayoutRewindInstruction.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPlayoutRewindInstruction.cs new file mode 100644 index 000000000..2f49d3498 --- /dev/null +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPlayoutRewindInstruction.cs @@ -0,0 +1,6 @@ +namespace ErsatzTV.Core.Scheduling.YamlScheduling.Models; + +public class YamlPlayoutRewindInstruction : YamlPlayoutInstruction +{ + public string Rewind { get; set; } +} \ No newline at end of file diff --git a/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutBuilder.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutBuilder.cs index 36745a061..2fb59e2c5 100644 --- a/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutBuilder.cs +++ b/ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutBuilder.cs @@ -349,6 +349,7 @@ public class YamlPlayoutBuilder( YamlPlayoutSkipItemsInstruction => new YamlPlayoutSkipItemsHandler(enumeratorCache), YamlPlayoutSkipToItemInstruction => new YamlPlayoutSkipToItemHandler(enumeratorCache), + YamlPlayoutRewindInstruction => new YamlPlayoutRewindHandler(), // content handlers YamlPlayoutAllInstruction => new YamlPlayoutAllHandler(enumeratorCache), @@ -408,6 +409,7 @@ public class YamlPlayoutBuilder( { "post_roll", typeof(YamlPostRollInstruction) }, { "mid_roll", typeof(YamlMidRollInstruction) }, { "repeat", typeof(YamlPlayoutRepeatInstruction) }, + { "rewind", typeof(YamlPlayoutRewindInstruction) }, { "sequence", typeof(YamlPlayoutSequenceInstruction) }, { "shuffle_sequence", typeof(YamlPlayoutShuffleSequenceInstruction) }, { "skip_items", typeof(YamlPlayoutSkipItemsInstruction) }, diff --git a/ErsatzTV/Resources/yaml-playout.schema.json b/ErsatzTV/Resources/yaml-playout.schema.json index 762f144d0..74e1dda76 100644 --- a/ErsatzTV/Resources/yaml-playout.schema.json +++ b/ErsatzTV/Resources/yaml-playout.schema.json @@ -62,6 +62,7 @@ "type": "array", "items": { "oneOf": [ + { "$ref": "#/$defs/control/rewindInstruction" }, { "$ref": "#/$defs/control/skipItemsInstruction" }, { "$ref": "#/$defs/control/skipToItemInstruction" }, { "$ref": "#/$defs/control/waitUntilInstruction" } @@ -284,6 +285,14 @@ } }, "control": { + "rewindInstruction": { + "type": "object", + "properties": { + "rewind": { "type": "string" } + }, + "required": [ "rewind" ], + "additionalProperties": false + }, "epgGroupInstruction": { "type": "object", "properties": {