Facebook shitpost remover

Block all shared posts by people who only post shared content.

// ==UserScript==
// @name         Facebook shitpost remover
// @version      1.0.1
// @description  Block all shared posts by people who only post shared content.
// @author       G-Rex
// @match        https://www.facebook.com/*
// @run-at       document-idle
// @grant        GM_getValue
// @grant        GM_setValue
//
// @namespace https://greasyfork.org/users/154522
// ==/UserScript==

(function() {
    'use strict';
    // Selectors
    var streamSelector = 'div[id^="topnews_main_stream"]';
    var storySelectors = [
        'div[id^="hyperfeed_story_id"]',
        'div[data-ownerid^="hyperfeed_story_id"]'
    ];

    var language = document.documentElement.lang;
    var nodeContentKey = (('innerText' in document.documentElement) ? 'innerText' : 'textContent');
    var mutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;

    var body;
    var stream;
    var observer;
    var localStorage = window.localStorage;
    var BLOCKED_IDS_STRING = 'blockedIds';
    var blockedIds = JSON.parse(GM_getValue(BLOCKED_IDS_STRING, "null"));//JSON.parse(localStorage.getItem(BLOCKED_IDS_STRING));

    if(!blockedIds) {
        blockedIds = [];
        //localStorage.setItem(BLOCKED_IDS_STRING, JSON.stringify(blockedIds));
        GM_setValue(BLOCKED_IDS_STRING, JSON.stringify(blockedIds));
    }

    function remove(story) {
        if(!story) {
            return;
        }

        story.remove();
    }

    function isBlocked(id) {
        if(!id || id == -1) {
            return false;
        }

        for(let i = 0; i < blockedIds.length; i++) {
            if(blockedIds[i] === id) {
                return true;
            }
        }

        return false;
    }

    function block(id) {
        if(isBlocked(id)) {
            return;
        }

        blockedIds.push(id);

        GM_setValue(BLOCKED_IDS_STRING, JSON.stringify(blockedIds));

        process();
    }

    function addBlockButton(story) {
        if(!story) {
            return;
        }

        let content = story.querySelector('div.mtm');

        let button = content.querySelector('button.shitpost-hider');

        if(button) {
            return;
        }

        button = document.createElement('button');
        let id = getPosterId(story);
        button.onclick = function() {block(id);};
        button.innerHTML = 'Hide';
        button.className = 'shitpost-hider';

        content.appendChild(button);
    }

    function isShared(story) {
        if(!story) {
            return false;
        }

        //get title element
        let title = story.querySelector('span.fwn.fcg span.fcg');

        if(!title) {
            return false;
        }

        //get poster element
        let poster = title.querySelector('a.profileLink');

        if(!poster) {
            return false;
        }

        //get poster id
        let hovercard = poster.getAttribute('data-hovercard');
        let idMatch = hovercard.match(/id=([0-9]+)/);
        let id = -1;

        if(idMatch) {
            id = idMatch[1];
        }

        //get text for title
        let titleText = title.innerText;

        //find shared in title
        if(titleText.indexOf("shared") >= 0 && titleText.indexOf("memory.") < 0) {
            return true;
        }

        return false;
    }

    function getPosterId(story) {
        if(!story) {
            return -1;
        }

        //get title element
        let title = story.querySelector('span.fwn.fcg span.fcg');

        if(!title) {
            return -1;
        }

        //get poster element
        let poster = title.querySelector('a.profileLink');

        if(!poster) {
            return -1;
        }

        //get poster id
        let hovercard = poster.getAttribute('data-hovercard');
        let idMatch = hovercard.match(/id=([0-9]+)/);
        let id = -1;

        if(idMatch) {
            id = idMatch[1];
        }

        return id;
    }

    function process() {
        // Locate the stream every iteration to allow for FB SPA navigation which
        // replaces the stream element
        stream = document.querySelector(streamSelector);
        if(!stream) {
            return;
        }

        var i;
        var j;
        var stories;
        for(i = 0; i < storySelectors.length; i++) {
            stories = stream.querySelectorAll(storySelectors[i]);
            if(!stories.length) {
                return;
            }

            for(j = 0; j < stories.length; j++) {
                if(isShared(stories[j])) {
                    let id = getPosterId(stories[j]);
                    if(isBlocked(id)) {
                        remove(stories[j]);
                    } else {
                        addBlockButton(stories[j]);
                    }
                }
            }
        }
    }

    if(mutationObserver) {
        body = document.querySelector('body');
        if(!body) {
            return;
        }

        observer = new mutationObserver(process);
        observer.observe(body, {
            'childList': true,
            'subtree': true
        });
    }
})();