// ==UserScript==
// @name No Ad IFrame
// @namespace https://staybrowser.com/
// @version 0.1.1
// @description No Ad IFrame created by Stay
// @description:en No Ad IFrame created by Stay
// @description:ja No Ad IFrame created by Stay
// @description:zh-TW No Ad IFrame created by Stay
// @description:zh-CN No Ad IFrame created by Stay
// @author You
// @match *://*/*
// @grant none
// @inject-into page
// @unwrap
// @run-at document-start
// @license MIT
// @compatible chrome
// @compatible firefox
// @compatible opera
// @compatible edge
// @compatible safari
// @allFrames true
// ==/UserScript==
(function () {
'use strict';
const TURN_ON_BLOCK_REMOVAL = true;
if (Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, "__src437__")) return;
Object.defineProperty(HTMLIFrameElement.prototype, "__src437__", {
value: undefined,
writable: true,
configurable: false,
enumerable: false
});
if (!Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, "__src437__")) return;
const pd1 = Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, "src");
const pd2 = Object.assign({}, pd1, {
configurable: true,
enumerable: true
});
const wSnb = Symbol();
const adFilter = {
'iframe[src*="doubleclick.net"]': 1,
'iframe[src*="googlesyndication.com"]': 1,
'iframe[src*="googleadservices.com"]': 1,
'iframe[src*="googletagservices.com"]': 1,
'iframe[src*="adservice.google.com"]': 1,
'iframe[src*="adservice.yahoo.com"]': 1,
'iframe[src*="amazon-adsystem.com"]': 1,
'iframe[src*="adroll.com"]': 1,
'iframe[src*="ads-twitter.com"]': 1,
'iframe[src*="criteo.com"]': 1,
'iframe[src*="taboola.com"]': 1,
'iframe[src*="outbrain.com"]': 1,
'iframe[src*="smartadserver.com"]': 1,
'iframe[src*="openx.net"]': 1,
'iframe[src*="rubiconproject.com"]': 1,
'iframe[id^="aswift_"][src*="ads"][3]': 1,
'iframe[id^="google_ads_iframe_"]': 1,
'iframe[name^="google_ads_iframe_"]': 1,
// 'iframe[src*="doubleclick.net"]': 1,
// 'iframe[src*="googlesyndication.com"]': 1,
'iframe[src*="adservice"]': 1,
'iframe[src*="adserver"]': 1,
// 'iframe[src*="/ads/"]': 1,
// 'iframe[class*="ad-"]': 1,
'iframe[data-ad-slot]': 1,
// Additional patterns
'iframe[id*="adframe"]': 1, // Common variation like "adframe"
'iframe[id*="ad_iframe"]': 1, // "ad_iframe" naming pattern
'iframe[id*="ad_container"]': 1, // Container-like naming often used for ads
'iframe[id*="ad_wrapper"]': 1, // Another container naming pattern
'iframe[class*="adslot"]': 1, // "adslot" is a known pattern (e.g., GPT ad slots)
'iframe[class*="adsense"]': 1, // "adsense" typically indicates Google AdSense
'iframe[class*="ad_frame"]': 1, // Variation with underscore
// 'iframe[class*="advert"]': 1, // "advert" is another clue
// Attribute patterns
'iframe[data-ad-client]': 1, // Data attribute used by some ad scripts
'iframe[data-ad-region]': 1, // Another ad-related data attribute
};
function createBase64DataURL(title) {
// Construct a minimal HTML5 page with the given title
const html = `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"/><title>${title}</title></head><body></body></html>`;
// Encode the HTML string into Base64
const base64String = btoa(html);
// Return as a Data URL
return `data:text/html;base64,${base64String}`;
}
const dynamicGeneration = () => {
const key = Math.floor(Math.random() * 314159265359 + 314159265359).toString(36);
return createBase64DataURL(key);
}
const caching = new Map();
const hKey = `e-${Math.floor(Math.random() * 314159265359 + 314159265359).toString(36)}`;
const checkOnly = (elm) => {
let noP = true;
let noQ = true;
let t = elm || 0;
while (t = t.previousSibling) {
if (t instanceof Text) {
if (t.textContent.trim().length > 0) {
noP = false;
break;
}
} else if (t instanceof Element) {
const nd = t.nodeName;
if (nd === 'NOSCRIPT' || nd === 'SCRIPT' || nd === 'STYLE') continue;
noP = false;
break;
} else if (t instanceof Comment) {
} else {
noP = false;
break;
}
}
if (noP === false) return false;
t = elm || 0;
while (t = t.nextSibling) {
if (t instanceof Text) {
if (t.textContent.trim().length > 0) {
noQ = false;
break;
}
} else if (t instanceof Element) {
const nd = t.nodeName;
if (nd === 'NOSCRIPT' || nd === 'SCRIPT' || nd === 'STYLE') continue;
noQ = false;
break;
} else if (t instanceof Comment) {
} else {
noQ = false;
break;
}
}
if (noQ === false) return false;
return true;
};
const hideIframe = (iframe) => {
let noscriptWrapOK = false;
try {
if (iframe instanceof HTMLIFrameElement && iframe.isConnected === true && (iframe.parentNode || 0).nodeName !== 'NOSCRIPT') {
const noscript = document.createElement('noscript');
iframe.replaceWith(noscript);
noscript.appendChild(iframe);
noscriptWrapOK = true;
}
} catch (e) {
console.warn(e);
}
if (TURN_ON_BLOCK_REMOVAL && noscriptWrapOK) {
let layerNMax = 8;
let parent = iframe;
let lastSuccess = iframe;
while (parent instanceof HTMLElement && checkOnly(parent)) {
lastSuccess = parent;
parent = parent.parentNode;
layerNMax--;
if (!layerNMax) break;
}
const effectNode = parent instanceof HTMLElement ? parent : lastSuccess;
if ((effectNode instanceof HTMLElement) && effectNode.nodeName !== "NOSCRIPT") {
effectNode.setAttribute(hKey, '');
let noscriptWrapOK = false;
try {
const noscript = document.createElement('noscript');
effectNode.replaceWith(noscript);
noscript.appendChild(effectNode);
noscriptWrapOK = true;
} catch (e) { }
if (!noscriptWrapOK) {
effectNode.style.setProperty('position', 'fixed', 'important');
effectNode.style.setProperty('left', '-130vw', 'important');
effectNode.style.setProperty('top', '-140vh', 'important');
}
}
}
};
const convertionUrl = (nv, iframe) => {
let btt = 0;
if (typeof nv == 'string' && nv.length > 15 && iframe instanceof HTMLIFrameElement) {
if ((iframe.parentNode || 0).nodeName === 'NOSCRIPT') return null;
if (nv.length >= 22 && nv.startsWith('data:text/html;base64,')) return null;
btt = 1;
} else if ((nv || '') === '' && iframe instanceof HTMLIFrameElement) {
btt = 2;
}
if (btt > 0) {
if (btt === 1) {
const cv = caching.get(nv);
if (cv !== undefined) return cv;
}
for (const adf of Object.keys(adFilter)) {
const adk = adf.replace(/\[\d+\w*\]/g, '');
if (iframe.matches(adk)) {
const w = adFilter[adf];
const bv = typeof w === 'string' ? w : dynamicGeneration();
if (btt === 1) {
caching.set(nv, bv);
caching.set(bv, bv);
}
return bv;
}
}
if (btt === 1) {
caching.set(nv, null);
}
}
return null;
};
const pd3 = {
set(nv) {
if (typeof nv === 'string') {
if (this[wSnb] === nv) return true;
if (nv.length >= 22 && nv.startsWith('data:text/html;base64,')) {
} else if (nv.length > 15) {
const bv = convertionUrl(nv, this);
if (bv) {
hideIframe(this);
if ((this.parentNode || 0).nodeName !== 'NOSCRIPT') nv = bv;
}
}
}
this[wSnb] = nv;
return true;
},
get() {
return this[wSnb];
},
configurable: true,
enumerable: true
};
Object.defineProperty(HTMLIFrameElement.prototype, wSnb, pd2);
Object.defineProperty(HTMLIFrameElement.prototype, "src", pd3);
document.addEventListener('load', function (evt) {
const evtTarget = evt.target;
if (evtTarget instanceof HTMLIFrameElement) {
const bv = convertionUrl(evtTarget.src, evtTarget);
if (bv) {
hideIframe(evtTarget);
if ((evtTarget.parentNode || 0).nodeName !== 'NOSCRIPT') evtTarget.src = bv;
evt.stopPropagation();
evt.stopImmediatePropagation();
evt.preventDefault();
}
}
}, true);
const um = new WeakSet();
const iframeAll = document.getElementsByTagName('iframe');
let iframeLC = 0;
new MutationObserver(() => {
const iframeTC = iframeAll.length;
if (iframeTC !== iframeLC) {
iframeLC = iframeTC;
for (const iframe of iframeAll) {
if (um.has(iframe)) continue;
um.add(iframe);
const bv = convertionUrl(iframe.src, iframe);
if (bv) {
hideIframe(iframe);
if ((iframe.parentNode || 0).nodeName !== 'NOSCRIPT') iframe.src = bv;
}
}
}
}).observe(document, { subtree: true, childList: true });
// Your code here...
})();