article.tsx: transform Bunny iframe → folxvideos HLS player when S3 available

This commit is contained in:
2026-06-07 16:27:15 +02:00
parent c8b0989d4c
commit 6c34d44cea
3 changed files with 68 additions and 2 deletions
+58
View File
@@ -204,6 +204,64 @@ export default function ArticlePage() {
}
}, [article?.content]);
// Replace Bunny iframe embeds with native HLS player (folxvideos S3 origin)
useEffect(() => {
if (!article?.content) return;
let cancelled = false;
const loadHlsJs = (): Promise<any> => new Promise((resolve, reject) => {
if ((window as any).Hls) return resolve((window as any).Hls);
const s = document.createElement("script");
s.src = "https://cdn.jsdelivr.net/npm/hls.js@1.5.17/dist/hls.min.js";
s.async = true;
s.onload = () => resolve((window as any).Hls);
s.onerror = reject;
document.head.appendChild(s);
});
const transform = async () => {
const iframes = document.querySelectorAll<HTMLIFrameElement>(
'iframe[src*="mediadelivery.net/embed/"], iframe[src*="iframe.mediadelivery.net/embed/"]'
);
if (iframes.length === 0) return;
let Hls: any = null;
try { Hls = await loadHlsJs(); } catch {}
for (const iframe of Array.from(iframes)) {
if (cancelled) break;
const m = iframe.src.match(/embed\/\d+\/([a-f0-9-]+)/i);
if (!m) continue;
const guid = m[1];
const folxUrl = `https://folxvideos.b-cdn.net/folx-tv/${guid}/master.m3u8`;
try {
const head = await fetch(folxUrl, { method: "HEAD" });
if (!head.ok) continue;
} catch { continue; }
const video = document.createElement("video");
video.controls = true;
video.preload = "metadata";
video.playsInline = true;
video.style.cssText = iframe.getAttribute("style") || "width:100%;aspect-ratio:16/9;border:none;";
video.className = iframe.className || "";
if (Hls && Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(folxUrl);
hls.attachMedia(video);
} else if (video.canPlayType("application/vnd.apple.mpegurl")) {
video.src = folxUrl;
} else {
continue; // can't play, keep iframe
}
iframe.replaceWith(video);
}
};
// Run after content is in DOM (next tick)
const t = setTimeout(transform, 50);
return () => { cancelled = true; clearTimeout(t); };
}, [article?.content]);
if (isLoading) {
return (
<div className="min-h-screen bg-background">