YouTube iFrame AdBlocker

Bypass YouTube's ad-blocker detection by dynamically replacing the video player with an iframe.

  1. // ==UserScript==
  2. // @name YouTube iFrame AdBlocker
  3. // @namespace Booth-Stash
  4. // @license MIT
  5. // @version 1.0
  6. // @description Bypass YouTube's ad-blocker detection by dynamically replacing the video player with an iframe.
  7. // @author JordanRO2
  8. // @match https://www.youtube.com/*
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. // Utility functions
  16. function getAutoplayState() {
  17. return localStorage.getItem('autoplayNext') === 'true';
  18. }
  19.  
  20. function setAutoplayState(state) {
  21. localStorage.setItem('autoplayNext', state.toString());
  22. }
  23.  
  24. function toggleAutoplayState(button) {
  25. const autoplayNext = !getAutoplayState();
  26. setAutoplayState(autoplayNext);
  27. button.title = autoplayNext ? 'Autoplay is on' : 'Autoplay is off';
  28. button.setAttribute('aria-label', autoplayNext ? 'Autoplay is on' : 'Autoplay is off');
  29. button.querySelector('.ytp-autonav-toggle-button').setAttribute('aria-checked', autoplayNext.toString());
  30. return autoplayNext;
  31. }
  32.  
  33. function isVideoEnded(iframeDoc) {
  34. return iframeDoc.querySelector('.html5-endscreen.ytp-show-tiles') !== null;
  35. }
  36.  
  37. // Main script
  38. function replaceElement(oldElement) {
  39. const urlParams = new URLSearchParams(window.location.search);
  40. const videoId = urlParams.get('v');
  41.  
  42. if (!videoId) {
  43. console.error('Video ID not found in URL');
  44. return;
  45. }
  46.  
  47. console.log(`Video ID: ${videoId}`);
  48. console.log('Old element found');
  49.  
  50. const newElement = document.createElement('iframe');
  51. newElement.width = "100%";
  52. newElement.height = "100%";
  53. newElement.src = `https://www.youtube.com/embed/${videoId}?autoplay=1`;
  54. newElement.title = "YouTube video player";
  55. newElement.frameBorder = "0";
  56. newElement.allow = "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share";
  57. newElement.allowFullscreen = true;
  58.  
  59. oldElement.parentNode.replaceChild(newElement, oldElement);
  60. console.log('Element replaced successfully');
  61.  
  62. newElement.onload = () => {
  63. const iframeDoc = newElement.contentDocument;
  64.  
  65. const refButton = iframeDoc.querySelector('.ytp-subtitles-button');
  66. const youtubeButton = iframeDoc.querySelector('.ytp-youtube-button');
  67.  
  68. if (youtubeButton) {
  69. youtubeButton.parentNode.removeChild(youtubeButton);
  70. } else {
  71. console.error('YouTube button not found');
  72. }
  73.  
  74. if (refButton) {
  75. const autoPlayButton = document.createElement('button');
  76. autoPlayButton.className = 'ytp-button';
  77. autoPlayButton.setAttribute('data-priority', '2');
  78. autoPlayButton.setAttribute('data-tooltip-target-id', 'ytp-autonav-toggle-button');
  79. autoPlayButton.title = getAutoplayState() ? 'Autoplay is on' : 'Autoplay is off';
  80. autoPlayButton.setAttribute('aria-label', getAutoplayState() ? 'Autoplay is on' : 'Autoplay is off');
  81. autoPlayButton.innerHTML = `
  82. <div class="ytp-autonav-toggle-button-container">
  83. <div class="ytp-autonav-toggle-button" aria-checked="${getAutoplayState().toString()}"></div>
  84. </div>
  85. `;
  86.  
  87. refButton.parentNode.insertBefore(autoPlayButton, refButton.nextSibling);
  88.  
  89. autoPlayButton.addEventListener('click', () => {
  90. const isAutoplayOn = toggleAutoplayState(autoPlayButton);
  91. if (isAutoplayOn && isVideoEnded(iframeDoc)) {
  92. playNextVideo();
  93. }
  94. });
  95. } else {
  96. console.error('Reference button not found');
  97. }
  98.  
  99. const endScreenObserver = new MutationObserver((mutations) => {
  100. for (const mutation of mutations) {
  101. if (mutation.target.classList.contains('ytp-show-tiles') && getAutoplayState()) {
  102. playNextVideo();
  103. break;
  104. }
  105. }
  106. });
  107.  
  108. endScreenObserver.observe(iframeDoc, { attributes: true, subtree: true, attributeFilter: ['class'] });
  109. };
  110. }
  111.  
  112. function playNextVideo() {
  113. const rendererElements = document.querySelectorAll('ytd-compact-video-renderer');
  114. for (let rendererElement of rendererElements) {
  115. if (!rendererElement.querySelector('ytd-compact-radio-renderer')) {
  116. const nextVideoLink = rendererElement.querySelector('a#thumbnail');
  117. if (nextVideoLink && nextVideoLink.href) {
  118. const autoplayURL = new URL(nextVideoLink.href);
  119. autoplayURL.searchParams.set('autoplay', '1');
  120. console.log(`Found next video link: ${autoplayURL.href}`);
  121. window.location.href = autoplayURL.href;
  122. return;
  123. }
  124. }
  125. }
  126. console.error('Next video link not found');
  127. }
  128.  
  129. const observer = new MutationObserver((mutationsList) => {
  130. for (let mutation of mutationsList) {
  131. if (mutation.addedNodes.length) {
  132. for (let node of mutation.addedNodes) {
  133. if (node.nodeName.toLowerCase() === 'ytd-enforcement-message-view-model') {
  134. replaceElement(node);
  135. }
  136. }
  137. }
  138. }
  139. });
  140.  
  141. observer.observe(document, { childList: true, subtree: true });
  142.  
  143. })();