Files
wondif_vue/server/api/youtube/oembed.post.js
2026-04-20 11:37:03 +02:00

79 lines
1.9 KiB
JavaScript

function isValidUrl(url) {
try {
new URL(url)
return true
} catch {
return false
}
}
function isYoutubeUrl(url) {
try {
const parsedUrl = new URL(url)
const host = parsedUrl.hostname.replace(/^www\./, "")
return host === "youtube.com" || host === "youtu.be" || host === "m.youtube.com"
} catch {
return false
}
}
export default defineCachedEventHandler(
async (event) => {
const body = await readBody(event).catch(() => null)
if (!body || !Array.isArray(body.urls)) {
throw createError({
statusCode: 400,
statusMessage: "Invalid payload. Expected { urls: string[] }",
})
}
const urls = body.urls
.map((url) => String(url).trim())
.filter((url) => isValidUrl(url))
.filter((url) => isYoutubeUrl(url))
.slice(0, 50)
if (urls.length === 0) {
return { results: [] }
}
const results = await Promise.all(
urls.map(async (url) => {
const endpoint = new URL("https://www.youtube.com/oembed")
endpoint.searchParams.set("url", url)
endpoint.searchParams.set("format", "json")
try {
const data = await $fetch(endpoint.toString(), { timeout: 10000 })
return {
url,
ok: true,
title: data?.title ?? null,
author_name: data?.author_name ?? null,
thumbnail_url: data?.thumbnail_url ?? null,
}
} catch (error) {
return {
url,
ok: false,
error: error?.message || "Unknown oEmbed error",
}
}
})
)
return { results }
},
{
maxAge: 60 * 60 * 6,
getKey: async (event) => {
const body = await readBody(event).catch(() => null)
const urls = Array.isArray(body?.urls) ? body.urls.join("|") : "none"
return `youtube:oembed:${urls}`
},
}
)