mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-15 21:56:18 -08:00
feat(portals): make year, genre and country metadata clickable (#1449)
Year, genre and country chips on movie and series detail pages now open a Discover page inside the portal: popular TMDB titles for that facet, matched against the user's own catalog. Generalizes the existing actor-page pattern (TMDB list -> what's in my library -> else portal search) to metadata facets. - All three TMDB merges emit structured `tmdb_genres`/`tmdb_countries` (+ `tmdb_media_type` on Stalker, whose embedded-VOD series route as movies). Cached details payloads already carry both, so existing rows need no refetch. - Chips are clickable only with TMDB backing, like person chips today; the year chip gates on a merge-written numeric `tmdb_id`, since provider payloads ship junk string ids. - `TmdbDiscoverService` fetches up to 5 `/discover` pages by popularity and caches them in memory only — popularity rankings are volatile and must not reach the persisted `tmdb_metadata` table. - New `discover` route in both portals; containers clone the actor route, staleness-guarded by a facet key because facets change via query params on the same route instance. - The grid, filter chips and badges move out of `ActorViewComponent` into a shared `TitleResultsComponent` used by both pages. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
00aa623b83
commit
486d04411f
68 files changed
+2287
-318
No files matched your search
@@ -1,5 +1,8 @@
|
||||
import {
|
||||
TmdbCountryFacet,
|
||||
TmdbEnrichedCastMember,
|
||||
TmdbGenreFacet,
|
||||
TmdbMediaType,
|
||||
TmdbRecommendation,
|
||||
TmdbSeriesStatus,
|
||||
} from './tmdb.interface';
|
||||
@@ -52,4 +55,13 @@ export interface StalkerVodInfo {
|
||||
tmdb_recommendations?: TmdbRecommendation[];
|
||||
/** Matched TMDB id — enables lazy season/episode enrichment */
|
||||
tmdb_id?: number;
|
||||
/** Populated by TMDB enrichment; per-entry clickable Discover chips */
|
||||
tmdb_genres?: TmdbGenreFacet[];
|
||||
tmdb_countries?: TmdbCountryFacet[];
|
||||
/**
|
||||
* Media type the enrichment matched this item as. Stalker embedded-VOD
|
||||
* series route as movies structurally, so the shared detail view needs
|
||||
* this to send Discover clicks to the right media type.
|
||||
*/
|
||||
tmdb_media_type?: TmdbMediaType;
|
||||
}
|
||||
@@ -99,6 +99,26 @@ export interface TmdbRecommendation {
|
||||
posterUrl: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Genre as stated by TMDB for one title. The id drives the Discover-page
|
||||
* filter (`with_genres`), so it must never be mixed across media types —
|
||||
* movie and TV genre id spaces differ.
|
||||
*/
|
||||
export interface TmdbGenreFacet {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Production country as stated by TMDB. `code` is ISO 3166-1 alpha-2 and
|
||||
* drives the Discover-page filter (`with_origin_country`); `name` is the
|
||||
* TMDB display name (English regardless of request language).
|
||||
*/
|
||||
export interface TmdbCountryFacet {
|
||||
code: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* One cached TMDB lookup. Two kinds of rows share the table, discriminated
|
||||
* by the `lookupKey` prefix:
|
||||
|
||||
@@ -32,6 +32,11 @@ export function normalizeXtreamVod(item: XtreamVodDetails): NormalizedVodMeta {
|
||||
tmdbCast: info?.tmdb_cast,
|
||||
tmdbDirectors: info?.tmdb_directors,
|
||||
tmdbRecommendations: info?.tmdb_recommendations,
|
||||
// Provider payloads carry tmdb_id as an untrusted string too; only
|
||||
// a merge-written number proves an enrichment match
|
||||
tmdbId: typeof info?.tmdb_id === 'number' ? info.tmdb_id : undefined,
|
||||
tmdbGenres: info?.tmdb_genres,
|
||||
tmdbCountries: info?.tmdb_countries,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -62,6 +67,10 @@ export function normalizeStalkerVod(item: StalkerVodDetails): NormalizedVodMeta
|
||||
tmdbCast: info?.tmdb_cast,
|
||||
tmdbDirectors: info?.tmdb_directors,
|
||||
tmdbRecommendations: info?.tmdb_recommendations,
|
||||
tmdbId: info?.tmdb_id,
|
||||
tmdbMediaType: info?.tmdb_media_type,
|
||||
tmdbGenres: info?.tmdb_genres,
|
||||
tmdbCountries: info?.tmdb_countries,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { XtreamVodDetails } from './xtream-vod-details.interface';
|
||||
import { StalkerVodDetails } from './stalker-vod-details.interface';
|
||||
import { TmdbEnrichedCastMember,
|
||||
import {
|
||||
TmdbCountryFacet,
|
||||
TmdbEnrichedCastMember,
|
||||
TmdbGenreFacet,
|
||||
TmdbMediaType,
|
||||
TmdbRecommendation,
|
||||
} from './tmdb.interface';
|
||||
|
||||
@@ -88,6 +92,14 @@ export interface NormalizedVodMeta {
|
||||
tmdbDirectors?: TmdbEnrichedCastMember[];
|
||||
/** TMDB recommendations (drives the cross-portal "Similar" rail) */
|
||||
tmdbRecommendations?: TmdbRecommendation[];
|
||||
/** Matched TMDB id — gates the clickable year chip (Discover page) */
|
||||
tmdbId?: number;
|
||||
/** Media type the enrichment matched as; Discover click routing */
|
||||
tmdbMediaType?: TmdbMediaType;
|
||||
/** Per-entry clickable genre chips (Discover page) */
|
||||
tmdbGenres?: TmdbGenreFacet[];
|
||||
/** Per-entry clickable country chips (Discover page) */
|
||||
tmdbCountries?: TmdbCountryFacet[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import {
|
||||
TmdbCountryFacet,
|
||||
TmdbEnrichedCastMember,
|
||||
TmdbGenreFacet,
|
||||
TmdbRecommendation,
|
||||
TmdbSeriesStatus,
|
||||
} from './tmdb.interface';
|
||||
@@ -44,6 +46,9 @@ export interface XtreamSerieInfo {
|
||||
tmdb_recommendations?: TmdbRecommendation[];
|
||||
/** Matched TMDB show id — enables lazy season/episode enrichment */
|
||||
tmdb_id?: number;
|
||||
/** Populated by TMDB enrichment; per-entry clickable Discover chips */
|
||||
tmdb_genres?: TmdbGenreFacet[];
|
||||
tmdb_countries?: TmdbCountryFacet[];
|
||||
}
|
||||
|
||||
export interface XtreamSerieEpisode {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import {
|
||||
TmdbCountryFacet,
|
||||
TmdbEnrichedCastMember,
|
||||
TmdbGenreFacet,
|
||||
TmdbRecommendation,
|
||||
} from './tmdb.interface';
|
||||
|
||||
@@ -52,6 +54,9 @@ export interface XtreamVodInfo {
|
||||
tmdb_directors?: TmdbEnrichedCastMember[];
|
||||
/** Populated by TMDB enrichment; matched against the catalog in views */
|
||||
tmdb_recommendations?: TmdbRecommendation[];
|
||||
/** Populated by TMDB enrichment; per-entry clickable Discover chips */
|
||||
tmdb_genres?: TmdbGenreFacet[];
|
||||
tmdb_countries?: TmdbCountryFacet[];
|
||||
}
|
||||
|
||||
export interface XtreamVodMovieData {
|
||||
|
||||
Reference in new issue
Block a user