diff --git a/bun.lock b/bun.lock index 8c52b4f5..e79fafc6 100644 --- a/bun.lock +++ b/bun.lock @@ -14,6 +14,7 @@ "astro": "^5.7.12", "astro-icon": "^1.1.5", "bits-ui": "^1.4.8", + "cheerio": "^1.0.0", "daisyui": "^5.0.35", "date-fns": "^4.1.0", "markdown-to-txt": "^2.0.1", diff --git a/package.json b/package.json index 99ae6842..6f0b21e3 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "astro": "^5.7.12", "astro-icon": "^1.1.5", "bits-ui": "^1.4.8", + "cheerio": "^1.0.0", "daisyui": "^5.0.35", "date-fns": "^4.1.0", "markdown-to-txt": "^2.0.1", diff --git a/src/pages/projects/[...id].astro b/src/pages/projects/[...id].astro index 03c16240..5f4857dd 100644 --- a/src/pages/projects/[...id].astro +++ b/src/pages/projects/[...id].astro @@ -8,6 +8,7 @@ import { getProjects } from "+/query"; import { Focus } from "+/schema.ts"; import type { GetStaticPaths } from "astro"; import { Icon } from "astro-icon/components"; +import { load as cheerioLoad } from "cheerio"; export const getStaticPaths = (async () => { const projects = await getProjects("all"); @@ -18,6 +19,31 @@ export const getStaticPaths = (async () => { }) satisfies GetStaticPaths; const { project } = Astro.props; const { Content } = await render(project); + +let iconSrc: string | undefined = undefined; +if (project.data.website && project.data.status !== "dead") { + const websiteRes = await fetch(project.data.website); + if (websiteRes.ok) { + const websiteHtml = await websiteRes.text(); + const website = cheerioLoad(websiteHtml); + const iconHref = website("link[rel='icon'], link[rel='shortcut icon']")[0] + ?.attribs.href; + if (iconHref) { + const faviconRes = await fetch(new URL(iconHref, project.data.website)); + iconSrc = `data:${faviconRes.headers.get("content-type")};base64,${Buffer.from(await faviconRes.arrayBuffer()).toString("base64")}`; + } else { + const faviconRes = await fetch( + `${new URL(project.data.website).origin}/favicon.ico`, + ); + if ( + faviconRes.ok && + !faviconRes.headers.get("content-type")?.startsWith("text/") + ) { + iconSrc = `data:${faviconRes.headers.get("content-type")};base64,${Buffer.from(await faviconRes.arrayBuffer()).toString("base64")}`; + } + } + } +} --- - + {iconSrc ? ( + favicon + ) : ( + + )} {project.data.title} へ )