feat(plex): rich media info — info page, in-player info overlay, IMDb + cast photos

Backend (no migration): item_detail now also returns IMDb score + id/url (from the
Plex Rating/Guid arrays), content rating, genres, director(s), studio, tagline, and
cast as {name, role, photo}. New host-whitelisted /person-image proxy serves cast
photos from Plex's public metadata CDN (keeps third-party requests off the browser).

Frontend: reusable PlexInfo component in two forms — a full info page opened from a
card's 'i' button (history subview, art backdrop, Play/Resume + watch controls) and a
lean overlay in the player toggled with 'I' (video keeps playing). Two per-user view
prefs (faint backdrop, cast row) persisted in preferences. Mark-unwatched / clear-resume
cover the watched-reset gap. i18n en/hu/de.
This commit is contained in:
npeter83 2026-07-05 22:57:18 +02:00
parent eed517b475
commit 690e17611c
10 changed files with 568 additions and 9 deletions

View file

@ -695,7 +695,15 @@ export interface PlexItemDetail {
playable: string; // direct | remux | transcode
thumb: string;
art: string;
cast: string[];
cast: PlexCastMember[];
imdb_rating?: number | null;
imdb_id?: string | null;
imdb_url?: string | null;
content_rating?: string | null;
genres: string[];
directors: string[];
studio?: string | null;
tagline?: string | null;
markers: PlexMarker[];
audio_streams: { ord: number; label: string; language?: string | null; default: boolean }[];
subtitle_streams: { ord: number; label: string; language?: string | null }[];
@ -707,6 +715,11 @@ export interface PlexItemDetail {
prev_id?: string | null;
next_id?: string | null;
}
export interface PlexCastMember {
name: string;
role?: string | null;
thumb?: string | null; // proxied person-image url, or null when Plex has no photo
}
export interface PlexPlaySession {
mode: "direct" | "hls";
url: string;