diff --git a/CHANGELOG.md b/CHANGELOG.md index 46e421211..a0d3b70c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - For example, a `Scripted Schedule` of `/home/jason/schedule.sh "party central" 23` will be executed like - `/home/jason/schedule.sh http://localhost:8409 00000000-0000...0000 reset "party central" 23` - This enables wrapper script re-use across multiple scripted schedules - - API reference is available at `/scalar/scripted-schedule` + - API reference is available at `/docs` ## [25.5.0] - 2025-09-01 ### Added diff --git a/ErsatzTV.Core/Api/ScriptedPlayout/ContextResponseModel.cs b/ErsatzTV.Core/Api/ScriptedPlayout/ContextResponseModel.cs index fb9b91804..4c27273f6 100644 --- a/ErsatzTV.Core/Api/ScriptedPlayout/ContextResponseModel.cs +++ b/ErsatzTV.Core/Api/ScriptedPlayout/ContextResponseModel.cs @@ -1,7 +1,18 @@ +using System.ComponentModel; + namespace ErsatzTV.Core.Api.ScriptedPlayout; -public record ContextResponseModel( - DateTimeOffset CurrentTime, - DateTimeOffset StartTime, - DateTimeOffset FinishTime, - bool IsDone); +public record ContextResponseModel +{ + [Description("The current time of the playout build")] + public DateTimeOffset CurrentTime { get; set; } + + [Description("The start time of the playout build")] + public DateTimeOffset StartTime { get; set; } + + [Description("The finish time of the playout build")] + public DateTimeOffset FinishTime { get; set; } + + [Description("Indicates whether the current playout build is complete")] + public bool IsDone { get; set; } +} diff --git a/ErsatzTV/Controllers/Api/ScriptedScheduleController.cs b/ErsatzTV/Controllers/Api/ScriptedScheduleController.cs index d91bc8991..c7176a6c2 100644 --- a/ErsatzTV/Controllers/Api/ScriptedScheduleController.cs +++ b/ErsatzTV/Controllers/Api/ScriptedScheduleController.cs @@ -13,7 +13,7 @@ namespace ErsatzTV.Controllers.Api; public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedPlayoutBuilderService) : ControllerBase { [HttpGet("context", Name = "GetContext")] - [Tags("Metadata")] + [Tags("Scripted Metadata")] [EndpointSummary("Get the current context")] public ActionResult GetContext([FromRoute] Guid buildId) { @@ -27,7 +27,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("add_collection", Name = "AddCollection")] - [Tags("Content")] + [Tags("Scripted Content")] [EndpointSummary("Add a collection")] public async Task AddCollection( [FromRoute] @@ -52,7 +52,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("add_marathon", Name = "AddMarathon")] - [Tags("Content")] + [Tags("Scripted Content")] [EndpointSummary("Add a marathon")] public async Task AddMarathon([FromRoute] Guid buildId, [FromBody] AddMarathonRequestModel request) { @@ -79,7 +79,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("add_multi_collection", Name = "AddMultiCollection")] - [Tags("Content")] + [Tags("Scripted Content")] [EndpointSummary("Add a multi-collection")] public async Task AddMultiCollection( [FromRoute] @@ -104,7 +104,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("add_playlist", Name = "AddPlaylist")] - [Tags("Content")] + [Tags("Scripted Content")] [EndpointSummary("Add a playlist")] public async Task AddPlaylist( [FromRoute] @@ -124,7 +124,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("add_smart_collection", Name = "AddSmartCollection")] - [Tags("Content")] + [Tags("Scripted Content")] [EndpointSummary("Add a smart collection")] public async Task AddSmartCollection( [FromRoute] @@ -149,7 +149,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("add_show", Name = "AddShow")] - [Tags("Content")] + [Tags("Scripted Content")] [EndpointSummary("Add a show")] public async Task AddShow( [FromRoute] @@ -174,7 +174,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("add_all", Name = "AddAll")] - [Tags("Scheduling")] + [Tags("Scripted Scheduling")] [EndpointSummary("Add all content")] public ActionResult AddAll([FromRoute] Guid buildId, [FromBody] AddAllRequestModel request) { @@ -195,7 +195,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("add_count", Name = "AddCount")] - [Tags("Scheduling")] + [Tags("Scripted Scheduling")] [EndpointSummary("Add a specific number of content items")] public ActionResult AddCount( [FromRoute] @@ -225,7 +225,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("add_duration", Name = "AddDuration")] - [Tags("Scheduling")] + [Tags("Scripted Scheduling")] [EndpointSummary("Add content for a specific duration")] public ActionResult AddDuration( [FromRoute] @@ -260,7 +260,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("pad_to_next", Name = "PadToNext")] - [Tags("Scheduling")] + [Tags("Scripted Scheduling")] [EndpointSummary("Add content until a specific minutes interval")] public ActionResult PadToNext( [FromRoute] Guid buildId, @@ -293,7 +293,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("pad_until", Name = "PadUntil")] - [Tags("Scheduling")] + [Tags("Scripted Scheduling")] [EndpointSummary("Add content until a specified time")] public ActionResult PadUntil( [FromRoute] Guid buildId, @@ -327,7 +327,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("start_epg_group", Name = "StartEpgGroup")] - [Tags("Control")] + [Tags("Scripted Control")] [EndpointSummary("Start a new EPG group")] public IActionResult StartEpgGroup([FromRoute] Guid buildId, [FromBody] StartEpgGroupRequestModel request) { @@ -342,7 +342,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("stop_epg_group", Name = "StopEpgGroup")] - [Tags("Control")] + [Tags("Scripted Control")] [EndpointSummary("Finish the current EPG group")] public IActionResult StopEpgGroup([FromRoute] Guid buildId) { @@ -357,7 +357,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("graphics_on", Name = "GraphicsOn")] - [Tags("Control")] + [Tags("Scripted Control")] [EndpointSummary("Turn on graphics elements")] public async Task GraphicsOn( [FromRoute] @@ -377,7 +377,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("graphics_off", Name = "GraphicsOff")] - [Tags("Control")] + [Tags("Scripted Control")] [EndpointSummary("Turn off graphics elements")] public async Task GraphicsOff( [FromRoute] @@ -397,7 +397,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("watermark_on", Name = "WatermarkOn")] - [Tags("Control")] + [Tags("Scripted Control")] [EndpointSummary("Turn on watermarks")] public async Task WatermarkOn([FromRoute] Guid buildId, [FromBody] WatermarkOnRequestModel request) { @@ -412,7 +412,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("watermark_off", Name = "WatermarkOff")] - [Tags("Control")] + [Tags("Scripted Control")] [EndpointSummary("Turn off watermarks")] public async Task WatermarkOff([FromRoute] Guid buildId, [FromBody] WatermarkOffRequestModel request) { @@ -427,7 +427,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("skip_items", Name = "SkipItems")] - [Tags("Control")] + [Tags("Scripted Control")] [EndpointSummary("Skip a specific number of items")] public IActionResult SkipItems([FromRoute] Guid buildId, [FromBody] SkipItemsRequestModel request) { @@ -442,7 +442,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("skip_to_item", Name = "SkipToItem")] - [Tags("Control")] + [Tags("Scripted Control")] [EndpointSummary("Skip to a specific episode")] public IActionResult SkipToItem([FromRoute] Guid buildId, [FromBody] SkipToItemRequestModel request) { @@ -457,7 +457,7 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP } [HttpPost("wait_until", Name = "WaitUntil")] - [Tags("Control")] + [Tags("Scripted Control")] [EndpointSummary("Wait until the specified time")] public ActionResult WaitUntil( [FromRoute] @@ -484,7 +484,14 @@ public class ScriptedScheduleController(IScriptedPlayoutBuilderService scriptedP try { var state = engine.GetState(); - return Ok(new ContextResponseModel(state.CurrentTime, state.Start, state.Finish, state.IsDone)); + var responseModel = new ContextResponseModel + { + CurrentTime = state.CurrentTime, + StartTime = state.Start, + FinishTime = state.Finish, + IsDone = state.IsDone + }; + return Ok(responseModel); } catch (InvalidOperationException ex) { diff --git a/ErsatzTV/Shared/MainLayout.razor b/ErsatzTV/Shared/MainLayout.razor index d38d70161..aef63b464 100644 --- a/ErsatzTV/Shared/MainLayout.razor +++ b/ErsatzTV/Shared/MainLayout.razor @@ -85,6 +85,7 @@ { M3U XMLTV + API } @* API *@ diff --git a/ErsatzTV/Startup.cs b/ErsatzTV/Startup.cs index b43c34abf..eec2fa4fd 100644 --- a/ErsatzTV/Startup.cs +++ b/ErsatzTV/Startup.cs @@ -599,10 +599,11 @@ public class Startup endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); endpoints.MapOpenApi().CacheOutput(); - endpoints.MapScalarApiReference(options => + endpoints.MapScalarApiReference("/docs", options => { options.AddDocument("scripted-schedule", "Scripted Schedule", "openapi/scripted-schedule.json"); options.HideClientButton = true; + options.Title = "ErsatzTV API Reference"; }); }); });