No Ad IFrame

No Ad IFrame created by Stay

目前为 2024-12-16 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name No Ad IFrame
  3. // @namespace https://staybrowser.com/
  4. // @version 0.1.1
  5.  
  6. // @description No Ad IFrame created by Stay
  7. // @description:en No Ad IFrame created by Stay
  8. // @description:ja No Ad IFrame created by Stay
  9. // @description:zh-TW No Ad IFrame created by Stay
  10. // @description:zh-CN No Ad IFrame created by Stay
  11.  
  12. // @author You
  13. // @match *://*/*
  14. // @grant none
  15. // @inject-into page
  16. // @unwrap
  17. // @run-at document-start
  18. // @license MIT
  19. // @compatible chrome
  20. // @compatible firefox
  21. // @compatible opera
  22. // @compatible edge
  23. // @compatible safari
  24. // @allFrames true
  25. // ==/UserScript==
  26. (function () {
  27. 'use strict';
  28.  
  29. const TURN_ON_BLOCK_REMOVAL = true;
  30.  
  31. if (Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, "__src437__")) return;
  32.  
  33. Object.defineProperty(HTMLIFrameElement.prototype, "__src437__", {
  34. value: undefined,
  35. writable: true,
  36. configurable: false,
  37. enumerable: false
  38. });
  39.  
  40. if (!Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, "__src437__")) return;
  41.  
  42. const pd1 = Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, "src");
  43. const pd2 = Object.assign({}, pd1, {
  44. configurable: true,
  45. enumerable: true
  46. });
  47.  
  48. const wSnb = Symbol();
  49.  
  50. const adFilter = {
  51.  
  52. 'iframe[src*="doubleclick.net"]': 1,
  53. 'iframe[src*="googlesyndication.com"]': 1,
  54. 'iframe[src*="googleadservices.com"]': 1,
  55. 'iframe[src*="googletagservices.com"]': 1,
  56. 'iframe[src*="adservice.google.com"]': 1,
  57. 'iframe[src*="adservice.yahoo.com"]': 1,
  58. 'iframe[src*="amazon-adsystem.com"]': 1,
  59. 'iframe[src*="adroll.com"]': 1,
  60. 'iframe[src*="ads-twitter.com"]': 1,
  61. 'iframe[src*="criteo.com"]': 1,
  62. 'iframe[src*="taboola.com"]': 1,
  63. 'iframe[src*="outbrain.com"]': 1,
  64. 'iframe[src*="smartadserver.com"]': 1,
  65. 'iframe[src*="openx.net"]': 1,
  66. 'iframe[src*="rubiconproject.com"]': 1,
  67.  
  68. 'iframe[id^="aswift_"][src*="ads"][3]': 1,
  69. 'iframe[id^="google_ads_iframe_"]': 1,
  70. 'iframe[name^="google_ads_iframe_"]': 1,
  71. // 'iframe[src*="doubleclick.net"]': 1,
  72. // 'iframe[src*="googlesyndication.com"]': 1,
  73. 'iframe[src*="adservice"]': 1,
  74. 'iframe[src*="adserver"]': 1,
  75. // 'iframe[src*="/ads/"]': 1,
  76. // 'iframe[class*="ad-"]': 1,
  77. 'iframe[data-ad-slot]': 1,
  78.  
  79. // Additional patterns
  80. 'iframe[id*="adframe"]': 1, // Common variation like "adframe"
  81. 'iframe[id*="ad_iframe"]': 1, // "ad_iframe" naming pattern
  82. 'iframe[id*="ad_container"]': 1, // Container-like naming often used for ads
  83. 'iframe[id*="ad_wrapper"]': 1, // Another container naming pattern
  84.  
  85. 'iframe[class*="adslot"]': 1, // "adslot" is a known pattern (e.g., GPT ad slots)
  86. 'iframe[class*="adsense"]': 1, // "adsense" typically indicates Google AdSense
  87. 'iframe[class*="ad_frame"]': 1, // Variation with underscore
  88. // 'iframe[class*="advert"]': 1, // "advert" is another clue
  89.  
  90. // Attribute patterns
  91. 'iframe[data-ad-client]': 1, // Data attribute used by some ad scripts
  92. 'iframe[data-ad-region]': 1, // Another ad-related data attribute
  93.  
  94. };
  95.  
  96. function createBase64DataURL(title) {
  97. // Construct a minimal HTML5 page with the given title
  98. const html = `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"/><title>${title}</title></head><body></body></html>`;
  99.  
  100. // Encode the HTML string into Base64
  101. const base64String = btoa(html);
  102.  
  103. // Return as a Data URL
  104. return `data:text/html;base64,${base64String}`;
  105. }
  106.  
  107.  
  108. const dynamicGeneration = () => {
  109. const key = Math.floor(Math.random() * 314159265359 + 314159265359).toString(36);
  110. return createBase64DataURL(key);
  111. }
  112.  
  113. const caching = new Map();
  114.  
  115. const hKey = `e-${Math.floor(Math.random() * 314159265359 + 314159265359).toString(36)}`;
  116.  
  117. const checkOnly = (elm) => {
  118.  
  119. let noP = true;
  120. let noQ = true;
  121. let t = elm || 0;
  122. while (t = t.previousSibling) {
  123.  
  124. if (t instanceof Text) {
  125. if (t.textContent.trim().length > 0) {
  126. noP = false;
  127. break;
  128. }
  129. } else if (t instanceof Element) {
  130. const nd = t.nodeName;
  131. if (nd === 'NOSCRIPT' || nd === 'SCRIPT' || nd === 'STYLE') continue;
  132. noP = false;
  133. break;
  134. } else if (t instanceof Comment) {
  135.  
  136. } else {
  137. noP = false;
  138. break;
  139. }
  140. }
  141. if (noP === false) return false;
  142.  
  143. t = elm || 0;
  144. while (t = t.nextSibling) {
  145.  
  146. if (t instanceof Text) {
  147. if (t.textContent.trim().length > 0) {
  148. noQ = false;
  149. break;
  150. }
  151. } else if (t instanceof Element) {
  152. const nd = t.nodeName;
  153. if (nd === 'NOSCRIPT' || nd === 'SCRIPT' || nd === 'STYLE') continue;
  154. noQ = false;
  155. break;
  156. } else if (t instanceof Comment) {
  157.  
  158. } else {
  159. noQ = false;
  160. break;
  161. }
  162. }
  163.  
  164. if (noQ === false) return false;
  165.  
  166. return true;
  167.  
  168.  
  169. };
  170. const hideIframe = (iframe) => {
  171. let noscriptWrapOK = false;
  172. try {
  173. if (iframe instanceof HTMLIFrameElement && iframe.isConnected === true && (iframe.parentNode || 0).nodeName !== 'NOSCRIPT') {
  174. const noscript = document.createElement('noscript');
  175. iframe.replaceWith(noscript);
  176. noscript.appendChild(iframe);
  177. noscriptWrapOK = true;
  178. }
  179. } catch (e) {
  180. console.warn(e);
  181. }
  182.  
  183. if (TURN_ON_BLOCK_REMOVAL && noscriptWrapOK) {
  184. let layerNMax = 8;
  185. let parent = iframe;
  186. let lastSuccess = iframe;
  187. while (parent instanceof HTMLElement && checkOnly(parent)) {
  188. lastSuccess = parent;
  189. parent = parent.parentNode;
  190. layerNMax--;
  191. if (!layerNMax) break;
  192. }
  193.  
  194. const effectNode = parent instanceof HTMLElement ? parent : lastSuccess;
  195.  
  196. if ((effectNode instanceof HTMLElement) && effectNode.nodeName !== "NOSCRIPT") {
  197. effectNode.setAttribute(hKey, '');
  198. let noscriptWrapOK = false;
  199. try {
  200. const noscript = document.createElement('noscript');
  201. effectNode.replaceWith(noscript);
  202. noscript.appendChild(effectNode);
  203. noscriptWrapOK = true;
  204. } catch (e) { }
  205. if (!noscriptWrapOK) {
  206. effectNode.style.setProperty('position', 'fixed', 'important');
  207. effectNode.style.setProperty('left', '-130vw', 'important');
  208. effectNode.style.setProperty('top', '-140vh', 'important');
  209. }
  210. }
  211.  
  212. }
  213.  
  214. };
  215.  
  216.  
  217. const convertionUrl = (nv, iframe) => {
  218.  
  219. let btt = 0;
  220.  
  221. if (typeof nv == 'string' && nv.length > 15 && iframe instanceof HTMLIFrameElement) {
  222. if ((iframe.parentNode || 0).nodeName === 'NOSCRIPT') return null;
  223. if (nv.length >= 22 && nv.startsWith('data:text/html;base64,')) return null;
  224. btt = 1;
  225. } else if ((nv || '') === '' && iframe instanceof HTMLIFrameElement) {
  226. btt = 2;
  227. }
  228.  
  229.  
  230. if (btt > 0) {
  231. if (btt === 1) {
  232. const cv = caching.get(nv);
  233. if (cv !== undefined) return cv;
  234. }
  235. for (const adf of Object.keys(adFilter)) {
  236. const adk = adf.replace(/\[\d+\w*\]/g, '');
  237. if (iframe.matches(adk)) {
  238. const w = adFilter[adf];
  239. const bv = typeof w === 'string' ? w : dynamicGeneration();
  240. if (btt === 1) {
  241. caching.set(nv, bv);
  242. caching.set(bv, bv);
  243. }
  244. return bv;
  245. }
  246. }
  247. if (btt === 1) {
  248. caching.set(nv, null);
  249. }
  250. }
  251. return null;
  252. };
  253. const pd3 = {
  254. set(nv) {
  255. if (typeof nv === 'string') {
  256. if (this[wSnb] === nv) return true;
  257. if (nv.length >= 22 && nv.startsWith('data:text/html;base64,')) {
  258. } else if (nv.length > 15) {
  259. const bv = convertionUrl(nv, this);
  260. if (bv) {
  261. hideIframe(this);
  262. if ((this.parentNode || 0).nodeName !== 'NOSCRIPT') nv = bv;
  263. }
  264. }
  265. }
  266. this[wSnb] = nv;
  267. return true;
  268. },
  269. get() {
  270. return this[wSnb];
  271. },
  272. configurable: true,
  273. enumerable: true
  274. };
  275.  
  276. Object.defineProperty(HTMLIFrameElement.prototype, wSnb, pd2);
  277.  
  278.  
  279. Object.defineProperty(HTMLIFrameElement.prototype, "src", pd3);
  280.  
  281.  
  282. document.addEventListener('load', function (evt) {
  283. const evtTarget = evt.target;
  284. if (evtTarget instanceof HTMLIFrameElement) {
  285. const bv = convertionUrl(evtTarget.src, evtTarget);
  286. if (bv) {
  287. hideIframe(evtTarget);
  288. if ((evtTarget.parentNode || 0).nodeName !== 'NOSCRIPT') evtTarget.src = bv;
  289. evt.stopPropagation();
  290. evt.stopImmediatePropagation();
  291. evt.preventDefault();
  292. }
  293. }
  294. }, true);
  295.  
  296. const um = new WeakSet();
  297.  
  298. const iframeAll = document.getElementsByTagName('iframe');
  299. let iframeLC = 0;
  300. new MutationObserver(() => {
  301. const iframeTC = iframeAll.length;
  302. if (iframeTC !== iframeLC) {
  303. iframeLC = iframeTC;
  304. for (const iframe of iframeAll) {
  305. if (um.has(iframe)) continue;
  306. um.add(iframe);
  307. const bv = convertionUrl(iframe.src, iframe);
  308. if (bv) {
  309. hideIframe(iframe);
  310. if ((iframe.parentNode || 0).nodeName !== 'NOSCRIPT') iframe.src = bv;
  311. }
  312. }
  313. }
  314. }).observe(document, { subtree: true, childList: true });
  315.  
  316. // Your code here...
  317. })();