Replace entire repo content with correct code from /root/shahikitchen-website/

This commit is contained in:
root
2026-06-29 16:22:09 +00:00
parent 57cc67d2d3
commit 50e3a34895
723 changed files with 20055 additions and 26101 deletions
+159
View File
@@ -0,0 +1,159 @@
#!/usr/bin/env node
/**
* Compress sweets modal videos → uniform 640×480 (4:3), ≤ 200 KB, no audio.
* Usage:
* node scripts/optimize-sweets-videos.mjs
* node scripts/optimize-sweets-videos.mjs public/videos/badam-barfi.mp4
*/
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { spawnSync } from 'child_process';
import ffmpegPath from 'ffmpeg-static';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const ROOT = path.join(__dirname, '..');
const VIDEOS_DIR = path.join(ROOT, 'public/videos');
const MENU_DATA = path.join(ROOT, 'infrastructure/menu/static-menu-data.ts');
const REPORT_PATH = path.join(__dirname, 'sweets-videos-optimize-report.json');
const MAX_BYTES = 200 * 1024;
const TARGET_WIDTH = 640;
const TARGET_HEIGHT = 480;
/** Sweets dish ids with video fields in menu data */
function getSweetsVideoFiles() {
const content = fs.readFileSync(MENU_DATA, 'utf8');
const sweetsIdx = content.indexOf('id: "sweets"');
const itemsStart = content.indexOf('items: [', sweetsIdx);
let depth = 0;
let itemsEnd = -1;
for (let i = itemsStart + 7; i < content.length; i++) {
if (content[i] === '[') depth++;
else if (content[i] === ']') {
depth--;
if (depth === 0) {
itemsEnd = i;
break;
}
}
}
const block = content.slice(itemsStart, itemsEnd + 1);
return [...block.matchAll(/video:\s*"([^"]+\.mp4)"/g)].map((m) => m[1]);
}
function compressVideo(inputPath, outputPath, { crf, fps, width, height }) {
const vf = `scale=${width}:${height}:force_original_aspect_ratio=increase,crop=${width}:${height},fps=${fps}`;
const result = spawnSync(
ffmpegPath,
[
'-y',
'-i', inputPath,
'-an',
'-vf', vf,
'-c:v', 'libx264',
'-preset', 'medium',
'-profile:v', 'baseline',
'-level', '3.0',
'-pix_fmt', 'yuv420p',
'-movflags', '+faststart',
'-crf', String(crf),
outputPath,
],
{ stdio: 'pipe' },
);
return result.status === 0 && fs.existsSync(outputPath);
}
function optimizeOne(inputPath) {
if (!fs.existsSync(inputPath)) return { skipped: true, reason: 'missing' };
const temp = `${inputPath}.opt.tmp.mp4`;
const attempts = [
{ crf: 34, fps: 24, width: TARGET_WIDTH, height: TARGET_HEIGHT },
{ crf: 36, fps: 20, width: TARGET_WIDTH, height: TARGET_HEIGHT },
{ crf: 38, fps: 18, width: TARGET_WIDTH, height: TARGET_HEIGHT },
{ crf: 40, fps: 15, width: 560, height: 420 },
{ crf: 42, fps: 12, width: 480, height: 360 },
{ crf: 44, fps: 10, width: 400, height: 300 },
];
let best = null;
for (const opts of attempts) {
if (fs.existsSync(temp)) fs.unlinkSync(temp);
if (!compressVideo(inputPath, temp, opts)) continue;
const bytes = fs.statSync(temp).size;
const entry = { ...opts, bytes, kb: Number((bytes / 1024).toFixed(1)) };
if (bytes <= MAX_BYTES) {
fs.renameSync(temp, inputPath);
return { ok: true, ...entry, warning: null };
}
if (!best || bytes < best.bytes) best = entry;
}
if (best && fs.existsSync(temp)) {
fs.renameSync(temp, inputPath);
return { ok: true, ...best, warning: 'exceeds-200kb' };
}
if (fs.existsSync(temp)) fs.unlinkSync(temp);
return { ok: false, reason: 'encode-failed' };
}
function main() {
if (!ffmpegPath) throw new Error('ffmpeg-static not available');
const arg = process.argv[2];
const files = arg
? [path.basename(arg).endsWith('.mp4') ? path.basename(arg) : `${arg}.mp4`]
: getSweetsVideoFiles();
console.log('Shahi Kitchen — sweets video optimize');
console.log(`Target: ${TARGET_WIDTH}×${TARGET_HEIGHT}, ≤ ${MAX_BYTES / 1024} KB\n`);
const results = [];
for (const file of files) {
const fullPath = path.join(VIDEOS_DIR, file);
const before = fs.existsSync(fullPath) ? fs.statSync(fullPath).size : 0;
const r = optimizeOne(fullPath);
if (r.skipped) {
console.log(`⚠ skip ${file} (${r.reason})`);
results.push({ file, skipped: true, reason: r.reason });
continue;
}
if (!r.ok) {
console.log(`${file} (${r.reason})`);
results.push({ file, ok: false, reason: r.reason });
continue;
}
const after = fs.statSync(fullPath).size;
const warn = r.warning ? ' ⚠' : '';
console.log(
`${file}: ${(before / 1024).toFixed(0)} KB → ${(after / 1024).toFixed(1)} KB ` +
`(${r.width}×${r.height}, crf ${r.crf}, ${r.fps}fps)${warn}`,
);
results.push({
file,
ok: true,
beforeKb: Number((before / 1024).toFixed(1)),
afterKb: Number((after / 1024).toFixed(1)),
width: r.width,
height: r.height,
crf: r.crf,
fps: r.fps,
warning: r.warning,
});
}
fs.writeFileSync(REPORT_PATH, JSON.stringify({ generatedAt: new Date().toISOString(), results }, null, 2));
console.log(`\nReport: ${REPORT_PATH}`);
}
main();