48 lines
1.3 KiB
TypeScript
48 lines
1.3 KiB
TypeScript
const SUPPORTED_HOSTS = new Set([
|
|
"youtube.com",
|
|
"m.youtube.com",
|
|
"youtu.be",
|
|
"youtube-nocookie.com",
|
|
]);
|
|
|
|
const VIDEO_ID_REGEX = /^[a-zA-Z0-9_-]{11}$/;
|
|
|
|
function normalizeHost(hostname: string) {
|
|
return hostname.toLowerCase().replace(/^www\./, "");
|
|
}
|
|
|
|
function fromPathSegments(pathname: string) {
|
|
const segments = pathname.split("/").filter(Boolean);
|
|
if (!segments.length) return null;
|
|
|
|
if (segments[0] === "watch") return null;
|
|
if (segments[0] === "shorts" && segments[1]) return segments[1];
|
|
if (segments[0] === "embed" && segments[1]) return segments[1];
|
|
|
|
return segments[0];
|
|
}
|
|
|
|
export function getYoutubeVideoId(link: string) {
|
|
try {
|
|
const url = new URL(link);
|
|
const host = normalizeHost(url.hostname);
|
|
|
|
if (!SUPPORTED_HOSTS.has(host)) return null;
|
|
|
|
const videoId = host === "youtu.be" ? fromPathSegments(url.pathname) : url.searchParams.get("v") ?? fromPathSegments(url.pathname);
|
|
if (!videoId || !VIDEO_ID_REGEX.test(videoId)) return null;
|
|
|
|
return videoId;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function getYoutubeEmbedUrl(link: string) {
|
|
const videoId = getYoutubeVideoId(link);
|
|
if (!videoId) return null;
|
|
|
|
// Use privacy-enhanced mode to reduce cross-site cookie noise in modern browsers.
|
|
return `https://www.youtube-nocookie.com/embed/${videoId}?rel=0&modestbranding=1`;
|
|
}
|