mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-08-29 06:15:39 -04:00
Add actor/cast information with person pages and search support
Integrate TMDB credits data into the app: cast carousels on title detail pages, person detail pages with biography and filmography, and person search results in the command palette. Includes new persons/titleCast DB tables, profile image caching, and a nightly credits refresh cron job. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -20,12 +20,14 @@ import { tmdbImageUrl } from "@/lib/tmdb/image";
|
||||
import type { TmdbVideo } from "@/lib/tmdb/types";
|
||||
import type {
|
||||
AvailabilityOffer,
|
||||
CastMember,
|
||||
Episode,
|
||||
ResolvedTitle,
|
||||
Season,
|
||||
} from "@/lib/types/title";
|
||||
import { refreshAvailability } from "./availability";
|
||||
import { extractAndStoreColors, parseColorPalette } from "./colors";
|
||||
import { getCastForTitle, refreshCredits } from "./credits";
|
||||
import {
|
||||
cacheEpisodeStills,
|
||||
cacheImagesForTitle,
|
||||
@@ -83,6 +85,9 @@ export async function importTitle(
|
||||
extractAndStoreColors(existing.id, show.poster_path).catch((err) =>
|
||||
log.debug("Color extraction failed:", err),
|
||||
),
|
||||
refreshCredits(existing.id).catch((err) =>
|
||||
log.debug("Credits enrichment failed:", err),
|
||||
),
|
||||
]);
|
||||
} else {
|
||||
refreshAvailability(existing.id).catch((err) =>
|
||||
@@ -91,6 +96,9 @@ export async function importTitle(
|
||||
refreshRecommendations(existing.id).catch((err) =>
|
||||
log.debug("Recommendations enrichment failed:", err),
|
||||
);
|
||||
refreshCredits(existing.id).catch((err) =>
|
||||
log.debug("Credits enrichment failed:", err),
|
||||
);
|
||||
}
|
||||
if (imageCacheEnabled()) {
|
||||
cacheImagesForTitle(existing.id).catch((err) =>
|
||||
@@ -140,6 +148,9 @@ export async function importTitle(
|
||||
extractAndStoreColors(row.id, movie.poster_path).catch((err) =>
|
||||
log.debug("Color extraction failed:", err),
|
||||
),
|
||||
refreshCredits(row.id).catch((err) =>
|
||||
log.debug("Credits enrichment failed:", err),
|
||||
),
|
||||
]);
|
||||
} else {
|
||||
refreshAvailability(row.id).catch((err) =>
|
||||
@@ -151,6 +162,9 @@ export async function importTitle(
|
||||
extractAndStoreColors(row.id, movie.poster_path).catch((err) =>
|
||||
log.debug("Color extraction failed:", err),
|
||||
);
|
||||
refreshCredits(row.id).catch((err) =>
|
||||
log.debug("Credits enrichment failed:", err),
|
||||
);
|
||||
}
|
||||
refreshTrailer(row.id).catch((err) =>
|
||||
log.debug("Trailer enrichment failed:", err),
|
||||
@@ -197,6 +211,9 @@ export async function importTitle(
|
||||
extractAndStoreColors(row.id, show.poster_path).catch((err) =>
|
||||
log.debug("Color extraction failed:", err),
|
||||
),
|
||||
refreshCredits(row.id).catch((err) =>
|
||||
log.debug("Credits enrichment failed:", err),
|
||||
),
|
||||
]);
|
||||
} else {
|
||||
refreshAvailability(row.id).catch((err) =>
|
||||
@@ -208,6 +225,9 @@ export async function importTitle(
|
||||
extractAndStoreColors(row.id, show.poster_path).catch((err) =>
|
||||
log.debug("Color extraction failed:", err),
|
||||
);
|
||||
refreshCredits(row.id).catch((err) =>
|
||||
log.debug("Credits enrichment failed:", err),
|
||||
);
|
||||
}
|
||||
refreshTrailer(row.id).catch((err) =>
|
||||
log.debug("Trailer enrichment failed:", err),
|
||||
@@ -277,6 +297,9 @@ export async function refreshTitle(titleId: string) {
|
||||
refreshTrailer(updated.id).catch((err) =>
|
||||
log.debug("Trailer enrichment failed:", err),
|
||||
);
|
||||
refreshCredits(updated.id).catch((err) =>
|
||||
log.debug("Credits enrichment failed:", err),
|
||||
);
|
||||
if (imageCacheEnabled()) {
|
||||
cacheImagesForTitle(updated.id).catch((err) =>
|
||||
log.debug("Image caching failed:", err),
|
||||
@@ -516,6 +539,7 @@ export async function getTitleWithChildren(id: string): Promise<{
|
||||
title: ResolvedTitle;
|
||||
seasons: Season[];
|
||||
availability: AvailabilityOffer[];
|
||||
cast: CastMember[];
|
||||
} | null> {
|
||||
let title = db.select().from(titles).where(eq(titles.id, id)).get();
|
||||
if (!title) return null;
|
||||
@@ -671,7 +695,9 @@ export async function getTitleWithChildren(id: string): Promise<{
|
||||
trailerVideoKey: title.trailerVideoKey,
|
||||
};
|
||||
|
||||
return { title: resolvedTitle, seasons: titleSeasons, availability };
|
||||
const cast = getCastForTitle(id);
|
||||
|
||||
return { title: resolvedTitle, seasons: titleSeasons, availability, cast };
|
||||
}
|
||||
|
||||
export function pickBestTrailer(videos: TmdbVideo[]): string | null {
|
||||
|
||||
Reference in New Issue
Block a user