mirror of
https://github.com/nestriness/nestri.git
synced 2025-12-15 02:05:37 +02:00
✨ feat: Add qwik-react (#103)
This adds the following pages: The landing page (/) The pricing page (/pricing) The contact page (/contact) The changelog page (/changelog) Terms Of Service page (/terms) Privacy Policy (/privacy)
This commit is contained in:
72
apps/nexus/src/image/banner.ts
Normal file
72
apps/nexus/src/image/banner.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
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") || "600");
|
||||
//We don't even use this, but let us keep it for future use
|
||||
const height = parseInt(c.req.query("height") || "900");
|
||||
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
|
||||
Reference in New Issue
Block a user