recipe-manager/audit-fix-images.js

76 lines
2.2 KiB
JavaScript

#!/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);