| 1 | /** https://github.com/juliusmarminge/jumr.dev/blob/main/app/og-image/get-fonts.ts */ |
| 2 | |
| 3 | export async function getFont<TWeights extends readonly number[]>({ |
| 4 | family, |
| 5 | weights, |
| 6 | text, |
| 7 | }: { |
| 8 | family: string; |
| 9 | weights: TWeights; |
| 10 | text?: string; |
| 11 | }): Promise<Record<TWeights[number], ArrayBuffer>> { |
| 12 | const API = `https://fonts.googleapis.com/css2?family=${family}:wght@${weights.join( |
| 13 | ";", |
| 14 | )}${text ? `&text=${encodeURIComponent(text)}` : ""}`; |
| 15 | |
| 16 | const css = await ( |
| 17 | await fetch(API, { |
| 18 | headers: { |
| 19 | // Make sure it returns TTF. |
| 20 | "User-Agent": |
| 21 | "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", |
| 22 | }, |
| 23 | }) |
| 24 | ).text(); |
| 25 | |
| 26 | const fonts = css |
| 27 | .split("@font-face {") |
| 28 | .splice(1) |
| 29 | .map((font) => { |
| 30 | const u = /src: url\((.+)\) format\('(opentype|truetype)'\)/.exec(font); |
| 31 | const w = /font-weight: (\d+)/.exec(font); |
| 32 | return u?.[1] && w?.[1] ? { url: u[1], weight: parseInt(w[1]) } : null; |
| 33 | }) |
| 34 | .filter( |
| 35 | (font): font is { url: string; weight: TWeights[number] } => !!font, |
| 36 | ); |
| 37 | |
| 38 | const promises = fonts.map(async (font) => { |
| 39 | const res = await fetch(font.url); |
| 40 | return [font.weight, await res.arrayBuffer()]; |
| 41 | }); |
| 42 | |
| 43 | // Object.fromEntries is typed as returning any *sigh* |
| 44 | // eslint-disable-next-line @typescript-eslint/no-unsafe-return |
| 45 | return Object.fromEntries(await Promise.all(promises)); |
| 46 | } |