/* eslint-disable @next/next/no-img-element */ import { ImageResponse } from "next/og"; import sharp from "sharp"; import { rarityGradient, rarityTextColor } from "@/lib/catalog/rarity"; import { getCachedPublicWeaponExport } from "@/lib/cache/public"; import { imageContentDisposition } from "@/lib/guides/export-image"; const anuphanFonts = Promise.all( [ { subset: "latin", weight: 400 as const }, { subset: "thai", weight: 400 as const }, { subset: "latin", weight: 700 as const }, { subset: "thai", weight: 700 as const }, ].map(async ({ subset, weight }) => { const response = await fetch( `https://unpkg.com/@fontsource/anuphan@5.3.0/files/anuphan-${subset}-${weight}-normal.woff`, ); if (!response.ok) throw new Error(`Unable to load Anuphan ${subset} ${weight}`); return { name: "Anuphan", data: await response.arrayBuffer(), weight, style: "normal" as const, }; }), ).catch(() => []); function metric(value: string): string { return `${Number(value).toLocaleString("en-US", { maximumFractionDigits: 2 })}%`; } async function pngDataUrl(url: string): Promise { try { const response = await fetch(url); if (!response.ok) return null; const png = await sharp(Buffer.from(await response.arrayBuffer())) .resize(120, 120, { fit: "contain" }) .png() .toBuffer(); return `data:image/png;base64,${png.toString("base64")}`; } catch { return null; } } export async function GET( _request: Request, context: { params: Promise<{ guideId: string }> }, ) { const { guideId } = await context.params; const guide = await getCachedPublicWeaponExport(guideId); if (!guide) return new Response("ไม่พบไกด์", { status: 404 }); const [fonts, weaponImages] = await Promise.all([ anuphanFonts, Promise.all(guide.weapons.map((row) => pngDataUrl(row.weapon.imageUrl))), ]); const weaponHeights = guide.weapons.map((row) => Math.max(126, 126 + (row.note ? Math.ceil(row.note.length / 52) * 22 : 0))); const height = Math.max(360, 190 + weaponHeights.reduce((sum, rowHeight) => sum + rowHeight, 0) + Math.max(0, guide.weapons.length - 1) * 14); return new ImageResponse(
อาวุธที่แนะนำ
อาวุธ
{guide.weapons.map((row, index) => (
{weaponImages[index] ? ( ) : (
{index + 1}
)}
{index + 1}. {row.weapon.name} R{row.refinement}
{row.note ?
{row.note}
: null}
{row.overallPercent ? (
{metric(row.overallPercent)}
ดาเมททั้งทีม
) : null} {row.personalPercent ? (
{metric(row.personalPercent)}
ดาเมจส่วนตัว
) : null}
))}
, { width: 1000, height, fonts: fonts.length ? fonts : undefined, headers: { "Cache-Control": "no-store", "Content-Disposition": imageContentDisposition(`${guide.guideName} อาวุธ`, "weapons"), "Content-Type": "image/png", }, }, ); }