removes annoying ads from adam4adam*.com sites, tested in MS Edge and Firefox
// ==UserScript== // @name adam4adam remove ads // @namespace electronsf // @icon // @version 0.1.3 // @license MIT // @include https://www.adam4adam.com/* // @include https://www.adam4adamsfw.com/* // @grant none // // @author [email protected] // @description removes annoying ads from adam4adam*.com sites, tested in MS Edge and Firefox // ==/UserScript== /* jshint esversion: 8 */ // toggle to see debug output in the javascript console var DEBUG = false // each line is a regex anchored to start of class name via '^' // and to the end of class name via $ var classRegexTargetSelfStr = ` promo-bar-ads (banner-)?vip.* ads-.+ header-banner mys-wrapper adsbygoogle.* stories-feed-container google-anno.* ` // special case: easier to identify the child of an elt we need // to remove than the elt itself var classRegexTargetParentStr = ` sticky-block ` const LOG_TAG = 'a4a de-ad-ifier :: ' var logRule = '===============================================\n' var iframesRemoved = false var classToCountInitMap = new Map() var classToRemovalCountMap = new Map() function constructRegex (multilineStr) { return new RegExp( '^(' + multilineStr.split(`\n`).join(`|`).replace(/^\|/, ``).replace(/\|$/, ``) + ')$' ) } const classRegexTargetSelf = constructRegex(classRegexTargetSelfStr) const classRegexTargetParent = constructRegex(classRegexTargetParentStr) function debugAllClassNames () { var classNamesArr = [] var cn Array.from(document.querySelectorAll('*')).forEach(e => { cn = e.className if (cn != '') { if (classToCountInitMap.has(cn)) { classToCountInitMap.set(cn, classToCountInitMap.get(cn) + 1) } else { classNamesArr.push(cn) classToCountInitMap.set(cn, 1) } } }) var classNamesStr, count classNamesArr.toSorted().forEach(cn => { classNamesStr += cn count = classToCountInitMap.get(cn) if (classToCountInitMap.get(cn) > 1) { classNamesStr += ' (' + count + ')' } classNamesStr += '\n' }) console.log( logRule + LOG_TAG + 'DEBUG Class Names\n' + logRule + classNamesStr + logRule ) } function debugPostReport () { var removalsArr = [] var count = 0 // classToRemovalCountMap.keys().forEach(cn => { classToRemovalCountMap.entries().forEach(entry => { removalsArr.push(entry[1] + '\t' + entry[0]) }) console.log( logRule + LOG_TAG + 'DEBUG Removal Report\n' + logRule + removalsArr.toSorted().join('\n') + '\n' + logRule ) } function doRemoval (elt) { if (classToRemovalCountMap.has(elt.className)) { classToRemovalCountMap.set( elt.className, classToRemovalCountMap.get(elt.className) + 1 ) } else { classToRemovalCountMap.set(elt.className, 1) } elt.remove() } function removeByClassRegex (classRegex, removeParent) { var pendingRemoval = [] Array.from(document.querySelectorAll('*')).forEach(e => { if (classRegex.test(e.className)) { pendingRemoval.push(e) } }) pendingRemoval.forEach(e => { console.log(LOG_TAG + "REMOVING element with class='" + e.className + "'") try { if (removeParent) { doRemoval(e.parentNode) } else { doRemoval(e) } } catch (error) { console.log(LOG_TAG + 'Error encountered: ' + error) } }) return pendingRemoval.length } var totalItn = 0 const wait = ms => new Promise(resolve => setTimeout(resolve, ms)) // itn: num iterations // ms: milliseconds between each iteration async function runIterations (itn, ms) { for (var i = 0; i < itn; i++) { totalItn++ console.log( LOG_TAG + 'run #' + totalItn + ': a4a removing ad-related elements' ) var removedCount = 0 removedCount += removeByClassRegex(classRegexTargetParent, true) removedCount += removeByClassRegex(classRegexTargetSelf, false) if (!iframesRemoved) { var numIframesRemoved = 0 Array.from(document.getElementsByTagName('iframe')).map(e => { iframesRemoved = true e.remove() }) } console.log( LOG_TAG + 'sleeping for ' + ms / 1000 + 'sec before running again' ) await wait(ms) } } async function doStart () { !DEBUG || debugAllClassNames() var phase1Itn = 3 var phase1Interval = 1000 var phase2Itn = 3 var phase2Interval = 3000 var startDelay = 0 runIterations(phase1Itn, phase1Interval) startDelay += phase1Itn * phase1Interval await wait(startDelay) runIterations(phase2Itn, phase2Interval) startDelay += phase2Itn * phase2Interval await wait(startDelay) !DEBUG || debugPostReport() console.log(LOG_TAG + 'finished!') return 0 } doStart()