← back to Nineoh Guide

db/ingest-cast.mjs

60 lines

// 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();