Files

48 lines
1.8 KiB
JavaScript

/*
* RustPad media player helpers.
* Project-owned code: keeps native video playback and YouTube embeds responsive.
*/
const initialized = new WeakSet();
function createYouTubeFrame(node) {
const videoId = String(node.dataset.videoId || "").trim();
if (!/^[A-Za-z0-9_-]{6,20}$/.test(videoId)) return;
const iframe = document.createElement("iframe");
iframe.src = `https://www.youtube-nocookie.com/embed/${encodeURIComponent(videoId)}?rel=0&modestbranding=1&playsinline=1`;
iframe.title = node.dataset.playerTitle || "YouTube video";
iframe.loading = "lazy";
iframe.allow = "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share";
iframe.referrerPolicy = "strict-origin-when-cross-origin";
iframe.allowFullscreen = true;
node.replaceChildren(iframe);
}
function initializeNativeVideo(video) {
video.controls = true;
video.playsInline = true;
video.preload = video.preload || "metadata";
const fallback = video.closest(".rustpad-media")?.querySelector(".rustpad-media__fallback");
if (!fallback) return;
const revealFallback = () => { fallback.hidden = false; };
video.addEventListener("error", revealFallback, { once: true });
video.querySelectorAll("source").forEach(source => source.addEventListener("error", revealFallback, { once: true }));
}
export function hydrateMediaPlayers(root = document) {
root.querySelectorAll("[data-rustpad-player]").forEach(node => {
if (initialized.has(node)) return;
initialized.add(node);
if (node.dataset.playerKind === "youtube") createYouTubeFrame(node);
else if (node instanceof HTMLVideoElement) initializeNativeVideo(node);
});
}
export function destroyMediaPlayers(root = document) {
root.querySelectorAll('[data-rustpad-player][data-player-kind="youtube"] iframe').forEach(frame => {
frame.src = "about:blank";
});
}