import { Context, Next } from "@oak/oak"; import { getDump } from "../services/dump-service.ts"; import { getUserByUsername } from "../services/user-service.ts"; import { getPlaylistById } from "../services/playlist-service.ts"; import { OG_SITE_NAME } from "../config.ts"; interface OGMeta { title: string; description?: string; imageUrl?: string; url: string; } function escapeAttr(s: string): string { return s .replace(/&/g, "&") .replace(/"/g, """) .replace(//g, ">"); } function buildTags(meta: OGMeta): string { const card = meta.imageUrl ? "summary_large_image" : "summary"; const tags = [ `${escapeAttr(meta.title)}`, ``, ``, ``, ``, ``, ]; if (meta.description) { tags.push( ``, ``, ); } if (meta.imageUrl) { tags.push( ``, ); } return tags.join("\n "); } function inject(html: string, meta: OGMeta): string { return html .replace(/[^<]*<\/title>/, "") .replace("</head>", ` ${buildTags(meta)}\n </head>`); } let cachedHtml: string | null | undefined; // undefined = not yet loaded, null = not found async function loadIndexHtml(): Promise<string | null> { if (cachedHtml !== undefined) return cachedHtml; for ( const path of [`${Deno.cwd()}/dist/index.html`, `${Deno.cwd()}/index.html`] ) { try { cachedHtml = await Deno.readTextFile(path); return cachedHtml; } catch { continue; } } cachedHtml = null; return null; } const DUMP_RE = /^\/dumps\/([^/]+)$/; const USER_RE = /^\/users\/([^/]+)$/; const PLAYLIST_RE = /^\/playlists\/([^/]+)$/; export async function ogMiddleware(ctx: Context, next: Next) { const { pathname } = ctx.request.url; if (pathname.startsWith("/api/") || pathname.includes(".")) { return await next(); } const origin = ctx.request.url.origin; const pageUrl = `${origin}${pathname}`; let meta: OGMeta | null = null; const dumpMatch = pathname.match(DUMP_RE); const userMatch = pathname.match(USER_RE); const playlistMatch = pathname.match(PLAYLIST_RE); if (dumpMatch) { try { const dump = getDump(dumpMatch[1]); let imageUrl: string | undefined; if (dump.kind === "file" && dump.fileMime?.startsWith("image/")) { imageUrl = `${origin}/api/files/${dump.id}`; } else if (dump.richContent?.thumbnailUrl) { imageUrl = dump.richContent.thumbnailUrl; } meta = { title: dump.title, description: dump.comment, imageUrl, url: pageUrl, }; } catch { /* not found or private — serve default */ } } else if (userMatch) { try { const user = getUserByUsername(userMatch[1]); const imageUrl = user.avatarMime ? `${origin}/api/avatars/${user.id}` : undefined; meta = { title: user.username, description: user.description, imageUrl, url: pageUrl, }; } catch { /* not found */ } } else if (playlistMatch) { try { const playlist = getPlaylistById(playlistMatch[1]); if (playlist.isPublic) { const imageUrl = playlist.imageMime ? `${origin}/api/playlists/${playlist.id}/image` : undefined; meta = { title: playlist.title, description: playlist.description, imageUrl, url: pageUrl, }; } } catch { /* not found or private */ } } if (!meta) return await next(); const html = await loadIndexHtml(); if (!html) return await next(); ctx.response.headers.set("Content-Type", "text/html; charset=utf-8"); ctx.response.body = inject(html, meta); }