← back to Fentucci Naturals
scripts/download-images.js
42 lines
#!/usr/bin/env node
// Download original full-res wixstatic images to images/<safe mfr_sku>.jpg
// Verifies every file is a real image > 5KB (guards the WallQuest image-collapse gotcha).
const fs = require('fs');
const path = require('path');
const ROOT = path.join(__dirname, '..');
const products = JSON.parse(fs.readFileSync(path.join(ROOT, 'data', 'products.json')));
function isImage(buf) {
if (buf.length < 4) return false;
if (buf[0] === 0xFF && buf[1] === 0xD8) return true; // JPEG
if (buf[0] === 0x89 && buf[1] === 0x50) return true; // PNG
if (buf.slice(0, 4).toString() === 'RIFF') return true; // WebP
return false;
}
(async () => {
const results = [];
let ok = 0, failed = 0, skipped = 0;
for (const p of products) {
const dest = path.join(ROOT, p.image_local);
if (fs.existsSync(dest) && fs.statSync(dest).size > 5120) { skipped++; continue; }
try {
const res = await fetch(p.image_url, { headers: { 'User-Agent': 'Mozilla/5.0' } });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const buf = Buffer.from(await res.arrayBuffer());
if (buf.length <= 5120) throw new Error(`too small: ${buf.length}B`);
if (!isImage(buf)) throw new Error('not an image (magic bytes)');
fs.writeFileSync(dest, buf);
ok++;
} catch (e) {
failed++;
results.push({ mfr_sku: p.mfr_sku, image_url: p.image_url, error: e.message });
console.error(`${p.mfr_sku}: ${e.message}`);
}
await new Promise(r => setTimeout(r, 150));
}
fs.writeFileSync(path.join(ROOT, 'data', 'image-failures.json'), JSON.stringify(results, null, 2));
console.log(`downloaded: ${ok}, cached: ${skipped}, failed: ${failed}`);
})();