fix(api): root library-browse artwork URLs and add season drill-in (#180)

Part of the #180 library picker fixes (API side).

Broken artwork: GetLibraryBrowseItemsHandler.Artwork returned Blazor-convention
values (a bare cache filename, or a RELATIVE jellyfin/emby proxy path). Blazor's
GetPosterUrl prefixes those with "artwork/posters/" against <base href="/">, but
the React SPA renders item.artwork raw as <img src> from under /app/, so every
image 404'd. The handler now returns rooted, directly-usable URLs
(/artwork/posters/... or /artwork/thumbnails/... per ArtworkKind; jellyfin/emby
mapped to their proxy routes with fillHeight/maxHeight; absolute http(s) URLs
passed through; empty stays empty).

Seasons with no poster of their own now fall back to the parent show's poster
(SeasonArtwork + the extra ShowMetadata.Artwork include).

Season drill-in: GET /api/library/browse gains an optional `parentId` query
param that, with mediaType=TelevisionSeason, returns that show's seasons
(season-number order, bypassing Lucene) so the SPA can expand a show into its
seasons. OpenAPI spec regenerated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 21:42:10 +02:00
co-authored by Claude Fable 5
parent e58da21a56
commit 54b18e73cd
6 changed files with 196 additions and 16 deletions
@@ -22,12 +22,13 @@ public class LibraryBrowseController(IMediator mediator) : ControllerBase
[FromQuery] LibraryBrowseMediaType? mediaType = null,
[FromQuery] int pageNum = 0,
[FromQuery] int pageSize = 100,
[FromQuery] int? parentId = null,
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),
new GetLibraryBrowseItems(query, libraryId, mediaType, clampedPageNum, clampedPageSize, parentId),
cancellationToken);
}
}
+8
View File
@@ -4968,6 +4968,14 @@
"format": "int32",
"default": 100
}
},
{
"name": "parentId",
"in": "query",
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {