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:
2026-03-05 14:36:39 -05:00
co-authored by Claude Opus 4.6
parent 9ecf7bbe3c
commit cd5d773e98
27 changed files with 3957 additions and 44 deletions
+56
View File
@@ -289,6 +289,62 @@ export const titleRecommendations = sqliteTable(
],
);
// ─── Persons & Cast ─────────────────────────────────────────────────
export const persons = sqliteTable(
"persons",
{
id: uuidPk(),
tmdbId: int("tmdbId").notNull(),
name: text("name").notNull(),
biography: text("biography"),
birthday: text("birthday"),
deathday: text("deathday"),
placeOfBirth: text("placeOfBirth"),
profilePath: text("profilePath"),
knownForDepartment: text("knownForDepartment"),
popularity: real("popularity"),
imdbId: text("imdbId"),
lastFetchedAt: int("lastFetchedAt", { mode: "timestamp" }),
},
(table) => [
uniqueIndex("persons_tmdbId_unique").on(table.tmdbId),
index("persons_name").on(table.name),
],
);
export const titleCast = sqliteTable(
"titleCast",
{
id: uuidPk(),
titleId: text("titleId")
.notNull()
.references(() => titles.id, { onDelete: "cascade" }),
personId: text("personId")
.notNull()
.references(() => persons.id, { onDelete: "cascade" }),
character: text("character"),
department: text("department").notNull().default("Acting"),
job: text("job"),
displayOrder: int("displayOrder").notNull().default(0),
episodeCount: int("episodeCount"),
lastFetchedAt: int("lastFetchedAt", { mode: "timestamp" }),
},
(table) => [
uniqueIndex("titleCast_unique").on(
table.titleId,
table.personId,
table.department,
table.character,
),
index("titleCast_titleId_displayOrder").on(
table.titleId,
table.displayOrder,
),
index("titleCast_personId").on(table.personId),
],
);
// ─── Webhook Connections ─────────────────────────────────────────────
export const webhookConnections = sqliteTable(