2022-12-12 17:55:57 +03:00
|
|
|
import opengraph from 'opengraph-io'
|
|
|
|
|
2022-12-12 22:06:57 +03:00
|
|
|
// This API-Endpoint will be cached via nuxt.config.ts -> nitro.routeRules['/api/og-image/**']
|
2022-12-12 16:26:30 +03:00
|
|
|
|
2022-12-12 18:27:33 +03:00
|
|
|
type OpenGraphClient = ReturnType<typeof opengraph>
|
2022-12-12 17:55:57 +03:00
|
|
|
|
2022-12-12 18:27:33 +03:00
|
|
|
let openGraphClient: OpenGraphClient
|
|
|
|
|
|
|
|
function getOpenGraphClient(): OpenGraphClient {
|
2022-12-12 23:51:50 +03:00
|
|
|
const appId = useRuntimeConfig().opengraphApi
|
|
|
|
if (typeof appId !== 'string')
|
2022-12-12 18:27:33 +03:00
|
|
|
throw new Error('Missing NUXT_OPENGRAPH_API environment variable.')
|
|
|
|
|
|
|
|
if (!openGraphClient)
|
2022-12-12 23:51:50 +03:00
|
|
|
openGraphClient = opengraph({ appId, fullRender: true })!
|
2022-12-12 17:55:57 +03:00
|
|
|
|
|
|
|
return openGraphClient
|
2022-12-12 16:26:30 +03:00
|
|
|
}
|
2022-12-11 01:09:11 +03:00
|
|
|
|
2022-12-12 18:00:26 +03:00
|
|
|
function extractOgImageUrl(html: string): string {
|
2022-12-12 23:58:03 +03:00
|
|
|
const match = html.match(/<meta[^>]*property="og:image"[^>]*content="([^"]+)"|<meta[^>]*content="([^"]+)"[^>]*property="og:image"/)
|
|
|
|
return match?.[1] ?? match?.[2] ?? ''
|
2022-12-12 18:00:26 +03:00
|
|
|
}
|
|
|
|
|
2022-12-12 18:53:43 +03:00
|
|
|
async function resolveOgImageUrlManually(cardUrl: string): Promise<string> {
|
|
|
|
const html = await $fetch<string>(cardUrl)
|
|
|
|
|
|
|
|
const ogImageUrl = extractOgImageUrl(html)
|
|
|
|
|
|
|
|
if (!ogImageUrl) {
|
|
|
|
// Throw an error so we can try to apply another fallback
|
|
|
|
throw new Error('Could not find og:image in html.')
|
|
|
|
}
|
|
|
|
|
|
|
|
return ogImageUrl
|
|
|
|
}
|
|
|
|
|
2022-12-11 01:09:11 +03:00
|
|
|
export default defineEventHandler(async (event) => {
|
2022-12-12 23:51:50 +03:00
|
|
|
const config = useRuntimeConfig()
|
2022-12-12 18:53:43 +03:00
|
|
|
const { url } = getRouterParams(event)
|
2022-12-12 22:56:43 +03:00
|
|
|
const { fallbackUrl } = getQuery(event)
|
2022-12-12 18:53:43 +03:00
|
|
|
|
|
|
|
const cardUrl = decodeURIComponent(url)
|
2022-12-11 01:09:11 +03:00
|
|
|
|
|
|
|
if (!cardUrl) {
|
|
|
|
throw createError({
|
|
|
|
statusCode: 422,
|
|
|
|
statusMessage: 'Missing cardUrl.',
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof cardUrl !== 'string') {
|
|
|
|
throw createError({
|
|
|
|
statusCode: 422,
|
|
|
|
statusMessage: 'cardUrl must be string.',
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-12-12 18:53:43 +03:00
|
|
|
// If anything goes wrong, fail gracefully
|
2022-12-12 18:31:29 +03:00
|
|
|
try {
|
|
|
|
// First we want to try to get the og:image from the html
|
|
|
|
// But sometimes it is not included due to async JS loading
|
2022-12-12 18:53:43 +03:00
|
|
|
let ogImageUrl = await resolveOgImageUrlManually(cardUrl).catch(() =>
|
|
|
|
// Try another fallback
|
|
|
|
'',
|
|
|
|
)
|
2022-12-12 17:55:57 +03:00
|
|
|
|
2022-12-12 23:51:50 +03:00
|
|
|
if (config.opengraphApi) {
|
2022-12-12 18:53:43 +03:00
|
|
|
// If no og:image was found, try to get it from opengraph.io
|
2022-12-12 18:31:29 +03:00
|
|
|
if (!ogImageUrl) {
|
2022-12-12 20:43:38 +03:00
|
|
|
const response = await getOpenGraphClient().getSiteInfo(cardUrl).catch(() =>
|
|
|
|
// Try another fallback
|
|
|
|
null,
|
|
|
|
)
|
2022-12-12 18:00:26 +03:00
|
|
|
|
2022-12-12 18:31:29 +03:00
|
|
|
ogImageUrl = response?.openGraph?.image?.url || response?.hybridGraph?.image || ''
|
|
|
|
}
|
2022-12-12 18:02:28 +03:00
|
|
|
}
|
2022-12-12 17:55:57 +03:00
|
|
|
|
2022-12-12 20:43:38 +03:00
|
|
|
if (!ogImageUrl) {
|
|
|
|
// If nothing helped, set cardUrl as default
|
2022-12-12 22:56:43 +03:00
|
|
|
ogImageUrl = decodeURIComponent(fallbackUrl as string)
|
2022-12-12 20:43:38 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
await sendRedirect(event, ogImageUrl)
|
2022-12-12 18:31:29 +03:00
|
|
|
}
|
|
|
|
catch (error) {
|
|
|
|
throw createError({
|
|
|
|
statusCode: 500,
|
|
|
|
statusMessage: (error as Error)?.message || 'Unknown error.',
|
|
|
|
cause: error,
|
|
|
|
})
|
|
|
|
}
|
2022-12-11 01:09:11 +03:00
|
|
|
})
|
2022-12-12 16:26:30 +03:00
|
|
|
|