← back to Nineoh Guide
db/apply-recaps.mjs
45 lines
// Generic season-by-season recap applier. Reads db/recaps/s{N}.json (keys =
// episode numbers, values = ORIGINAL recap text) and writes them into
// episodes.summary_short_original with recap_status='ai-draft' (human review gate).
// Run: node db/apply-recaps.mjs (all seasons present)
// node db/apply-recaps.mjs 2 (just season 2)
import pg from "pg";
import { readdirSync, readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
const DATABASE_URL =
process.env.DATABASE_URL ?? "postgresql://localhost/nineoh_guide?host=/tmp";
const pool = new pg.Pool({ connectionString: DATABASE_URL });
const dir = join(dirname(fileURLToPath(import.meta.url)), "recaps");
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 only = process.argv[2] ? Number(process.argv[2]) : null;
const files = readdirSync(dir).filter((f) => /^s\d+\.json$/.test(f));
let total = 0;
for (const f of files) {
const season = Number(f.match(/^s(\d+)\.json$/)[1]);
if (only && season !== only) continue;
const data = JSON.parse(readFileSync(join(dir, f), "utf8"));
let n = 0;
for (const [ep, text] of Object.entries(data)) {
if (ep.startsWith("_")) continue; // skip _note
const res = await pool.query(
`update episodes set summary_short_original=$1, recap_status='ai-draft', spoiler_rating=0
where show_id=$2 and season_number=$3 and episode_number=$4`,
[text, show.id, season, Number(ep)]
);
n += res.rowCount;
}
console.log(`season ${season}: ${n} recaps applied`);
total += n;
}
const tally = await pool.query(`select recap_status, count(*) from episodes group by recap_status order by 1`);
console.log("total applied:", total);
console.table(tally.rows);
console.log("All recaps are ai-draft — review before marking published.");
await pool.end();