Comment the image generator
This commit is contained in:
parent
076433b21c
commit
9522e043a1
1 changed files with 25 additions and 18 deletions
|
|
@ -9,41 +9,36 @@ import { format } from "@tusbar/cache-control";
|
|||
const cache = new TTLCache({ max: 10000, ttl: 1000 * 60 * 60 })
|
||||
import fnv from "fnv-plus"
|
||||
|
||||
// import type { Endpoints } from "@octokit/types";
|
||||
|
||||
// let repoRegex = new RegExp("https?://github\.com/(?<repo>[a-zA-Z0-9]+/[a-zA-Z0-9]+)/?")
|
||||
|
||||
const fontFile = await fetch('https://og-playground.vercel.app/inter-latin-ext-700-normal.woff');
|
||||
const fontData: ArrayBuffer = await fontFile.arrayBuffer();
|
||||
|
||||
// const height = 630;
|
||||
// const width = 1200;
|
||||
const defaultWidth = 800;
|
||||
const defaultRatio = 0.5
|
||||
// const defaultWidth = 800;
|
||||
|
||||
// JSX stub
|
||||
const h = (type: any, props: any) => { return { type, props } }
|
||||
|
||||
type a = RequestHandler;
|
||||
/** @type {RequestHandler} */
|
||||
export async function GET({ url, request }) {
|
||||
// First, get the information about the post
|
||||
// We have the slug and date of the post, which we can use to look up the post
|
||||
const slug = url.searchParams.get('slug')
|
||||
let dateParts = url.searchParams.get('date')?.split(/[\/-]/)?.map((p: string) => parseInt(p, 10))
|
||||
if (dateParts && dateParts.length > 3) {
|
||||
throw error(404, 'Post not found (bad date)')
|
||||
}
|
||||
// Next, get the width and ratio of the image
|
||||
// to determine the size of the image
|
||||
const width = Number(url.searchParams.get('width'))
|
||||
const ratio = Number(url.searchParams.get('ratio'))
|
||||
// If the width or ratio is too big, don't render the image to prevent DoS attacks
|
||||
if (width > 10000 || ratio > 50) {
|
||||
throw error(400, 'Image too big')
|
||||
}
|
||||
let image;
|
||||
|
||||
// let start = new Date(dateParts[0] || 1, dateParts[1] || 0, dateParts[2] || 0);
|
||||
// // @ts-ignore
|
||||
// let end = new Date(...dateParts);
|
||||
// console.log(dateParts)
|
||||
|
||||
// get post with metadata
|
||||
// Look up the post in the database
|
||||
const page = pages
|
||||
.filter((post) => slug === post.slug)
|
||||
.filter((post) => {
|
||||
|
|
@ -61,16 +56,21 @@ export async function GET({ url, request }) {
|
|||
throw error(404, 'Post not found')
|
||||
}
|
||||
|
||||
// Generate a cache key based on the post's canonical URL, reading time, width, and ratio
|
||||
// Caching the image based on this key ensures that the image is not regenerated every time
|
||||
// The cache key is also used for browser caching
|
||||
let cache_key = fnv.hash(page.canonical + "\x00" + page.readingTime.text + "\x00" + width + "\x00" + ratio).str()
|
||||
|
||||
let recieved_etag = request.headers.get("if-none-match");
|
||||
|
||||
if (recieved_etag == cache_key) {
|
||||
console.log("304")
|
||||
let received_etag = request.headers.get("if-none-match");
|
||||
// If the client has a cached version of the image, return a 304 Not Modified response, indicating that the image has not changed
|
||||
// This means we don't even have to have the image cached in memory
|
||||
if (received_etag == cache_key) {
|
||||
return new Response(null, { status: 304 })
|
||||
}
|
||||
|
||||
// If the image is not cached, generate the image and cache it
|
||||
if (!cache.has(cache_key)) {
|
||||
// First, render the HTML / JSX-based template
|
||||
let template = h("div", {
|
||||
style: {
|
||||
display: 'flex',
|
||||
|
|
@ -114,6 +114,7 @@ export async function GET({ url, request }) {
|
|||
children: `Published on ${new Date(page.date).toLocaleDateString()} by Jade Ellis · ${page.readingTime.text}`
|
||||
})]
|
||||
});
|
||||
// Then, convert the vdom to SVG using satori
|
||||
const svg = await satori(template, {
|
||||
fonts: [
|
||||
{
|
||||
|
|
@ -126,6 +127,7 @@ export async function GET({ url, request }) {
|
|||
width: defaultWidth,
|
||||
});
|
||||
|
||||
// Then, convert the SVG to a PNG image using resvg
|
||||
const resvg = new Resvg(svg, {
|
||||
fitTo: {
|
||||
mode: 'width',
|
||||
|
|
@ -134,20 +136,25 @@ export async function GET({ url, request }) {
|
|||
});
|
||||
|
||||
image = resvg.render().asPng();
|
||||
// Finally, save the image to the cache
|
||||
cache.set(cache_key, image);
|
||||
} else {
|
||||
// If the image is cached, return it
|
||||
image = cache.get(cache_key) as Buffer
|
||||
}
|
||||
|
||||
// Finally, return the image as a response
|
||||
return new Response(image, {
|
||||
headers: {
|
||||
'Content-Type': 'image/png',
|
||||
// Cache the image for 24 hours
|
||||
'Cache-Control': format({
|
||||
public: true,
|
||||
// immutable: true
|
||||
maxAge: 60 * 60 * 24
|
||||
}),
|
||||
// Set the cache key as the ETag
|
||||
'ETag': cache_key,
|
||||
// Allow cross-origin requests to serve the image
|
||||
'Cross-Origin-Resource-Policy': 'cross-origin'
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue