(
request: FastifyRequest<{
Querystring: {
url: string;
};
}>,
reply: FastifyReply,
)
| 513 | } |
| 514 | |
| 515 | export async function getOgImage( |
| 516 | request: FastifyRequest<{ |
| 517 | Querystring: { |
| 518 | url: string; |
| 519 | }; |
| 520 | }>, |
| 521 | reply: FastifyReply, |
| 522 | ) { |
| 523 | try { |
| 524 | const url = validateUrl(request.query.url); |
| 525 | if (!url) { |
| 526 | return getFavicon(request, reply); |
| 527 | } |
| 528 | const cacheKey = createCacheKey(url.toString(), 'og'); |
| 529 | |
| 530 | // Check cache first |
| 531 | const cached = await getFromCacheBinary(cacheKey); |
| 532 | if (cached) { |
| 533 | reply.header('Content-Type', cached.contentType); |
| 534 | reply.header('Cache-Control', 'public, max-age=604800, immutable'); |
| 535 | return reply.send(cached.buffer); |
| 536 | } |
| 537 | |
| 538 | let imageUrl: URL; |
| 539 | |
| 540 | // If it's a direct image URL, use it directly |
| 541 | if (isDirectImage(url)) { |
| 542 | imageUrl = url; |
| 543 | } else { |
| 544 | // For website URLs, extract OG image from HTML |
| 545 | const meta = await parseUrlMeta(url.toString()); |
| 546 | if (meta?.ogImage) { |
| 547 | imageUrl = new URL(meta.ogImage); |
| 548 | } else { |
| 549 | // No OG image found, return a fallback |
| 550 | return getFavicon(request, reply); |
| 551 | } |
| 552 | } |
| 553 | |
| 554 | // Fetch the image |
| 555 | const { buffer, contentType, status } = await fetchImage(imageUrl); |
| 556 | |
| 557 | if (status !== 200 || buffer.length === 0) { |
| 558 | return getFavicon(request, reply); |
| 559 | } |
| 560 | |
| 561 | // Process the image (resize to 1200x630 for OG standards, or serve as-is if reasonable size) |
| 562 | const processedBuffer = await processOgImage( |
| 563 | buffer, |
| 564 | imageUrl.toString(), |
| 565 | contentType, |
| 566 | ); |
| 567 | |
| 568 | // Cache the result |
| 569 | await setToCacheBinary(cacheKey, processedBuffer, 'image/png'); |
| 570 | |
| 571 | reply.header('Content-Type', 'image/png'); |
| 572 | reply.header('Cache-Control', 'public, max-age=3600, immutable'); |
nothing calls this directly
no test coverage detected