diff --git a/CHANGELOG.md b/CHANGELOG.md index f42b5df2c..1ef68b443 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - This allows defining search queries directly on schedule items without creating smart collections beforehand - As an example, this can be used to filter or combine existing smart collections - Filter: `smart_collection:"sd movies" AND plot:"christmas"` - - Combine: `smart_collection:"old commercials" AND smart_collection:"nick promos"` + - Combine: `smart_collection:"old commercials" OR smart_collection:"nick promos"` +- Scripted schedules: add `custom_title` to `start_epg_group` ### Fixed - Fix HLS Direct playback with Jellyfin 10.11 diff --git a/ErsatzTV.Core/Api/ScriptedPlayout/ControlStartEpgGroup.cs b/ErsatzTV.Core/Api/ScriptedPlayout/ControlStartEpgGroup.cs index a0ba77a2c..0367cd5a9 100644 --- a/ErsatzTV.Core/Api/ScriptedPlayout/ControlStartEpgGroup.cs +++ b/ErsatzTV.Core/Api/ScriptedPlayout/ControlStartEpgGroup.cs @@ -6,4 +6,7 @@ public record ControlStartEpgGroup { [Description("When true, will make a new EPG group. When false, will continue the existing EPG group.")] public bool Advance { get; set; } = true; + + [Description("Custom title to apply to all items in the EPG group.")] + public string CustomTitle { get; set; } } diff --git a/ErsatzTV.Core/Scheduling/Engine/ISchedulingEngine.cs b/ErsatzTV.Core/Scheduling/Engine/ISchedulingEngine.cs index 6887805ad..b52ab146c 100644 --- a/ErsatzTV.Core/Scheduling/Engine/ISchedulingEngine.cs +++ b/ErsatzTV.Core/Scheduling/Engine/ISchedulingEngine.cs @@ -119,7 +119,7 @@ public interface ISchedulingEngine Option PeekNext(string content); // control instructions - void LockGuideGroup(bool advance); + void LockGuideGroup(bool advance, string customTitle); void UnlockGuideGroup(); Task GraphicsOn( diff --git a/ErsatzTV.Core/Scheduling/Engine/SchedulingEngine.cs b/ErsatzTV.Core/Scheduling/Engine/SchedulingEngine.cs index 4310ed4e1..065ffd4b8 100644 --- a/ErsatzTV.Core/Scheduling/Engine/SchedulingEngine.cs +++ b/ErsatzTV.Core/Scheduling/Engine/SchedulingEngine.cs @@ -737,12 +737,21 @@ public class SchedulingEngine( OutPoint = itemDuration, GuideGroup = _state.PeekNextGuideGroup(), FillerKind = fillerKind, - CustomTitle = string.IsNullOrWhiteSpace(customTitle) ? null : customTitle, + CustomTitle = null, DisableWatermarks = disableWatermarks, PlayoutItemWatermarks = [], PlayoutItemGraphicsElements = [] }; + if (!string.IsNullOrWhiteSpace(customTitle)) + { + playoutItem.CustomTitle = customTitle; + } + else if (!string.IsNullOrWhiteSpace(_state.CustomTitle)) + { + playoutItem.CustomTitle = _state.CustomTitle; + } + foreach (int watermarkId in _state.GetChannelWatermarkIds()) { playoutItem.PlayoutItemWatermarks.Add( @@ -918,13 +927,22 @@ public class SchedulingEngine( InPoint = TimeSpan.Zero, OutPoint = itemDuration, FillerKind = GetFillerKind(fillerKind), - CustomTitle = string.IsNullOrWhiteSpace(customTitle) ? null : customTitle, + CustomTitle = null, DisableWatermarks = disableWatermarks, GuideGroup = _state.PeekNextGuideGroup(), PlayoutItemWatermarks = [], PlayoutItemGraphicsElements = [] }; + if (!string.IsNullOrWhiteSpace(customTitle)) + { + playoutItem.CustomTitle = customTitle; + } + else if (!string.IsNullOrWhiteSpace(_state.CustomTitle)) + { + playoutItem.CustomTitle = _state.CustomTitle; + } + foreach (int watermarkId in _state.GetChannelWatermarkIds()) { playoutItem.PlayoutItemWatermarks.Add( @@ -986,9 +1004,9 @@ public class SchedulingEngine( return enumeratorDetails.Enumerator.Current; } - public void LockGuideGroup(bool advance) + public void LockGuideGroup(bool advance, string customTitle) { - _state.LockGuideGroup(advance); + _state.LockGuideGroup(advance, customTitle); } public void UnlockGuideGroup() @@ -1519,6 +1537,7 @@ public class SchedulingEngine( public DateTimeOffset Finish { get; set; } public DateTimeOffset Start { get; set; } public DateTimeOffset CurrentTime { get; set; } + public string CustomTitle { get; private set; } // guide group public int PeekNextGuideGroup() @@ -1551,7 +1570,7 @@ public class SchedulingEngine( } } - public void LockGuideGroup(bool advance = true) + public void LockGuideGroup(bool advance = true, string customTitle = null) { if (advance) { @@ -1559,6 +1578,11 @@ public class SchedulingEngine( } _guideGroupLocked = true; + + if (!string.IsNullOrWhiteSpace(customTitle)) + { + CustomTitle = customTitle; + } } public void UnlockGuideGroup() => _guideGroupLocked = false; diff --git a/ErsatzTV/Controllers/Api/ScriptedScheduleController.cs b/ErsatzTV/Controllers/Api/ScriptedScheduleController.cs index 6019d09af..a7d5a2a8b 100644 --- a/ErsatzTV/Controllers/Api/ScriptedScheduleController.cs +++ b/ErsatzTV/Controllers/Api/ScriptedScheduleController.cs @@ -445,7 +445,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP return NotFound($"Active build engine not found for build {buildId}."); } - engine.LockGuideGroup(request.Advance); + engine.LockGuideGroup(request.Advance, request.CustomTitle); return Ok(); } diff --git a/ErsatzTV/wwwroot/openapi/scripted-schedule-tagged.json b/ErsatzTV/wwwroot/openapi/scripted-schedule-tagged.json index 1896a32c7..aba89b254 100644 --- a/ErsatzTV/wwwroot/openapi/scripted-schedule-tagged.json +++ b/ErsatzTV/wwwroot/openapi/scripted-schedule-tagged.json @@ -1778,6 +1778,11 @@ "advance": { "type": "boolean", "description": "When true, will make a new EPG group. When false, will continue the existing EPG group." + }, + "customTitle": { + "type": "string", + "description": "Custom title to apply to all items in the EPG group.", + "nullable": true } } }, diff --git a/ErsatzTV/wwwroot/openapi/scripted-schedule.json b/ErsatzTV/wwwroot/openapi/scripted-schedule.json index fa736cc73..c03289d7f 100644 --- a/ErsatzTV/wwwroot/openapi/scripted-schedule.json +++ b/ErsatzTV/wwwroot/openapi/scripted-schedule.json @@ -1778,6 +1778,11 @@ "advance": { "type": "boolean", "description": "When true, will make a new EPG group. When false, will continue the existing EPG group." + }, + "customTitle": { + "type": "string", + "description": "Custom title to apply to all items in the EPG group.", + "nullable": true } } }, diff --git a/ErsatzTV/wwwroot/openapi/v1.json b/ErsatzTV/wwwroot/openapi/v1.json index 734c4f49c..d3512df18 100644 --- a/ErsatzTV/wwwroot/openapi/v1.json +++ b/ErsatzTV/wwwroot/openapi/v1.json @@ -915,6 +915,7 @@ "None", "Aac", "Ac3", + "AacLatm", "Copy" ] },