Load the home-page catalog once with a lightweight artists API, batch pan/zoom updates per frame, use dynamic year labels, and speed up movement-flow zoom. Add sync-image-paths and fetch-artist-images plus docs for the post-seed pipeline.
81 lines
2.6 KiB
JavaScript
81 lines
2.6 KiB
JavaScript
/**
|
|
* Download artist portrait images from Wikipedia (and fallbacks) into data/images/portraits/.
|
|
* Run: npm run fetch-artist-images
|
|
* Flags: --force (re-fetch even when portrait_path is set), --limit=N
|
|
*/
|
|
require('dotenv').config();
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const pool = require('../server/db');
|
|
const { saveArtistPortrait, findLocalPortraitPath } = require('./image-fetcher');
|
|
|
|
const FORCE = process.argv.includes('--force');
|
|
const LIMIT = parseInt(process.argv.find((a) => a.startsWith('--limit='))?.split('=')[1] || '0', 10);
|
|
const IMAGE_DIR = path.resolve(process.env.IMAGE_DIR || path.join(__dirname, '../data/images'));
|
|
|
|
function portraitFileExists(portraitPath) {
|
|
return !!portraitPath && fs.existsSync(path.join(IMAGE_DIR, portraitPath));
|
|
}
|
|
|
|
function needsPortrait(artist, force) {
|
|
if (force) return true;
|
|
const local = findLocalPortraitPath(artist.name, IMAGE_DIR);
|
|
if (local) return artist.portrait_path !== local;
|
|
if (artist.portrait_path) return !portraitFileExists(artist.portrait_path);
|
|
return true;
|
|
}
|
|
|
|
async function main() {
|
|
const { rows: artists } = await pool.query(`
|
|
SELECT id, name, wikipedia_title, portrait_path
|
|
FROM artists
|
|
ORDER BY name
|
|
`);
|
|
|
|
let targets = artists.filter((a) => needsPortrait(a, FORCE));
|
|
if (LIMIT > 0) targets = targets.slice(0, LIMIT);
|
|
|
|
console.log(
|
|
`Artists total: ${artists.length}, to fetch: ${targets.length}${FORCE ? ' (force)' : ''}${LIMIT > 0 ? ` (limit ${LIMIT})` : ''}`
|
|
);
|
|
|
|
let updated = 0;
|
|
let linked = 0;
|
|
let failed = 0;
|
|
|
|
for (const artist of targets) {
|
|
try {
|
|
const local = findLocalPortraitPath(artist.name, IMAGE_DIR);
|
|
if (local) {
|
|
await pool.query('UPDATE artists SET portrait_path = $1 WHERE id = $2', [local, artist.id]);
|
|
console.log(`↺ ${artist.name} — ${local}`);
|
|
linked += 1;
|
|
continue;
|
|
}
|
|
|
|
const wikiTitle = artist.wikipedia_title || artist.name;
|
|
const saved = await saveArtistPortrait(artist.name, wikiTitle, IMAGE_DIR);
|
|
if (!saved.path) {
|
|
console.warn(`✗ ${artist.name} — no portrait found`);
|
|
failed += 1;
|
|
continue;
|
|
}
|
|
|
|
await pool.query('UPDATE artists SET portrait_path = $1 WHERE id = $2', [saved.path, artist.id]);
|
|
console.log(`✓ ${artist.name} — ${saved.path} (${saved.source || 'Wikipedia'})`);
|
|
updated += 1;
|
|
} catch (err) {
|
|
console.error(`✗ ${artist.name} — ${err.message}`);
|
|
failed += 1;
|
|
}
|
|
}
|
|
|
|
console.log(`\nDone: ${updated} downloaded, ${linked} linked from disk, ${failed} failed`);
|
|
await pool.end();
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|