118 lines
4.1 KiB
JavaScript
118 lines
4.1 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Relink variants for existing Photo docs based on files in uploads/.
|
|
* For each Photo doc, derive baseName from its filename and fill in:
|
|
* - path -> uploads/<base>-main (or first available in group)
|
|
* - variants.medium / variants.thumb -> matching files if present
|
|
*
|
|
* Dry run by default; set APPLY=1 to save.
|
|
*/
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const mongoose = require('mongoose');
|
|
const Photo = require('../models/photo');
|
|
|
|
const MONGO_URI = process.env.MONGO_URI || 'mongodb://localhost:27017/photogallery';
|
|
const APPLY = process.env.APPLY === '1';
|
|
const UPLOAD_DIR = path.join(__dirname, '..', 'uploads');
|
|
const VARIANT_KEYS = { '': 'main', '-md': 'medium', '-sm': 'thumb' };
|
|
|
|
function parseFile(file) {
|
|
const ext = path.extname(file);
|
|
if (ext.toLowerCase() !== '.webp') return null;
|
|
const base = path.basename(file, ext);
|
|
const match = base.match(/^(.*?)(-md|-sm)?$/);
|
|
if (!match) return null;
|
|
return { baseName: match[1], variantKey: VARIANT_KEYS[match[2] || ''], filename: file };
|
|
}
|
|
|
|
function scanUploads() {
|
|
const groups = {};
|
|
const files = fs.readdirSync(UPLOAD_DIR).filter(f => f.toLowerCase().endsWith('.webp'));
|
|
for (const file of files) {
|
|
const parsed = parseFile(file);
|
|
if (!parsed) continue;
|
|
const { baseName, variantKey, filename } = parsed;
|
|
if (!groups[baseName]) groups[baseName] = {};
|
|
groups[baseName][variantKey] = filename;
|
|
}
|
|
return groups;
|
|
}
|
|
|
|
async function main() {
|
|
await mongoose.connect(MONGO_URI);
|
|
console.log(`Connected to Mongo: ${MONGO_URI}`);
|
|
const groups = scanUploads();
|
|
let updated = 0;
|
|
const missingGroups = [];
|
|
|
|
const docs = await Photo.find({});
|
|
// Index docs by filename/path and baseName to improve matching
|
|
const byFilename = new Map();
|
|
const byPath = new Map();
|
|
const byBase = new Map(); // baseName -> array of docs
|
|
for (const doc of docs) {
|
|
const fname = doc.filename || path.basename(doc.path || '');
|
|
byFilename.set(fname, doc);
|
|
if (doc.path) {
|
|
const rel = doc.path.replace(/\\/g, '/');
|
|
byPath.set(rel.startsWith('uploads/') ? rel.slice(''.length) : rel, doc);
|
|
byPath.set(rel, doc);
|
|
}
|
|
const parsed = parseFile(fname);
|
|
if (parsed) {
|
|
const arr = byBase.get(parsed.baseName) || [];
|
|
arr.push(doc);
|
|
byBase.set(parsed.baseName, arr);
|
|
}
|
|
}
|
|
|
|
for (const [baseName, variants] of Object.entries(groups)) {
|
|
const mainFile = variants.main || Object.values(variants)[0];
|
|
const relMain = path.join('uploads', mainFile).replace(/\\/g, '/');
|
|
let doc =
|
|
byFilename.get(mainFile) ||
|
|
byPath.get(relMain) ||
|
|
(() => {
|
|
const arr = byBase.get(baseName) || [];
|
|
return arr.length === 1 ? arr[0] : null;
|
|
})();
|
|
|
|
if (!doc) {
|
|
missingGroups.push(baseName);
|
|
continue;
|
|
}
|
|
|
|
const newPath = relMain;
|
|
const newVariants = {
|
|
medium: variants.medium ? path.join('uploads', variants.medium).replace(/\\/g, '/') : undefined,
|
|
thumb: variants.thumb ? path.join('uploads', variants.thumb).replace(/\\/g, '/') : undefined,
|
|
};
|
|
|
|
const pathChanged = doc.path !== newPath;
|
|
const medChanged = (doc.variants?.medium || undefined) !== newVariants.medium;
|
|
const thumbChanged = (doc.variants?.thumb || undefined) !== newVariants.thumb;
|
|
|
|
if (pathChanged || medChanged || thumbChanged) {
|
|
if (APPLY) {
|
|
doc.path = newPath;
|
|
doc.variants = newVariants;
|
|
await doc.save();
|
|
}
|
|
updated++;
|
|
}
|
|
}
|
|
|
|
console.log(`Relinked variants for ${updated} photos.${APPLY ? '' : ' (dry run, no writes)'}`);
|
|
if (missingGroups.length) {
|
|
const sample = missingGroups.slice(0, 10).join(', ');
|
|
console.log(`Skipped ${missingGroups.length} upload groups with no matching Photo doc. Examples: ${sample}`);
|
|
}
|
|
await mongoose.disconnect();
|
|
}
|
|
|
|
main().catch(err => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|