diff --git a/ErsatzTV.Application/Channels/Queries/GetChannelStatesForApi.cs b/ErsatzTV.Application/Channels/Queries/GetChannelStatesForApi.cs new file mode 100644 index 000000000..26a0c92fb --- /dev/null +++ b/ErsatzTV.Application/Channels/Queries/GetChannelStatesForApi.cs @@ -0,0 +1,5 @@ +using ErsatzTV.Core.Api.Channels; + +namespace ErsatzTV.Application.Channels; + +public record GetChannelStatesForApi : IRequest>; diff --git a/ErsatzTV.Core/Api/Channels/ChannelNowPlayingResponseModel.cs b/ErsatzTV.Core/Api/Channels/ChannelNowPlayingResponseModel.cs new file mode 100644 index 000000000..fcc3dc851 --- /dev/null +++ b/ErsatzTV.Core/Api/Channels/ChannelNowPlayingResponseModel.cs @@ -0,0 +1,6 @@ +namespace ErsatzTV.Core.Api.Channels; + +public record ChannelNowPlayingResponseModel( + string Title, + DateTimeOffset StartUtc, + DateTimeOffset FinishUtc); diff --git a/ErsatzTV.Core/Api/Channels/ChannelStateResponseModel.cs b/ErsatzTV.Core/Api/Channels/ChannelStateResponseModel.cs new file mode 100644 index 000000000..3a57cfade --- /dev/null +++ b/ErsatzTV.Core/Api/Channels/ChannelStateResponseModel.cs @@ -0,0 +1,7 @@ +namespace ErsatzTV.Core.Api.Channels; + +public record ChannelStateResponseModel( + int ChannelId, + string ChannelNumber, + bool OnAir, + ChannelNowPlayingResponseModel NowPlaying); diff --git a/ErsatzTV.Tests/Controllers/ChannelControllerTests.cs b/ErsatzTV.Tests/Controllers/ChannelControllerTests.cs index ccdbeee46..505faac17 100644 --- a/ErsatzTV.Tests/Controllers/ChannelControllerTests.cs +++ b/ErsatzTV.Tests/Controllers/ChannelControllerTests.cs @@ -6,6 +6,7 @@ using ErsatzTV.Application.Playouts; using ErsatzTV.Controllers.Api; using ErsatzTV.Controllers.Api.Requests; using ErsatzTV.Core; +using ErsatzTV.Core.Api.Channels; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Errors; using LanguageExt; @@ -34,6 +35,25 @@ public class ChannelControllerTests _controller = new ChannelController(writer, _mediator); } + [Test] + public async Task GetState_Should_Return_200_With_Channel_State() + { + var state = new ChannelStateResponseModel( + 7, + "7.1", + true, + new ChannelNowPlayingResponseModel( + "Retro Cartoons", + new DateTimeOffset(2026, 7, 2, 17, 0, 0, TimeSpan.Zero), + new DateTimeOffset(2026, 7, 2, 17, 30, 0, TimeSpan.Zero))); + _mediator.Send(Arg.Any(), Arg.Any()) + .Returns([state]); + + IActionResult result = await _controller.GetState(CancellationToken.None); + + result.ShouldBeOfType().Value.ShouldBe(new List { state }); + } + [Test] public async Task Create_Should_Return_201_With_Location_And_Body() { diff --git a/ErsatzTV/Controllers/Api/ChannelController.cs b/ErsatzTV/Controllers/Api/ChannelController.cs index 0386f2fd8..bdd03861b 100644 --- a/ErsatzTV/Controllers/Api/ChannelController.cs +++ b/ErsatzTV/Controllers/Api/ChannelController.cs @@ -21,6 +21,18 @@ public class ChannelController(ChannelWriter workerCh [EndpointGroupName("general")] public async Task> GetAll() => await mediator.Send(new GetAllChannelsForApi()); + [HttpGet("/api/channels/state")] + [Tags("Channels")] + [EndpointSummary("Get channel runtime state")] + [EndpointGroupName("general")] + [ProducesResponseType(typeof(List), StatusCodes.Status200OK)] + public async Task GetState(CancellationToken cancellationToken) + { + List result = + await mediator.Send(new GetChannelStatesForApi(), cancellationToken); + return new OkObjectResult(result); + } + [HttpGet("/api/channels/{id:int}", Name = "GetChannelById")] [Tags("Channels")] [EndpointSummary("Get a channel by id")]