Sync checkup flags with image harmonize; tighten gallery collision and exit-to-timeline.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
41d2d5d844
commit
67594ea4d3
@@ -1,11 +1,13 @@
|
||||
/**
|
||||
* Bidirectional image harmonize (dev <-> prod) by file mtime,
|
||||
* then merge artists/paintings catalog rows (checkup flags + image paths),
|
||||
* then regenerate painting + portrait thumbnails on both image roots.
|
||||
*
|
||||
* Usage:
|
||||
* npm run harmonize:images
|
||||
* npm run harmonize:images -- --dry-run
|
||||
* npm run harmonize:images -- --skip-thumbnails
|
||||
* npm run harmonize:images -- --skip-db
|
||||
*/
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
@@ -17,6 +19,9 @@ const { printCliResult } = require('./lib/cli-result');
|
||||
const IMAGE_SUBDIRS = ['portraits', 'paintings'];
|
||||
const MTIME_TOLERANCE_MS = 1000;
|
||||
|
||||
/** Tables that carry checkup flags and image/portrait path links. */
|
||||
const IMAGE_CATALOG_TABLES = ['artists', 'paintings'];
|
||||
|
||||
const THUMB_SCRIPTS = [
|
||||
'regenerate-thumbnails.js',
|
||||
'regenerate-portrait-thumbs.js',
|
||||
@@ -24,10 +29,13 @@ const THUMB_SCRIPTS = [
|
||||
|
||||
function parseArgs(argv) {
|
||||
const configArg = argv.find((a) => a.startsWith('--config='));
|
||||
const preferArg = argv.find((a) => a.startsWith('--prefer='));
|
||||
return {
|
||||
dryRun: argv.includes('--dry-run'),
|
||||
verbose: argv.includes('--verbose'),
|
||||
skipThumbnails: argv.includes('--skip-thumbnails'),
|
||||
skipDb: argv.includes('--skip-db'),
|
||||
prefer: preferArg ? preferArg.slice('--prefer='.length).trim().toLowerCase() : null,
|
||||
configPath: configArg ? configArg.slice('--config='.length) : null,
|
||||
};
|
||||
}
|
||||
@@ -117,6 +125,35 @@ function regenerateThumbnails({ label, imageDir, database }) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge artists + paintings so checkup flags and image/portrait path links
|
||||
* travel with the file sync (harmonize:images alone used to leave DB stale).
|
||||
*/
|
||||
function syncImageCatalogRows({ dryRun, prefer, verbose }) {
|
||||
console.log('\n--- Catalog (artists + paintings checkup / image paths) ---');
|
||||
const args = [
|
||||
path.join(__dirname, 'harmonize-db.js'),
|
||||
`--tables=${IMAGE_CATALOG_TABLES.join(',')}`,
|
||||
];
|
||||
if (dryRun) args.push('--dry-run');
|
||||
if (verbose) args.push('--verbose');
|
||||
if (prefer === 'dev' || prefer === 'prod') args.push(`--prefer=${prefer}`);
|
||||
|
||||
const result = spawnSync(process.execPath, args, {
|
||||
cwd: rootDir,
|
||||
stdio: 'inherit',
|
||||
env: {
|
||||
...process.env,
|
||||
// Parent already confirmed prod writes for this harmonize:images run.
|
||||
CONFIRM_PROD: '1',
|
||||
},
|
||||
});
|
||||
const code = result.status ?? 1;
|
||||
if (code !== 0) {
|
||||
throw new Error(`Image catalog sync failed: harmonize-db.js exited ${code}`);
|
||||
}
|
||||
}
|
||||
|
||||
function timestampSlug(date = new Date()) {
|
||||
const pad = (n) => String(n).padStart(2, '0');
|
||||
return [
|
||||
@@ -146,7 +183,7 @@ async function main() {
|
||||
|
||||
if (!dryRun && process.env.CONFIRM_PROD !== '1') {
|
||||
await confirmProdAction(
|
||||
'Harmonize will copy image files between dev and prod, then regenerate painting and portrait thumbnails on both sides (prod files and gallery_prod paths may be updated).',
|
||||
'Harmonize will copy image files between dev and prod, merge artists/paintings checkup flags and image paths, then regenerate thumbnails on both sides (prod files and gallery_prod may be updated).',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -205,7 +242,23 @@ async function main() {
|
||||
fs.mkdirSync(reportDir, { recursive: true });
|
||||
const reportPath = path.join(reportDir, `harmonize_images_${timestampSlug()}.json`);
|
||||
|
||||
const thumbDetails = [];
|
||||
const extraDetails = [];
|
||||
|
||||
if (!options.skipDb) {
|
||||
syncImageCatalogRows({
|
||||
dryRun,
|
||||
prefer: options.prefer,
|
||||
verbose: options.verbose,
|
||||
});
|
||||
extraDetails.push(
|
||||
dryRun
|
||||
? 'Catalog checkup/path sync previewed (artists, paintings; dry-run)'
|
||||
: 'Catalog checkup flags + image paths merged (artists, paintings)',
|
||||
);
|
||||
} else {
|
||||
extraDetails.push('Catalog checkup/path sync skipped (--skip-db)');
|
||||
}
|
||||
|
||||
if (!dryRun && !options.skipThumbnails) {
|
||||
require('dotenv').config({ path: path.join(rootDir, '.env') });
|
||||
const devDb = process.env.DB_NAME || 'gallery_dev';
|
||||
@@ -215,24 +268,26 @@ async function main() {
|
||||
imageDir: devDir,
|
||||
database: devDb,
|
||||
});
|
||||
thumbDetails.push(`Dev thumbs regenerated (${devDb} @ ${devDir})`);
|
||||
extraDetails.push(`Dev thumbs regenerated (${devDb} @ ${devDir})`);
|
||||
|
||||
regenerateThumbnails({
|
||||
label: 'prod',
|
||||
imageDir: prodDir,
|
||||
database: PROD_DB_NAME,
|
||||
});
|
||||
thumbDetails.push(`Prod thumbs regenerated (${PROD_DB_NAME} @ ${prodDir})`);
|
||||
extraDetails.push(`Prod thumbs regenerated (${PROD_DB_NAME} @ ${prodDir})`);
|
||||
} else if (options.skipThumbnails) {
|
||||
thumbDetails.push('Thumbnails skipped (--skip-thumbnails)');
|
||||
extraDetails.push('Thumbnails skipped (--skip-thumbnails)');
|
||||
} else {
|
||||
thumbDetails.push('Thumbnails skipped (dry-run)');
|
||||
extraDetails.push('Thumbnails skipped (dry-run)');
|
||||
}
|
||||
|
||||
fs.writeFileSync(reportPath, JSON.stringify({
|
||||
generatedAt: new Date().toISOString(),
|
||||
dryRun,
|
||||
skipThumbnails: options.skipThumbnails,
|
||||
skipDb: options.skipDb,
|
||||
prefer: options.prefer,
|
||||
devDir,
|
||||
prodDir,
|
||||
stats: {
|
||||
@@ -240,7 +295,7 @@ async function main() {
|
||||
prodToDev: stats.prodToDev,
|
||||
skipped: stats.skipped,
|
||||
},
|
||||
thumbnails: thumbDetails,
|
||||
steps: extraDetails,
|
||||
actions: options.verbose ? stats.actions : stats.actions.slice(0, 500),
|
||||
}, null, 2));
|
||||
|
||||
@@ -253,7 +308,7 @@ async function main() {
|
||||
`Dev: ${devDir}`,
|
||||
`Prod: ${prodDir}`,
|
||||
`Report: ${reportPath}`,
|
||||
...thumbDetails,
|
||||
...extraDetails,
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user