Files
dwroller/scripts/merge-npcs-from-api.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

92 lines
2.5 KiB
JavaScript

// merge-npcs-from-api.js
// Fetches NPCs from local API and upserts them into the bestiary DB
const fs = require('fs');
const path = require('path');
const http = require('http');
const API_URL = 'http://192.168.1.144:5000/api/npcs';
const BESTIARY_PATH = path.join(__dirname, '../database/deathwatch-bestiary-extracted.json');
const BACKUP_PATH = path.join(__dirname, `../database/deathwatch-bestiary-extracted.backup.${Date.now()}.json`);
function fetchAPI(url) {
return new Promise((resolve, reject) => {
http.get(url, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
try {
resolve(JSON.parse(data));
} catch (e) {
reject(e);
}
});
}).on('error', reject);
});
}
function normalizeNPC(apiNpc) {
// Map API NPC to bestiary format
return {
name: apiNpc.name,
type: apiNpc.type,
chapter: apiNpc.chapter,
faction: apiNpc.faction,
threat: apiNpc.threat_level,
description: apiNpc.description,
source: apiNpc.source,
stats: {
...apiNpc.stats
},
equipment: apiNpc.equipment,
abilities: apiNpc.abilities,
apiId: apiNpc.id
};
}
async function main() {
// Backup bestiary
fs.copyFileSync(BESTIARY_PATH, BACKUP_PATH);
console.log('Backed up bestiary to', BACKUP_PATH);
// Read bestiary object
let bestiaryObj = {};
try {
bestiaryObj = JSON.parse(fs.readFileSync(BESTIARY_PATH, 'utf8'));
} catch (e) {
console.error('Could not read bestiary, starting with empty results array.');
bestiaryObj = { results: [] };
}
if (!Array.isArray(bestiaryObj.results)) bestiaryObj.results = [];
const bestiary = bestiaryObj.results;
// Fetch API NPCs
let apiNpcs;
try {
const apiData = await fetchAPI(API_URL);
apiNpcs = apiData.npcs || [];
} catch (e) {
console.error('Failed to fetch from API:', e);
return;
}
let added = 0, updated = 0;
for (const apiNpc of apiNpcs) {
const norm = normalizeNPC(apiNpc);
// Try to match by name or bestiaryName
const idx = bestiary.findIndex(e => (e.name && e.name === norm.name) || (e.bestiaryName && e.bestiaryName === norm.name));
if (idx === -1) {
bestiary.push(norm);
added++;
} else {
bestiary[idx] = { ...bestiary[idx], ...norm };
updated++;
}
}
bestiaryObj.count = bestiary.length;
fs.writeFileSync(BESTIARY_PATH, JSON.stringify(bestiaryObj, null, 2));
console.log(`NPCs merged. Added: ${added}, Updated: ${updated}`);
}
main();