Last active
October 31, 2024 18:11
-
-
Save 25yeht/8d598b2daf9ec3d1a29af7ae0c1be407 to your computer and use it in GitHub Desktop.
Block Ads Pretty Much All Ads On Websites!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
javascript: | |
Object.defineProperties(function() { | |
function randomInt(min, max) { | |
return Math.floor(Math.random() * (max - min + 1)) + min; | |
} | |
function rn(arr) { | |
const randomIndex = randomInt(0, arr.length - 1); | |
return arr[randomIndex]; | |
} | |
function randomHtmlId(len = 10) { | |
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-'; | |
let result = ''; | |
for (let i = 0; i < len; i++) { | |
result += characters.charAt(randomInt(0, characters.length - 1)); | |
} | |
while (/^\d/.test(result)) { | |
result = ''; | |
for (let i = 0; i < len; i++) { | |
result += characters.charAt(randomInt(0, characters.length - 1)); | |
} | |
} | |
return result; | |
} | |
const spoofedElements = [document.body]; | |
const originalGetComputedStyle = getComputedStyle.bind(window); | |
const cloneNode = Node.prototype.cloneNode; | |
const adBlockingId = randomHtmlId(); | |
const adBlockingStyleSheet = document.createElement("style"); | |
const adBlockingStyles = "." + adBlockingId + "{ display: none !important; }"; | |
adBlockingStyleSheet.textContent = adBlockingStyles; | |
var spoofedAdBlockingStyles = ""; | |
const spoofAdBlockingStylesProperty = { | |
get: function() { | |
return spoofedAdBlockingStyles; | |
}, | |
set: function(val) { | |
return spoofedAdBlockingStyles = String(val); | |
} | |
}; | |
Object.defineProperty(adBlockingStyleSheet, "textContent", spoofAdBlockingStylesProperty); | |
Object.defineProperty(adBlockingStyleSheet, "innerHTML", spoofAdBlockingStylesProperty); | |
Object.defineProperty(adBlockingStyleSheet, "innerText", spoofAdBlockingStylesProperty); | |
Object.defineProperty(adBlockingStyleSheet, "outerText", spoofAdBlockingStylesProperty); | |
Object.defineProperty(adBlockingStyleSheet, "outerHTML", { | |
get: function() { | |
return "<style>" + spoofedAdBlockingStyles + "</style>"; | |
}, | |
set: function(val) { | |
return spoofedAdBlockingStyles = String(val); | |
} | |
}); | |
document.head.appendChild(adBlockingStyleSheet); | |
const originalDisplays = new Map(); | |
function spoofStyleDeclaration(result, elt) { | |
Object.defineProperty(result, "display", { | |
get: function() { | |
return originalDisplays.has(elt) ? originalDisplays.get(elt) : "block"; | |
} | |
}); | |
const realGPV = result.getPropertyValue.bind(result); | |
result.getPropertyValue = function(property) { | |
const result = realGPV(...arguments); | |
if(property === "display") return originalDisplays.has(elt) ? originalDisplays.get(elt) : "block"; | |
return result; | |
}; | |
return result; | |
} | |
getComputedStyle = function(elt, pseudoElt) { | |
const result = originalGetComputedStyle(...arguments); | |
if(pseudoElt) return result; | |
if(spoofedElements.includes(elt)) { | |
return spoofStyleDeclaration(result, elt); | |
} | |
return result; | |
}; | |
getComputedStyle.toString = function() { | |
return "function getComputedStyle() { [native code] }"; | |
}; | |
getComputedStyle[Symbol.toPrimitive] = function() { | |
return "function getComputedStyle() { [native code] }"; | |
}; | |
function parseAttributeList(el, attribute) { | |
const classesString = el.getAttribute(attribute); | |
return classesString ? classesString.split(" ") : []; | |
} | |
function parseClassName(name) { | |
const parsedRaw = name.split(/[-_]+|\B(?=[A-Z])/); | |
const parsed = []; | |
for(const word of parsedRaw) { | |
parsed.push(word.toLowerCase()); | |
} | |
return parsed; | |
} | |
function parseAttributeListWords(el, attribute) { | |
const classList = parseAttributeList(el, attribute); | |
let classWords = []; | |
for(const className of classList) { | |
classWords = classWords.concat(parseClassName(className)); | |
} | |
return classWords; | |
} | |
function parseAttributesListWords(el, attributes) { | |
let result = []; | |
for(const attribute of attributes) { | |
result = result.concat(parseAttributeListWords(el, attribute)); | |
} | |
return result; | |
} | |
function includesAny(arrOrString, includes) { | |
let doesInclude = false; | |
for(let i = 0; i < includes.length; i++) { | |
let searchString = includes[i]; | |
if(arrOrString.includes(searchString)) { | |
doesInclude = true; | |
break; | |
} | |
} | |
return doesInclude; | |
} | |
const adTokens = ["ad", "ads", "adsense", "adsbygoogle", "aswift", "sponsored", "advertisement", "advertizement", "advert", "interads"]; | |
function checkIfElementIsAnAd(el) { | |
if(el === document.documentElement || el === document.body) return false; | |
const text = el.textContent.trim().toLowerCase(); | |
const colorProperty = getComputedStyle(el).getPropertyValue("color"); | |
let parsed = parseAttributesListWords(el, ["class", "id", "title", "aria-label"]); | |
let isAnAd = includesAny(parsed, adTokens); | |
for(const token of parsed) { | |
if(token.startsWith("ads") || token.includes("advert") || token.endsWith("ads")) { | |
isAnAd = true; | |
break; | |
} | |
} | |
if(el.tagName === "IFRAME" && el.src) { | |
const srcURL = new URL(el.src); | |
if(srcURL.host.includes("syndicatedsearch") || srcURL.host.includes("doubleclick") || srcURL.hostname.endsWith(".goog")) isAnAd = true; | |
} | |
if(text === "advertisement" && colorProperty && colorProperty !== "rgb(0, 0, 0)" && colorProperty !== "rgb(255, 255, 255)") isAnAd = true; | |
if(el.getAttribute("style") && el.getAttribute("style").length > 9000 && countImportant(el.getAttribute("style")) > 200) isAnAd = true; | |
return isAnAd; | |
} | |
var isBlocking = false; | |
function blockAdElement(el, force) { | |
const isAd = checkIfElementIsAnAd(el); | |
if(!isAd && !force) return; | |
if(!el.classList.contains(adBlockingId)) { | |
originalDisplays.set(el, originalGetComputedStyle(el).getPropertyValue("display")); | |
el.classList.add(adBlockingId); | |
} | |
if(spoofedElements.includes(el)) return; | |
if(originalGetComputedStyle(el).display !== "none") { | |
let originalDisplay = originalGetComputedStyle(el).getPropertyValue("display"); | |
let originalDisplayPriority = originalGetComputedStyle(el).getPropertyPriority("display"); | |
el.style.setProperty("display", "none", "important"); | |
Object.defineProperty(el.style, "display", { | |
get: function() { | |
return originalDisplay + (originalDisplayPriority ? " !" + originalDisplayPriority : ""); | |
}, | |
set: function() {} | |
}); | |
const realGPV = el.style.getPropertyValue.bind(el.style); | |
el.style.getPropertyValue = function(property) { | |
const result = realGPV(...arguments); | |
if(property === "display") return originalDisplay; | |
return result; | |
}; | |
el.style.setProperty = function(property, value, priority) { | |
if(property.toLowerCase() === "display") { | |
originalDisplay = value; | |
originalDisplayPriority = priority ? priority : ""; | |
return; | |
} | |
}; | |
} | |
spoofedElements.push(el); | |
} | |
function countImportant(str) { | |
const matches = str.match(/!important/g); | |
return matches ? matches.length : 0; | |
} | |
function noGoogleVignette() { | |
try { | |
history.replaceState(null, null, location.href.slice(0, location.href.length - 16)); | |
} catch(err) {} | |
} | |
function blockGoogleVignettePath() { | |
const hash = location.hash; | |
if(hash === "#google_vignette") noGoogleVignette(); | |
} | |
function blockAds(nodesToCheck) { | |
if(isBlocking) return; | |
isBlocking = true; | |
for(const node of nodesToCheck) { | |
if(node.nodeType !== 1) continue; | |
blockAdElement(node); | |
} | |
blockGoogleVignettePath(); | |
isBlocking = false; | |
} | |
const observer = new MutationObserver(function(mutations) { | |
let nodesToCheck = []; | |
for(const mutation of mutations) { | |
nodesToCheck.push(mutation.target); | |
nodesToCheck = nodesToCheck.concat(mutation.addedNodes); | |
if(Array.from(mutation.removedNodes).includes(adBlockingStyleSheet)) document.head.appendChild(adBlockingStyleSheet); | |
} | |
blockAds(nodesToCheck); | |
}); | |
observer.observe(document, { childList: true, subtree: true, attributes: true }); | |
blockAds(Array.from(document.querySelectorAll("*"))); | |
}, { | |
toString: { | |
get: function() { | |
return function() { | |
return ""; | |
} | |
} | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment