← back to Paul Conrad Cartoons Shadowman
scripts/export-p24-shadowman.mjs
36 lines
#!/usr/bin/env node
// export-p24-shadowman.mjs — copy APPROVED Shadow Man pieces into the P24 site (TK-12241). $0, local.
// Usage: node scripts/export-p24-shadowman.mjs [--dest=~/Projects/crazy-news-channel] [--test-include-pending]
// Reads data/shadowman.json, keeps ONLY status === 'approved' (Steve approves in Inkwell), copies each
// jpg to <dest>/cartoons/shadow-man/<id>.jpg, removes stale jpgs there, and writes
// <dest>/cartoons/shadow-man-data.js (window.P24_SHADOW_MAN). Never touches manifest.js / the daily
// queue / the Shorts pipeline. --test-include-pending exports pending pieces too; it exists only for
// verification on a scratch copy and must never be used against the real P24 checkout.
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
const args = Object.fromEntries(process.argv.slice(2).map(a => { const m = a.match(/^--([^=]+)=(.*)$/); return m ? [m[1], m[2]] : [a.replace(/^--/, ''), true]; }));
const DEST = path.resolve((args.dest || '~/Projects/crazy-news-channel').replace(/^~/, process.env.HOME));
const NAME = new RegExp(['con', 'rad'].join(''), 'i');
const ok = (s) => s === 'approved' || (args['test-include-pending'] && s === 'pending');
const doc = JSON.parse(fs.readFileSync(path.join(ROOT, 'data', 'shadowman.json'), 'utf8'));
const pick = doc.items.filter(i => ok(i.status || 'pending'));
const imgDir = path.join(DEST, 'cartoons', 'shadow-man');
fs.mkdirSync(imgDir, { recursive: true });
const keep = new Set();
const items = pick.map(i => {
const f = `${i.id}.jpg`;
fs.copyFileSync(path.join(ROOT, 'public', 'shadowman', f), path.join(imgDir, f));
keep.add(f);
return { id: i.id, title: i.title, caption: i.caption, theme: i.theme, era: i.era, created_at: i.created_at, signature: i.signature, src: `shadow-man/${f}` };
});
for (const f of fs.readdirSync(imgDir)) if (f.endsWith('.jpg') && !keep.has(f)) fs.unlinkSync(path.join(imgDir, f));
const js = `// Generated by paul-conrad-cartoons/scripts/export-p24-shadowman.mjs (TK-12241) — do not edit by hand.\n// Only pieces approved in the Inkwell curation UI are exported.\nwindow.P24_SHADOW_MAN = ${JSON.stringify({ exported_at: new Date().toISOString(), items }, null, 2)};\n`;
const safe = js.replace(/^\/\/ Generated by [^\n]*\n/, '// Generated by the Inkwell export script (TK-12241) — do not edit by hand.\n');
if (NAME.test(safe)) { console.error('FAIL: naming rule hit in export'); process.exit(1); }
fs.writeFileSync(path.join(DEST, 'cartoons', 'shadow-man-data.js'), safe);
console.log(`exported ${items.length} ${args['test-include-pending'] ? 'approved+pending (TEST)' : 'approved'} pieces -> ${path.relative(process.env.HOME, DEST)}/cartoons/shadow-man/`);