78 lines
2.2 KiB
JavaScript
78 lines
2.2 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Scans ./img recursively and writes ./images.json — the manifest the
|
|
* single-page app fetches at runtime. No backend required.
|
|
*
|
|
* Usage:
|
|
* node scripts/generate-manifest.mjs
|
|
*
|
|
* Re-run this whenever you add, rename, or remove images.
|
|
*/
|
|
import { readdir, stat, writeFile } from "node:fs/promises";
|
|
import { join, relative, sep, extname } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const ROOT = fileURLToPath(new URL("..", import.meta.url));
|
|
const IMG_DIR = join(ROOT, "img");
|
|
const OUT_FILE = join(ROOT, "images.json");
|
|
|
|
const IMAGE_EXTS = new Set([
|
|
".png", ".jpg", ".jpeg", ".gif", ".webp", ".avif",
|
|
".svg", ".bmp", ".ico", ".tif", ".tiff",
|
|
]);
|
|
|
|
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: "base" });
|
|
|
|
async function walk(dir) {
|
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
const files = [];
|
|
|
|
for (const entry of entries) {
|
|
if (entry.name.startsWith(".")) continue; // skip dotfiles/dirs
|
|
const full = join(dir, entry.name);
|
|
|
|
if (entry.isDirectory()) {
|
|
files.push(...(await walk(full)));
|
|
} else if (entry.isFile() && IMAGE_EXTS.has(extname(entry.name).toLowerCase())) {
|
|
const info = await stat(full);
|
|
files.push({
|
|
name: entry.name,
|
|
path: relative(ROOT, full).split(sep).join("/"), // POSIX-style for URLs
|
|
size: info.size,
|
|
mtime: info.mtime.toISOString(),
|
|
});
|
|
}
|
|
}
|
|
return files;
|
|
}
|
|
|
|
async function main() {
|
|
let files;
|
|
try {
|
|
files = await walk(IMG_DIR);
|
|
} catch (err) {
|
|
if (err.code === "ENOENT") {
|
|
console.error(`✗ Image folder not found: ${IMG_DIR}`);
|
|
console.error(" Create it and add some images, then re-run.");
|
|
process.exit(1);
|
|
}
|
|
throw err;
|
|
}
|
|
|
|
files.sort((a, b) => collator.compare(a.path, b.path));
|
|
|
|
const manifest = {
|
|
generatedAt: new Date().toISOString(),
|
|
count: files.length,
|
|
images: files,
|
|
};
|
|
|
|
await writeFile(OUT_FILE, JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
console.log(`✓ Wrote ${files.length} image${files.length === 1 ? "" : "s"} to images.json`);
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|