NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Remove Facebook ads // @namespace http://openuserjs.org/users/ScriptBuggy // @version 0.5 // @description Uses mutation observer to take action when elements added to page. Looks for ads based on Spon appearing in non hidden elements! // @author Skarn // @license MIT // @copyright 2020, ScriptBuggy (https://openuserjs.org/users/ScriptBuggy) // @match https://www.facebook.com* // @include https://www.facebook.com* // ==/UserScript== // ==OpenUserJS== // @author ScriptBuggy // ==/OpenUserJS== (function () { 'use strict'; //set up an observer object var observerOptions = { childList: true, subtree: true } var observer = new MutationObserver(callback); var processedNodes = new Set(); var targetNode; //init trytryagain(init); function trytryagain(fnToTry) { if (fnToTry.timer) { window.clearTimeout(fnToTry.timer); fnToTry.timer = null; } var tries = 10; var tryNumber = 0; tryNumber++; try { fnToTry(); } catch (e) { if (tryNumber > tries) { //give up. return; } //try again fnToTry.timer = window.setTimeout(function () { fnToTry(); }, 2000); } } function init() { //GM_addStyle(".userContentWrapper {opacity: 0; transition: opacity 0.1s;}"); targetNode = document.getElementById("mainContainer"); removeAds(targetNode); //observe trytryagain(restartObserver); //right column removal - more fiddly than worthwhile - might remove later or make optional document.querySelector('#rightCol').style.display = 'none'; var content = document.querySelector('#contentArea') || document.querySelector('#timeline_story_column'); if (content) { content.style.left = '0px'; content.style.setProperty("width", "calc(100% - 50px)", "important"); content.style.setProperty("left", "0px", "important"); } } function restartObserver() { targetNode = document.getElementById("mainContainer"); observer.disconnect(); observer.observe(targetNode, observerOptions); } function removeAds(addedNode) { try { if (processedNodes.has(addedNode)) { return; } processedNodes.add(addedNode); observer.disconnect(); var interestingNodes = addedNode.querySelectorAll('.c_1kvvzw3p2b.v_1kvvzw3p30.o_1kvvzw3p2o') interestingNodes.forEach(function (item) { var interestingCharacters = item.querySelectorAll('.c_1kvvzw3p2b'); var visibleChars = ''; if (interestingCharacters.length > 1) { interestingCharacters.forEach(function (char) { if (char.children.length === 0) { var stylePosition = window.getComputedStyle(char).position; if (stylePosition !== 'absolute' && stylePosition !== 'fixed') { visibleChars = visibleChars + char.textContent; } } }); var rx = /.*S.*p.*o.*n.*s.*o.*r.*e.*d.*/; var match = visibleChars.match(rx); if (match && match.length > 0) { var section = item.closest('.userContentWrapper'); if (section) { section.style.display = 'none'; } } } }); observer.observe(targetNode, observerOptions); } catch (e) { //error during ad removal - skip it, but re-enable observer still observer.observe(targetNode, observerOptions); } } function callback(mutationList, observer) { //wipe ads out of whatever was added to the page mutationList.forEach((mutation) => { switch (mutation.type) { case 'childList': var addedNodes = mutation.addedNodes; if (addedNodes && addedNodes.length > 0) { var addedNode = addedNodes[0]; if (addedNode.nodeType === 1) { removeAds(addedNode); } } break; } }); //every time the page dom is modified, restart the observer //this is because clicking on linked pages etc. for some reason killed observer //doesn't hurt to reinitialise it every time. trytryagain(restartObserver); } })();