Replace entire repo content with correct code from /root/shahikitchen-website/
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Sync sweets videos: ftp-images/bilder-bp/sweets/{dish}/bild/*.mp4 → public/videos/{dishId}.mp4
|
||||
* Then compress to uniform 640×480, ≤ 200 KB for modal playback.
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/sync-sweets-videos.mjs
|
||||
* node scripts/sync-sweets-videos.mjs --dry-run
|
||||
* node scripts/sync-sweets-videos.mjs --skip-optimize
|
||||
*/
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { spawnSync } from 'child_process';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
const SOURCE_DIR = path.join(ROOT, 'ftp-images/bilder-bp/sweets');
|
||||
const OUTPUT_DIR = path.join(ROOT, 'public/videos');
|
||||
const REPORT_PATH = path.join(__dirname, 'sweets-videos-sync-report.json');
|
||||
|
||||
const DRY_RUN = process.argv.includes('--dry-run');
|
||||
const SKIP_OPTIMIZE = process.argv.includes('--skip-optimize');
|
||||
|
||||
const FOLDER_TO_DISH = {
|
||||
'badam-barfi': 'badam-barfi',
|
||||
'besan-patisa': 'baisan-patisa',
|
||||
'cham-cham': 'cham-cham',
|
||||
'chochlate-barfi': 'chocolate-barfi',
|
||||
'coconut-barfi': 'coconut-barfi',
|
||||
'gajar-barfi': 'gajar-barfi',
|
||||
'gulab-jaman': 'gulab-jaman',
|
||||
'habshi-halwa': 'habshi-halwa',
|
||||
'jalebi': 'jalebi',
|
||||
'laddu': 'laddu',
|
||||
'milk-cake-akhrot': 'milk-cake-akhrot',
|
||||
'milk-cake-plain': 'milk-cake-plain',
|
||||
'namak-paray': 'namakpare',
|
||||
'paira': 'paira',
|
||||
'patisa': 'patisa',
|
||||
'pink-barfi': 'pink-barfi',
|
||||
'pistacho-barfi': 'pistachio-barfi',
|
||||
'qalakand': 'qalakand',
|
||||
'ras-gulay': 'ras-gulay',
|
||||
'ras-malai': 'rasmalai',
|
||||
'shakar-paray': 'shakar-paray',
|
||||
'cream-gulab-jaman': 'cream-gulab-jaman',
|
||||
'lambay-gulab-jaman': 'lambay-gulab-jaman',
|
||||
'milk-cake-khajoor': 'milk-cake-khajoor',
|
||||
'plain-barfi': 'plain-barfi',
|
||||
'baisan-barfi': 'baisan-barfi',
|
||||
'besan-barfi': 'baisan-barfi',
|
||||
'basen-barfi': 'baisan-barfi',
|
||||
};
|
||||
|
||||
const SKIP_FOLDERS = new Set(['samosa-aloo', 'samosa-keema', 'samosa-chaat']);
|
||||
|
||||
function normalize(value) {
|
||||
return String(value || '')
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '');
|
||||
}
|
||||
|
||||
function pickVideo(files) {
|
||||
const mp4s = files.filter((f) => /\.mp4$/i.test(f));
|
||||
if (!mp4s.length) return null;
|
||||
return mp4s.sort((a, b) => a.localeCompare(b))[0];
|
||||
}
|
||||
|
||||
function runOptimize(fileName) {
|
||||
const r = spawnSync(process.execPath, [path.join(__dirname, 'optimize-sweets-videos.mjs'), fileName], {
|
||||
stdio: 'inherit',
|
||||
cwd: ROOT,
|
||||
});
|
||||
return r.status === 0;
|
||||
}
|
||||
|
||||
function main() {
|
||||
console.log('Shahi Kitchen — sweets video sync\n');
|
||||
if (!fs.existsSync(SOURCE_DIR)) throw new Error(`Missing: ${SOURCE_DIR}`);
|
||||
if (!DRY_RUN) fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||
|
||||
const synced = [];
|
||||
|
||||
for (const folder of fs.readdirSync(SOURCE_DIR, { withFileTypes: true })) {
|
||||
if (!folder.isDirectory()) continue;
|
||||
const folderNorm = normalize(folder.name);
|
||||
if (SKIP_FOLDERS.has(folderNorm)) continue;
|
||||
|
||||
const dishId = FOLDER_TO_DISH[folderNorm];
|
||||
if (!dishId) {
|
||||
console.log(`⚠ Unmapped folder: ${folder.name}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const mediaDir = ['bild', 'bilder']
|
||||
.map((sub) => path.join(SOURCE_DIR, folder.name, sub))
|
||||
.find((d) => fs.existsSync(d));
|
||||
if (!mediaDir) continue;
|
||||
|
||||
const videoFile = pickVideo(fs.readdirSync(mediaDir));
|
||||
if (!videoFile) continue;
|
||||
|
||||
const src = path.join(mediaDir, videoFile);
|
||||
const outputFile = `${dishId}.mp4`;
|
||||
const dest = path.join(OUTPUT_DIR, outputFile);
|
||||
|
||||
if (!DRY_RUN) {
|
||||
fs.copyFileSync(src, dest);
|
||||
if (!SKIP_OPTIMIZE) {
|
||||
console.log(` optimizing ${outputFile}…`);
|
||||
runOptimize(outputFile);
|
||||
}
|
||||
}
|
||||
|
||||
const kb = (DRY_RUN ? fs.statSync(src).size : fs.statSync(dest).size) / 1024;
|
||||
synced.push({ dishId, folder: folder.name, sourceFile: videoFile, outputFile, kb: Number(kb.toFixed(1)) });
|
||||
const sub = path.basename(mediaDir);
|
||||
console.log(`✓ ${dishId} ← ${folder.name}/${sub}/${videoFile} (${kb.toFixed(0)} KB)`);
|
||||
}
|
||||
|
||||
const report = { generatedAt: new Date().toISOString(), dryRun: DRY_RUN, synced };
|
||||
if (!DRY_RUN) fs.writeFileSync(REPORT_PATH, JSON.stringify(report, null, 2));
|
||||
console.log(`\nSynced: ${synced.length} videos`);
|
||||
if (!DRY_RUN) console.log(`Report: ${REPORT_PATH}`);
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user