feat(api): carry poster and rating through search and lists

Widen the unified search so both §9.2 halves can render a thumbnail
and a rating: TMDB results gain vote_average/vote_count from the
search bodies, library results read the #145 artwork columns, and
episodes take their series' art. GET /api/movies and /api/series gain
the same two fields for the #151 grid. Mirrors in web updated.
This commit is contained in:
Miguel Palhas
2026-08-23 22:45:08 +01:00
parent 30382585ea
commit 5e2bb5dff7
21 changed files with 357 additions and 66 deletions
+4
View File
@@ -17,6 +17,10 @@ export interface LibrarySeries {
auto_track: boolean;
upstream_ended: boolean;
blocked: boolean;
/** Stored artwork (§9.6) — a grid tile renders without a TMDB call. */
poster_path: string | null;
/** TMDB's rating, out of 10; `null` when TMDB has no votes for it. */
vote_average: number | null;
status: SeriesStatus;
wanted_episodes: number;
available_episodes: number;
+18
View File
@@ -15,6 +15,10 @@ export interface LibraryMovie {
wanted: boolean;
state: "missing" | "downloading" | "available";
blocked: boolean;
/** Stored artwork (§9.6) — a row renders without a TMDB call. */
poster_path: string | null;
/** TMDB's rating, out of 10; `null` when TMDB has no votes for it. */
vote_average: number | null;
/** The §5.7 rule relaxed to allow an import, when a file carries one. */
waiver?: unknown;
}
@@ -28,6 +32,8 @@ export interface LibrarySeriesHit {
original_language: string | null;
root_id: number;
blocked: boolean;
poster_path: string | null;
vote_average: number | null;
}
export interface LibraryEpisodeHit {
@@ -39,6 +45,9 @@ export interface LibraryEpisodeHit {
tag: string;
/** The episode title — what the search matched on. */
title: string;
/** The series' poster — an episode has no artwork of its own worth showing at row size. */
poster_path: string | null;
vote_average: number | null;
}
export type LibraryResult = LibraryMovie | LibrarySeriesHit | LibraryEpisodeHit;
@@ -51,6 +60,10 @@ export interface TmdbMovie {
original_language: string;
year: number | null;
overview: string | null;
poster_path: string | null;
/** TMDB's rating, out of 10; `null` when TMDB has no votes for it. */
vote_average: number | null;
vote_count: number;
}
export interface TmdbSeries {
@@ -60,6 +73,9 @@ export interface TmdbSeries {
original_language: string;
year: number | null;
overview: string | null;
poster_path: string | null;
vote_average: number | null;
vote_count: number;
}
export type TmdbResult = TmdbMovie | TmdbSeries;
@@ -142,6 +158,8 @@ export interface ApiSeries {
overrides: Record<string, unknown>;
upstream_ended: boolean;
blocked: boolean;
poster_path: string | null;
vote_average: number | null;
status: string;
wanted_episodes: number;
available_episodes: number;