Files
Art-gallery/scripts/fetch-artist-images.js
Danila KhodjaefandCursor 96285737f5 Rename npm scripts to environment-prefixed names (dev:/prod:/devtoprod:/prodto:dev:/infra:).
Align package.json scripts and their references across scripts/, infra/, and db/ SQL with the dev-first workflow naming scheme.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 12:37:21 +03:00

81 lines
2.6 KiB
JavaScript

/**
* Download artist portrait images from Wikipedia (and fallbacks) into data/images/portraits/.
* Run: npm run dev: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);
});