Skip to content

Instantly share code, notes, and snippets.

@htsign
Last active March 9, 2026 15:35
Show Gist options
  • Select an option

  • Save htsign/cc246428156299e2028e87813d3b95d8 to your computer and use it in GitHub Desktop.

Select an option

Save htsign/cc246428156299e2028e87813d3b95d8 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Embedded YouTube fix
// @description this monitors and auto-refreshes crashed embedded YouTube players in the background for a seamless viewing experience
// @namespace https://htsign.hateblo.jp
// @version 0.5.5
// @author htsign
// @match *://*/*
// @match https://www.youtube.com/embed/*
// @updateURL https://gist.github.com/htsign/cc246428156299e2028e87813d3b95d8/raw/Embedded-YouTube-fix.user.js
// @downloadURL https://gist.github.com/htsign/cc246428156299e2028e87813d3b95d8/raw/Embedded-YouTube-fix.user.js
// @grant none
// @license MIT
// ==/UserScript==
(() => {
'use strict';
const ID = 'embedded-youtube-fix';
/** @type {RegExp[]} */
const BROKEN_PAGES = [];
const iframes = document.getElementsByTagName('iframe');
// parent
if (window.self === window.top) {
/**
* tracks visible iframes and the timestamp of the last message sent
*
* @type {WeakMap<HTMLIFrameElement, number>}
*/
const visibles = new WeakMap();
/**
* @param {HTMLIFrameElement} target
*/
const postId = target => target.contentWindow?.postMessage(ID, 'https://www.youtube.com');
const observer = new IntersectionObserver(entries => {
for (const { target, isIntersecting } of entries) {
if (isIntersecting) {
const current = performance.now();
if (!visibles.has(target) || current - visibles.get(target) > 1000) {
postId(target);
}
visibles.set(target, current);
}
else {
visibles.delete(target);
}
}
});
window.addEventListener('message', ({ data, source, origin }) => {
if (origin !== 'https://www.youtube.com') return;
if (data !== ID) return;
const iframe = Array.prototype.find.call(iframes, el => el.contentWindow === source);
if (iframe == null) return;
if (!iframe.hasAttribute('referrerpolicy')) {
iframe.setAttribute('referrerpolicy', 'strict-origin-when-cross-origin');
return;
}
const url = new URL(iframe.src);
if (
['playlist', 'videoseries'].some(path => url.pathname.endsWith(`/${path}`))
&& url.searchParams.has('list')
&& url.searchParams.has('feature')
) {
url.searchParams.delete('feature');
}
if (url.searchParams.get('feature') === 'oembed') {
url.searchParams.delete('feature');
}
url.searchParams.set(ID, url.searchParams.get(ID) ^ 1);
if (BROKEN_PAGES.some(pageRegex => pageRegex.test(url.href))) {
// fallback for cases where copying elements breaks the original site's scripts
iframe.src = url.toString();
}
else {
// avoid multiple back button presses
const newIframe = iframe.cloneNode();
newIframe.src = url.toString();
iframe.replaceWith(newIframe);
observer.observe(newIframe);
}
});
const loop = () => {
for (const iframe of iframes) {
observer.observe(iframe);
if (visibles.has(iframe)) {
postId(iframe);
}
}
setTimeout(loop, 500);
};
requestIdleCallback(loop);
}
// inside of iframe
else if (location.href.startsWith('https://www.youtube.com/embed/')) {
window.addEventListener('message', ({ data, source, origin }) => {
if (data !== ID) return;
const error = document.querySelector('.ytp-error');
const subreason = error?.querySelector('.ytp-error-content-wrap-subreason');
if (subreason && getComputedStyle(subreason).display !== 'none') {
source.postMessage(ID, origin);
}
});
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment