Forked from StigNygaard/Stigs-Facebook-Homefeed-Cleanr.user.js
Created
September 27, 2016 10:28
-
-
Save carandraug/58505695bb234aa75456a9b93a7d37a5 to your computer and use it in GitHub Desktop.
Cleaning up the homefeed on Facebook. Removes Suggested Posts and Sponsored content from the homefeed.
This file contains 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 Stig's Facebook Homefeed Cleanr | |
// @namespace dk.rockland.userscript.facebook.cleanr | |
// @description Cleaning up the homefeed on Facebook. Removes Suggested Posts and Sponsored content from the homefeed. | |
// @match *://*.facebook.com/* | |
// @version 2016.09.07.1 | |
// @author Stig Nygaard, http://www.rockland.dk | |
// @homepageURL http://www.rockland.dk/userscript/facebook/cleanr/ | |
// @supportURL http://www.rockland.dk/userscript/facebook/cleanr/ | |
// @grant GM_getValue | |
// @grant GM_setValue | |
// @grant GM_info | |
// @noframes | |
// ==/UserScript== | |
// Copyright 2016 Stig Nygaard | |
// | |
// Licensed under the Apache License, Version 2.0 (the "License"); | |
// you may not use this file except in compliance with the License. | |
// You may obtain a copy of the License at | |
// | |
// http://www.apache.org/licenses/LICENSE-2.0 | |
// | |
// Unless required by applicable law or agreed to in writing, software | |
// distributed under the License is distributed on an "AS IS" BASIS, | |
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
// See the License for the specific language governing permissions and | |
// limitations under the License. | |
// CHANGELOG - The most important updates/versions: | |
var changelog = [ | |
{version: '2016.09.07.0', description: 'Language detection fix (Do a hard reload after changing language). More configuration options coming up soon...'}, | |
{version: '2016.08.30.0', description: 'Optimizations...'}, | |
{version: '2016.08.27.1', description: 'Ahem, though the script was actually kind of working, previous version was actually doing it internally in a different way than intended. That should be fixed now ;-)'}, | |
{version: '2016.08.25.0', description: 'Fixes for some functionality-problems... And the script source is now available under Apache License 2.0 !'}, | |
{version: '2016.07.03.0', description: 'Danish support added: Removing posts when "Foreslået opslag" or "Sponsoreret".'}, | |
{version: '2016.06.24.1', description: '1st release. English Facebook supported.'} | |
]; // Coming-up/planned: Choose method observer/scroll-trigger/interval. Moving to GitHub repository. Further configuration options to tailor your homefeed. | |
var DEBUG = false; | |
var INFO = true; // Trace the hidden posts in log - even if debug=false | |
var cleaning_runcountINFO = false; | |
var setupObserverINFO = false; | |
function log(s, info) { | |
if ((info && window.console) || (DEBUG && window.console)) { | |
window.console.log('*Cleanr* '+s); | |
} | |
} | |
var cleanr = cleanr || { | |
list: [ | |
{language: 'English', filter: ['Suggested Post', 'Sponsored']}, | |
// {language: 'English', filter: ['Suggested Post', 'Sponsored', ' liked this.', 'Like Page', "'s Birthday", "'s birthday"]}, // my personnal settings | |
{language: 'Dansk', filter: ['Foreslået opslag', 'Sponsoreret']} | |
], | |
activefilter: null, | |
languageDetected: false, | |
cleaning_running: false, | |
cleaning_runcount: 0, | |
postlist: null, | |
startTime: Date.now(), | |
lazystart: 0, | |
insertStyle: function() { // transition: all 3s ease; | |
if (!document.getElementById('cleanrStyle')) { | |
var style = document.createElement('style'); | |
style.type = 'text/css'; | |
style.id = 'cleanrStyle'; | |
if(DEBUG) { | |
style.innerHTML = 'div.cleaned > div {background-color:#FFB !important} #configBox {position:absolute;width:200px;right:-220px} .configBox {opacity:0.6}'; | |
} else { | |
style.innerHTML = 'div.cleaned > div {display:none !important} #configBox {position:absolute;width:200px;right:-220px} .configBox {opacity:0.6}'; | |
} | |
document.getElementsByTagName('head')[0].appendChild(style); | |
log('cleanrStyle has been ADDED'); | |
} | |
}, | |
configure: function() { | |
var lan = cleanr.list[0].language; | |
var languageselection = document.querySelector('._2cpb > div.fsm.fwn.fcg'); | |
if (languageselection) { | |
languageselection = languageselection.textContent; | |
log('languageselection=[' + languageselection + ']'); | |
for (var i = 0; i < cleanr.list.length; i++) { | |
if (languageselection.indexOf(cleanr.list[i].language) === 0) { | |
cleanr.activefilter = cleanr.list[i].filter; | |
lan = cleanr.list[i].language; | |
log('Language set to ' + lan, INFO); | |
} | |
} | |
cleanr.languageDetected = true; // well, at least we have checked | |
} else { | |
log('languageselection not found.') | |
} | |
var contentCol = document.querySelector('div#contentCol'); | |
if (contentCol && !document.getElementById('cleanrsettings')) { | |
contentCol.insertAdjacentHTML('afterbegin', | |
'<div id="configBox" class="configBox">' + | |
'<div title="Facebook Homefeed Cleanr version ' + GM_info.script.version + '">' + | |
'<a href="javascript:if(document.getElementById(\'cleanrsettings\').style.display==\'none\')document.getElementById(\'cleanrsettings\').style.display=\'block\';else document.getElementById(\'cleanrsettings\').style.display=\'none\';void(0)">Cleanr settings</a>' + | |
'</div>' + | |
'<form id="cleanrsettings" name="cleanrsettings" style="display:none;padding:1em 0 1em 0">' + | |
'<fieldset><legend>Filter mode</legend>' + | |
'<div><label for="hideId"><input type="radio" name="mode" id="hideId" value="hide" '+(DEBUG?'':'checked="checked" ')+'/> Hide (Normal mode)</label></div>' + | |
'<div><label for="highlightId"><input type="radio" name="mode" id="highlightId" value="highlight" '+(DEBUG?'checked="checked" ':'')+'/> Highlight (Debug mode)</label></div>' + | |
'</fieldset>' + | |
'<fieldset id="filterlist"><legend>Filters (<span id="filterlanguage">' + lan + '</span>)</legend>' + | |
'</fieldset>' + | |
//'<fieldset><legend>Method</legend>' + | |
//'<div><label for="defaultId"><input type="radio" name="method" id="defaultId" value="default" /> Default/auto (Currently <em>Observer</em>) - Recommended method until it eventually stops working</label></div>' + | |
//'<div><label for="observerId"><input type="radio" name="method" id="observerId" value="observer" /> Force <em>Observer</em></label></div>' + | |
//'<div><label for="scrollId"><input type="radio" name="method" id="scrollId" value="scroll" /> Force <em>Scroll-triggered</em></label></div>' + | |
//'<div><label for="intervalId"><input type="radio" name="method" id="intervalId" value="interval" /> Force <em>Interval-driven</em></label></div>' + | |
//'</fieldset>' + | |
'<button type="button" id="updateSettings" style="margin-top:.5em">Update settings</button>' + | |
'<p>Most important and recent updates:</p>' + | |
'<div id="changelog">' + | |
'</div>' + | |
'</form>' + | |
'</div>'); | |
var flist = document.getElementById('filterlist'); | |
if (flist) { | |
for (i = 0; i < cleanr.activefilter.length; i++) { | |
flist.insertAdjacentHTML('beforeend', '<div><input type="checkbox" id="f' + i + '" value="' + cleanr.activefilter[i] + '" checked="checked" disabled="disabled" /><label for="f'+i+'"> ' + cleanr.activefilter[i] + '</label></div>'); | |
} | |
flist.insertAdjacentHTML('beforeend', '<p style="margin-bottom:0;display:none">Filters are <em>case sensitive</em>.</p>'); | |
} | |
var updateSettingsBtn = document.getElementById('updateSettings'); | |
if (updateSettingsBtn) { | |
updateSettingsBtn.addEventListener('click', cleanr.saveSettings); | |
} | |
var clog = document.getElementById('changelog'); | |
if (clog) { | |
for (i = 0; i < changelog.length; i++) { | |
clog.insertAdjacentHTML('beforeend', '<div><em>' + changelog[i].version + ':</em><br />' + changelog[i].description + '</div>'); | |
} | |
} | |
} | |
}, | |
loadSettings: function() { | |
DEBUG = (''+GM_getValue( 'debug', DEBUG)) === 'true'; | |
}, | |
saveSettings: function() { | |
GM_setValue('debug', (document.forms['cleanrsettings'].elements['mode'].value==='highlight') ); | |
location.reload(); | |
}, | |
cleaning: function () { | |
cleanr.lazystart = 0; | |
if(cleanr.cleanr_running) return; | |
cleanr.cleanr_running = true; | |
cleanr.cleaning_runcount++; | |
log('Running cleaning() #'+cleanr.cleaning_runcount + ' at time='+cleanr.secondsSinceStart()+' sec. after start.', cleaning_runcountINFO); | |
if (!cleanr.postlist) cleanr.postlist = document.getElementsByClassName('_5jmm'); | |
if (!cleanr.languageDetected) { | |
cleanr.configure(); | |
} | |
log('Running cleaning() #'+cleanr.cleaning_runcount + '. Cleaning on a postlist of length=' + cleanr.postlist.length, cleaning_runcountINFO); | |
/* | |
for (var i = 0; i < cleanr.postlist.length; i++) { | |
if (!cleanr.postlist[i].classList.contains('cleaned')) { | |
for (var j = 0; j < cleanr.activefilter.length; j++) { | |
if (cleanr.postlist[i].textContent.indexOf(cleanr.activefilter[j]) > -1) { | |
cleanr.postlist[i].classList.add('cleaned'); | |
log('Hiding or highlighting item because <' + cleanr.activefilter[j] + '> : [ ' + cleanr.postlist[i].textContent.substring(0, 500) + ' ]', INFO); | |
} | |
} | |
} | |
} | |
*/ | |
for (var i = cleanr.postlist.length -1; i > 0; i--) { | |
var itemCleaned = cleanr.postlist[i].classList.contains('cleaned'); | |
if (itemCleaned && (cleanr.cleaning_runcount % 3 < 2)) { // well, usually return, but not always because apparently there can be some left-overs... | |
cleanr.cleanr_running = false; | |
return; // quick exit cleaning | |
} | |
if (!itemCleaned) { | |
for (var j = 0; j < cleanr.activefilter.length; j++) { | |
if (cleanr.postlist[i].textContent.indexOf(cleanr.activefilter[j]) > -1) { | |
cleanr.postlist[i].classList.add('cleaned'); | |
log('Hiding or highlighting item because <' + cleanr.activefilter[j] + '> : [ ' + cleanr.postlist[i].textContent.substring(0, 500) + ' ]', INFO); | |
break; | |
} | |
} | |
} | |
} | |
cleanr.cleanr_running = false; | |
}, | |
lazystartCleaning: function(mutations) { | |
log('Running lazystartCleaning(), lazystart=' + cleanr.lazystart, cleaning_runcountINFO); | |
cleanr.lazystart++; | |
if (cleanr.lazystart > 1) { | |
log('Running lazystartCleaning(), but skipping cleaning() because a lazystart pending...', cleaning_runcountINFO); | |
} else { | |
log('Running lazystartCleaning() and scheduling cleaning() ' + (typeof mutations === 'undefined' ? ' without mutations.' : (' with ' + mutations.length + ' mutation records.')), cleaning_runcountINFO); | |
window.setTimeout(cleanr.cleaning, 100); // Let it breathe 100ms first...... | |
} | |
}, | |
setupObserver: function () { | |
log('Running setupObserver()...'); | |
cleanr.insertStyle(); | |
var observed = document.querySelector('div[id^="feed_stream_"]') || document.querySelector('div[id^="topnews_main_stream"]') || document.getElementById('stream_pagelet'); | |
if (!observed) { | |
log('Object to observe NOT found - re-trying later...', setupObserverINFO); | |
} else if (observed.classList.contains('hasObserver')) { | |
log('Everything is okay! - But checking again later...', setupObserverINFO); | |
} else { | |
var oldObserved = document.getElementsByClassName('hasObserver').item(0); // Maybe we had an observer on another element? | |
if (oldObserved) { | |
oldObserved.disconnect(); | |
log(' *** An old observer was removed from element with id='+oldObserved.id+'. ***', setupObserverINFO); | |
} | |
cleanr.cleaning(); | |
log('Now adding Observer and starting...', setupObserverINFO); | |
// var observer = new MutationObserver(cleanr.cleaning); | |
var observer = new MutationObserver(cleanr.lazystartCleaning); | |
var config = {childList: true, attributes: false, characterData: false, subtree: true}; | |
observer.observe(observed, config); | |
observed.classList.add('hasObserver'); | |
log('Observer added and running on element with id='+observed.id+'...', setupObserverINFO); | |
} | |
}, | |
secondsSinceStart: function() { | |
return ((Date.now()-cleanr.startTime)/1000).toFixed(3); | |
}, | |
registerScroll: function () { | |
cleanr.hasScrolled = true; | |
}, | |
scrollTick: function() { | |
if (cleanr.hasScrolled) { | |
cleanr.hasScrolled = false; | |
cleanr.cleaning(); | |
} | |
}, | |
init: function () { | |
log('Running init()'); | |
cleanr.activefilter = cleanr.list[0].filter; // Default to English filters | |
cleanr.loadSettings(); | |
cleanr.insertStyle(); | |
// initial cleanups... | |
setTimeout(cleanr.cleaning,100); | |
setTimeout(cleanr.cleaning,300); | |
setTimeout(cleanr.cleaning,700); | |
setTimeout(cleanr.cleaning,1200); | |
// Methods: | |
if (true) { // observer | |
setInterval(cleanr.setupObserver, 2000); // Every twice second, check if observer is (still) running - and setup if not... | |
} else if (false) { // scroll trigger | |
window.addEventListener("scroll", cleanr.registerScroll); | |
setInterval(cleanr.scrollTick, 250); | |
} else if (false) { // simple interval check | |
setInterval(cleanr.cleaning, 250); | |
} | |
} | |
}; | |
cleanr.init(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment