generated from gitea_admin/default
finalisation home page
This commit is contained in:
108
server/api/instagram/oembed.post.js
Normal file
108
server/api/instagram/oembed.post.js
Normal file
@@ -0,0 +1,108 @@
|
||||
function isValidUrl(u) {
|
||||
try {
|
||||
new URL(u);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isInstagramPostUrl(u) {
|
||||
try {
|
||||
const url = new URL(u);
|
||||
const host = url.hostname.replace(/^www\./, "");
|
||||
|
||||
if (host !== "instagram.com") return false;
|
||||
|
||||
const p = url.pathname;
|
||||
return p.startsWith("/p/") || p.startsWith("/reel/") || p.startsWith("/tv/");
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export default defineCachedEventHandler(
|
||||
async (event) => {
|
||||
const config = useRuntimeConfig();
|
||||
|
||||
const appId = config.instagramAppId;
|
||||
const clientToken = config.instagramClientToken;
|
||||
|
||||
if (!appId || !clientToken) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage:
|
||||
"Missing Instagram oEmbed credentials (instagramAppId / instagramClientToken).",
|
||||
});
|
||||
}
|
||||
|
||||
const body = await readBody(event).catch(() => null);
|
||||
|
||||
if (!body || !Array.isArray(body.urls)) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid payload. Expected { urls: string[] }",
|
||||
});
|
||||
}
|
||||
|
||||
// normalise + filtre
|
||||
const urls = body.urls
|
||||
.map((u) => String(u).trim())
|
||||
.filter((u) => isValidUrl(u))
|
||||
.filter((u) => isInstagramPostUrl(u))
|
||||
.slice(0, 24);
|
||||
|
||||
if (urls.length === 0) {
|
||||
return { results: [] };
|
||||
}
|
||||
|
||||
// Token Meta oEmbed: APP_ID|CLIENT_TOKEN
|
||||
const accessToken = `${appId}|${clientToken}`;
|
||||
|
||||
const results = await Promise.all(
|
||||
urls.map(async (url) => {
|
||||
const endpoint = new URL(
|
||||
"https://graph.facebook.com/v19.0/instagram_oembed"
|
||||
);
|
||||
endpoint.searchParams.set("url", url);
|
||||
endpoint.searchParams.set("omitscript", "true");
|
||||
endpoint.searchParams.set("access_token", accessToken);
|
||||
|
||||
try {
|
||||
const data = await $fetch(endpoint.toString(), { timeout: 10000 });
|
||||
|
||||
return {
|
||||
url,
|
||||
ok: true,
|
||||
html: data?.html || "",
|
||||
title: data?.title ?? null,
|
||||
author_name: data?.author_name ?? null,
|
||||
thumbnail_url: data?.thumbnail_url ?? null,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
url,
|
||||
ok: false,
|
||||
error:
|
||||
e?.data?.error?.message ||
|
||||
e?.message ||
|
||||
"Unknown oEmbed error",
|
||||
};
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
return { results };
|
||||
},
|
||||
{
|
||||
// cache 6h
|
||||
maxAge: 60 * 60 * 6,
|
||||
|
||||
// clé de cache basée sur le payload (urls)
|
||||
getKey: async (event) => {
|
||||
const body = await readBody(event).catch(() => null);
|
||||
const urls = Array.isArray(body?.urls) ? body.urls.join("|") : "none";
|
||||
return `instagram:oembed:${urls}`;
|
||||
},
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user