Last active
December 11, 2025 20:53
-
-
Save joshuafredrickson/bb7ff4dc1e150f41d00a5d708b55f500 to your computer and use it in GitHub Desktop.
Fix YouTube 153 errors on existing embedded iframes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <script> | |
| (function () { | |
| const OEMBED_URL_BASE = "https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v="; | |
| const processedIframes = new WeakSet(); | |
| function getVideoIdFromSrc(src) { | |
| if (!src) return null; | |
| try { | |
| const url = new URL(src, window.location.origin); | |
| if (url.hostname.includes("youtu.be")) { | |
| const idPath = url.pathname.replace(/\/+/, ""); | |
| if (idPath) return idPath; | |
| } | |
| const path = url.pathname || ""; | |
| const embedIndex = path.indexOf("/embed/"); | |
| if (embedIndex !== -1) { | |
| const rest = path.substring(embedIndex + 7); | |
| if (rest) return rest.split("/")[0]; | |
| } | |
| const v = url.searchParams.get("v"); | |
| if (v) return v; | |
| } catch (e) { | |
| const m = src.match(/embed\/([^?&]+)/); | |
| if (m && m[1]) return m[1]; | |
| } | |
| return null; | |
| } | |
| async function replaceIframeFromOEmbed(iframe, videoId) { | |
| if (!videoId) return; | |
| const url = OEMBED_URL_BASE + encodeURIComponent(videoId) + "&format=json"; | |
| try { | |
| const res = await fetch(url); | |
| if (!res.ok) return; | |
| const data = await res.json(); | |
| if (!data || !data.html) return; | |
| const tmp = document.createElement("div"); | |
| tmp.innerHTML = data.html; | |
| const newIframe = tmp.querySelector("iframe"); | |
| if (!newIframe) return; | |
| // Preserve layout/styling attributes from the original iframe | |
| if (iframe.className) { | |
| newIframe.className = iframe.className; | |
| } | |
| if (iframe.getAttribute("style")) { | |
| newIframe.setAttribute("style", iframe.getAttribute("style")); | |
| } | |
| const width = iframe.getAttribute("width"); | |
| const height = iframe.getAttribute("height"); | |
| if (width) newIframe.setAttribute("width", width); | |
| if (height) newIframe.setAttribute("height", height); | |
| iframe.replaceWith(newIframe); | |
| } catch (e) { | |
| // swallow | |
| } | |
| } | |
| function applyPolicy(root) { | |
| const base = root || document; | |
| const elements = []; | |
| if (base.tagName === "IFRAME") { | |
| elements.push(base); | |
| } | |
| base | |
| .querySelectorAll('iframe[src*="youtube.com"], iframe[src*="youtu.be"]') | |
| .forEach((el) => elements.push(el)); | |
| elements.forEach((el) => { | |
| const src = el.getAttribute("src") || ""; | |
| if (processedIframes.has(el)) { | |
| return; | |
| } | |
| // Only touch iframes that do NOT already specify a referrerpolicy | |
| if (el.hasAttribute("referrerpolicy")) { | |
| processedIframes.add(el); | |
| return; | |
| } | |
| const videoId = getVideoIdFromSrc(src); | |
| if (!videoId) { | |
| processedIframes.add(el); | |
| return; | |
| } | |
| processedIframes.add(el); | |
| replaceIframeFromOEmbed(el, videoId); | |
| }); | |
| } | |
| // Run once on load/DOM ready | |
| if (document.readyState === "loading") { | |
| document.addEventListener("DOMContentLoaded", () => applyPolicy(document)); | |
| } else { | |
| applyPolicy(document); | |
| } | |
| window.addEventListener("load", () => applyPolicy(document)); | |
| // Watch for iframes that get injected later | |
| const mo = new MutationObserver((mutations) => { | |
| for (const m of mutations) { | |
| for (const n of m.addedNodes || []) { | |
| if (n.nodeType !== 1) continue; // elements only | |
| applyPolicy(n); | |
| } | |
| } | |
| }); | |
| mo.observe(document.documentElement, { childList: true, subtree: true }); | |
| })(); | |
| </script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment