c64-basic/screenshot-cache.mjs

36 lines
1.4 KiB
JavaScript

import { createHash } from 'node:crypto';
import { readFileSync, statSync } from 'node:fs';
import { mkdir, stat, rename } from 'node:fs/promises';
import { join } from 'node:path';
import sharp from 'sharp';
const versions = new Map();
const pending = new Map();
const encoding = 'webp-q90-v1';
export function screenshotVersion(path) {
const info = statSync(path);
const signature = `${info.mtimeMs}:${info.ctimeMs}:${info.size}`;
const cached = versions.get(path);
if (cached?.signature === signature) return cached.version;
const version = createHash('sha256').update(encoding).update(readFileSync(path)).digest('hex');
versions.set(path, { signature, version });
return version;
}
export async function cachedScreenshot(source, directory, version) {
const destination = join(directory, `${version}.webp`);
if (pending.has(destination)) return pending.get(destination);
const conversion = (async () => {
await mkdir(directory, { recursive: true });
try { await stat(destination); return destination; }
catch (error) { if (error.code !== 'ENOENT') throw error; }
const temporary = `${destination}.${process.pid}.tmp`;
await sharp(source).webp({ quality: 90 }).toFile(temporary);
await rename(temporary, destination);
return destination;
})();
pending.set(destination, conversion);
try { return await conversion; }
finally { pending.delete(destination); }
}