91 lines
2.4 KiB
TypeScript
91 lines
2.4 KiB
TypeScript
import { readdir } from "fs/promises";
|
|
import { join } from "path";
|
|
import { createHash } from "crypto";
|
|
import exifr from "exifr";
|
|
import { z } from "zod";
|
|
|
|
const galleryDir = import.meta.dev
|
|
? join(process.cwd(), "public/gallery")
|
|
: join(process.cwd(), ".output/public/gallery");
|
|
|
|
const exifSchema = z.object({
|
|
DateTimeOriginal: z.date(),
|
|
Make: z.string(),
|
|
Model: z.string(),
|
|
LensModel: z.string(),
|
|
FNumber: z.number(),
|
|
ExposureTime: z.number(),
|
|
ISO: z.number(),
|
|
FocalLength: z.number(),
|
|
ExifImageWidth: z.number(),
|
|
ExifImageHeight: z.number(),
|
|
});
|
|
|
|
export default defineCachedEventHandler(
|
|
async () => {
|
|
try {
|
|
const files = await readdir(galleryDir);
|
|
const imageFiles = files.filter((file) =>
|
|
/\.(jpg|jpeg|png|webp)$/i.test(file),
|
|
);
|
|
|
|
const imagesWithExif = await Promise.all(
|
|
imageFiles.map(async (filename) => {
|
|
const filePath = join(galleryDir, filename);
|
|
const rawExif = await exifr.parse(filePath, {
|
|
tiff: true,
|
|
exif: true,
|
|
gps: false,
|
|
interop: false,
|
|
ifd1: false,
|
|
});
|
|
|
|
const exif = exifSchema.parse(rawExif);
|
|
|
|
return {
|
|
filename,
|
|
url: `/gallery/${filename}`,
|
|
width: exif.ExifImageWidth,
|
|
height: exif.ExifImageHeight,
|
|
exif: {
|
|
date: exif.DateTimeOriginal,
|
|
camera: `${exif.Make} ${exif.Model}`,
|
|
lens: exif.LensModel,
|
|
settings: {
|
|
aperture: `f/${exif.FNumber}`,
|
|
shutter: `1/${Math.round(1 / exif.ExposureTime)}s`,
|
|
iso: String(exif.ISO),
|
|
focalLength: `${exif.FocalLength}mm`,
|
|
},
|
|
},
|
|
};
|
|
}),
|
|
);
|
|
|
|
return imagesWithExif;
|
|
} catch (err) {
|
|
console.log(err);
|
|
throw createError({
|
|
statusCode: 500,
|
|
message: "Failed to read gallery directory",
|
|
});
|
|
}
|
|
},
|
|
{
|
|
maxAge: 60 * 60 * 24,
|
|
getKey: async () => {
|
|
try {
|
|
const files = await readdir(galleryDir);
|
|
const imageFiles = files.filter((file) =>
|
|
/\.(jpg|jpeg|png|webp)$/i.test(file),
|
|
);
|
|
const filesConcat = imageFiles.sort().join("");
|
|
const hash = createHash("sha256").update(filesConcat).digest("hex");
|
|
return `gallery:${hash}`;
|
|
} catch {
|
|
return "gallery:0";
|
|
}
|
|
},
|
|
},
|
|
);
|