feat(api): add library browse endpoint
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 4m10s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 4m47s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped

refs #65
This commit is contained in:
2026-07-06 00:01:06 +02:00
parent a5de775480
commit 127a130737
10 changed files with 1397 additions and 0 deletions
@@ -0,0 +1,33 @@
using ErsatzTV.Application.LibraryBrowse;
using ErsatzTV.Core.Api.LibraryBrowse;
using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace ErsatzTV.Controllers.Api;
[ApiController]
public class LibraryBrowseController(IMediator mediator) : ControllerBase
{
private const int MaxPageSize = 100;
[HttpGet("/api/library/browse", Name = "BrowseLibrary")]
[Tags("Library")]
[EndpointSummary("Browse and search library items")]
[EndpointGroupName("general")]
[ProducesResponseType(typeof(PagedLibraryBrowseItemsResponseModel), StatusCodes.Status200OK)]
public async Task<PagedLibraryBrowseItemsResponseModel> Browse(
[FromQuery] string query = "",
[FromQuery] int? libraryId = null,
[FromQuery] LibraryBrowseMediaType? mediaType = null,
[FromQuery] int pageNum = 0,
[FromQuery] int pageSize = 100,
CancellationToken cancellationToken = default)
{
int clampedPageNum = Math.Max(0, pageNum);
int clampedPageSize = Math.Clamp(pageSize, 1, MaxPageSize);
return await mediator.Send(
new GetLibraryBrowseItems(query, libraryId, mediaType, clampedPageNum, clampedPageSize),
cancellationToken);
}
}
+224
View File
@@ -1995,6 +1995,80 @@
}
}
},
"/api/library/browse": {
"get": {
"tags": [
"Library"
],
"summary": "Browse and search library items",
"operationId": "BrowseLibrary",
"parameters": [
{
"name": "query",
"in": "query",
"schema": {
"type": "string",
"default": ""
}
},
{
"name": "libraryId",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "mediaType",
"in": "query",
"schema": {
"$ref": "#/components/schemas/LibraryBrowseMediaType"
}
},
{
"name": "pageNum",
"in": "query",
"schema": {
"type": "integer",
"format": "int32",
"default": 0
}
},
{
"name": "pageSize",
"in": "query",
"schema": {
"type": "integer",
"format": "int32",
"default": 100
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"text/plain": {
"schema": {
"$ref": "#/components/schemas/PagedLibraryBrowseItemsResponseModel"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/PagedLibraryBrowseItemsResponseModel"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/PagedLibraryBrowseItemsResponseModel"
}
}
}
}
}
}
},
"/api/maintenance/gc": {
"get": {
"tags": [
@@ -5346,6 +5420,134 @@
"type": "string",
"format": "binary"
},
"LibraryBrowseItemResponseModel": {
"required": [
"id",
"mediaType",
"title",
"libraryId",
"libraryName",
"artwork",
"duration",
"itemCount",
"collectionKind",
"collectionType",
"collectionId",
"multiCollectionId",
"smartCollectionId",
"rerunCollectionId",
"mediaItemId",
"playlistId"
],
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"mediaType": {
"$ref": "#/components/schemas/LibraryBrowseMediaType"
},
"title": {
"type": "string"
},
"libraryId": {
"type": [
"null",
"integer"
],
"format": "int32"
},
"libraryName": {
"type": [
"null",
"string"
]
},
"artwork": {
"type": "string"
},
"duration": {
"pattern": "^-?(\\d+\\.)?\\d{2}:\\d{2}:\\d{2}(\\.\\d{1,7})?$",
"type": [
"null",
"string"
]
},
"itemCount": {
"type": [
"null",
"integer"
],
"format": "int32"
},
"collectionKind": {
"type": [
"null",
"string"
]
},
"collectionType": {
"$ref": "#/components/schemas/CollectionType"
},
"collectionId": {
"type": [
"null",
"integer"
],
"format": "int32"
},
"multiCollectionId": {
"type": [
"null",
"integer"
],
"format": "int32"
},
"smartCollectionId": {
"type": [
"null",
"integer"
],
"format": "int32"
},
"rerunCollectionId": {
"type": [
"null",
"integer"
],
"format": "int32"
},
"mediaItemId": {
"type": [
"null",
"integer"
],
"format": "int32"
},
"playlistId": {
"type": [
"null",
"integer"
],
"format": "int32"
}
}
},
"LibraryBrowseMediaType": {
"enum": [
"Movie",
"TelevisionShow",
"TelevisionSeason",
"Artist",
"Collection",
"SmartCollection",
"MultiCollection",
"RerunCollection",
"Playlist"
],
"type": "string"
},
"LibraryMediaKind": {
"enum": [
"Movies",
@@ -5646,6 +5848,25 @@
],
"type": "string"
},
"PagedLibraryBrowseItemsResponseModel": {
"required": [
"totalCount",
"page"
],
"type": "object",
"properties": {
"totalCount": {
"type": "integer",
"format": "int32"
},
"page": {
"type": "array",
"items": {
"$ref": "#/components/schemas/LibraryBrowseItemResponseModel"
}
}
}
},
"PagedPlayoutItemsResponseModel": {
"required": [
"totalCount",
@@ -7215,6 +7436,9 @@
{
"name": "Libraries"
},
{
"name": "Library"
},
{
"name": "Maintenance"
},