Files
dwroller/scripts/upsert-missing-wounds-from-pdfs.js
Alex caf8a03553 feat: Add scripts for upserting and validating bestiary data
- Implemented `upsert-allewis-from-5001.js` to fetch and update Allewis data from API.
- Created `upsert-missing-movement-from-5001.js` to fill missing movement and wounds data from API.
- Developed `upsert-missing-movement-from-pdfs.js` to extract movement and wounds from PDF text.
- Added `upsert-missing-profiles-from-pdfs.js` to fill missing profiles from PDF data.
- Introduced `upsert-missing-wounds-from-pdfs.js` to update wounds data from PDF sources.
- Created `validate-bestiary.js` to validate the structure of the bestiary JSON.
- Updated `BestiaryTab.jsx` component to display bestiary data with improved structure and search functionality.
- Added tests for `BestiaryTab` to ensure proper rendering and functionality.
2025-08-17 16:21:00 +02:00

78 lines
2.6 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const BESTIARY = path.resolve(__dirname, '..', 'database', 'deathwatch-bestiary-extracted.json');
const DB_DIR = path.resolve(__dirname, '..', 'database');
const BACKUPS = path.resolve(__dirname, '..', 'database', 'backups');
function backup(srcPath, tag) {
if (!fs.existsSync(BACKUPS)) fs.mkdirSync(BACKUPS, { recursive: true });
const ts = Date.now();
const dest = path.join(BACKUPS, path.basename(srcPath) + `.backup.${tag}.${ts}.json`);
fs.copyFileSync(srcPath, dest);
return dest;
}
function loadJSON(p) {
try { return JSON.parse(fs.readFileSync(p,'utf8')); } catch(e){ return null; }
}
function findWoundsFor(nameLower) {
const files = fs.readdirSync(DB_DIR).filter(f => f.endsWith('.json'));
for (const f of files) {
const p = path.join(DB_DIR, f);
let j;
try { j = JSON.parse(fs.readFileSync(p,'utf8')); } catch(e){ continue; }
if (!j.results || !Array.isArray(j.results)) continue;
for (const r of j.results) {
if (!r.stats) continue;
if (r.stats.wounds) {
const hay = (r.stats.snippet || r.pageText || r.snippet || '').toLowerCase();
if (hay.includes(nameLower)) return {file: p, result: r};
}
}
}
return null;
}
function main() {
const bestiary = loadJSON(BESTIARY);
if (!bestiary) { console.error('Failed loading bestiary'); process.exit(2); }
const results = bestiary.results || [];
const toUpdate = [];
for (const entry of results) {
const stats = entry.stats || {};
const woundsMissing = stats.wounds === null || stats.wounds === undefined;
if (!woundsMissing) continue;
const nameLower = (entry.bestiaryName || '').toLowerCase();
const found = findWoundsFor(nameLower);
if (found) toUpdate.push({entry, found});
}
if (!toUpdate.length) { console.log('No wounds candidates found in local PDF JSONs.'); process.exit(0); }
console.log(`Found ${toUpdate.length} wounds candidate(s) to upsert.`);
backup(BESTIARY, 'pdffill-wounds');
let updated = 0;
for (const u of toUpdate) {
const e = u.entry;
const r = u.found.result;
e.pdf = path.basename(u.found.file);
e.page = r.foundPage || e.page || null;
e.pageText = e.pageText || null;
e.stats = e.stats || {};
if (r.stats.wounds) {
e.stats.wounds = r.stats.wounds;
updated++;
console.log(`Set wounds for ${e.bestiaryName} -> ${r.stats.wounds} (from ${u.found.file})`);
}
}
fs.writeFileSync(BESTIARY, JSON.stringify(bestiary, null, 2), 'utf8');
console.log(`Wrote ${updated} wounds updates to ${BESTIARY}`);
}
main();