Files
yt2press/compress-images.js
2026-07-13 20:12:51 +07:00

94 lines
2.2 KiB
JavaScript

import fs from "node:fs/promises";
import path from "node:path";
import sharp from "sharp";
const SRC_DIR = path.resolve("docs/public"); // change if needed
const OUT_DIR = path.resolve("docs/public/images"); // change if needed
const MAX_W = 800;
const MAX_H = 600;
const FORMAT = "webp";
const WEBP_QUALITY = 75; // tweak 60-85 if you want smaller/larger
async function walk(dir) {
const entries = await fs.readdir(dir, { withFileTypes: true });
console.log(dir, entries.filter((e) => !e.isDirectory()).length);
const files = [];
for (const e of entries) {
const p = path.join(dir, e.name);
if (p === OUT_DIR) continue;
if (e.isDirectory()) files.push(...(await walk(p)));
else files.push(p);
}
return files;
}
function isImage(file) {
return /\.(png|jpe?g|webp|avif)$/i.test(file);
}
async function ensureDir(p) {
await fs.mkdir(p, { recursive: true });
}
async function processOne(inPath, outPathBase) {
await ensureDir(path.dirname(outPathBase));
await sharp(inPath)
.rotate() // respects EXIF orientation
.resize({
width: MAX_W,
height: MAX_H,
fit: "inside", // preserve aspect, fit within box
withoutEnlargement: true, // don't upscale small images
})
.toFormat(FORMAT, {
quality: WEBP_QUALITY,
effort: 4,
})
.toFile(`${outPathBase}.${FORMAT}`);
}
async function main() {
const files = (await walk(SRC_DIR)).filter(isImage);
await ensureDir(OUT_DIR);
let done = 0;
for (const inPath of files) {
const rel = path.relative(SRC_DIR, inPath);
// strip original extension and write same relative path
const outBase = path
.join(OUT_DIR, rel)
.replace(/\.(png|jpe?g|webp|avif)$/i, "");
const outPath = `${outBase}.${FORMAT}`;
// simple cache: skip if output exists and is newer than input
try {
const [stIn, stOut] = await Promise.all([
fs.stat(inPath),
fs.stat(outPath),
]);
if (stOut.mtimeMs >= stIn.mtimeMs) continue;
} catch {
// output missing -> process
}
await processOne(inPath, outBase);
done++;
}
console.log(
`Optimized ${done} image(s) to max ${MAX_W}x${MAX_H} (${FORMAT}).`,
);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});