← back to Nineoh Guide
ingest factual cast + character names (TVmaze, names-only, no photos/bios) — populates /cast
fc018158f9b330a0d7827775a33bd7e1cbe0da9c · 2026-07-25 10:28:56 -0700 · Steve
Files touched
Diff
commit fc018158f9b330a0d7827775a33bd7e1cbe0da9c
Author: Steve <steve@designerwallcoverings.com>
Date: Sat Jul 25 10:28:56 2026 -0700
ingest factual cast + character names (TVmaze, names-only, no photos/bios) — populates /cast
---
db/ingest-cast.mjs | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/db/ingest-cast.mjs b/db/ingest-cast.mjs
new file mode 100644
index 0000000..14cf4a3
--- /dev/null
+++ b/db/ingest-cast.mjs
@@ -0,0 +1,59 @@
+// Ingests FACTUAL cast data only — actor names + character names (both facts,
+// not copyrightable). Deliberately does NOT store TVmaze person photos (publicity
+// rights + image licensing are gated) or any biography text (we write our own).
+// Run: node db/ingest-cast.mjs
+import pg from "pg";
+
+const DATABASE_URL =
+ process.env.DATABASE_URL ?? "postgresql://localhost/nineoh_guide?host=/tmp";
+const pool = new pg.Pool({ connectionString: DATABASE_URL });
+
+const show = (await pool.query(`select id from shows where canonical_title='90210'`)).rows[0];
+if (!show) {
+ console.error("Run db/seed.mjs first.");
+ process.exit(1);
+}
+const showId = show.id;
+
+// TVmaze show id 578 = 90210 (2008 CW). Cast endpoint returns main cast: person + character.
+const res = await fetch("https://api.tvmaze.com/shows/578/cast");
+const cast = await res.json();
+
+let people = 0;
+let characters = 0;
+for (const c of cast) {
+ const personName = c.person?.name;
+ const charName = c.character?.name;
+ if (!personName) continue;
+
+ // Upsert person by name (names are facts; no photo, no bio stored).
+ const p = await pool.query(
+ `insert into cast_people (name, publicity_risk_level)
+ select $1, 'editorial-only'
+ where not exists (select 1 from cast_people where name = $1)
+ returning id`,
+ [personName]
+ );
+ if (p.rowCount) people++;
+
+ if (charName) {
+ const ch = await pool.query(
+ `insert into characters (name, show_id)
+ select $1, $2
+ where not exists (select 1 from characters where name = $1 and show_id = $2)
+ returning id`,
+ [charName, showId]
+ );
+ if (ch.rowCount) characters++;
+ }
+}
+
+const totals = await pool.query(
+ `select (select count(*) from cast_people) as people,
+ (select count(*) from characters where show_id=$1) as chars`,
+ [showId]
+);
+console.log(`inserted this run — people:${people} characters:${characters}`);
+console.log(`totals — cast_people:${totals.rows[0].people} characters:${totals.rows[0].chars}`);
+console.log("Names only. No photos (image-license gated), no bios (we write our own original).");
+await pool.end();
← 1b02ed5 contrarian fixes: correct Expo API-base wiring (expo-constan
·
back to Nineoh Guide
·
write 6 original spoiler-safe S1 recaps (our wording, ground c260ce8 →