Last active
February 7, 2019 00:33
-
-
Save theftprevention/e3e935945f730d0dc2563f34ab38ca55 to your computer and use it in GitHub Desktop.
Periodically removes sponsored content from the Facebook news feed.
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
// ==UserScript== | |
// @name Remove Facebook Ads | |
// @version 1.0 | |
// @description Removes sponsored content from the Facebook news feed. | |
// @author theftprevention | |
// @match https://www.facebook.com/ | |
// @grant none | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
var interval = 1000; | |
var reg_sponsored = /^Sponsored$/i; | |
var rightColumnPageletSelector = ".home_right_column .pagelet-group:not(#stories_pagelet_rhc):not(#pagelet_reminders)"; | |
var subtitleSelector = "[data-testid='story-subtitle'] > span:first-child"; | |
var titleSelector = "a[href][data-hovercard]:not([tabindex='-1'])"; | |
var whitelist = new WeakSet(); | |
/** | |
* @returns {Array<HTMLElement>} | |
*/ | |
function findAds() { | |
var a = 0; | |
var ads = []; | |
var i, l; | |
var element; | |
var subtitle; | |
var subtitles = document.querySelectorAll(subtitleSelector); | |
// 1. Sponsored news feed stories | |
for (i = 0, l = subtitles.length; i < l; i++) { | |
subtitle = subtitles[i]; | |
if (whitelist.has(subtitle)) { | |
continue; | |
} | |
whitelist.add(subtitle); | |
element = getParentStoryElement(subtitle); | |
if (!element || whitelist.has(element)) { | |
continue; | |
} | |
if (reg_sponsored.test(getDisplayedInnerText(subtitle))) { | |
ads[a++] = element; | |
} else { | |
whitelist.add(element); | |
} | |
} | |
// 2. Right column pagelet advertisements | |
var pagelets = document.querySelectorAll(rightColumnPageletSelector); | |
for (i = 0, l = pagelets.length; i < l; i++) { | |
ads[a++] = pagelets[i]; | |
} | |
return ads; | |
} | |
/** | |
* @param {HTMLElement} element | |
* @returns {string} | |
*/ | |
function getDisplayedInnerText(element) { | |
var style = getComputedStyle(element); | |
if (style.display === 'none') { | |
return ''; | |
} | |
var child; | |
var children = element.childNodes; | |
var text = ''; | |
for (var i = 0, l = children.length; i < l; i++) { | |
child = children[i]; | |
switch (child.nodeType) { | |
case Node.ELEMENT_NODE: | |
text += getDisplayedInnerText(child); | |
break; | |
case Node.TEXT_NODE: | |
text += child.textContent; | |
break; | |
} | |
} | |
return text; | |
} | |
/** | |
* @param {ChildNode} node | |
* @returns {HTMLElement | undefined} | |
*/ | |
function getParentStoryElement(node) { | |
var element = node.parentElement; | |
while (element && element !== document.body) { | |
if (element.getAttribute('data-testid') === 'fbfeed_story') { | |
return element; | |
} | |
element = element.parentElement; | |
} | |
} | |
/** | |
* @returns {Array<HTMLElement>} | |
*/ | |
function removeAds() { | |
var ad; | |
var ads = findAds(); | |
var count = ads.length; | |
var i = count; | |
var parent; | |
var title; | |
var titleElement; | |
while (i--) { | |
ad = ads[i]; | |
parent = ad.parentNode; | |
if (parent) { | |
titleElement = ad.getAttribute('data-testid') === 'fbfeed_story' ? ad.querySelector(titleSelector) : null; | |
title = titleElement ? titleElement.textContent.trim() : ''; | |
try { | |
parent.removeChild(ad); | |
if (title) { | |
console.log('Removed an advertisement from %c' + title + '%c.', 'font-weight: bold', ''); | |
} | |
} catch (e) { | |
if (e instanceof Error) { | |
if (title) { | |
console.error('Failed to remove an advertisement from %c' + title + '%c: (' + e.name + ') ' + e.message, 'font-weight: bold', ''); | |
} else { | |
console.error('Failed to remove an advertisement: (' + e.name + ') ' + e.message); | |
} | |
} | |
} | |
} | |
} | |
return ads; | |
} | |
/** | |
* @returns {void} | |
*/ | |
function initialize() { | |
document.removeEventListener('DOMContentLoaded', initialize); | |
setInterval(removeAds, interval); | |
} | |
if (document.readyState === 'loading') { | |
document.addEventListener('DOMContentLoaded', initialize); | |
} else { | |
initialize(); | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment