From 70f357f8f98a1817a1049bcd8839fcce0431c2df Mon Sep 17 00:00:00 2001 From: Timothy Date: Sun, 12 Jul 2026 02:33:39 +0200 Subject: [PATCH] feat(api): #288 ChannelDetailResponseModel for edit form + SPA repoints + final regen Mint ChannelDetailResponseModel (faithful detail DTO exposing the raw editable field set the channel editor reads: raw FFmpegProfileId/WatermarkId/FallbackFillerId ids, the mode enums, logo, playoutCount, id) and route GetById/Create/Update through it, replacing the lean list ChannelResponseModel that resolved the profile to a name and dropped the editable ids (a functional regression for draftFromChannel). The lean ChannelResponseModel stays unchanged for GET /api/channels. webEncodedName dropped (SPA never reads it). Logo is mirrored as a Core ChannelLogoResponseModel since the Application ArtworkContentTypeModel can't be referenced from Core. Repoint the hand-written SPA client aliases now that the VMs are gone from the schema: Channel -> ChannelDetailResponseModel, MediaCollection/SmartCollection -> *ResponseModel, ProgramSchedule -> ProgramScheduleResponseModel. Fix #288 honest-nullability test fallout in search.test.ts (null -> [] for now-non-null id arrays). Include the already-on-disk playouts.ts WithDayNames removal and regenerate v1.json + v1.d.ts + endpoint-index.md (authoritative final regen; the reset endpoint's {channelNumber}->{id} re-key surfaces in the generated docs and the OpenApi error-contract test). Refs #288 #197 Co-Authored-By: Claude Opus 4.8 (1M context) --- ErsatzTV.Application/Channels/Mapper.cs | 35 + .../Channels/Queries/GetChannelByIdForApi.cs | 2 +- .../Queries/GetChannelByIdForApiHandler.cs | 8 +- .../Channels/ChannelDetailResponseModel.cs | 55 + .../GetChannelByIdForApiHandlerTests.cs | 25 +- .../Controllers/ChannelControllerTests.cs | 44 +- .../OpenApiErrorResponseContractTests.cs | 4 +- .../OpenApiSerializerContractTests.cs | 12 +- ErsatzTV/Controllers/Api/ChannelController.cs | 14 +- ErsatzTV/wwwroot/openapi/v1.json | 6171 +++++++++++++++-- docs/endpoint-index.md | 193 +- web/src/api/channels.ts | 2 +- web/src/api/collections.ts | 4 +- web/src/api/generated/v1.d.ts | 179 +- web/src/api/playouts.ts | 21 +- web/src/api/schedules.ts | 2 +- web/src/api/search.test.ts | 18 +- 17 files changed, 5806 insertions(+), 983 deletions(-) create mode 100644 ErsatzTV.Core/Api/Channels/ChannelDetailResponseModel.cs diff --git a/ErsatzTV.Application/Channels/Mapper.cs b/ErsatzTV.Application/Channels/Mapper.cs index bbe5a8c78..558f9f061 100644 --- a/ErsatzTV.Application/Channels/Mapper.cs +++ b/ErsatzTV.Application/Channels/Mapper.cs @@ -38,6 +38,41 @@ internal static class Mapper channel.IsEnabled, channel.ShowInEpg); + internal static ChannelDetailResponseModel ProjectToDetailResponseModel(Channel channel, int playoutCount) + { + ArtworkContentTypeModel logo = GetLogo(channel); + return new ChannelDetailResponseModel( + channel.Id, + channel.Number, + channel.Name, + channel.Group, + channel.Categories, + channel.FFmpegProfileId, + channel.SlugSeconds, + new ChannelLogoResponseModel(logo.Path, logo.ContentType), + channel.StreamSelectorMode, + channel.StreamSelector, + channel.PreferredAudioLanguageCode, + channel.PreferredAudioTitle, + channel.PlayoutSource, + channel.PlayoutMode, + channel.MirrorSourceChannelId, + channel.PlayoutOffset, + channel.StreamingMode, + channel.WatermarkId, + channel.FallbackFillerId, + playoutCount, + channel.PreferredSubtitleLanguageCode, + channel.SubtitleMode, + channel.MusicVideoCreditsMode, + channel.MusicVideoCreditsTemplate, + channel.SongVideoMode, + channel.TranscodeMode, + channel.IdleBehavior, + channel.IsEnabled, + channel.ShowInEpg); + } + internal static ChannelResponseModel ProjectToResponseModel(Channel channel) => new( channel.Id, diff --git a/ErsatzTV.Application/Channels/Queries/GetChannelByIdForApi.cs b/ErsatzTV.Application/Channels/Queries/GetChannelByIdForApi.cs index bc527dde3..adf640e2b 100644 --- a/ErsatzTV.Application/Channels/Queries/GetChannelByIdForApi.cs +++ b/ErsatzTV.Application/Channels/Queries/GetChannelByIdForApi.cs @@ -2,4 +2,4 @@ using ErsatzTV.Core.Api.Channels; namespace ErsatzTV.Application.Channels; -public record GetChannelByIdForApi(int Id) : IRequest>; +public record GetChannelByIdForApi(int Id) : IRequest>; diff --git a/ErsatzTV.Application/Channels/Queries/GetChannelByIdForApiHandler.cs b/ErsatzTV.Application/Channels/Queries/GetChannelByIdForApiHandler.cs index 95b04ab2f..8773964db 100644 --- a/ErsatzTV.Application/Channels/Queries/GetChannelByIdForApiHandler.cs +++ b/ErsatzTV.Application/Channels/Queries/GetChannelByIdForApiHandler.cs @@ -5,9 +5,11 @@ using static ErsatzTV.Application.Channels.Mapper; namespace ErsatzTV.Application.Channels; public class GetChannelByIdForApiHandler(IChannelRepository channelRepository) - : IRequestHandler> + : IRequestHandler> { - public Task> Handle(GetChannelByIdForApi request, CancellationToken cancellationToken) => + public Task> Handle( + GetChannelByIdForApi request, + CancellationToken cancellationToken) => channelRepository.GetChannel(request.Id) - .MapT(ProjectToResponseModel); + .MapT(channel => ProjectToDetailResponseModel(channel, channel.Playouts?.Count ?? 0)); } diff --git a/ErsatzTV.Core/Api/Channels/ChannelDetailResponseModel.cs b/ErsatzTV.Core/Api/Channels/ChannelDetailResponseModel.cs new file mode 100644 index 000000000..850c9e14a --- /dev/null +++ b/ErsatzTV.Core/Api/Channels/ChannelDetailResponseModel.cs @@ -0,0 +1,55 @@ +#nullable enable +using ErsatzTV.Core.Domain; + +namespace ErsatzTV.Core.Api.Channels; + +// Faithful channel-detail DTO for the SPA channel editor (GET/POST/PUT /api/channels[/{id}]). +// Exposes the raw editable field set the editor reads (raw FFmpegProfileId / WatermarkId / +// FallbackFillerId ids and the mode enums), unlike the lean list ChannelResponseModel which +// resolves the profile to a display name and drops the editable ids. Mirrors the effective +// nullability of the (now-removed-from-the-schema) ChannelViewModel so the SPA form logic is +// unaffected. WebEncodedName is intentionally dropped: the SPA never reads it. +public record ChannelDetailResponseModel( + int Id, + string Number, + string Name, + string Group, + string Categories, + int FFmpegProfileId, + double? SlugSeconds, + ChannelLogoResponseModel Logo, + ChannelStreamSelectorMode StreamSelectorMode, + string StreamSelector, + string PreferredAudioLanguageCode, + string PreferredAudioTitle, + ChannelPlayoutSource PlayoutSource, + ChannelPlayoutMode PlayoutMode, + int? MirrorSourceChannelId, + TimeSpan? PlayoutOffset, + StreamingMode StreamingMode, + int? WatermarkId, + int? FallbackFillerId, + int PlayoutCount, + string PreferredSubtitleLanguageCode, + ChannelSubtitleMode SubtitleMode, + ChannelMusicVideoCreditsMode MusicVideoCreditsMode, + string MusicVideoCreditsTemplate, + ChannelSongVideoMode SongVideoMode, + ChannelTranscodeMode TranscodeMode, + ChannelIdleBehavior IdleBehavior, + bool IsEnabled, + bool ShowInEpg); + +// Wire-compatible mirror of the Application-layer ArtworkContentTypeModel (which lives in +// ErsatzTV.Application and therefore can't be referenced from Core). Same serialized shape the +// SPA's UpdateChannelRequest.logo already expects, so draftFromChannel's round-trip is lossless. +public record ChannelLogoResponseModel(string Path, string ContentType) +{ + public bool IsExternalUrl => Domain.Artwork.IsExternalUrl(Path); + + public bool HasContentType => !string.IsNullOrWhiteSpace(ContentType); + + // The artwork serve routes sniff the content type from the stored file and no longer honor a + // client-supplied ?contentType= (issue #283), so the directly-usable URL is just the path. + public string UrlWithContentType => Path; +} diff --git a/ErsatzTV.Tests/Application/Channels/GetChannelByIdForApiHandlerTests.cs b/ErsatzTV.Tests/Application/Channels/GetChannelByIdForApiHandlerTests.cs index 3b49f5646..3c651108c 100644 --- a/ErsatzTV.Tests/Application/Channels/GetChannelByIdForApiHandlerTests.cs +++ b/ErsatzTV.Tests/Application/Channels/GetChannelByIdForApiHandlerTests.cs @@ -13,7 +13,7 @@ namespace ErsatzTV.Tests.Application.Channels; public class GetChannelByIdForApiHandlerTests { [Test] - public async Task Should_Project_ResponseModel_When_Found() + public async Task Should_Project_DetailResponseModel_When_Found() { IChannelRepository repository = Substitute.For(); repository.GetChannel(7) @@ -25,26 +25,35 @@ public class GetChannelByIdForApiHandlerTests Name = "Retro Cartoons", Group = "Kids", Categories = "animation", + FFmpegProfileId = 3, FFmpegProfile = new FFmpegProfile { Name = "HLS 720p" }, + Artwork = [], PreferredAudioLanguageCode = "eng", StreamingMode = StreamingMode.HttpLiveStreamingSegmenter, + WatermarkId = 11, + FallbackFillerId = 12, IsEnabled = false, ShowInEpg = false })); var handler = new GetChannelByIdForApiHandler(repository); - Option result = + Option result = await handler.Handle(new GetChannelByIdForApi(7), CancellationToken.None); result.IsSome.ShouldBeTrue(); - ChannelResponseModel channel = result.IfNone(() => throw new InvalidOperationException()); + ChannelDetailResponseModel channel = result.IfNone(() => throw new InvalidOperationException()); channel.Id.ShouldBe(7); channel.Number.ShouldBe("7.1"); - channel.SortNumber.ShouldBe(7.1); channel.Name.ShouldBe("Retro Cartoons"); - channel.FFmpegProfile.ShouldBe("HLS 720p"); - channel.Language.ShouldBe("eng"); - channel.StreamingMode.ShouldBe("HLS Segmenter"); + channel.Group.ShouldBe("Kids"); + channel.Categories.ShouldBe("animation"); + // Detail model exposes the raw editable ids the editor re-drafts (not a resolved name). + channel.FFmpegProfileId.ShouldBe(3); + channel.WatermarkId.ShouldBe(11); + channel.FallbackFillerId.ShouldBe(12); + channel.PreferredAudioLanguageCode.ShouldBe("eng"); + channel.StreamingMode.ShouldBe(StreamingMode.HttpLiveStreamingSegmenter); + channel.PlayoutCount.ShouldBe(0); channel.IsEnabled.ShouldBeFalse(); channel.ShowInEpg.ShouldBeFalse(); } @@ -56,7 +65,7 @@ public class GetChannelByIdForApiHandlerTests repository.GetChannel(Arg.Any()).Returns(Option.None); var handler = new GetChannelByIdForApiHandler(repository); - Option result = + Option result = await handler.Handle(new GetChannelByIdForApi(99), CancellationToken.None); result.IsNone.ShouldBeTrue(); diff --git a/ErsatzTV.Tests/Controllers/ChannelControllerTests.cs b/ErsatzTV.Tests/Controllers/ChannelControllerTests.cs index 570ac80a6..97971c94e 100644 --- a/ErsatzTV.Tests/Controllers/ChannelControllerTests.cs +++ b/ErsatzTV.Tests/Controllers/ChannelControllerTests.cs @@ -101,9 +101,9 @@ public class ChannelControllerTests { _mediator.Send(Arg.Any(), Arg.Any()) .Returns(Right(new CreateChannelResult(5))); - ChannelResponseModel model = MakeResponseModel(5); + ChannelDetailResponseModel model = MakeDetailModel(5); _mediator.Send(Arg.Any(), Arg.Any()) - .Returns(Option.Some(model)); + .Returns(Option.Some(model)); IActionResult result = await _controller.Create(MakeCreateRequest(number: "5"), CancellationToken.None); @@ -119,7 +119,7 @@ public class ChannelControllerTests _mediator.Send(Arg.Any(), Arg.Any()) .Returns(Right(new CreateChannelResult(5))); _mediator.Send(Arg.Any(), Arg.Any()) - .Returns(Option.Some(MakeResponseModel(5))); + .Returns(Option.Some(MakeDetailModel(5))); await _controller.Create(MakeCreateRequest(number: "12", name: "Movies"), CancellationToken.None); @@ -192,9 +192,9 @@ public class ChannelControllerTests { _mediator.Send(Arg.Any(), Arg.Any()) .Returns(Right(MakeVm(7))); - ChannelResponseModel model = MakeResponseModel(7); + ChannelDetailResponseModel model = MakeDetailModel(7); _mediator.Send(Arg.Any(), Arg.Any()) - .Returns(Option.Some(model)); + .Returns(Option.Some(model)); IActionResult result = await _controller.Update(7, MakeUpdateRequest(number: "5"), CancellationToken.None); @@ -361,9 +361,9 @@ public class ChannelControllerTests [Test] public async Task GetById_Should_Return_200_With_ResponseModel_For_Some() { - ChannelResponseModel model = MakeResponseModel(4); + ChannelDetailResponseModel model = MakeDetailModel(4); _mediator.Send(Arg.Any(), Arg.Any()) - .Returns(Option.Some(model)); + .Returns(Option.Some(model)); IActionResult result = await _controller.GetById(4, CancellationToken.None); @@ -374,7 +374,7 @@ public class ChannelControllerTests public async Task GetById_Should_Return_404_For_None() { _mediator.Send(Arg.Any(), Arg.Any()) - .Returns(Option.None); + .Returns(Option.None); IActionResult result = await _controller.GetById(4, CancellationToken.None); @@ -486,17 +486,35 @@ public class ChannelControllerTests null, 0); - private static ChannelResponseModel MakeResponseModel(int id) => + private static ChannelDetailResponseModel MakeDetailModel(int id) => new( id, "5", - 5.0, "Test", "ErsatzTV", string.Empty, - "HLS 720p", - "eng", - "MPEG-TS", + 1, + null, + new ChannelLogoResponseModel(string.Empty, string.Empty), + ChannelStreamSelectorMode.Default, + string.Empty, + string.Empty, + string.Empty, + ChannelPlayoutSource.Generated, + ChannelPlayoutMode.Continuous, + null, + null, + StreamingMode.TransportStreamHybrid, + null, + null, + 0, + string.Empty, + ChannelSubtitleMode.None, + ChannelMusicVideoCreditsMode.None, + string.Empty, + ChannelSongVideoMode.Default, + ChannelTranscodeMode.OnDemand, + ChannelIdleBehavior.StopOnDisconnect, true, false); diff --git a/ErsatzTV.Tests/Controllers/OpenApiErrorResponseContractTests.cs b/ErsatzTV.Tests/Controllers/OpenApiErrorResponseContractTests.cs index 2e0c8638a..c4ea019bc 100644 --- a/ErsatzTV.Tests/Controllers/OpenApiErrorResponseContractTests.cs +++ b/ErsatzTV.Tests/Controllers/OpenApiErrorResponseContractTests.cs @@ -114,8 +114,8 @@ public class OpenApiErrorResponseContractTests [TestCase("/api/channels/bulk/group", "post", "422")] [TestCase("/api/channels/bulk/delete", "post", "404")] [TestCase("/api/channels/bulk/delete", "post", "422")] - [TestCase("/api/channels/{channelNumber}/playout/reset", "post", "404")] - [TestCase("/api/channels/{channelNumber}/playout/reset", "post", "409")] + [TestCase("/api/channels/{id}/playout/reset", "post", "404")] + [TestCase("/api/channels/{id}/playout/reset", "post", "409")] [TestCase("/api/channel-templates/default", "get", "404")] [TestCase("/api/channel-templates/default/{id}", "put", "404")] [TestCase("/api/channel-templates/default/{id}", "put", "422")] diff --git a/ErsatzTV.Tests/Controllers/OpenApiSerializerContractTests.cs b/ErsatzTV.Tests/Controllers/OpenApiSerializerContractTests.cs index e990d1c89..1388a65ae 100644 --- a/ErsatzTV.Tests/Controllers/OpenApiSerializerContractTests.cs +++ b/ErsatzTV.Tests/Controllers/OpenApiSerializerContractTests.cs @@ -1,6 +1,4 @@ using System.Text.Json; -using ErsatzTV.Application.Artworks; -using ErsatzTV.Application.Channels; using ErsatzTV.Core.Api.Channels; using ErsatzTV.Core.Api.MediaItems; using ErsatzTV.Core.Api.Settings; @@ -35,13 +33,15 @@ public class OpenApiSerializerContractTests private static IEnumerable Cases() { - yield return new TestCaseData(FullyPopulatedChannel(), "ChannelViewModel").SetName("ChannelViewModel"); + yield return new TestCaseData(FullyPopulatedChannelDetail(), "ChannelDetailResponseModel") + .SetName("ChannelDetailResponseModel"); yield return new TestCaseData(FullyPopulatedFFmpegSettings(), "FFmpegSettingsResponseModel") .SetName("FFmpegSettingsResponseModel"); // WatermarkViewModel was dropped from the API surface by #126: schedule-item endpoints no longer // expose the polymorphic ProgramScheduleItemViewModel (which transitively pulled in WatermarkViewModel // and the other collection VMs) — they return the flat ScheduleItemResponseModel, embedding watermarks - // as NamedIdResponseModel. ChannelViewModel below still exercises the VM path of the schema transformer. + // as NamedIdResponseModel. ChannelDetailResponseModel above still exercises the "ffmpegProfileId" + // special-case naming path of the schema transformer. yield return new TestCaseData(FullyPopulatedMediaItemInfo(), "MediaItemInfoResponseModel") .SetName("MediaItemInfoResponseModel"); @@ -73,7 +73,7 @@ public class OpenApiSerializerContractTests $"OpenAPI schema '{schemaName}' property names must match the runtime Newtonsoft JSON keys."); } - private static ChannelViewModel FullyPopulatedChannel() => new( + private static ChannelDetailResponseModel FullyPopulatedChannelDetail() => new( 1, "1", "Name", @@ -81,7 +81,7 @@ public class OpenApiSerializerContractTests "Categories", 1, 1.0, - new ArtworkContentTypeModel("path", "image/png"), + new ChannelLogoResponseModel("path", "image/png"), default, "selector", "en", diff --git a/ErsatzTV/Controllers/Api/ChannelController.cs b/ErsatzTV/Controllers/Api/ChannelController.cs index cfc6362e3..283ff9a59 100644 --- a/ErsatzTV/Controllers/Api/ChannelController.cs +++ b/ErsatzTV/Controllers/Api/ChannelController.cs @@ -68,11 +68,11 @@ public class ChannelController( [Tags("Channels")] [EndpointSummary("Get a channel by id")] [EndpointGroupName("general")] - [ProducesResponseType(typeof(ChannelResponseModel), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ChannelDetailResponseModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] public async Task GetById(int id, CancellationToken cancellationToken) { - Option result = await mediator.Send(new GetChannelByIdForApi(id), cancellationToken); + Option result = await mediator.Send(new GetChannelByIdForApi(id), cancellationToken); return result.ToGetResult(); } @@ -80,7 +80,7 @@ public class ChannelController( [Tags("Channels")] [EndpointSummary("Create a channel")] [EndpointGroupName("general")] - [ProducesResponseType(typeof(ChannelResponseModel), StatusCodes.Status201Created)] + [ProducesResponseType(typeof(ChannelDetailResponseModel), StatusCodes.Status201Created)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status422UnprocessableEntity)] public async Task Create( @@ -92,7 +92,7 @@ public class ChannelController( Left: error => Task.FromResult(error.ToErrorResult()), Right: async created => { - Option channel = + Option channel = await mediator.Send(new GetChannelByIdForApi(created.ChannelId), cancellationToken); return channel.Match( Some: model => (IActionResult)new CreatedResult($"/api/channels/{model.Id}", model), @@ -130,7 +130,7 @@ public class ChannelController( [Tags("Channels")] [EndpointSummary("Update a channel")] [EndpointGroupName("general")] - [ProducesResponseType(typeof(ChannelResponseModel), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ChannelDetailResponseModel), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status422UnprocessableEntity)] public async Task Update( @@ -145,8 +145,8 @@ public class ChannelController( Right: async _ => { // Re-project through the read-side query so the response carries the same - // ChannelResponseModel shape (incl. SortNumber and FFmpegProfile name) as GET. - Option channel = + // ChannelDetailResponseModel shape (raw editable ids the editor re-drafts) as GET. + Option channel = await mediator.Send(new GetChannelByIdForApi(id), cancellationToken); return channel.Match( Some: model => (IActionResult)new OkObjectResult(model), diff --git a/ErsatzTV/wwwroot/openapi/v1.json b/ErsatzTV/wwwroot/openapi/v1.json index a219dedd9..7d7765ad2 100644 --- a/ErsatzTV/wwwroot/openapi/v1.json +++ b/ErsatzTV/wwwroot/openapi/v1.json @@ -63,8 +63,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/artwork/uploads": { @@ -142,8 +165,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/blocks/groups": { @@ -182,14 +228,28 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ "Blocks" ], "summary": "Create a block group", + "operationId": "BlockCreateGroup", "requestBody": { "content": { "application/json-patch+json": { @@ -275,8 +335,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/blocks/groups/{id}": { @@ -286,6 +369,7 @@ ], "summary": "Delete a block group", "description": "Deletes the block group. The database cascade removes every block (and its items) in the group.", + "operationId": "BlockDeleteGroup", "parameters": [ { "name": "id", @@ -320,8 +404,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/blocks": { @@ -330,6 +437,7 @@ "Blocks" ], "summary": "Get all blocks", + "operationId": "BlockGetAll", "responses": { "200": { "description": "OK", @@ -359,8 +467,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ @@ -368,6 +489,7 @@ ], "summary": "Create a block", "description": "Creates an empty block in the given block group. The block defaults to 30 minutes.", + "operationId": "BlockCreate", "requestBody": { "content": { "application/json-patch+json": { @@ -453,8 +575,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/blocks/{id}": { @@ -515,14 +660,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ "Blocks" ], "summary": "Delete a block", + "operationId": "BlockDelete", "parameters": [ { "name": "id", @@ -557,8 +726,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -566,6 +758,7 @@ ], "summary": "Replace a block and its items", "description": "Replaces the block's name/minutes/stop-scheduling and its full item list. Item indexes are assigned from the array order. Minutes must be greater than zero, divisible by 5, and at most 24 hours. Send the ETag from the items GET as If-Match to reject a stale overwrite with 412 (issue #253); a successful response carries the new ETag.", + "operationId": "BlockReplace", "parameters": [ { "name": "id", @@ -702,8 +895,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/blocks/{id}/items": { @@ -713,6 +919,7 @@ ], "summary": "Get block items", "description": "Returns the block's items and a strong ETag of the block's version. Pass that ETag back as If-Match on the replace (PUT) to detect a concurrent edit (issue #253).", + "operationId": "BlockGetItems", "parameters": [ { "name": "id", @@ -773,8 +980,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/blocks/{id}/preview": { @@ -784,6 +1014,7 @@ ], "summary": "Preview a block playout", "description": "Builds a preview playout from the supplied block definition without persisting any changes to the block, its items, or any playout. Returns the resulting start/finish/title/duration list.", + "operationId": "BlockPreview", "parameters": [ { "name": "id", @@ -869,8 +1100,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/blocks/{id}/copy": { @@ -880,6 +1134,7 @@ ], "summary": "Copy a block", "description": "Copies the block and its items into another (or the same) block group under a new name.", + "operationId": "BlockCopy", "parameters": [ { "name": "id", @@ -976,8 +1231,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/channels": { @@ -985,6 +1263,7 @@ "tags": [ "Channel" ], + "operationId": "ChannelGetAll", "responses": { "200": { "description": "OK", @@ -1014,14 +1293,28 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ "Channels" ], "summary": "Create a channel", + "operationId": "ChannelCreate", "requestBody": { "content": { "application/json-patch+json": { @@ -1053,17 +1346,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/ChannelViewModel" + "$ref": "#/components/schemas/ChannelDetailResponseModel" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/ChannelViewModel" + "$ref": "#/components/schemas/ChannelDetailResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/ChannelViewModel" + "$ref": "#/components/schemas/ChannelDetailResponseModel" } } } @@ -1107,8 +1400,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/channels/state": { @@ -1117,6 +1433,7 @@ "Channels" ], "summary": "Get channel runtime state", + "operationId": "ChannelGetState", "responses": { "200": { "description": "OK", @@ -1146,8 +1463,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/guide": { @@ -1157,6 +1487,7 @@ ], "summary": "Get the JSON channel guide (EPG)", "description": "Returns per-channel programme arrays for the EPG grid. When omitted, start defaults to now, and end defaults to start plus the configured XmltvDaysToBuild window.", + "operationId": "ChannelGetGuide", "parameters": [ { "name": "start", @@ -1195,8 +1526,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/channels/music-video-credits-templates": { @@ -1235,8 +1589,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/channels/stream-selectors": { @@ -1275,8 +1642,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/channels/{id}": { @@ -1303,17 +1683,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/ChannelViewModel" + "$ref": "#/components/schemas/ChannelDetailResponseModel" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/ChannelViewModel" + "$ref": "#/components/schemas/ChannelDetailResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/ChannelViewModel" + "$ref": "#/components/schemas/ChannelDetailResponseModel" } } } @@ -1337,14 +1717,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ "Channels" ], "summary": "Update a channel", + "operationId": "ChannelUpdate", "parameters": [ { "name": "id", @@ -1387,17 +1791,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/ChannelViewModel" + "$ref": "#/components/schemas/ChannelDetailResponseModel" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/ChannelViewModel" + "$ref": "#/components/schemas/ChannelDetailResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/ChannelViewModel" + "$ref": "#/components/schemas/ChannelDetailResponseModel" } } } @@ -1441,14 +1845,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ "Channels" ], "summary": "Delete a channel", + "operationId": "ChannelDelete", "parameters": [ { "name": "id", @@ -1503,8 +1931,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/channels/from-lineup": { @@ -1600,8 +2051,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/channels/bulk/renumber": { @@ -1610,6 +2084,7 @@ "Channels" ], "summary": "Renumber channels", + "operationId": "ChannelBulkRenumber", "requestBody": { "content": { "application/json-patch+json": { @@ -1678,8 +2153,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/channels/bulk/group": { @@ -1688,6 +2186,7 @@ "Channels" ], "summary": "Move channels to a group", + "operationId": "ChannelBulkMoveToGroup", "requestBody": { "content": { "application/json-patch+json": { @@ -1756,8 +2255,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/channels/bulk/delete": { @@ -1766,6 +2288,7 @@ "Channels" ], "summary": "Delete channels", + "operationId": "ChannelBulkDelete", "requestBody": { "content": { "application/json-patch+json": { @@ -1834,24 +2357,49 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, - "/api/channels/{channelNumber}/playout/reset": { + "/api/channels/{id}/playout/reset": { "post": { "tags": [ "Channels" ], "summary": "Reset channel playout", "description": "When mode is omitted, classic playouts use Refresh (rebuild while maintaining collection progress) and all other playout kinds use Reset (rebuild from scratch), matching the Blazor UI. Pass mode to force a specific PlayoutBuildMode.", + "operationId": "ChannelResetPlayout", "parameters": [ { - "name": "channelNumber", + "name": "id", "in": "path", "required": true, "schema": { - "type": "string" + "type": "integer", + "format": "int32" } }, { @@ -1905,8 +2453,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/channel-templates": { @@ -1945,8 +2516,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ @@ -2039,8 +2623,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/channel-templates/default": { @@ -2090,8 +2697,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/channel-templates/default/{id}": { @@ -2172,8 +2792,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/channel-templates/{id}": { @@ -2234,8 +2877,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -2339,8 +3005,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ @@ -2402,8 +3091,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/collections": { @@ -2412,6 +3124,7 @@ "Collections" ], "summary": "Get all collections", + "operationId": "CollectionGetAll", "responses": { "200": { "description": "OK", @@ -2420,7 +3133,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/MediaCollectionViewModel" + "$ref": "#/components/schemas/MediaCollectionResponseModel" } } }, @@ -2428,7 +3141,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/MediaCollectionViewModel" + "$ref": "#/components/schemas/MediaCollectionResponseModel" } } }, @@ -2436,19 +3149,33 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/MediaCollectionViewModel" + "$ref": "#/components/schemas/MediaCollectionResponseModel" } } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ "Collections" ], "summary": "Create a collection", + "operationId": "CollectionCreate", "requestBody": { "content": { "application/json-patch+json": { @@ -2480,17 +3207,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/MediaCollectionViewModel" + "$ref": "#/components/schemas/MediaCollectionResponseModel" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/MediaCollectionViewModel" + "$ref": "#/components/schemas/MediaCollectionResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/MediaCollectionViewModel" + "$ref": "#/components/schemas/MediaCollectionResponseModel" } } } @@ -2534,8 +3261,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/collections/{id}": { @@ -2562,17 +3312,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/MediaCollectionViewModel" + "$ref": "#/components/schemas/MediaCollectionResponseModel" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/MediaCollectionViewModel" + "$ref": "#/components/schemas/MediaCollectionResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/MediaCollectionViewModel" + "$ref": "#/components/schemas/MediaCollectionResponseModel" } } } @@ -2596,14 +3346,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ "Collections" ], "summary": "Update a collection", + "operationId": "CollectionUpdate", "parameters": [ { "name": "id", @@ -2646,17 +3420,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/MediaCollectionViewModel" + "$ref": "#/components/schemas/MediaCollectionResponseModel" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/MediaCollectionViewModel" + "$ref": "#/components/schemas/MediaCollectionResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/MediaCollectionViewModel" + "$ref": "#/components/schemas/MediaCollectionResponseModel" } } } @@ -2700,14 +3474,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ "Collections" ], "summary": "Delete a collection", + "operationId": "CollectionDelete", "parameters": [ { "name": "id", @@ -2762,8 +3560,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/collections/{id}/items": { @@ -2843,14 +3664,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ "Collections" ], "summary": "Add items to a collection", + "operationId": "CollectionAddItems", "parameters": [ { "name": "id", @@ -2930,8 +3775,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/collections/{id}/custom-order": { @@ -2941,6 +3809,7 @@ ], "summary": "Set a collection's custom playback order", "description": "Replaces the custom playback order of a manual collection. CustomIndex is assigned from array position (the request body has no index field); ids that are not members of the collection are ignored. Set UseCustomPlaybackOrder on the collection for this order to take effect.", + "operationId": "CollectionUpdateCustomOrder", "parameters": [ { "name": "id", @@ -3060,8 +3929,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/collections/{id}/items/{mediaItemId}": { @@ -3070,6 +3952,7 @@ "Collections" ], "summary": "Remove an item from a collection", + "operationId": "CollectionRemoveItem", "parameters": [ { "name": "id", @@ -3133,8 +4016,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/decos/groups": { @@ -3173,14 +4079,28 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ "Decos" ], "summary": "Create a deco group", + "operationId": "DecoCreateGroup", "requestBody": { "content": { "application/json-patch+json": { @@ -3266,8 +4186,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/decos/groups/{id}": { @@ -3277,6 +4220,7 @@ ], "summary": "Delete a deco group", "description": "Deletes the deco group. The database cascade removes every deco in the group (and each deco's break content and watermark/graphics-element assignments); any playout that used a removed deco has its default deco cleared.", + "operationId": "DecoDeleteGroup", "parameters": [ { "name": "id", @@ -3311,8 +4255,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/decos": { @@ -3322,6 +4289,7 @@ ], "summary": "Get all decos", "description": "Returns every deco as a flat list, ordered by group name then deco name.", + "operationId": "DecoGetAll", "responses": { "200": { "description": "OK", @@ -3351,8 +4319,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ @@ -3360,6 +4341,7 @@ ], "summary": "Create a deco", "description": "Creates a deco in the given deco group. The deco inherits everything by default.", + "operationId": "DecoCreate", "requestBody": { "content": { "application/json-patch+json": { @@ -3445,8 +4427,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/decos/{id}": { @@ -3507,8 +4512,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ @@ -3516,6 +4544,7 @@ ], "summary": "Delete a deco", "description": "Deletes the deco. Any playout that used it as its default deco has that default cleared.", + "operationId": "DecoDelete", "parameters": [ { "name": "id", @@ -3550,8 +4579,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -3559,6 +4611,7 @@ ], "summary": "Replace a deco", "description": "Replaces the full state of the deco (name and all six sections). Send the entire desired state, including unchanged sections. Merge is only valid for the watermark and graphics-element modes. Break content allows at most one item per placement.", + "operationId": "DecoReplace", "parameters": [ { "name": "id", @@ -3655,8 +4708,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/deco-templates/groups": { @@ -3695,14 +4771,28 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ "DecoTemplates" ], "summary": "Create a deco template group", + "operationId": "DecoTemplateCreateGroup", "requestBody": { "content": { "application/json-patch+json": { @@ -3788,8 +4878,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/deco-templates/groups/{id}": { @@ -3799,6 +4912,7 @@ ], "summary": "Delete a deco template group", "description": "Deletes the deco template group. The database cascade removes every deco template (and its items) in the group; any playout template that used a removed deco template has that reference cleared.", + "operationId": "DecoTemplateDeleteGroup", "parameters": [ { "name": "id", @@ -3833,8 +4947,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/deco-templates": { @@ -3844,6 +4981,7 @@ ], "summary": "Get all deco templates", "description": "Returns every deco template as a flat list, ordered by group name then deco template name.", + "operationId": "DecoTemplateGetAll", "responses": { "200": { "description": "OK", @@ -3873,8 +5011,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ @@ -3882,6 +5033,7 @@ ], "summary": "Create a deco template", "description": "Creates an empty deco template in the given deco template group.", + "operationId": "DecoTemplateCreate", "requestBody": { "content": { "application/json-patch+json": { @@ -3967,8 +5119,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/deco-templates/{id}": { @@ -4029,14 +5204,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ "DecoTemplates" ], "summary": "Delete a deco template", + "operationId": "DecoTemplateDelete", "parameters": [ { "name": "id", @@ -4071,8 +5270,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -4080,6 +5302,7 @@ ], "summary": "Replace a deco template and its items", "description": "Replaces the deco template's name and its full item list. Each item assigns a deco to a start/end time of day; an end time of 00:00:00 means the item runs to the end of the day. Items must not overlap. Send the ETag from the items GET as If-Match to reject a stale overwrite with 412 (issue #253); a successful response carries the new ETag.", + "operationId": "DecoTemplateReplace", "parameters": [ { "name": "id", @@ -4216,8 +5439,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/deco-templates/{id}/items": { @@ -4227,6 +5463,7 @@ ], "summary": "Get deco template items", "description": "Returns the deco template's items and a strong ETag of the deco template's version. Pass that ETag back as If-Match on the replace (PUT) to detect a concurrent edit (issue #253).", + "operationId": "DecoTemplateGetItems", "parameters": [ { "name": "id", @@ -4287,8 +5524,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/emby": { @@ -4318,8 +5578,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/emby/connection": { @@ -4350,8 +5623,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -4445,8 +5731,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/emby/disconnect": { @@ -4480,8 +5789,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/emby/{id}/libraries": { @@ -4551,8 +5873,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -4666,8 +6011,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/emby/{id}/path-replacements": { @@ -4737,8 +6105,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -4851,8 +6242,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/emby/{id}/refresh-libraries": { @@ -4916,8 +6330,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/emby/{id}/scan-collections": { @@ -4990,8 +6427,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/ffmpeg/profiles": { @@ -5030,8 +6490,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ @@ -5144,8 +6617,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/ffmpeg/hardware-acceleration-kinds": { @@ -5185,8 +6671,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/ffmpeg/profiles/{id}": { @@ -5247,8 +6746,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -5372,8 +6894,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ @@ -5455,8 +6990,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/filler-presets": { @@ -5505,8 +7053,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ @@ -5619,8 +7190,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/filler-presets/{id}": { @@ -5681,8 +7265,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -5806,8 +7413,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ @@ -5889,8 +7509,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/graphics-elements": { @@ -5939,8 +7572,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/health": { @@ -5979,8 +7635,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/images/folders": { @@ -6031,8 +7700,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/images/folders/{id}/duration": { @@ -6139,8 +7831,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/jellyfin": { @@ -6170,8 +7875,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/jellyfin/connection": { @@ -6202,8 +7920,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -6297,8 +8028,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/jellyfin/disconnect": { @@ -6332,8 +8086,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/jellyfin/{id}/libraries": { @@ -6403,8 +8170,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -6518,8 +8308,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/jellyfin/{id}/path-replacements": { @@ -6589,8 +8402,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -6703,8 +8539,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/jellyfin/{id}/refresh-libraries": { @@ -6768,8 +8627,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/jellyfin/{id}/scan-collections": { @@ -6842,8 +8724,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/languages": { @@ -6882,8 +8787,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/libraries/scan-status": { @@ -6922,8 +8840,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/libraries/{id}/scan": { @@ -6933,6 +8864,7 @@ ], "summary": "Scan library", "description": "Queues a scan of the whole library. Pass ?deep=true for a deep (metadata-refresh) scan.", + "operationId": "LibrariesScanLibrary", "parameters": [ { "name": "id", @@ -7015,8 +8947,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/libraries/{id}/scan-show": { @@ -7025,6 +8980,7 @@ "Libraries" ], "summary": "Scan show", + "operationId": "LibrariesScanShow", "parameters": [ { "name": "id", @@ -7124,8 +9080,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/library/browse": { @@ -7207,8 +9186,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/libraries/local": { @@ -7247,14 +9249,28 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ "Libraries" ], "summary": "Create a local library", + "operationId": "LocalLibrariesCreate", "requestBody": { "content": { "application/json-patch+json": { @@ -7320,8 +9336,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/libraries/local/{id}": { @@ -7382,8 +9421,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -7391,6 +9453,7 @@ ], "summary": "Update a local library", "description": "Replaces the library's name and full path list. MediaKind is immutable after create and is not part of this request. Paths are identified by normalized path string, not id — a renamed path is a delete-old + add-new (its id changes).", + "operationId": "LocalLibrariesUpdate", "parameters": [ { "name": "id", @@ -7507,14 +9570,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ "Libraries" ], "summary": "Delete a local library", + "operationId": "LocalLibrariesDelete", "parameters": [ { "name": "id", @@ -7569,8 +9656,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/libraries/local/paths/{pathId}/move": { @@ -7580,6 +9690,7 @@ ], "summary": "Move a local library path to another local library", "description": "Moves a path (and its scanned media) from its current library to a different local library of the same media kind. Blazor's move dialog enforces same-kind/different-library only client-side; this endpoint enforces both server-side so API/MCP clients cannot bypass them.", + "operationId": "LocalLibrariesMovePath", "parameters": [ { "name": "pathId", @@ -7679,8 +9790,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/libraries/local/path-exists": { @@ -7690,6 +9824,7 @@ ], "summary": "Check whether a filesystem path exists", "description": "Server-side existence check for the SPA's add-path UX (a browser cannot call Directory.Exists). This is a check-then-act convenience only — Create/Update still validate new paths at save time (design #202 §C2).", + "operationId": "LocalLibrariesCheckPathExists", "requestBody": { "content": { "application/json-patch+json": { @@ -7735,8 +9870,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/logs": { @@ -7811,8 +9969,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/maintenance/gc": { @@ -7821,6 +10002,7 @@ "Maintenance" ], "summary": "Garbage collect", + "operationId": "MaintenanceGarbageCollection", "parameters": [ { "name": "force", @@ -7834,8 +10016,31 @@ "responses": { "200": { "description": "OK" + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/maintenance/empty_trash": { @@ -7844,6 +10049,7 @@ "Maintenance" ], "summary": "Empty trash", + "operationId": "MaintenanceEmptyTrash", "responses": { "200": { "description": "OK" @@ -7867,8 +10073,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/maintenance/clean_artwork": { @@ -7877,11 +10096,25 @@ "Maintenance" ], "summary": "Clean artwork cache", + "operationId": "MaintenanceCleanArtwork", "responses": { "202": { "description": "Accepted" + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-items": { @@ -7939,8 +10172,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-items/{id}/info": { @@ -8021,8 +10277,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources": { @@ -8061,8 +10340,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/movies/{id}": { @@ -8123,8 +10415,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/multi-collections": { @@ -8182,14 +10497,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ "Multi Collections" ], "summary": "Create a multi collection", + "operationId": "MultiCollectionCreate", "requestBody": { "content": { "application/json-patch+json": { @@ -8275,8 +10614,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/multi-collections/{id}": { @@ -8337,14 +10699,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ "Multi Collections" ], "summary": "Update a multi collection", + "operationId": "MultiCollectionUpdate", "parameters": [ { "name": "id", @@ -8481,14 +10867,28 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ "Multi Collections" ], "summary": "Delete a multi collection", + "operationId": "MultiCollectionDelete", "parameters": [ { "name": "id", @@ -8543,8 +10943,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playlists/groups": { @@ -8583,8 +11006,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ @@ -8657,8 +11093,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playlists/groups/{id}": { @@ -8764,8 +11223,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ @@ -8827,8 +11309,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playlists": { @@ -8878,8 +11383,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ @@ -8952,8 +11480,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playlists/{id}": { @@ -9014,8 +11565,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -9169,8 +11743,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ @@ -9232,8 +11819,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playlists/{id}/items": { @@ -9304,8 +11914,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ @@ -9392,8 +12025,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playlists/preview": { @@ -9478,8 +12134,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playouts": { @@ -9537,8 +12216,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ @@ -9546,6 +12248,7 @@ ], "summary": "Create a playout", "description": "Creates a playout of any kind (Classic, Block, Sequential, Scripted, or ExternalJson) for a channel. Classic requires ProgramScheduleId; Sequential/Scripted/ExternalJson require ScheduleFile; Block requires neither. A channel may only have one playout.", + "operationId": "PlayoutCreate", "requestBody": { "content": { "application/json-patch+json": { @@ -9631,8 +12334,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playouts/warnings/count": { @@ -9665,8 +12391,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playouts/{id}": { @@ -9727,8 +12466,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -9736,6 +12498,7 @@ ], "summary": "Update playout scheduling details", "description": "DailyRebuildTime is always applied; omit it (null) to clear the daily reset. ScheduleFile is only valid for Sequential, Scripted, and ExternalJson playouts; omit it (null) to leave it unchanged.", + "operationId": "PlayoutUpdate", "parameters": [ { "name": "id", @@ -9852,14 +12615,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ "Playouts" ], "summary": "Delete a playout", + "operationId": "PlayoutDelete", "parameters": [ { "name": "id", @@ -9934,8 +12721,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playouts/{id}/items": { @@ -10022,8 +12832,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playouts/{id}/deco": { @@ -10033,6 +12866,7 @@ ], "summary": "Set (or clear) a playout's default deco", "description": "Assigns the default deco for a block playout. Send a null decoId to clear it.", + "operationId": "PlayoutUpdateDefaultDeco", "parameters": [ { "name": "id", @@ -10149,8 +12983,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playouts/{id}/alternate-schedules": { @@ -10241,8 +13098,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -10250,6 +13130,7 @@ ], "summary": "Replace a classic playout's alternate schedules", "description": "Replaces a Classic playout's alternate schedules. Items are ordered by priority: the first item is the highest priority and the last item is the catch-all default whose schedule becomes the playout's default schedule. Index is assigned from array order (the request body has no Index field). The list must contain at least one item, and every ProgramScheduleId must exist. Only valid for Classic playouts.", + "operationId": "PlayoutReplaceAlternateSchedules", "parameters": [ { "name": "id", @@ -10415,8 +13296,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playouts/{id}/templates": { @@ -10507,8 +13401,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -10516,6 +13433,7 @@ ], "summary": "Replace a block playout's templates", "description": "Replaces a Block playout's templates. Items are ordered by priority (first = highest priority); Index is assigned from array order (the request body has no Index field). Every TemplateId must exist, and any supplied DecoTemplateId must exist. An empty list clears all templates. Only valid for Block playouts.", + "operationId": "PlayoutReplaceTemplates", "parameters": [ { "name": "id", @@ -10681,8 +13599,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playouts/{id}/blocks": { @@ -10753,8 +13684,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playouts/{id}/blocks/{blockId}/history": { @@ -10843,8 +13797,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playouts/history/{id}": { @@ -10926,8 +13903,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playouts/reset-all": { @@ -10957,8 +13957,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playouts/{id}/erase-items": { @@ -11043,8 +14056,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playouts/{id}/erase-items-and-history": { @@ -11129,8 +14165,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/playouts/items/{id}/scheduling-context": { @@ -11192,8 +14251,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/plex": { @@ -11224,8 +14306,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/plex/pin-flow": { @@ -11296,8 +14391,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/plex/sign-out": { @@ -11331,8 +14439,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/plex/{id}/libraries": { @@ -11402,8 +14523,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -11517,8 +14661,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/plex/{id}/path-replacements": { @@ -11588,8 +14755,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -11703,8 +14893,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/plex/{id}/refresh-libraries": { @@ -11769,8 +14982,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/media-sources/plex/{id}/scan-collections": { @@ -11843,8 +15079,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/rerun-collections": { @@ -11902,14 +15161,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ "Rerun Collections" ], "summary": "Create a rerun collection", + "operationId": "RerunCollectionCreate", "requestBody": { "content": { "application/json-patch+json": { @@ -11995,8 +15278,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/rerun-collections/{id}": { @@ -12057,14 +15363,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ "Rerun Collections" ], "summary": "Update a rerun collection", + "operationId": "RerunCollectionUpdate", "parameters": [ { "name": "id", @@ -12201,14 +15531,28 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ "Rerun Collections" ], "summary": "Delete a rerun collection", + "operationId": "RerunCollectionDelete", "parameters": [ { "name": "id", @@ -12263,15 +15607,39 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/ffmpeg/resolution/by-name/{name}": { "get": { "tags": [ - "Resolution" + "Settings" ], + "summary": "Get a resolution by name", "operationId": "GetResolutionByName", "parameters": [ { @@ -12289,22 +15657,65 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/ResolutionViewModel" + "$ref": "#/components/schemas/ResolutionResponseModel" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/ResolutionViewModel" + "$ref": "#/components/schemas/ResolutionResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/ResolutionViewModel" + "$ref": "#/components/schemas/ResolutionResponseModel" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" } } } } - } + }, + "security": [ + { } + ] } }, "/api/settings/resolutions": { @@ -12343,8 +15754,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ @@ -12437,8 +15861,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/settings/resolutions/{id}": { @@ -12522,8 +15959,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/schedules": { @@ -12532,6 +15982,7 @@ "Schedules" ], "summary": "Get all schedules", + "operationId": "ScheduleGetAll", "responses": { "200": { "description": "OK", @@ -12540,7 +15991,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/ProgramScheduleViewModel" + "$ref": "#/components/schemas/ProgramScheduleResponseModel" } } }, @@ -12548,7 +15999,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/ProgramScheduleViewModel" + "$ref": "#/components/schemas/ProgramScheduleResponseModel" } } }, @@ -12556,19 +16007,33 @@ "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/ProgramScheduleViewModel" + "$ref": "#/components/schemas/ProgramScheduleResponseModel" } } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ "Schedules" ], "summary": "Create a schedule", + "operationId": "ScheduleCreate", "requestBody": { "content": { "application/json-patch+json": { @@ -12600,17 +16065,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/ProgramScheduleViewModel" + "$ref": "#/components/schemas/ProgramScheduleResponseModel" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/ProgramScheduleViewModel" + "$ref": "#/components/schemas/ProgramScheduleResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/ProgramScheduleViewModel" + "$ref": "#/components/schemas/ProgramScheduleResponseModel" } } } @@ -12654,8 +16119,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/schedules/{id}": { @@ -12682,17 +16170,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/ProgramScheduleViewModel" + "$ref": "#/components/schemas/ProgramScheduleResponseModel" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/ProgramScheduleViewModel" + "$ref": "#/components/schemas/ProgramScheduleResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/ProgramScheduleViewModel" + "$ref": "#/components/schemas/ProgramScheduleResponseModel" } } } @@ -12716,14 +16204,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ "Schedules" ], "summary": "Update a schedule", + "operationId": "ScheduleUpdate", "parameters": [ { "name": "id", @@ -12766,17 +16278,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/ProgramScheduleViewModel" + "$ref": "#/components/schemas/ProgramScheduleResponseModel" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/ProgramScheduleViewModel" + "$ref": "#/components/schemas/ProgramScheduleResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/ProgramScheduleViewModel" + "$ref": "#/components/schemas/ProgramScheduleResponseModel" } } } @@ -12820,14 +16332,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ "Schedules" ], "summary": "Delete a schedule", + "operationId": "ScheduleDelete", "parameters": [ { "name": "id", @@ -12882,8 +16418,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/schedules/{id}/items": { @@ -12893,6 +16452,7 @@ ], "summary": "Get schedule items", "description": "Returns the schedule's items plus a computed, best-effort runtime estimate: each item carries a nullable durationEstimate and the envelope carries a nullable totalDurationEstimate. Estimates are derived from referenced collection/media runtimes and are null when unbounded or unknown. The response also carries a strong ETag of the schedule's version; pass that ETag back as If-Match on the replace (PUT) to detect a concurrent edit (issue #253).", + "operationId": "ScheduleGetItems", "parameters": [ { "name": "id", @@ -12944,14 +16504,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ "Schedules" ], "summary": "Add a schedule item", + "operationId": "ScheduleAddItem", "parameters": [ { "name": "id", @@ -13048,8 +16632,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -13057,6 +16664,7 @@ ], "summary": "Replace schedule items", "description": "Replaces the schedule's full item list; item indexes are assigned from the array order. Send the ETag from the items GET as If-Match to reject a stale overwrite with 412 (issue #253); a successful response carries the new ETag.", + "operationId": "ScheduleReplaceItems", "parameters": [ { "name": "id", @@ -13202,8 +16810,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/schedules/{id}/items/{itemId}": { @@ -13212,6 +16833,7 @@ "Schedules" ], "summary": "Delete a schedule item", + "operationId": "ScheduleDeleteItem", "parameters": [ { "name": "id", @@ -13275,8 +16897,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/search": { @@ -13295,6 +16940,15 @@ "default": "" } }, + { + "name": "pageNum", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, { "name": "pageSize", "in": "query", @@ -13345,8 +16999,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/search/all-items": { @@ -13407,8 +17084,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/search/collections": { @@ -13458,8 +17158,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/search/television-shows": { @@ -13509,8 +17232,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/search/television-seasons": { @@ -13560,8 +17306,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/search/smart-collections": { @@ -13611,8 +17380,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/search/artists": { @@ -13662,8 +17454,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/search/multi-collections": { @@ -13713,8 +17528,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/seasons/{id}": { @@ -13775,8 +17613,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/sessions": { @@ -13785,6 +17646,7 @@ "Sessions" ], "summary": "Get sessions", + "operationId": "SessionGetSessions", "responses": { "200": { "description": "OK", @@ -13814,8 +17676,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/session/{channelNumber}": { @@ -13824,6 +17699,7 @@ "Sessions" ], "summary": "Stop session", + "operationId": "SessionStopSession", "parameters": [ { "name": "channelNumber", @@ -13837,8 +17713,31 @@ "responses": { "200": { "description": "OK" + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/settings/ffmpeg": { @@ -13868,8 +17767,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -13962,8 +17874,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/settings/playout": { @@ -13993,8 +17918,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -14087,8 +18025,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/settings/xmltv": { @@ -14118,8 +18069,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -14212,8 +18176,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/settings/scanner": { @@ -14243,8 +18220,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -14337,8 +18327,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/settings/logging": { @@ -14368,8 +18371,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -14462,8 +18478,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/settings/ui": { @@ -14493,8 +18522,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -14587,8 +18629,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/settings/hdhr": { @@ -14618,8 +18673,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -14712,8 +18780,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/shows/{id}": { @@ -14774,8 +18855,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/smart-collections": { @@ -14784,6 +18888,7 @@ "Smart Collections" ], "summary": "Get all smart collections", + "operationId": "SmartCollectionGetAll", "responses": { "200": { "description": "OK", @@ -14813,14 +18918,28 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ "Smart Collections" ], "summary": "Create a smart collection", + "operationId": "SmartCollectionCreate", "requestBody": { "content": { "application/json-patch+json": { @@ -14852,17 +18971,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/SmartCollectionViewModel" + "$ref": "#/components/schemas/SmartCollectionResponseModel" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/SmartCollectionViewModel" + "$ref": "#/components/schemas/SmartCollectionResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/SmartCollectionViewModel" + "$ref": "#/components/schemas/SmartCollectionResponseModel" } } } @@ -14906,8 +19025,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/smart-collections/{id}": { @@ -14934,17 +19076,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/SmartCollectionViewModel" + "$ref": "#/components/schemas/SmartCollectionResponseModel" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/SmartCollectionViewModel" + "$ref": "#/components/schemas/SmartCollectionResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/SmartCollectionViewModel" + "$ref": "#/components/schemas/SmartCollectionResponseModel" } } } @@ -14968,14 +19110,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ "Smart Collections" ], "summary": "Update a smart collection", + "operationId": "SmartCollectionUpdate", "parameters": [ { "name": "id", @@ -15018,17 +19184,17 @@ "content": { "text/plain": { "schema": { - "$ref": "#/components/schemas/SmartCollectionViewModel" + "$ref": "#/components/schemas/SmartCollectionResponseModel" } }, "application/json": { "schema": { - "$ref": "#/components/schemas/SmartCollectionViewModel" + "$ref": "#/components/schemas/SmartCollectionResponseModel" } }, "text/json": { "schema": { - "$ref": "#/components/schemas/SmartCollectionViewModel" + "$ref": "#/components/schemas/SmartCollectionResponseModel" } } } @@ -15072,14 +19238,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ "Smart Collections" ], "summary": "Delete a smart collection", + "operationId": "SmartCollectionDelete", "parameters": [ { "name": "id", @@ -15134,8 +19324,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/templates/groups": { @@ -15174,14 +19387,28 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ "Templates" ], "summary": "Create a template group", + "operationId": "TemplateCreateGroup", "requestBody": { "content": { "application/json-patch+json": { @@ -15267,8 +19494,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/templates/groups/{id}": { @@ -15278,6 +19528,7 @@ ], "summary": "Delete a template group", "description": "Deletes the template group. The database cascade removes every template (and its items) in the group.", + "operationId": "TemplateDeleteGroup", "parameters": [ { "name": "id", @@ -15312,8 +19563,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/templates": { @@ -15323,6 +19597,7 @@ ], "summary": "Get all templates", "description": "Returns every template. Pass templateGroupId to filter to the templates in a single template group.", + "operationId": "TemplateGetAll", "parameters": [ { "name": "templateGroupId", @@ -15362,8 +19637,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ @@ -15371,6 +19669,7 @@ ], "summary": "Create a template", "description": "Creates an empty template in the given template group.", + "operationId": "TemplateCreate", "requestBody": { "content": { "application/json-patch+json": { @@ -15456,8 +19755,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/templates/{id}": { @@ -15518,14 +19840,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ "Templates" ], "summary": "Delete a template", + "operationId": "TemplateDelete", "parameters": [ { "name": "id", @@ -15560,8 +19906,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -15569,6 +19938,7 @@ ], "summary": "Replace a template and its items", "description": "Replaces the template's name and its full item list. Each item assigns a block to a start time of day; items must not overlap (an item's end time is its start time plus the assigned block's duration). Send the ETag from the items GET as If-Match to reject a stale overwrite with 412 (issue #253); a successful response carries the new ETag.", + "operationId": "TemplateReplace", "parameters": [ { "name": "id", @@ -15705,8 +20075,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/templates/{id}/items": { @@ -15716,6 +20099,7 @@ ], "summary": "Get template items", "description": "Returns the template's items and a strong ETag of the template's version. Pass that ETag back as If-Match on the replace (PUT) to detect a concurrent edit (issue #253).", + "operationId": "TemplateGetItems", "parameters": [ { "name": "id", @@ -15776,8 +20160,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/templates/{id}/copy": { @@ -15787,6 +20194,7 @@ ], "summary": "Copy a template", "description": "Copies the template and its items into another (or the same) template group under a new name.", + "operationId": "TemplateCopy", "parameters": [ { "name": "id", @@ -15883,8 +20291,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/trakt/lists": { @@ -15934,8 +20365,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ @@ -15943,6 +20397,7 @@ ], "summary": "Add a Trakt list by URL", "description": "Dispatches to the same background worker channel used by the classic UI's \"Add Trakt List\" dialog; the list is fetched, saved, and matched asynchronously. Poll GET /api/trakt/status while busy.", + "operationId": "TraktAdd", "requestBody": { "content": { "application/json-patch+json": { @@ -16011,8 +20466,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/trakt/lists/{id}": { @@ -16073,14 +20551,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ "Trakt" ], "summary": "Delete a Trakt list", + "operationId": "TraktDelete", "parameters": [ { "name": "id", @@ -16135,14 +20637,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ "Trakt" ], "summary": "Update a Trakt list's settings", + "operationId": "TraktUpdate", "parameters": [ { "name": "id", @@ -16239,8 +20765,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/trakt/lists/{id}/match": { @@ -16249,6 +20798,7 @@ "Trakt" ], "summary": "Match a Trakt list's items", + "operationId": "TraktMatch", "parameters": [ { "name": "id", @@ -16303,8 +20853,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/trakt/status": { @@ -16335,8 +20908,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/troubleshoot/info": { @@ -16366,8 +20952,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/troubleshoot/validate-schedule": { @@ -16443,8 +21042,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/troubleshoot/playback.m3u8": { @@ -16453,6 +21065,7 @@ "Troubleshooting" ], "summary": "Start a troubleshooting playback session", + "operationId": "TroubleshootTroubleshootPlayback", "parameters": [ { "name": "mediaItem", @@ -16599,14 +21212,38 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "get": { "tags": [ "Troubleshooting" ], "summary": "Start a troubleshooting playback session", + "operationId": "TroubleshootTroubleshootPlaybackGET", "parameters": [ { "name": "mediaItem", @@ -16753,8 +21390,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/troubleshoot/playback/archive": { @@ -16763,22 +21423,50 @@ "Troubleshooting" ], "summary": "Download the last troubleshooting playback session archive", + "operationId": "TroubleshootTroubleshootPlaybackArchive", "responses": { "200": { "description": "OK" + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "get": { "tags": [ "Troubleshooting" ], "summary": "Download the last troubleshooting playback session archive", + "operationId": "TroubleshootTroubleshootPlaybackArchiveGET", "responses": { "200": { "description": "OK" + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/troubleshoot/playback/sample/{mediaItemId}": { @@ -16787,6 +21475,7 @@ "Troubleshooting" ], "summary": "Download a media sample archive for troubleshooting", + "operationId": "TroubleshootTroubleshootPlaybackSample", "parameters": [ { "name": "mediaItemId", @@ -16801,14 +21490,38 @@ "responses": { "200": { "description": "OK" + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "get": { "tags": [ "Troubleshooting" ], "summary": "Download a media sample archive for troubleshooting", + "operationId": "TroubleshootTroubleshootPlaybackSampleGET", "parameters": [ { "name": "mediaItemId", @@ -16823,8 +21536,31 @@ "responses": { "200": { "description": "OK" + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/troubleshoot/playback/stream-selectors": { @@ -16863,8 +21599,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/troubleshoot/playback/subtitles/{mediaItemId}": { @@ -16935,8 +21684,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/troubleshoot/playback/status": { @@ -16967,8 +21739,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/version": { @@ -16998,8 +21783,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/watermarks": { @@ -17038,8 +21836,21 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "post": { "tags": [ @@ -17152,8 +21963,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } }, "/api/watermarks/{id}": { @@ -17214,8 +22038,31 @@ } } } + }, + "401": { + "description": "API key missing or invalid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "put": { "tags": [ @@ -17339,8 +22186,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] }, "delete": { "tags": [ @@ -17422,8 +22282,21 @@ } } } + }, + "400": { + "description": "Request validation failed (model binding or FluentValidation).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } } - } + }, + "security": [ + { } + ] } } }, @@ -18213,6 +23086,152 @@ } } }, + "ChannelDetailResponseModel": { + "required": [ + "id", + "number", + "name", + "group", + "categories", + "ffmpegProfileId", + "slugSeconds", + "logo", + "streamSelectorMode", + "streamSelector", + "preferredAudioLanguageCode", + "preferredAudioTitle", + "playoutSource", + "playoutMode", + "mirrorSourceChannelId", + "playoutOffset", + "streamingMode", + "watermarkId", + "fallbackFillerId", + "playoutCount", + "preferredSubtitleLanguageCode", + "subtitleMode", + "musicVideoCreditsMode", + "musicVideoCreditsTemplate", + "songVideoMode", + "transcodeMode", + "idleBehavior", + "isEnabled", + "showInEpg" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "number": { + "type": "string" + }, + "name": { + "type": "string" + }, + "group": { + "type": "string" + }, + "categories": { + "type": "string" + }, + "ffmpegProfileId": { + "type": "integer", + "format": "int32" + }, + "slugSeconds": { + "type": [ + "null", + "number" + ], + "format": "double" + }, + "logo": { + "$ref": "#/components/schemas/ChannelLogoResponseModel" + }, + "streamSelectorMode": { + "$ref": "#/components/schemas/ChannelStreamSelectorMode" + }, + "streamSelector": { + "type": "string" + }, + "preferredAudioLanguageCode": { + "type": "string" + }, + "preferredAudioTitle": { + "type": "string" + }, + "playoutSource": { + "$ref": "#/components/schemas/ChannelPlayoutSource" + }, + "playoutMode": { + "$ref": "#/components/schemas/ChannelPlayoutMode" + }, + "mirrorSourceChannelId": { + "type": [ + "null", + "integer" + ], + "format": "int32" + }, + "playoutOffset": { + "pattern": "^-?(\\d+\\.)?\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,7})?$", + "type": [ + "null", + "string" + ] + }, + "streamingMode": { + "$ref": "#/components/schemas/StreamingMode" + }, + "watermarkId": { + "type": [ + "null", + "integer" + ], + "format": "int32" + }, + "fallbackFillerId": { + "type": [ + "null", + "integer" + ], + "format": "int32" + }, + "playoutCount": { + "type": "integer", + "format": "int32" + }, + "preferredSubtitleLanguageCode": { + "type": "string" + }, + "subtitleMode": { + "$ref": "#/components/schemas/ChannelSubtitleMode" + }, + "musicVideoCreditsMode": { + "$ref": "#/components/schemas/ChannelMusicVideoCreditsMode" + }, + "musicVideoCreditsTemplate": { + "type": "string" + }, + "songVideoMode": { + "$ref": "#/components/schemas/ChannelSongVideoMode" + }, + "transcodeMode": { + "$ref": "#/components/schemas/ChannelTranscodeMode" + }, + "idleBehavior": { + "$ref": "#/components/schemas/ChannelIdleBehavior" + }, + "isEnabled": { + "type": "boolean" + }, + "showInEpg": { + "type": "boolean" + } + } + }, "ChannelGuideChannelResponseModel": { "required": [ "number", @@ -18305,6 +23324,33 @@ ], "type": "string" }, + "ChannelLogoResponseModel": { + "required": [ + "path", + "contentType" + ], + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "contentType": { + "type": "string" + }, + "isExternalUrl": { + "type": "boolean" + }, + "hasContentType": { + "type": "boolean" + }, + "urlWithContentType": { + "type": [ + "null", + "string" + ] + } + } + }, "ChannelMusicVideoCreditsMode": { "enum": [ "None", @@ -18617,185 +23663,6 @@ ], "type": "string" }, - "ChannelViewModel": { - "required": [ - "id", - "number", - "name", - "group", - "categories", - "ffmpegProfileId", - "slugSeconds", - "logo", - "streamSelectorMode", - "streamSelector", - "preferredAudioLanguageCode", - "preferredAudioTitle", - "playoutSource", - "playoutMode", - "mirrorSourceChannelId", - "playoutOffset", - "streamingMode", - "watermarkId", - "fallbackFillerId", - "playoutCount", - "preferredSubtitleLanguageCode", - "subtitleMode", - "musicVideoCreditsMode", - "musicVideoCreditsTemplate", - "songVideoMode", - "transcodeMode", - "idleBehavior", - "isEnabled", - "showInEpg" - ], - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "number": { - "type": [ - "null", - "string" - ] - }, - "name": { - "type": [ - "null", - "string" - ] - }, - "group": { - "type": [ - "null", - "string" - ] - }, - "categories": { - "type": [ - "null", - "string" - ] - }, - "ffmpegProfileId": { - "type": "integer", - "format": "int32" - }, - "slugSeconds": { - "type": [ - "null", - "number" - ], - "format": "double" - }, - "logo": { - "$ref": "#/components/schemas/ArtworkContentTypeModel" - }, - "streamSelectorMode": { - "$ref": "#/components/schemas/ChannelStreamSelectorMode" - }, - "streamSelector": { - "type": [ - "null", - "string" - ] - }, - "preferredAudioLanguageCode": { - "type": [ - "null", - "string" - ] - }, - "preferredAudioTitle": { - "type": [ - "null", - "string" - ] - }, - "playoutSource": { - "$ref": "#/components/schemas/ChannelPlayoutSource" - }, - "playoutMode": { - "$ref": "#/components/schemas/ChannelPlayoutMode" - }, - "mirrorSourceChannelId": { - "type": [ - "null", - "integer" - ], - "format": "int32" - }, - "playoutOffset": { - "pattern": "^-?(\\d+\\.)?\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,7})?$", - "type": [ - "null", - "string" - ] - }, - "streamingMode": { - "$ref": "#/components/schemas/StreamingMode" - }, - "watermarkId": { - "type": [ - "null", - "integer" - ], - "format": "int32" - }, - "fallbackFillerId": { - "type": [ - "null", - "integer" - ], - "format": "int32" - }, - "playoutCount": { - "type": "integer", - "format": "int32" - }, - "preferredSubtitleLanguageCode": { - "type": [ - "null", - "string" - ] - }, - "subtitleMode": { - "$ref": "#/components/schemas/ChannelSubtitleMode" - }, - "musicVideoCreditsMode": { - "$ref": "#/components/schemas/ChannelMusicVideoCreditsMode" - }, - "musicVideoCreditsTemplate": { - "type": [ - "null", - "string" - ] - }, - "songVideoMode": { - "$ref": "#/components/schemas/ChannelSongVideoMode" - }, - "transcodeMode": { - "$ref": "#/components/schemas/ChannelTranscodeMode" - }, - "idleBehavior": { - "$ref": "#/components/schemas/ChannelIdleBehavior" - }, - "isEnabled": { - "type": "boolean" - }, - "showInEpg": { - "type": "boolean" - }, - "webEncodedName": { - "type": [ - "null", - "string" - ] - } - } - }, "ChannelWatermarkImageSource": { "enum": [ "Custom", @@ -20263,7 +25130,16 @@ } }, "DayOfWeek": { - "type": "integer" + "enum": [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday" + ], + "type": "string" }, "DecoBreakContentRequest": { "required": [ @@ -21187,10 +26063,7 @@ "format": "int32" }, "name": { - "type": [ - "null", - "string" - ] + "type": "string" }, "fillerKind": { "$ref": "#/components/schemas/FillerKind" @@ -21231,10 +26104,7 @@ "format": "int32" }, "name": { - "type": [ - "null", - "string" - ] + "type": "string" } } }, @@ -21382,16 +26252,10 @@ "type": "object", "properties": { "code": { - "type": [ - "null", - "string" - ] + "type": "string" }, "englishName": { - "type": [ - "null", - "string" - ] + "type": "string" } } }, @@ -21587,10 +26451,7 @@ "format": "int32" }, "name": { - "type": [ - "null", - "string" - ] + "type": "string" }, "mediaKind": { "$ref": "#/components/schemas/LibraryMediaKind" @@ -21603,10 +26464,7 @@ "format": "int32" }, "paths": { - "type": [ - "null", - "array" - ], + "type": "array", "items": { "$ref": "#/components/schemas/LocalLibraryPathResponseModel" } @@ -21626,10 +26484,7 @@ "format": "int32" }, "path": { - "type": [ - "null", - "string" - ] + "type": "string" }, "mediaItemCount": { "type": "integer", @@ -21651,10 +26506,7 @@ "format": "int32" }, "name": { - "type": [ - "null", - "string" - ] + "type": "string" }, "mediaKind": { "$ref": "#/components/schemas/LibraryMediaKind" @@ -21762,70 +26614,27 @@ ], "type": "string" }, - "MediaCollectionViewModel": { + "MediaCollectionResponseModel": { "required": [ - "collectionType", "id", "name", - "useCustomPlaybackOrder", - "state" + "collectionType", + "useCustomPlaybackOrder" ], "type": "object", "properties": { - "collectionType": { - "$ref": "#/components/schemas/CollectionType" - }, "id": { "type": "integer", "format": "int32" }, "name": { - "type": [ - "null", - "string" - ] + "type": "string" + }, + "collectionType": { + "$ref": "#/components/schemas/CollectionType" }, "useCustomPlaybackOrder": { "type": "boolean" - }, - "version": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "mediaItemId": { - "type": "integer", - "format": "int32" - }, - "title": { - "type": [ - "null", - "string" - ] - }, - "subtitle": { - "type": [ - "null", - "string" - ] - }, - "sortTitle": { - "type": [ - "null", - "string" - ] - }, - "poster": { - "type": [ - "null", - "string" - ] - }, - "state": { - "$ref": "#/components/schemas/MediaItemState" - }, - "hasMediaInfo": { - "type": "boolean" } } }, @@ -22423,10 +27232,7 @@ "format": "int32" }, "name": { - "type": [ - "null", - "string" - ] + "type": "string" } } }, @@ -22537,10 +27343,7 @@ "format": "int32" }, "page": { - "type": [ - "null", - "array" - ], + "type": "array", "items": { "$ref": "#/components/schemas/PlayoutItemResponseModel" } @@ -22559,10 +27362,7 @@ "format": "int32" }, "page": { - "type": [ - "null", - "array" - ], + "type": "array", "items": { "$ref": "#/components/schemas/PlayoutListItemResponseModel" } @@ -22646,16 +27446,10 @@ "format": "int32" }, "remotePath": { - "type": [ - "null", - "string" - ] + "type": "string" }, "localPath": { - "type": [ - "null", - "string" - ] + "type": "string" } } }, @@ -23113,10 +27907,7 @@ "type": "boolean" }, "message": { - "type": [ - "null", - "string" - ] + "type": "string" } } }, @@ -23628,10 +28419,7 @@ "type": "object", "properties": { "authUrl": { - "type": [ - "null", - "string" - ] + "type": "string" } } }, @@ -23671,7 +28459,7 @@ } } }, - "ProgramScheduleViewModel": { + "ProgramScheduleResponseModel": { "required": [ "id", "name", @@ -23679,8 +28467,7 @@ "treatCollectionsAsShows", "shuffleScheduleItems", "randomStartPoint", - "fixedStartTimeBehavior", - "version" + "fixedStartTimeBehavior" ], "type": "object", "properties": { @@ -23689,10 +28476,7 @@ "format": "int32" }, "name": { - "type": [ - "null", - "string" - ] + "type": "string" }, "keepMultiPartEpisodesTogether": { "type": "boolean" @@ -23708,10 +28492,6 @@ }, "fixedStartTimeBehavior": { "$ref": "#/components/schemas/FixedStartTimeBehavior" - }, - "version": { - "type": "integer", - "format": "int32" } } }, @@ -23723,10 +28503,7 @@ "type": "object", "properties": { "address": { - "type": [ - "null", - "string" - ] + "type": "string" }, "hasApiKey": { "type": "boolean" @@ -23763,10 +28540,7 @@ "format": "int32" }, "name": { - "type": [ - "null", - "string" - ] + "type": "string" }, "mediaKind": { "$ref": "#/components/schemas/LibraryMediaKind" @@ -23789,16 +28563,10 @@ "format": "int32" }, "name": { - "type": [ - "null", - "string" - ] + "type": "string" }, "address": { - "type": [ - "null", - "string" - ] + "type": "string" } } }, @@ -23817,10 +28585,7 @@ "type": "boolean" }, "servers": { - "type": [ - "null", - "array" - ], + "type": "array", "items": { "$ref": "#/components/schemas/RemoteMediaSourceItemResponseModel" } @@ -24271,39 +29036,6 @@ } } }, - "ResolutionViewModel": { - "required": [ - "id", - "name", - "width", - "height", - "isCustom" - ], - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": [ - "null", - "string" - ] - }, - "width": { - "type": "integer", - "format": "int32" - }, - "height": { - "type": "integer", - "format": "int32" - }, - "isCustom": { - "type": "boolean" - } - } - }, "SaveRemoteConnectionRequest": { "required": [ "address", @@ -25083,100 +29815,70 @@ "type": "object", "properties": { "movieIds": { - "type": [ - "null", - "array" - ], + "type": "array", "items": { "type": "integer", "format": "int32" } }, "showIds": { - "type": [ - "null", - "array" - ], + "type": "array", "items": { "type": "integer", "format": "int32" } }, "seasonIds": { - "type": [ - "null", - "array" - ], + "type": "array", "items": { "type": "integer", "format": "int32" } }, "episodeIds": { - "type": [ - "null", - "array" - ], + "type": "array", "items": { "type": "integer", "format": "int32" } }, "artistIds": { - "type": [ - "null", - "array" - ], + "type": "array", "items": { "type": "integer", "format": "int32" } }, "musicVideoIds": { - "type": [ - "null", - "array" - ], + "type": "array", "items": { "type": "integer", "format": "int32" } }, "otherVideoIds": { - "type": [ - "null", - "array" - ], + "type": "array", "items": { "type": "integer", "format": "int32" } }, "songIds": { - "type": [ - "null", - "array" - ], + "type": "array", "items": { "type": "integer", "format": "int32" } }, "imageIds": { - "type": [ - "null", - "array" - ], + "type": "array", "items": { "type": "integer", "format": "int32" } }, "remoteStreamIds": { - "type": [ - "null", - "array" - ], + "type": "array", "items": { "type": "integer", "format": "int32" @@ -25399,42 +30101,10 @@ "format": "int32" }, "name": { - "type": [ - "null", - "string" - ] + "type": "string" }, "query": { - "type": [ - "null", - "string" - ] - } - } - }, - "SmartCollectionViewModel": { - "required": [ - "id", - "name", - "query" - ], - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": [ - "null", - "string" - ] - }, - "query": { - "type": [ - "null", - "string" - ] + "type": "string" } } }, @@ -26955,6 +31625,51 @@ } } }, + "ValidationProblemDetails": { + "type": "object", + "properties": { + "type": { + "type": [ + "null", + "string" + ] + }, + "title": { + "type": [ + "null", + "string" + ] + }, + "status": { + "type": [ + "null", + "integer" + ], + "format": "int32" + }, + "detail": { + "type": [ + "null", + "string" + ] + }, + "instance": { + "type": [ + "null", + "string" + ] + }, + "errors": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, "VideoScanKind": { "enum": [ "Unknown", @@ -27081,10 +31796,7 @@ "format": "int32" }, "name": { - "type": [ - "null", - "string" - ] + "type": "string" } } }, @@ -27129,6 +31841,14 @@ ], "type": "string" } + }, + "securitySchemes": { + "ApiKey": { + "type": "apiKey", + "description": "API key sent in the 'X-Api-Key' request header. Required for all mutating requests and, under the default posture (Api:RequireKeyForReads=true), for reads as well.", + "name": "X-Api-Key", + "in": "header" + } } }, "tags": [ @@ -27216,9 +31936,6 @@ { "name": "Rerun Collections" }, - { - "name": "Resolution" - }, { "name": "Settings" }, diff --git a/docs/endpoint-index.md b/docs/endpoint-index.md index dd7a82884..385e6d786 100644 --- a/docs/endpoint-index.md +++ b/docs/endpoint-index.md @@ -20,23 +20,23 @@ | Method | Path | Operation | Summary | |---|---|---|---| -| GET | `/api/blocks` | | Get all blocks | -| POST | `/api/blocks` | | Create a block | +| GET | `/api/blocks` | BlockGetAll | Get all blocks | +| POST | `/api/blocks` | BlockCreate | Create a block | | GET | `/api/blocks/groups` | GetBlockGroups | Get all block groups | -| POST | `/api/blocks/groups` | | Create a block group | -| DELETE | `/api/blocks/groups/{id}` | | Delete a block group | -| DELETE | `/api/blocks/{id}` | | Delete a block | +| POST | `/api/blocks/groups` | BlockCreateGroup | Create a block group | +| DELETE | `/api/blocks/groups/{id}` | BlockDeleteGroup | Delete a block group | +| DELETE | `/api/blocks/{id}` | BlockDelete | Delete a block | | GET | `/api/blocks/{id}` | GetBlockById | Get a block by id | -| PUT | `/api/blocks/{id}` | | Replace a block and its items | -| POST | `/api/blocks/{id}/copy` | | Copy a block | -| GET | `/api/blocks/{id}/items` | | Get block items | -| POST | `/api/blocks/{id}/preview` | | Preview a block playout | +| PUT | `/api/blocks/{id}` | BlockReplace | Replace a block and its items | +| POST | `/api/blocks/{id}/copy` | BlockCopy | Copy a block | +| GET | `/api/blocks/{id}/items` | BlockGetItems | Get block items | +| POST | `/api/blocks/{id}/preview` | BlockPreview | Preview a block playout | ## Channel | Method | Path | Operation | Summary | |---|---|---|---| -| GET | `/api/channels` | | | +| GET | `/api/channels` | ChannelGetAll | | ## Channel Templates @@ -54,60 +54,60 @@ | Method | Path | Operation | Summary | |---|---|---|---| -| POST | `/api/channels` | | Create a channel | -| POST | `/api/channels/bulk/delete` | | Delete channels | -| POST | `/api/channels/bulk/group` | | Move channels to a group | -| POST | `/api/channels/bulk/renumber` | | Renumber channels | +| POST | `/api/channels` | ChannelCreate | Create a channel | +| POST | `/api/channels/bulk/delete` | ChannelBulkDelete | Delete channels | +| POST | `/api/channels/bulk/group` | ChannelBulkMoveToGroup | Move channels to a group | +| POST | `/api/channels/bulk/renumber` | ChannelBulkRenumber | Renumber channels | | POST | `/api/channels/from-lineup` | CreateChannelFromLineup | Create a channel from a library lineup | | GET | `/api/channels/music-video-credits-templates` | GetMusicVideoCreditsTemplates | Get available music video credits template names | -| GET | `/api/channels/state` | | Get channel runtime state | +| GET | `/api/channels/state` | ChannelGetState | Get channel runtime state | | GET | `/api/channels/stream-selectors` | GetChannelStreamSelectors | Get available channel stream selector names | -| POST | `/api/channels/{channelNumber}/playout/reset` | | Reset channel playout | -| DELETE | `/api/channels/{id}` | | Delete a channel | +| DELETE | `/api/channels/{id}` | ChannelDelete | Delete a channel | | GET | `/api/channels/{id}` | GetChannelById | Get a channel by id | -| PUT | `/api/channels/{id}` | | Update a channel | -| GET | `/api/guide` | | Get the JSON channel guide (EPG) | +| PUT | `/api/channels/{id}` | ChannelUpdate | Update a channel | +| POST | `/api/channels/{id}/playout/reset` | ChannelResetPlayout | Reset channel playout | +| GET | `/api/guide` | ChannelGetGuide | Get the JSON channel guide (EPG) | ## Collections | Method | Path | Operation | Summary | |---|---|---|---| -| GET | `/api/collections` | | Get all collections | -| POST | `/api/collections` | | Create a collection | -| DELETE | `/api/collections/{id}` | | Delete a collection | +| GET | `/api/collections` | CollectionGetAll | Get all collections | +| POST | `/api/collections` | CollectionCreate | Create a collection | +| DELETE | `/api/collections/{id}` | CollectionDelete | Delete a collection | | GET | `/api/collections/{id}` | GetCollectionById | Get a collection by id | -| PUT | `/api/collections/{id}` | | Update a collection | -| PUT | `/api/collections/{id}/custom-order` | | Set a collection's custom playback order | +| PUT | `/api/collections/{id}` | CollectionUpdate | Update a collection | +| PUT | `/api/collections/{id}/custom-order` | CollectionUpdateCustomOrder | Set a collection's custom playback order | | GET | `/api/collections/{id}/items` | GetCollectionItems | Get the items in a manual collection | -| POST | `/api/collections/{id}/items` | | Add items to a collection | -| DELETE | `/api/collections/{id}/items/{mediaItemId}` | | Remove an item from a collection | +| POST | `/api/collections/{id}/items` | CollectionAddItems | Add items to a collection | +| DELETE | `/api/collections/{id}/items/{mediaItemId}` | CollectionRemoveItem | Remove an item from a collection | ## DecoTemplates | Method | Path | Operation | Summary | |---|---|---|---| -| GET | `/api/deco-templates` | | Get all deco templates | -| POST | `/api/deco-templates` | | Create a deco template | +| GET | `/api/deco-templates` | DecoTemplateGetAll | Get all deco templates | +| POST | `/api/deco-templates` | DecoTemplateCreate | Create a deco template | | GET | `/api/deco-templates/groups` | GetDecoTemplateGroups | Get all deco template groups | -| POST | `/api/deco-templates/groups` | | Create a deco template group | -| DELETE | `/api/deco-templates/groups/{id}` | | Delete a deco template group | -| DELETE | `/api/deco-templates/{id}` | | Delete a deco template | +| POST | `/api/deco-templates/groups` | DecoTemplateCreateGroup | Create a deco template group | +| DELETE | `/api/deco-templates/groups/{id}` | DecoTemplateDeleteGroup | Delete a deco template group | +| DELETE | `/api/deco-templates/{id}` | DecoTemplateDelete | Delete a deco template | | GET | `/api/deco-templates/{id}` | GetDecoTemplateById | Get a deco template by id | -| PUT | `/api/deco-templates/{id}` | | Replace a deco template and its items | -| GET | `/api/deco-templates/{id}/items` | | Get deco template items | +| PUT | `/api/deco-templates/{id}` | DecoTemplateReplace | Replace a deco template and its items | +| GET | `/api/deco-templates/{id}/items` | DecoTemplateGetItems | Get deco template items | ## Decos | Method | Path | Operation | Summary | |---|---|---|---| -| GET | `/api/decos` | | Get all decos | -| POST | `/api/decos` | | Create a deco | +| GET | `/api/decos` | DecoGetAll | Get all decos | +| POST | `/api/decos` | DecoCreate | Create a deco | | GET | `/api/decos/groups` | GetDecoGroups | Get all deco groups | -| POST | `/api/decos/groups` | | Create a deco group | -| DELETE | `/api/decos/groups/{id}` | | Delete a deco group | -| DELETE | `/api/decos/{id}` | | Delete a deco | +| POST | `/api/decos/groups` | DecoCreateGroup | Create a deco group | +| DELETE | `/api/decos/groups/{id}` | DecoDeleteGroup | Delete a deco group | +| DELETE | `/api/decos/{id}` | DecoDelete | Delete a deco | | GET | `/api/decos/{id}` | GetDecoById | Get a deco by id | -| PUT | `/api/decos/{id}` | | Replace a deco | +| PUT | `/api/decos/{id}` | DecoReplace | Replace a deco | ## Emby @@ -190,15 +190,15 @@ | Method | Path | Operation | Summary | |---|---|---|---| | GET | `/api/libraries/local` | GetLocalLibraries | Get all local libraries | -| POST | `/api/libraries/local` | | Create a local library | -| POST | `/api/libraries/local/path-exists` | | Check whether a filesystem path exists | -| POST | `/api/libraries/local/paths/{pathId}/move` | | Move a local library path to another local library | -| DELETE | `/api/libraries/local/{id}` | | Delete a local library | +| POST | `/api/libraries/local` | LocalLibrariesCreate | Create a local library | +| POST | `/api/libraries/local/path-exists` | LocalLibrariesCheckPathExists | Check whether a filesystem path exists | +| POST | `/api/libraries/local/paths/{pathId}/move` | LocalLibrariesMovePath | Move a local library path to another local library | +| DELETE | `/api/libraries/local/{id}` | LocalLibrariesDelete | Delete a local library | | GET | `/api/libraries/local/{id}` | GetLocalLibrary | Get a local library by id | -| PUT | `/api/libraries/local/{id}` | | Update a local library | +| PUT | `/api/libraries/local/{id}` | LocalLibrariesUpdate | Update a local library | | GET | `/api/libraries/scan-status` | GetLibraryScanStatus | Get active library scan status | -| POST | `/api/libraries/{id}/scan` | | Scan library | -| POST | `/api/libraries/{id}/scan-show` | | Scan show | +| POST | `/api/libraries/{id}/scan` | LibrariesScanLibrary | Scan library | +| POST | `/api/libraries/{id}/scan-show` | LibrariesScanShow | Scan show | | GET | `/api/library/browse` | BrowseLibrary | Browse and search library items | ## Logs @@ -211,9 +211,9 @@ | Method | Path | Operation | Summary | |---|---|---|---| -| POST | `/api/maintenance/clean_artwork` | | Clean artwork cache | -| POST | `/api/maintenance/empty_trash` | | Empty trash | -| POST | `/api/maintenance/gc` | | Garbage collect | +| POST | `/api/maintenance/clean_artwork` | MaintenanceCleanArtwork | Clean artwork cache | +| POST | `/api/maintenance/empty_trash` | MaintenanceEmptyTrash | Empty trash | +| POST | `/api/maintenance/gc` | MaintenanceGarbageCollection | Garbage collect | ## Media Items @@ -239,10 +239,10 @@ | Method | Path | Operation | Summary | |---|---|---|---| | GET | `/api/multi-collections` | GetMultiCollections | Get all multi collections (paged) | -| POST | `/api/multi-collections` | | Create a multi collection | -| DELETE | `/api/multi-collections/{id}` | | Delete a multi collection | +| POST | `/api/multi-collections` | MultiCollectionCreate | Create a multi collection | +| DELETE | `/api/multi-collections/{id}` | MultiCollectionDelete | Delete a multi collection | | GET | `/api/multi-collections/{id}` | GetMultiCollectionById | Get a multi collection by id | -| PUT | `/api/multi-collections/{id}` | | Update a multi collection | +| PUT | `/api/multi-collections/{id}` | MultiCollectionUpdate | Update a multi collection | ## Playlists @@ -266,24 +266,24 @@ | Method | Path | Operation | Summary | |---|---|---|---| | GET | `/api/playouts` | GetPlayouts | List playouts | -| POST | `/api/playouts` | | Create a playout | +| POST | `/api/playouts` | PlayoutCreate | Create a playout | | GET | `/api/playouts/history/{id}` | GetPlayoutHistoryDetails | Decode a playout history row | | GET | `/api/playouts/items/{id}/scheduling-context` | GetPlayoutItemSchedulingContext | Decode a playout item's scheduling context | | POST | `/api/playouts/reset-all` | ResetAllPlayouts | Reset all playouts | | GET | `/api/playouts/warnings/count` | GetPlayoutWarningsCount | Count playouts with a failed build | -| DELETE | `/api/playouts/{id}` | | Delete a playout | +| DELETE | `/api/playouts/{id}` | PlayoutDelete | Delete a playout | | GET | `/api/playouts/{id}` | GetPlayoutById | Get a playout by id | -| PUT | `/api/playouts/{id}` | | Update playout scheduling details | +| PUT | `/api/playouts/{id}` | PlayoutUpdate | Update playout scheduling details | | GET | `/api/playouts/{id}/alternate-schedules` | GetPlayoutAlternateSchedules | Get a classic playout's alternate schedules | -| PUT | `/api/playouts/{id}/alternate-schedules` | | Replace a classic playout's alternate schedules | +| PUT | `/api/playouts/{id}/alternate-schedules` | PlayoutReplaceAlternateSchedules | Replace a classic playout's alternate schedules | | GET | `/api/playouts/{id}/blocks` | GetPlayoutBlocks | Get the blocks scheduled by a block playout | | GET | `/api/playouts/{id}/blocks/{blockId}/history` | GetPlayoutBlockHistory | Get a block's playout history | -| PUT | `/api/playouts/{id}/deco` | | Set (or clear) a playout's default deco | +| PUT | `/api/playouts/{id}/deco` | PlayoutUpdateDefaultDeco | Set (or clear) a playout's default deco | | POST | `/api/playouts/{id}/erase-items` | ErasePlayoutItems | Erase a playout's items | | POST | `/api/playouts/{id}/erase-items-and-history` | ErasePlayoutItemsAndHistory | Erase a playout's items and history | | GET | `/api/playouts/{id}/items` | GetPlayoutItems | Get upcoming items (and unscheduled gaps) for a playout | | GET | `/api/playouts/{id}/templates` | GetPlayoutTemplates | Get a block playout's templates | -| PUT | `/api/playouts/{id}/templates` | | Replace a block playout's templates | +| PUT | `/api/playouts/{id}/templates` | PlayoutReplaceTemplates | Replace a block playout's templates | ## Plex @@ -304,30 +304,24 @@ | Method | Path | Operation | Summary | |---|---|---|---| | GET | `/api/rerun-collections` | GetRerunCollections | Get all rerun collections (paged) | -| POST | `/api/rerun-collections` | | Create a rerun collection | -| DELETE | `/api/rerun-collections/{id}` | | Delete a rerun collection | +| POST | `/api/rerun-collections` | RerunCollectionCreate | Create a rerun collection | +| DELETE | `/api/rerun-collections/{id}` | RerunCollectionDelete | Delete a rerun collection | | GET | `/api/rerun-collections/{id}` | GetRerunCollectionById | Get a rerun collection by id | -| PUT | `/api/rerun-collections/{id}` | | Update a rerun collection | - -## Resolution - -| Method | Path | Operation | Summary | -|---|---|---|---| -| GET | `/api/ffmpeg/resolution/by-name/{name}` | GetResolutionByName | | +| PUT | `/api/rerun-collections/{id}` | RerunCollectionUpdate | Update a rerun collection | ## Schedules | Method | Path | Operation | Summary | |---|---|---|---| -| GET | `/api/schedules` | | Get all schedules | -| POST | `/api/schedules` | | Create a schedule | -| DELETE | `/api/schedules/{id}` | | Delete a schedule | +| GET | `/api/schedules` | ScheduleGetAll | Get all schedules | +| POST | `/api/schedules` | ScheduleCreate | Create a schedule | +| DELETE | `/api/schedules/{id}` | ScheduleDelete | Delete a schedule | | GET | `/api/schedules/{id}` | GetScheduleById | Get a schedule by id | -| PUT | `/api/schedules/{id}` | | Update a schedule | -| GET | `/api/schedules/{id}/items` | | Get schedule items | -| POST | `/api/schedules/{id}/items` | | Add a schedule item | -| PUT | `/api/schedules/{id}/items` | | Replace schedule items | -| DELETE | `/api/schedules/{id}/items/{itemId}` | | Delete a schedule item | +| PUT | `/api/schedules/{id}` | ScheduleUpdate | Update a schedule | +| GET | `/api/schedules/{id}/items` | ScheduleGetItems | Get schedule items | +| POST | `/api/schedules/{id}/items` | ScheduleAddItem | Add a schedule item | +| PUT | `/api/schedules/{id}/items` | ScheduleReplaceItems | Replace schedule items | +| DELETE | `/api/schedules/{id}/items/{itemId}` | ScheduleDeleteItem | Delete a schedule item | ## Search @@ -346,13 +340,14 @@ | Method | Path | Operation | Summary | |---|---|---|---| -| DELETE | `/api/session/{channelNumber}` | | Stop session | -| GET | `/api/sessions` | | Get sessions | +| DELETE | `/api/session/{channelNumber}` | SessionStopSession | Stop session | +| GET | `/api/sessions` | SessionGetSessions | Get sessions | ## Settings | Method | Path | Operation | Summary | |---|---|---|---| +| GET | `/api/ffmpeg/resolution/by-name/{name}` | GetResolutionByName | Get a resolution by name | | GET | `/api/settings/ffmpeg` | GetFfmpegSettings | Get global FFmpeg settings | | PUT | `/api/settings/ffmpeg` | UpdateFfmpegSettings | Update global FFmpeg settings | | GET | `/api/settings/hdhr` | GetHdhrSettings | Get HDHomeRun emulation settings | @@ -375,11 +370,11 @@ | Method | Path | Operation | Summary | |---|---|---|---| -| GET | `/api/smart-collections` | | Get all smart collections | -| POST | `/api/smart-collections` | | Create a smart collection | -| DELETE | `/api/smart-collections/{id}` | | Delete a smart collection | +| GET | `/api/smart-collections` | SmartCollectionGetAll | Get all smart collections | +| POST | `/api/smart-collections` | SmartCollectionCreate | Create a smart collection | +| DELETE | `/api/smart-collections/{id}` | SmartCollectionDelete | Delete a smart collection | | GET | `/api/smart-collections/{id}` | GetSmartCollectionById | Get a smart collection by id | -| PUT | `/api/smart-collections/{id}` | | Update a smart collection | +| PUT | `/api/smart-collections/{id}` | SmartCollectionUpdate | Update a smart collection | ## Television @@ -392,27 +387,27 @@ | Method | Path | Operation | Summary | |---|---|---|---| -| GET | `/api/templates` | | Get all templates | -| POST | `/api/templates` | | Create a template | +| GET | `/api/templates` | TemplateGetAll | Get all templates | +| POST | `/api/templates` | TemplateCreate | Create a template | | GET | `/api/templates/groups` | GetTemplateGroups | Get all template groups | -| POST | `/api/templates/groups` | | Create a template group | -| DELETE | `/api/templates/groups/{id}` | | Delete a template group | -| DELETE | `/api/templates/{id}` | | Delete a template | +| POST | `/api/templates/groups` | TemplateCreateGroup | Create a template group | +| DELETE | `/api/templates/groups/{id}` | TemplateDeleteGroup | Delete a template group | +| DELETE | `/api/templates/{id}` | TemplateDelete | Delete a template | | GET | `/api/templates/{id}` | GetTemplateById | Get a template by id | -| PUT | `/api/templates/{id}` | | Replace a template and its items | -| POST | `/api/templates/{id}/copy` | | Copy a template | -| GET | `/api/templates/{id}/items` | | Get template items | +| PUT | `/api/templates/{id}` | TemplateReplace | Replace a template and its items | +| POST | `/api/templates/{id}/copy` | TemplateCopy | Copy a template | +| GET | `/api/templates/{id}/items` | TemplateGetItems | Get template items | ## Trakt | Method | Path | Operation | Summary | |---|---|---|---| | GET | `/api/trakt/lists` | GetTraktLists | Get paged Trakt lists | -| POST | `/api/trakt/lists` | | Add a Trakt list by URL | -| DELETE | `/api/trakt/lists/{id}` | | Delete a Trakt list | +| POST | `/api/trakt/lists` | TraktAdd | Add a Trakt list by URL | +| DELETE | `/api/trakt/lists/{id}` | TraktDelete | Delete a Trakt list | | GET | `/api/trakt/lists/{id}` | GetTraktListById | Get a Trakt list by id | -| PUT | `/api/trakt/lists/{id}` | | Update a Trakt list's settings | -| POST | `/api/trakt/lists/{id}/match` | | Match a Trakt list's items | +| PUT | `/api/trakt/lists/{id}` | TraktUpdate | Update a Trakt list's settings | +| POST | `/api/trakt/lists/{id}/match` | TraktMatch | Match a Trakt list's items | | GET | `/api/trakt/status` | GetTraktStatus | Get Trakt background operation status | ## Troubleshooting @@ -420,12 +415,12 @@ | Method | Path | Operation | Summary | |---|---|---|---| | GET | `/api/troubleshoot/info` | GetTroubleshootingInfo | Get troubleshooting diagnostic info | -| GET | `/api/troubleshoot/playback.m3u8` | | Start a troubleshooting playback session | -| HEAD | `/api/troubleshoot/playback.m3u8` | | Start a troubleshooting playback session | -| GET | `/api/troubleshoot/playback/archive` | | Download the last troubleshooting playback session archive | -| HEAD | `/api/troubleshoot/playback/archive` | | Download the last troubleshooting playback session archive | -| GET | `/api/troubleshoot/playback/sample/{mediaItemId}` | | Download a media sample archive for troubleshooting | -| HEAD | `/api/troubleshoot/playback/sample/{mediaItemId}` | | Download a media sample archive for troubleshooting | +| GET | `/api/troubleshoot/playback.m3u8` | TroubleshootTroubleshootPlaybackGET | Start a troubleshooting playback session | +| HEAD | `/api/troubleshoot/playback.m3u8` | TroubleshootTroubleshootPlayback | Start a troubleshooting playback session | +| GET | `/api/troubleshoot/playback/archive` | TroubleshootTroubleshootPlaybackArchiveGET | Download the last troubleshooting playback session archive | +| HEAD | `/api/troubleshoot/playback/archive` | TroubleshootTroubleshootPlaybackArchive | Download the last troubleshooting playback session archive | +| GET | `/api/troubleshoot/playback/sample/{mediaItemId}` | TroubleshootTroubleshootPlaybackSampleGET | Download a media sample archive for troubleshooting | +| HEAD | `/api/troubleshoot/playback/sample/{mediaItemId}` | TroubleshootTroubleshootPlaybackSample | Download a media sample archive for troubleshooting | | GET | `/api/troubleshoot/playback/status` | GetTroubleshootingPlaybackStatus | Get the status of the current or last troubleshooting playback session | | GET | `/api/troubleshoot/playback/stream-selectors` | GetTroubleshootingStreamSelectors | List available channel stream selectors | | GET | `/api/troubleshoot/playback/subtitles/{mediaItemId}` | GetTroubleshootingSubtitles | List selectable subtitle streams for a media item | diff --git a/web/src/api/channels.ts b/web/src/api/channels.ts index 6ecb4cfb4..3eb445cc1 100644 --- a/web/src/api/channels.ts +++ b/web/src/api/channels.ts @@ -4,7 +4,7 @@ import type { components } from './generated/v1'; export type ChannelSummary = components['schemas']['ChannelResponseModel']; export type ChannelState = components['schemas']['ChannelStateResponseModel']; -export type Channel = components['schemas']['ChannelViewModel']; +export type Channel = components['schemas']['ChannelDetailResponseModel']; export type UpdateChannelRequest = components['schemas']['UpdateChannelRequest']; export type BulkRenumberChannelsRequest = components['schemas']['BulkRenumberChannelsRequest']; export type BulkMoveChannelsToGroupRequest = components['schemas']['BulkMoveChannelsToGroupRequest']; diff --git a/web/src/api/collections.ts b/web/src/api/collections.ts index ca3b0ee71..56603523f 100644 --- a/web/src/api/collections.ts +++ b/web/src/api/collections.ts @@ -2,8 +2,8 @@ import { ApiError, request, requestWithMeta, type ResponseWithMeta } from './cli import type { components } from './generated/v1'; import type { LibraryBrowseItem, PagedLibraryBrowseItems } from './libraryBrowse'; -export type MediaCollection = components['schemas']['MediaCollectionViewModel']; -export type SmartCollection = components['schemas']['SmartCollectionViewModel']; +export type MediaCollection = components['schemas']['MediaCollectionResponseModel']; +export type SmartCollection = components['schemas']['SmartCollectionResponseModel']; export type CreateCollectionRequest = components['schemas']['CreateCollectionRequest']; export type UpdateCollectionRequest = components['schemas']['UpdateCollectionRequest']; export type AddItemsToCollectionRequest = components['schemas']['AddItemsToCollectionRequest']; diff --git a/web/src/api/generated/v1.d.ts b/web/src/api/generated/v1.d.ts index d51908279..b55bf47c6 100644 --- a/web/src/api/generated/v1.d.ts +++ b/web/src/api/generated/v1.d.ts @@ -134,6 +134,37 @@ export interface components { }; "BulkRenumberChannelsRequest": { "channels": Array; + }; + "ChannelDetailResponseModel": { + "id": number; + "number": string; + "name": string; + "group": string; + "categories": string; + "ffmpegProfileId": number; + "slugSeconds": null | number; + "logo": components["schemas"]["ChannelLogoResponseModel"]; + "streamSelectorMode": components["schemas"]["ChannelStreamSelectorMode"]; + "streamSelector": string; + "preferredAudioLanguageCode": string; + "preferredAudioTitle": string; + "playoutSource": components["schemas"]["ChannelPlayoutSource"]; + "playoutMode": components["schemas"]["ChannelPlayoutMode"]; + "mirrorSourceChannelId": null | number; + "playoutOffset": null | string; + "streamingMode": components["schemas"]["StreamingMode"]; + "watermarkId": null | number; + "fallbackFillerId": null | number; + "playoutCount": number; + "preferredSubtitleLanguageCode": string; + "subtitleMode": components["schemas"]["ChannelSubtitleMode"]; + "musicVideoCreditsMode": components["schemas"]["ChannelMusicVideoCreditsMode"]; + "musicVideoCreditsTemplate": string; + "songVideoMode": components["schemas"]["ChannelSongVideoMode"]; + "transcodeMode": components["schemas"]["ChannelTranscodeMode"]; + "idleBehavior": components["schemas"]["ChannelIdleBehavior"]; + "isEnabled": boolean; + "showInEpg": boolean; }; "ChannelGuideChannelResponseModel": { "number": string; @@ -154,6 +185,13 @@ export interface components { "channels": Array; }; "ChannelIdleBehavior": "StopOnDisconnect" | "KeepRunning"; + "ChannelLogoResponseModel": { + "path": string; + "contentType": string; + "isExternalUrl"?: boolean; + "hasContentType"?: boolean; + "urlWithContentType"?: null | string; + }; "ChannelMusicVideoCreditsMode": "None" | "GenerateSubtitles"; "ChannelNowPlayingResponseModel": { "title": string; @@ -215,38 +253,6 @@ export interface components { "fixedStartTimeBehavior": components["schemas"]["FixedStartTimeBehavior"]; }; "ChannelTranscodeMode": "OnDemand"; - "ChannelViewModel": { - "id": number; - "number": null | string; - "name": null | string; - "group": null | string; - "categories": null | string; - "ffmpegProfileId": number; - "slugSeconds": null | number; - "logo": components["schemas"]["ArtworkContentTypeModel"]; - "streamSelectorMode": components["schemas"]["ChannelStreamSelectorMode"]; - "streamSelector": null | string; - "preferredAudioLanguageCode": null | string; - "preferredAudioTitle": null | string; - "playoutSource": components["schemas"]["ChannelPlayoutSource"]; - "playoutMode": components["schemas"]["ChannelPlayoutMode"]; - "mirrorSourceChannelId": null | number; - "playoutOffset": null | string; - "streamingMode": components["schemas"]["StreamingMode"]; - "watermarkId": null | number; - "fallbackFillerId": null | number; - "playoutCount": number; - "preferredSubtitleLanguageCode": null | string; - "subtitleMode": components["schemas"]["ChannelSubtitleMode"]; - "musicVideoCreditsMode": components["schemas"]["ChannelMusicVideoCreditsMode"]; - "musicVideoCreditsTemplate": null | string; - "songVideoMode": components["schemas"]["ChannelSongVideoMode"]; - "transcodeMode": components["schemas"]["ChannelTranscodeMode"]; - "idleBehavior": components["schemas"]["ChannelIdleBehavior"]; - "isEnabled": boolean; - "showInEpg": boolean; - "webEncodedName"?: null | string; - }; "ChannelWatermarkImageSource": "Custom" | "ChannelLogo" | "Resource"; "ChannelWatermarkMode": "None" | "Permanent" | "Intermittent" | "OpacityExpression"; "CollectionType": "Collection" | "TelevisionShow" | "TelevisionSeason" | "Artist" | "MultiCollection" | "SmartCollection" | "Playlist" | "RerunFirstRun" | "RerunRerun" | "SearchQuery" | "Movie" | "Episode" | "MusicVideo" | "OtherVideo" | "Song" | "Image" | "RemoteStream" | "FakeCollection" | "FakePlaylistItem"; @@ -515,7 +521,7 @@ export interface components { "zIndex": number; "placeWithinSourceContent": boolean; }; - "DayOfWeek": number; + "DayOfWeek": "Sunday" | "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday"; "DecoBreakContentRequest": { "id": number; "collectionType": components["schemas"]["CollectionType"]; @@ -689,7 +695,7 @@ export interface components { }; "FillerPresetResponseModel": { "id": number; - "name": null | string; + "name": string; "fillerKind": components["schemas"]["FillerKind"]; }; "FillWithGroupMode": "None" | "FillWithOrderedGroups" | "FillWithShuffledGroups"; @@ -697,7 +703,7 @@ export interface components { "FixedStartTimeBehavior": "Strict" | "Flexible"; "GraphicsElementResponseModel": { "id": number; - "name": null | string; + "name": string; }; "GuideMode": "Normal" | "Filler"; "HardwareAccelerationKind": "None" | "Qsv" | "Nvenc" | "Vaapi" | "VideoToolbox" | "Amf" | "V4l2m2m" | "Rkmpp"; @@ -727,8 +733,8 @@ export interface components { "durationSeconds": null | number; }; "LanguageCodeResponseModel": { - "code": null | string; - "englishName": null | string; + "code": string; + "englishName": string; }; "LibraryBrowseItemResponseModel": { "id": number; @@ -758,20 +764,20 @@ export interface components { }; "LocalLibraryDetailResponseModel": { "id": number; - "name": null | string; + "name": string; "mediaKind": components["schemas"]["LibraryMediaKind"]; "isLocked": boolean; "mediaItemCount": number; - "paths": null | Array; + "paths": Array; }; "LocalLibraryPathResponseModel": { "id": number; - "path": null | string; + "path": string; "mediaItemCount": number; }; "LocalLibraryResponseModel": { "id": number; - "name": null | string; + "name": string; "mediaKind": components["schemas"]["LibraryMediaKind"]; "isLocked": boolean; }; @@ -796,19 +802,11 @@ export interface components { "httpMinimumLogLevel": components["schemas"]["LogEventLevel"]; }; "MarathonGroupBy": "None" | "Show" | "Season" | "Artist" | "Album" | "Director"; - "MediaCollectionViewModel": { - "collectionType": components["schemas"]["CollectionType"]; + "MediaCollectionResponseModel": { "id": number; - "name": null | string; + "name": string; + "collectionType": components["schemas"]["CollectionType"]; "useCustomPlaybackOrder": boolean; - "version"?: number; - "mediaItemId"?: number; - "title"?: null | string; - "subtitle"?: null | string; - "sortTitle"?: null | string; - "poster"?: null | string; - "state": components["schemas"]["MediaItemState"]; - "hasMediaInfo"?: boolean; }; "MediaItemInfoChapterResponseModel": { "title": null | string; @@ -915,7 +913,7 @@ export interface components { "MultipleMode": "Count" | "CollectionSize" | "PlaylistItemSize" | "MultiEpisodeGroupSize"; "NamedIdResponseModel": { "id": number; - "name": null | string; + "name": string; }; "NormalizeLoudnessMode": "Off" | "LoudNorm"; "OutputFormatKind": "None" | "Mkv" | "MpegTs" | "Mp4" | "Hls" | "HlsMp4" | "Nut"; @@ -937,11 +935,11 @@ export interface components { }; "PagedPlayoutItemsResponseModel": { "totalCount": number; - "page": null | Array; + "page": Array; }; "PagedPlayoutsResponseModel": { "totalCount": number; - "page": null | Array; + "page": Array; }; "PagedRerunCollectionsResponseModel": { "totalCount": number; @@ -958,8 +956,8 @@ export interface components { }; "PathReplacementResponseModel": { "id": number; - "remotePath": null | string; - "localPath": null | string; + "remotePath": string; + "localPath": string; }; "PlaybackOrder": "None" | "Chronological" | "Random" | "Shuffle" | "ShuffleInOrder" | "MultiEpisodeShuffle" | "SeasonEpisode" | "RandomRotation" | "Marathon"; "PlaylistGroupResponseModel": { @@ -1042,7 +1040,7 @@ export interface components { "PlayoutBuildStatusResponseModel": { "lastBuild": string; "success": boolean; - "message": null | string; + "message": string; }; "PlayoutHistoryDetailsResponseModel": { "playbackOrder": components["schemas"]["PlaybackOrder"]; @@ -1138,7 +1136,7 @@ export interface components { "endYear": null | number; }; "PlexPinFlowResponseModel": { - "authUrl": null | string; + "authUrl": string; }; "ProblemDetails": { "type"?: null | string; @@ -1147,18 +1145,17 @@ export interface components { "detail"?: null | string; "instance"?: null | string; }; - "ProgramScheduleViewModel": { + "ProgramScheduleResponseModel": { "id": number; - "name": null | string; + "name": string; "keepMultiPartEpisodesTogether": boolean; "treatCollectionsAsShows": boolean; "shuffleScheduleItems": boolean; "randomStartPoint": boolean; "fixedStartTimeBehavior": components["schemas"]["FixedStartTimeBehavior"]; - "version": number; }; "RemoteConnectionResponseModel": { - "address": null | string; + "address": string; "hasApiKey": boolean; }; "RemoteLibraryPreferenceRequest": { @@ -1167,19 +1164,19 @@ export interface components { }; "RemoteLibraryResponseModel": { "id": number; - "name": null | string; + "name": string; "mediaKind": components["schemas"]["LibraryMediaKind"]; "shouldSyncItems": boolean; }; "RemoteMediaSourceItemResponseModel": { "id": number; - "name": null | string; - "address": null | string; + "name": string; + "address": string; }; "RemoteMediaSourceStateResponseModel": { "isAuthorized": boolean; "isLocked": boolean; - "servers": null | Array; + "servers": Array; }; "ReplaceBlockRequest": { "name": null | string; @@ -1258,13 +1255,6 @@ export interface components { "width": number; "height": number; "isCustom": boolean; - }; - "ResolutionViewModel": { - "id": number; - "name": null | string; - "width": number; - "height": number; - "isCustom": boolean; }; "SaveRemoteConnectionRequest": { "address": null | string; @@ -1384,16 +1374,16 @@ export interface components { "name": string; }; "SearchResultAllItemsResponseModel": { - "movieIds": null | Array; - "showIds": null | Array; - "seasonIds": null | Array; - "episodeIds": null | Array; - "artistIds": null | Array; - "musicVideoIds": null | Array; - "otherVideoIds": null | Array; - "songIds": null | Array; - "imageIds": null | Array; - "remoteStreamIds": null | Array; + "movieIds": Array; + "showIds": Array; + "seasonIds": Array; + "episodeIds": Array; + "artistIds": Array; + "musicVideoIds": Array; + "otherVideoIds": Array; + "songIds": Array; + "imageIds": Array; + "remoteStreamIds": Array; }; "SearchResultGroupResponseModel": { "totalCount": number; @@ -1439,13 +1429,8 @@ export interface components { }; "SmartCollectionResponseModel": { "id": number; - "name": null | string; - "query": null | string; - }; - "SmartCollectionViewModel": { - "id": number; - "name": null | string; - "query": null | string; + "name": string; + "query": string; }; "StartType": "Dynamic" | "Fixed"; "StreamingMode": "TransportStream" | "HttpLiveStreamingDirect" | "HttpLiveStreamingSegmenter" | "TransportStreamHybrid"; @@ -1749,6 +1734,16 @@ export interface components { "isValid": boolean; "messages": Array; "json": string; + }; + "ValidationProblemDetails": { + "type"?: null | string; + "title"?: null | string; + "status"?: null | number; + "detail"?: null | string; + "instance"?: null | string; + "errors"?: { + [key: string]: Array; + }; }; "VideoScanKind": "Unknown" | "Progressive" | "Interlaced"; "WatermarkFullResponseModel": { @@ -1773,7 +1768,7 @@ export interface components { "WatermarkLocation": "BottomRight" | "BottomLeft" | "TopRight" | "TopLeft" | "TopMiddle" | "RightMiddle" | "BottomMiddle" | "LeftMiddle" | "MiddleCenter"; "WatermarkResponseModel": { "id": number; - "name": null | string; + "name": string; }; "WatermarkSize": "Scaled" | "ActualSize"; "XmltvBlockBehavior": "SplitTimeEvenly" | "UseActualTimes"; diff --git a/web/src/api/playouts.ts b/web/src/api/playouts.ts index 16dd50102..1c23f8373 100644 --- a/web/src/api/playouts.ts +++ b/web/src/api/playouts.ts @@ -14,10 +14,11 @@ export type PlayoutItemSchedulingContext = components['schemas']['PlayoutItemSch export type CreatePlayoutRequest = components['schemas']['CreatePlayoutRequest']; export type UpdatePlayoutDetailsRequest = components['schemas']['UpdatePlayoutDetailsRequest']; -// The OpenAPI generator types DayOfWeek as `number` (the OpenAPI schema is derived from -// System.Text.Json metadata), but the MVC pipeline serializes with Newtonsoft + StringEnumConverter, -// so DayOfWeek is a day-name string on the wire ("Sunday" … "Saturday"). We override the generated -// `daysOfWeek` shape accordingly on both request and response DTOs. +// DayOfWeek is a day-name string on the wire ("Sunday" … "Saturday"). As of #287 the OpenAPI +// schema emits it as a string enum (added to Startup.UseStringEnumSchemas), so the generated +// `daysOfWeek` shape is already correct and no override is needed — the DTO aliases below point +// straight at the generated schemas. This local union is kept for the DAYS_OF_WEEK ordering +// constant and equals components['schemas']['DayOfWeek']. export type DayOfWeek = | 'Sunday' | 'Monday' @@ -38,14 +39,10 @@ export const DAYS_OF_WEEK: DayOfWeek[] = [ 'Sunday' ]; -type WithDayNames = Omit & { daysOfWeek: DayOfWeek[] }; - -export type PlayoutAlternateSchedule = WithDayNames; -export type PlayoutAlternateScheduleItemRequest = WithDayNames< - components['schemas']['PlayoutAlternateScheduleItemRequest'] ->; -export type PlayoutTemplate = WithDayNames; -export type PlayoutTemplateItemRequest = WithDayNames; +export type PlayoutAlternateSchedule = components['schemas']['PlayoutAlternateScheduleResponseModel']; +export type PlayoutAlternateScheduleItemRequest = components['schemas']['PlayoutAlternateScheduleItemRequest']; +export type PlayoutTemplate = components['schemas']['PlayoutTemplateResponseModel']; +export type PlayoutTemplateItemRequest = components['schemas']['PlayoutTemplateItemRequest']; // Declared as `type` (not `interface`) so they satisfy the client's `Record` // RequestBody bound, matching the generated request DTOs. diff --git a/web/src/api/schedules.ts b/web/src/api/schedules.ts index aa85d14ce..7736f3370 100644 --- a/web/src/api/schedules.ts +++ b/web/src/api/schedules.ts @@ -12,7 +12,7 @@ export type ScheduleItem = components['schemas']['ScheduleItemResponseModel']; export type ScheduleItemsResponse = components['schemas']['ScheduleItemsResponseModel']; export type ScheduleItemRequest = components['schemas']['ScheduleItemRequest']; export type ReplaceScheduleItemsRequest = components['schemas']['ReplaceScheduleItemsRequest']; -export type ProgramSchedule = components['schemas']['ProgramScheduleViewModel']; +export type ProgramSchedule = components['schemas']['ProgramScheduleResponseModel']; export type CreateScheduleRequest = components['schemas']['CreateScheduleRequest']; export type UpdateScheduleRequest = components['schemas']['UpdateScheduleRequest']; export type NamedId = components['schemas']['NamedIdResponseModel']; diff --git a/web/src/api/search.test.ts b/web/src/api/search.test.ts index ceed1af3d..65362a781 100644 --- a/web/src/api/search.test.ts +++ b/web/src/api/search.test.ts @@ -88,16 +88,16 @@ describe('toAddItemsRequestFromSearch', () => { it('fills every bucket, defaulting null arrays to []', () => { expect( toAddItemsRequestFromSearch({ - artistIds: null, - episodeIds: null, - imageIds: null, + artistIds: [], + episodeIds: [], + imageIds: [], movieIds: [1, 2], - musicVideoIds: null, - otherVideoIds: null, - remoteStreamIds: null, - seasonIds: null, - showIds: null, - songIds: null + musicVideoIds: [], + otherVideoIds: [], + remoteStreamIds: [], + seasonIds: [], + showIds: [], + songIds: [] }) ).toEqual({ artistIds: [],