/* * 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"; }); }