Expand the gallery with prev/next browsing and fullscreen detail view, golden influence lamps and chronological wall layout in 3D halls, and scripts/docs for catalog expansion, influence edges, and multi-source image fetching. Co-authored-by: Cursor <cursoragent@cursor.com>
71 lines
2.0 KiB
JavaScript
71 lines
2.0 KiB
JavaScript
/**
|
|
* Find paintings whose thumbnail aspect ratio differs from the full image
|
|
* (likely wrong thumbnail from an external search result).
|
|
*/
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const sharp = require('sharp');
|
|
const pool = require('../server/db');
|
|
|
|
const IMAGE_DIR = path.resolve(process.env.IMAGE_DIR || './data/images');
|
|
|
|
function localPath(rel) {
|
|
return path.join(IMAGE_DIR, rel);
|
|
}
|
|
|
|
async function aspectRatio(filePath) {
|
|
const meta = await sharp(filePath).metadata();
|
|
if (!meta.width || !meta.height) return null;
|
|
return meta.width / meta.height;
|
|
}
|
|
|
|
(async () => {
|
|
const rows = await pool.query(
|
|
`SELECT p.id, p.title, p.image_path, p.thumbnail_path, a.name AS artist_name
|
|
FROM paintings p
|
|
JOIN artists a ON a.id = p.artist_id
|
|
WHERE p.image_path IS NOT NULL AND p.thumbnail_path IS NOT NULL
|
|
ORDER BY a.name, p.title`
|
|
);
|
|
|
|
const mismatches = [];
|
|
|
|
for (const row of rows.rows) {
|
|
const fullPath = localPath(row.image_path);
|
|
const thumbPath = localPath(row.thumbnail_path);
|
|
if (!fs.existsSync(fullPath) || !fs.existsSync(thumbPath)) continue;
|
|
|
|
try {
|
|
const [fullAr, thumbAr] = await Promise.all([
|
|
aspectRatio(fullPath),
|
|
aspectRatio(thumbPath),
|
|
]);
|
|
if (!fullAr || !thumbAr) continue;
|
|
const delta = Math.abs(fullAr - thumbAr) / fullAr;
|
|
if (delta > 0.15) {
|
|
mismatches.push({
|
|
id: row.id,
|
|
artist: row.artist_name,
|
|
title: row.title,
|
|
fullAr: fullAr.toFixed(3),
|
|
thumbAr: thumbAr.toFixed(3),
|
|
delta: (delta * 100).toFixed(1) + '%',
|
|
});
|
|
}
|
|
} catch {
|
|
/* ignore unreadable files */
|
|
}
|
|
}
|
|
|
|
console.log('Checked:', rows.rows.length);
|
|
console.log('Aspect-ratio mismatches:', mismatches.length);
|
|
mismatches.forEach((m) =>
|
|
console.log(`#${m.id} ${m.artist} — ${m.title} (full ${m.fullAr}, thumb ${m.thumbAr}, Δ ${m.delta})`)
|
|
);
|
|
|
|
await pool.end();
|
|
})().catch((err) => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|