Files
iptvnator/libs/shared/interfaces/src/lib/xtream-vod-details.interface.ts
T
4grayandClaude Opus 4.8 5aa44d19d4 feat(tmdb): clickable director/creator chips and directing credits on person pages (#1227)
* feat(tmdb): clickable director/creator chips and directing credits on person pages

Directors were plain merged text — no photos, no navigation — while the
data was already sitting in the cached TMDB payloads (credits.crew and
created_by both carry id + profile_path; they just were not typed or
parsed).

- tmdb-merge: enrichedDirectors (crew, job === 'Director', deduped by
  person id) and enrichedCreators (created_by) produce the same chip
  shape as the cast (TmdbEnrichedCastMember) into a new tmdb_directors
  field on all three merges (Xtream VOD, Xtream series, Stalker); types
  widened (crew id/profile_path, created_by id/profile_path).
- Detail views (shared VodDetailsComponent, Xtream vod/serial routes,
  Stalker series view) render the Director row as clickable avatar chips
  when tmdb_directors is present — same markup and openActor handler as
  the cast strip — falling back to the plain text otherwise. Stalker
  re-normalization allowlist preserves the new field.
- Person pages: mapPersonFilmography now merges combined_credits.crew
  (jobs Director/Creator) into the filmography — acting wins the
  per-title dedup, directing-only titles show the job in the character
  slot. Everything else (library matching, All-portals scope, filters,
  search fallback, back button) works unchanged because the person page
  is role-agnostic. Existing caches work as-is: crew/created_by were
  always part of the stored payloads.

Tests: merge spec (director/creator chips + crew-row dedup ×3 merges),
person spec (crew credits, Producer excluded, acting-wins dedup),
stalker-vod.utils passthrough. Docs updated (CLAUDE.md + architecture).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(tmdb): address director-pages review — split oversized spec, stable track keys, translated crew roles

- tmdb-merge.spec.ts grew past the 400-line lint ceiling — the Stalker
  merge suite moved to tmdb-merge-stalker.spec.ts (fixes the CI Lint job).
- All cast/director chip loops now track by TMDB person id with an
  index fallback ('p<id>' / 'i<index>') instead of member.name — distinct
  people can share a name and creator payloads carry no dedup (greptile).
- Directing-only filmography credits carry the role in a new crewJob
  field ('Director' | 'Creator') instead of stuffing TMDB's raw English
  job into character; ActorViewComponent renders it through translated
  labels (XTREAM.CREW_JOB_DIRECTOR/CREATOR, added to all 18 locales via
  the i18n patch workflow, matching each locale's existing glossary —
  pt "Diretor", de "Regisseur") (Codex).

Tests: person spec asserts character/crewJob separation; merge suites
green after the split (15 + stalker file).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 08:42:41 +02:00

76 lines
2.0 KiB
TypeScript

import {
TmdbEnrichedCastMember,
TmdbRecommendation,
} from './tmdb.interface';
export interface XtreamVodInfo {
kinopoisk_url: string;
tmdb_id: number | string;
name: string;
o_name: string;
cover_big: string;
movie_image: string;
releasedate: string;
episode_run_time: number;
youtube_trailer: string;
director: string;
actors: string;
cast: string;
description: string;
plot: string;
age: string;
mpaa_rating: string;
rating_count_kinopoisk: number;
country: string;
genre: string;
backdrop_path: string[];
duration_secs: number;
duration: string;
video: string[];
audio: string[];
bitrate: number;
rating: number | string;
runtime?: string;
status?: string;
rating_kinopoisk?: string;
rating_imdb?: string;
/** Populated by TMDB enrichment; absent in raw provider responses */
tmdb_cast?: TmdbEnrichedCastMember[];
/** Directors (movies) / creators (series) as clickable person chips */
tmdb_directors?: TmdbEnrichedCastMember[];
/** Populated by TMDB enrichment; matched against the catalog in views */
tmdb_recommendations?: TmdbRecommendation[];
}
export interface XtreamVodMovieData {
stream_id: number;
name: string;
added: string;
category_id: string;
container_extension: string;
custom_sid: string | null;
direct_source: string;
category_ids?: number[];
}
export interface XtreamVodDetails {
info?: XtreamVodInfo | [] | null;
movie_data?: XtreamVodMovieData;
}
export function getXtreamVodInfo(
details: Pick<XtreamVodDetails, 'info'> | null | undefined
): XtreamVodInfo | null {
const info = details?.info;
if (!info || Array.isArray(info) || typeof info !== 'object') {
return null;
}
return info;
}
export function hasXtreamVodInfo(
details: Pick<XtreamVodDetails, 'info'> | null | undefined
): details is XtreamVodDetails & { info: XtreamVodInfo } {
return getXtreamVodInfo(details) !== null;
}