AdBlock for Facebook

Block / Hide "Sponsored" posts on Facebook

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name         AdBlock for Facebook
// @namespace    fb-adblock
// @version      1.6
// @description  Block / Hide "Sponsored" posts on Facebook
// @author       Thor Lancaster
// @match        https://www.facebook.com/*
// @grant        none
// ==/UserScript==

// Add abDbg=true as a URL parameter to debug ad classification

(function() {
    'use strict';
    var initialWait = 1500;
    setTimeout(function(){
    if(document.getElementById("stream_pagelet") == null){
        console.log("AdBlock for Facebook currently only works on news feeds. Aborting.");
        return;
    }
    console.log("AdBlock for Facebook running");
    document.abDbg = window.location.href.includes("abDbg=true");
    document.abCheckAll = false; // If true, check every post every time. Comsumes more CPU
    document.abTestCheck = null; // Set to an element for debugging to determine if this script thinks it's an ad
    var el = (document.getElementById("stream_pagelet"));
    var feed = el.querySelectorAll('[role="feed"]')[0];
    setInterval(function(f){
        try{
            checkAds(f);
            if(document.abTestCheck != null){ // Check test element to determine whether it is an article and/or an and
                var el = document.abTestCheck;
                document.abTestCheck = null;
                if(!el.getAttribute("role") == "article"){
                    console.log("Element is not an article");
                }
                if(isAd(el)){
                    console.log("Element is an ad");
                } else {
                    console.log("Element is not an ad");
                }
            }
        } catch(e){ // Log error before it is swallowed by FB's obfusicated debugging maw
            console.error(e);
        }
    }, 2000, document);
    // TODO check for ads when feed updates rather than every 2 seconds
    }, initialWait);

    function checkAds(feed){
        document.lastABRun = new Date().getTime();
        var posts = feed.querySelectorAll('[role="article"]');
        for(var x = 0; x < posts.length; x++){
            var post = posts[x];
            // Calculate a quick checksum so that if text changes, the post will be re-scanned
            // I suspect that FB was creating non-ad posts and inserting them after a delay
            // To spoof the previous version of this script
            if(!post.abCheckSum || post.abCheckSum != abCheckSum(post) || document.abCheckAll){
                post.abCheckSum = abCheckSum(post);
                var isAdType = isAd(post);
                if(isAdType == 1){
                    if(document.abDbg){
                        markPost(post, "#F70");
                    } else {
                        removePost(post);
                    }
                }
                // Blank post, should never happen
                else if(isAdType == -1){
                    //console.log("ABCHECK blank post");
                }
                else if(isAdType == 0 && document.abDbg){
                    markPost(post, "#0F7"); // for debugging
                }
            }
        }
    }
    // Color a FB post for debugging purposes
    function markPost(post, color){
        var els = post.querySelectorAll("*");
        for(var x = 0; x < els.length; x++){
            els[x].style.background = color;
        }
    }
    function removePost(post){
        post.parentElement.removeChild(post);
        //post.style.height = "0px";
        //post.style.opacity = "0";
    }
    function isAd(post){
        if(post.getAttribute("aria-label") == "Comment"){ // Don't scan comments for ads
            return 0;
        }
        var scan = post.innerText.substring(0, 128);
        if(scan.length == 0){
            return -1; // Blank post
        }
        if(scan.includes("·")){
            var start = scan.substring(0, scan.indexOf("·"));
            if(isSpnsrd(start)){
                //console.log("IS AN AD");
                return 1;
            }
        }
        //console.log("IS NOT AN AD");
        return 0;
    }
    // Scan for a string that represents "Sponsored"
    var SPONSORED = "Sponsored";
    function isSpnsrd(str){
        var spPtr = 0;
        for(var x = 0; x < str.length; x++){
            var chr = str[x];
            if(chr == SPONSORED[spPtr]){
                spPtr++;
                if(spPtr == SPONSORED.length){
                    return true;
                }
            } else {
                var toReset = true;
                if(chr == "\n"){
                    toReset = false;
                } else{
                    for(var y = spPtr; y >= 0; y--){
                        if(chr == SPONSORED[y]){
                            toReset = false;
                        }
                    }
                }
                if(toReset){
                    spPtr = 0;
                }
            }
        }
        return false;
    }

    // Calculate the checksum of an element through it's innerText
    function abCheckSum(el){
        return checkSum(el.innerText);
    }

    // Fast Checksum algorithm. Works great, open-source
    // See https://stackoverflow.com/questions/811195/fast-open-source-checksum-for-small-strings
    function checkSum(s)
    {
        var chk = 0x12345678;
        var len = s.length;
        for (var i = 0; i < len; i++) {
            chk += (s.charCodeAt(i) * (i + 1));
        }
        return (chk & 0xffffffff).toString(16);
    }
})();