Files
ascension-talent-calc/tools/audit-icons.mjs
T

63 lines
2.0 KiB
JavaScript
Executable File

#!/usr/bin/env node
import fs from 'node:fs/promises';
import path from 'node:path';
const ICON_BASE = (process.env.ICON_BASE || 'https://exil.es/icons/spells/').replace(/\/?$/, '/');
const dataDir = path.resolve('./talent-builder/public/data');
function toFilename(raw) {
const s = (raw || '').trim().replace(/\\/g, '/');
const base = s.split('/').pop().replace(/\.(blp|png|jpg|jpeg)$/i, '');
return base.toLowerCase() + '.png';
}
const files = await fs.readdir(dataDir);
const jsons = files.filter(f => f.endsWith('.json') && !f.includes('.invalid.'));
const icons = new Set();
for (const f of jsons) {
try {
const j = JSON.parse(await fs.readFile(path.join(dataDir, f), 'utf8'));
for (const tab of Object.values(j)) {
for (const t of tab.talents || []) icons.add(toFilename(t.iconTexture));
}
} catch (e) {
console.error(`Skipping ${f}: ${e.message}`);
}
}
let missing = []; let ok = 0; let foundInItems = 0;
for (const icon of icons) {
const url = ICON_BASE + icon;
try {
const r = await fetch(url, { method: 'HEAD' });
if (!r.ok) {
// Try alternative path for inv_ icons
if (icon.startsWith('inv_')) {
const altUrl = 'https://exil.es/icons/items/' + icon;
const r2 = await fetch(altUrl, { method: 'HEAD' });
if (r2.ok) {
foundInItems++;
ok++;
} else {
missing.push({ icon, status: r.status });
}
} else {
missing.push({ icon, status: r.status });
}
} else {
ok++;
}
} catch (e) { missing.push({ icon, error: String(e) }); }
}
console.log('Icon base:', ICON_BASE);
console.log('Alternative path for inv_* icons: https://exil.es/icons/items/');
console.log('Total unique icons:', icons.size);
console.log('Available in primary path:', ok - foundInItems);
console.log('Available in items path:', foundInItems);
console.log('Total available:', ok);
console.log('Missing:', missing.length);
if (missing.length) {
console.log('\nMissing list:');
for (const m of missing) console.log(m.icon, m.status || m.error || 'ERR');
}