#!/usr/bin/env node import initSqlJs from 'sql.js'; import fs from 'fs'; import path from 'path'; const DB_PATH = 'data/recipes.db'; const IMAGES_DIR = 'data/images'; async function auditAndFixImages() { const SQL = await initSqlJs(); const dbBuffer = fs.readFileSync(DB_PATH); const db = new SQL.Database(dbBuffer); // Get all recipes const recipes = db.exec(`SELECT id, title, image_url FROM recipes ORDER BY id`); if (recipes.length === 0) { console.log('No recipes found'); return; } // Get all image files in data/images const imageFiles = fs.readdirSync(IMAGES_DIR).filter(f => f.endsWith('.jpg')); console.log(`\nšŸ“‚ Found ${imageFiles.length} images in ${IMAGES_DIR}/`); console.log(`šŸ“Š Found ${recipes[0].values.length} recipes in database\n`); let withImages = 0; let withoutImages = 0; let fixed = 0; recipes[0].values.forEach(([id, title, imageUrl]) => { if (imageUrl && imageUrl.trim().length > 0) { withImages++; return; } // Recipe has no image — try to find one by matching filename const titleSlug = title .toLowerCase() .replace(/[^a-z0-9]+/g, '_') .replace(/^_+|_+$/g, ''); // Look for matching image const matchingImage = imageFiles.find(filename => { const baseName = filename.replace(/_.{5}\.jpg$/, ''); // Remove random suffix return baseName === titleSlug || filename.startsWith(titleSlug); }); if (matchingImage) { const newUrl = `/images/${matchingImage}`; db.run(`UPDATE recipes SET image_url = ? WHERE id = ?`, [newUrl, id]); console.log(`āœ“ Fixed: ${id}. ${title} → ${newUrl}`); fixed++; } else { console.log(`āœ— Missing: ${id}. ${title}`); withoutImages++; } }); // Save database if (fixed > 0) { const data = db.export(); fs.writeFileSync(DB_PATH, data); console.log(`\nāœ… Updated ${fixed} recipes with images`); } db.close(); console.log(`\nšŸ“Š Summary:`); console.log(` - Recipes with images: ${withImages}`); console.log(` - Recipes fixed: ${fixed}`); console.log(` - Still missing images: ${withoutImages}`); } auditAndFixImages().catch(console.error);