Guest User

Untitled

a guest
Feb 11th, 2026
420
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.82 KB | None | 0 0
  1. // ==UserScript==
  2. // @name yout-ube iframe player
  3. // @namespace https://example.com/
  4. // @description Replaces YouTube player with yout-ube iframe and blocks videoplayback on the parent page.
  5. // @match https://www.youtube.com/*
  6. // @match https://m.youtube.com/*
  7. // @run-at document-start
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (() => {
  12. "use strict";
  13.  
  14. const TARGET_HOST = "www.yout-ube.com";
  15. const IFRAME_ATTR = "data-gm-yout-ube-iframe";
  16. const WRAP_ATTR = "data-gm-yout-ube-wrap";
  17.  
  18. const BLOCK_PATTERNS = [
  19. /\/\/[^/]*googlevideo\.com\/videoplayback/i,
  20. /\/videoplayback(\?|$)/i,
  21. ];
  22.  
  23. const shouldBlockUrl = (url) => {
  24. try {
  25. const s = String(url || "");
  26. return BLOCK_PATTERNS.some((re) => re.test(s));
  27. } catch {
  28. return false;
  29. }
  30. };
  31.  
  32. const buildIframeUrl = () => {
  33. const u = new URL(location.href);
  34. u.hostname = TARGET_HOST;
  35. return u.toString();
  36. };
  37.  
  38. const isWatchPage = () =>
  39. location.pathname === "/watch" && new URL(location.href).searchParams.has("v");
  40.  
  41. const pauseAndNukeMedia = (root = document) => {
  42. try {
  43. root.querySelectorAll("video,audio").forEach((el) => {
  44. try { el.pause?.(); } catch {}
  45. try { el.muted = true; el.volume = 0; } catch {}
  46. try {
  47. el.removeAttribute("src");
  48. el.querySelectorAll?.("source").forEach((s) => s.remove());
  49. el.load?.();
  50. } catch {}
  51. });
  52. } catch {}
  53. };
  54.  
  55. const stopAllInjectedIframes = () => {
  56. document.querySelectorAll(`iframe[${IFRAME_ATTR}]`).forEach((ifr) => {
  57. try { ifr.src = "about:blank"; } catch {}
  58. try { ifr.remove(); } catch {}
  59. });
  60. document.querySelectorAll(`div[${WRAP_ATTR}]`).forEach((w) => {
  61. try { w.remove(); } catch {}
  62. });
  63. };
  64.  
  65. const installBlockers = () => {
  66. if (typeof window.fetch === "function") {
  67. const origFetch = window.fetch;
  68. window.fetch = function (input, init) {
  69. const url = (typeof input === "string") ? input : (input && input.url);
  70. if (shouldBlockUrl(url)) {
  71. return Promise.reject(new TypeError("Blocked by userscript: videoplayback"));
  72. }
  73. return origFetch.apply(this, arguments);
  74. };
  75. }
  76.  
  77. if (window.XMLHttpRequest) {
  78. const origOpen = XMLHttpRequest.prototype.open;
  79. const origSend = XMLHttpRequest.prototype.send;
  80.  
  81. XMLHttpRequest.prototype.open = function (method, url) {
  82. this.__gm_blocked_url__ = url;
  83. return origOpen.apply(this, arguments);
  84. };
  85.  
  86. XMLHttpRequest.prototype.send = function () {
  87. if (shouldBlockUrl(this.__gm_blocked_url__)) {
  88. try { this.abort(); } catch {}
  89. return;
  90. }
  91. return origSend.apply(this, arguments);
  92. };
  93. }
  94.  
  95. const mo = new MutationObserver((mutList) => {
  96. for (const m of mutList) {
  97. for (const n of m.addedNodes) {
  98. if (!(n instanceof Element)) continue;
  99. if (n.matches?.("video,audio")) pauseAndNukeMedia(n.parentNode || document);
  100. else if (n.querySelector) {
  101. if (n.querySelector("video,audio")) pauseAndNukeMedia(n);
  102. }
  103. }
  104. }
  105. });
  106.  
  107. const startObs = () => {
  108. if (!document.documentElement) return;
  109. mo.observe(document.documentElement, { childList: true, subtree: true });
  110. };
  111.  
  112. if (document.documentElement) startObs();
  113. else document.addEventListener("readystatechange", startObs, { once: true });
  114. };
  115.  
  116. const findPlayerHost = () => {
  117. const selectors = [
  118. "#player.ytd-watch-flexy",
  119. "#player-container.ytd-watch-flexy",
  120. "ytd-player#ytd-player",
  121. "#movie_player",
  122. "ytd-watch-flexy #player",
  123. ];
  124.  
  125. for (const sel of selectors) {
  126. const el = document.querySelector(sel);
  127. if (el) {
  128. if (el.id === "movie_player" && el.parentElement) return el.parentElement;
  129. return el;
  130. }
  131. }
  132. return null;
  133. };
  134.  
  135. const ensureIframePlayer = () => {
  136. if (!isWatchPage()) return;
  137.  
  138. const host = findPlayerHost();
  139. if (!host) return;
  140.  
  141. const desiredSrc = buildIframeUrl();
  142.  
  143. const existingIframe = host.querySelector(`iframe[${IFRAME_ATTR}]`);
  144. if (existingIframe) {
  145. if (existingIframe.src !== desiredSrc) {
  146. existingIframe.src = "about:blank";
  147. existingIframe.src = desiredSrc;
  148. }
  149. return;
  150. }
  151.  
  152. host.textContent = "";
  153.  
  154. const wrap = document.createElement("div");
  155. wrap.setAttribute(WRAP_ATTR, "1");
  156. wrap.style.position = "relative";
  157. wrap.style.width = "100%";
  158.  
  159. wrap.style.aspectRatio = "16 / 9";
  160. wrap.style.minHeight = "360px";
  161. host.style.width = "100%";
  162.  
  163. const iframe = document.createElement("iframe");
  164. iframe.setAttribute(IFRAME_ATTR, "1");
  165. iframe.src = desiredSrc;
  166. iframe.allow =
  167. "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share";
  168. iframe.allowFullscreen = true;
  169. iframe.referrerPolicy = "origin-when-cross-origin";
  170. iframe.loading = "eager";
  171.  
  172. iframe.style.position = "absolute";
  173. iframe.style.inset = "0";
  174. iframe.style.width = "100%";
  175. iframe.style.height = "100%";
  176. iframe.style.border = "0";
  177. iframe.style.display = "block";
  178.  
  179. wrap.appendChild(iframe);
  180. host.appendChild(wrap);
  181. };
  182.  
  183. const handleRouteChange = () => {
  184. pauseAndNukeMedia(document);
  185.  
  186. if (isWatchPage()) {
  187. ensureIframePlayer();
  188. } else {
  189. stopAllInjectedIframes();
  190. pauseAndNukeMedia(document);
  191. }
  192. };
  193.  
  194. const installSpaHooks = () => {
  195. const schedule = (() => {
  196. let t = null;
  197. return () => {
  198. if (t) clearTimeout(t);
  199. t = setTimeout(() => {
  200. t = null;
  201. handleRouteChange();
  202. }, 50);
  203. };
  204. })();
  205.  
  206. window.addEventListener("yt-navigate-start", schedule, true);
  207. window.addEventListener("yt-navigate-finish", schedule, true);
  208. window.addEventListener("yt-page-data-updated", schedule, true);
  209. window.addEventListener("popstate", schedule, true);
  210. window.addEventListener("hashchange", schedule, true);
  211.  
  212. const mo = new MutationObserver(() => {
  213. if (isWatchPage()) ensureIframePlayer();
  214. });
  215.  
  216. const start = () => {
  217. if (!document.documentElement) return;
  218. mo.observe(document.documentElement, { childList: true, subtree: true });
  219. };
  220.  
  221. if (document.documentElement) start();
  222. else document.addEventListener("readystatechange", start, { once: true });
  223.  
  224. let lastHref = location.href;
  225. setInterval(() => {
  226. if (location.href !== lastHref) {
  227. lastHref = location.href;
  228. handleRouteChange();
  229. }
  230. }, 250);
  231.  
  232. handleRouteChange();
  233. };
  234.  
  235. installBlockers();
  236. installSpaHooks();
  237. })();
  238.  
Advertisement
Add Comment
Please, Sign In to add comment