diff --git a/src/pages/og/[...slug].png.ts b/src/pages/og/[...slug].png.ts new file mode 100644 index 0000000..94a1a41 --- /dev/null +++ b/src/pages/og/[...slug].png.ts @@ -0,0 +1,24 @@ +import type { APIContext, APIRoute } from "astro"; +import { getEntry } from "astro:content"; +import { getOgImage } from "./_OgImage"; + +export const prerender = false; + +export async function GET({ params, redirect }: APIContext) { + const { slug } = params; + if (slug === undefined) { + return new Response(null, { + status: 500, + statusText: "No slug provided", + }); + } + const post = await getEntry("post", slug); + if (post === undefined) { + return new Response(null, { + status: 404, + statusText: "Not found", + }); + } + const body = await getOgImage(post?.data.title ?? "No title"); + return new Response(body); +} diff --git a/src/pages/og/_OgImage.tsx b/src/pages/og/_OgImage.tsx new file mode 100644 index 0000000..d4780c5 --- /dev/null +++ b/src/pages/og/_OgImage.tsx @@ -0,0 +1,130 @@ +import satori from "satori"; +import sharp from "sharp"; + +interface OgImageProps { + text: string; +} + +const OgImage = ({ text }: OgImageProps): JSX.Element => { + return ( + + + {text} + + + + + + + + ゆっきー + + + ゆっきーの砂場 + + + + + ); +}; +export async function getOgImage(text: string): Promise { + const notoSansJpUrl = `https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@600`; + const reggeaeOneUlr = + "https://fonts.googleapis.com/css2?family=Reggae+One&display=swap&text=ゆっきーの砂場"; + const notoSansJpFontData = await getFontData(notoSansJpUrl); + const reggeaeOneFontData = await getFontData(reggeaeOneUlr); + const svg = await satori(, { + width: 800, + height: 400, + fonts: [ + { + name: "Noto Sans JP", + data: notoSansJpFontData, + style: "normal", + }, + { + name: "Reggae One", + data: reggeaeOneFontData, + style: "normal", + }, + ], + }); + + return await sharp(Buffer.from(svg)).png().toBuffer(); +} + +const getFontData = async (url: string): Promise => { + const css = await ( + await fetch(url, { + headers: { + "User-Agent": + "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1", + }, + }) + ).text(); + + const resource = css.match( + /src: url\((.+)\) format\('(opentype|truetype)'\)/ + ); + + if (resource === null) { + throw new Error("Font resource not found"); + } + + return await fetch(resource[1]).then(async (res) => await res.arrayBuffer()); +}; diff --git a/src/pages/post/[...slug].astro b/src/pages/post/[...slug].astro index 9c7e817..6b4dec5 100644 --- a/src/pages/post/[...slug].astro +++ b/src/pages/post/[...slug].astro @@ -10,7 +10,7 @@ export async function getStaticPaths() { const { entry } = Astro.props; const { Content } = await entry.render(); --- - + diff --git a/tsconfig.json b/tsconfig.json index 8a703f3..aa69280 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,10 @@ { "extends": "astro/tsconfigs/strict", "compilerOptions": { - "types": ["bun-types"] + "types": [ + "bun-types" + ], + "jsx": "react-jsx", + "jsxImportSource": "react" } -} +} \ No newline at end of file