Files
netris-nestri/apps/nexus/src/image/banner.ts
2024-09-01 00:34:50 +03:00

73 lines
2.7 KiB
TypeScript

import { Hono } from 'hono'
import { kvCaches } from "@nestri/cache"
import resize, { initResize } from '@jsquash/resize';
import decodeJpeg, { init as initDecodeJpeg } from '@jsquash/jpeg/decode';
import encodeAvif, { init as initEncodeAvif } from '@jsquash/avif/encode.js';
import JPEG_DEC_WASM from "@jsquash/jpeg/codec/dec/mozjpeg_dec.wasm";
import RESIZE_WASM from "@jsquash/resize/lib/resize/pkg/squoosh_resize_bg.wasm";
import AVIF_ENC_WASM from "@jsquash/avif/codec/enc/avif_enc.wasm";
const cacheOptions = {
key: "nexus",
namespace: "cover-cache"
};
const middleware = kvCaches(cacheOptions);
const decodeImage = async (buffer: ArrayBuffer) => {
await initDecodeJpeg(JPEG_DEC_WASM);
return decodeJpeg(buffer);
}
const resizeImage = async (image: { width: number; height: number }, width: number, height: number) => {
await initResize(RESIZE_WASM);
// Resize image with respect to aspect ratio
const aspectRatio = image.width / image.height;
const newWidth = width;
const newHeight = width / aspectRatio;
return resize(image, { width: newWidth, height: newHeight, fitMethod: "stretch" });
}
const encodeImage = async (image: { width: number; height: number }, format: string) => {
if (format === 'avif') {
await initEncodeAvif(AVIF_ENC_WASM);
return encodeAvif(image);
}
throw new Error(`Unsupported image format: ${format}`);
}
const app = new Hono()
app.notFound((c) => c.json({ message: 'Not Found', ok: false }, 404))
app.get('/:id', middleware, async (c) => {
const [gameId, imageType] = c.req.param("id").split('.');
const width = parseInt(c.req.query("width") || "460");
//We don't even use this, but let us keep it for future use
const height = parseInt(c.req.query("height") || "215");
if (!gameId || !imageType) {
return c.text("Invalid image parameters", 400)
}
//Support Avif only because of it's small size
const validImageTypes = ["avif"] //['jpg', 'png', 'webp', 'avif'];
if (!validImageTypes.includes(imageType)) {
return c.text('Invalid image type', 400);
}
const imageUrl = `https://shared.cloudflare.steamstatic.com/store_item_assets/steam/apps/${gameId}/header.jpg`;
const image = await fetch(imageUrl);
if (!image.ok) {
return c.text('Image not found', 404);
}
const imageBuffer = await image.arrayBuffer();
const imageData = await decodeImage(imageBuffer);
const resizedImage = await resizeImage(imageData, width, height);
const resizedImageBuffer = await encodeImage(resizedImage, imageType);
return c.newResponse(resizedImageBuffer, 200, {
"Content-Type": `image/${imageType}`,
'Cache-Control': 'public, max-age=31536000, immutable'
})
})
export default app