Greasy Fork

Greasy Fork is available in English.

facebook - ad block v3

Hides sponsored posts in FB's news-feed (Sept 2021)

当前为 2021-09-18 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         facebook - ad block v3
// @version      3.06
// @description  Hides sponsored posts in FB's news-feed (Sept 2021)
// @author       zbluebugz
// @match        https://*.facebook.com/*
// @-icon         https://www.google.com/s2/favicons?domain=facebook.com
// @-icon64URL    https://www.google.com/s2/favicons?domain=facebook.com
// @run-at       document-idle
// @namespace http://greasyfork.icu/users/812551
// ==/UserScript==
/*
Comments:
    original: https://pastebin.com/raw/vmaiA8jJ
    05/09/2021: FB has changed the way sponsored posts are marked - made harder to detect
                - this script detects the new way.
    06/09/2021: Detected a couple of slight variations in how sponsored posts are marked
    14/09/2021: Detected another slight variation in how sponsored posts are marked
    14/09/2021: Fixed bug with getting textNode values.
    18/09/2021: Detected another variation how sponsored posts are marked. Code detection rewritten.
*/

(function () {
    'use strict';

    var title = 'facebook - ad block';

    // -- START KEYWORDS

    // Keyword: Sponsored posts'
    // - if more than one keyword, use this format: ['keyword 1', 'keyword 2']
    var SPONSORED_WORDS = ['Sponsored'];

    // Keyword: Sponsored like posts - (often flagged as sponsored posts - not all the time)
    // var suggestions = ['Shop Now', 'Learn More', 'Sign Up', 'Download', 'Get Offer', 'Apply Now', 'Book Now', 'Play Game', 'Get Quote'];
    // var suggestions = ['Shop Now', 'Sign Up', 'Download', 'Get Offer', 'Book Now', 'Play Game', 'Get Quote'];
    var suggestions = [];

    // Hide certain promotional elements ...
    const TOGGLE_SUGGESTED_CONTENT = false;
    const TOGGLE_SUGGESTED_EVENTS = false;
    const TOGGLE_PEOPLE_YOU_MAY_KNOW = true;
    const TOGGLE_SUGGESTED_PAGES = true ;
    const TOGGLE_PAID_PARTNERSHIP = true;
    const TOGGLE_SUGGESTED_GROUPS = false;

    const TOGGLE_CREATE_ROOM = true;

    // Keywords: text to find for certain promotional elements
    if(TOGGLE_SUGGESTED_CONTENT) 	suggestions.push('Suggested for you');
    if(TOGGLE_SUGGESTED_EVENTS) 	suggestions.push('Suggested Events');
    if(TOGGLE_PEOPLE_YOU_MAY_KNOW) 	suggestions.push('People you may know');
    if(TOGGLE_SUGGESTED_PAGES) 	 	suggestions.push('Suggested Pages');
    if(TOGGLE_PAID_PARTNERSHIP) 	suggestions.push('Paid partnership');
    if(TOGGLE_SUGGESTED_GROUPS)	 	suggestions.push('Suggested groups');

    // -- END KEYWORDS

    // -- rest of code - no more keywords to adjust.

    // hide or highlight the selected posts
    let HIDE_STYLE = (true) ? 'display:none !important' : 'border:3px solid yellow !important';

    // how often to run this script (milliseconds)
    const CHECK_RATE_MS = 100;

    function hide(el) {
        return el.setAttribute('style',HIDE_STYLE);
    }

    function doChanges() {

        if(TOGGLE_CREATE_ROOM){
            var create_room = document.querySelector('div[data-pagelet="VideoChatHomeUnitNoDDD"]');
            if(create_room) hide(create_room);
        }

        function findSponsoredPosts() {
            // get collection of posts, ignore those already read by this script.
            let posts = Array.from(
                document.querySelectorAll('div[data-pagelet*=FeedUnit]:not([adbpr])')
                // next line for use in debugging - ignores the posts that have been already processed.
                //document.querySelectorAll('div[data-pagelet*=FeedUnit]')
            );
            // loop through each post to see if it is a sponsored one or not
            let hidePosts = [];
            let csr; // window.getComputedStyle(element) results
            posts.forEach(
                post => {
                    // flag this post as not to be read/processed again
                    post.setAttribute('adbpr', true);
                    // within this unread post, find the SPAN element(s) having aria-label = Sponsored
                    // (usually only one is found)
                    let alSpans = Array.from(post.querySelectorAll('span[aria-label="Sponsored"]'));
                    // is the word "Sponsored" visible?
                    // - there are several spans having single letters - all randomised, but will make up "sponsored" when certain span tags are "visible".
                    alSpans.forEach(sp => {
                        let daText = '';
                        // get the next sibling from the <span aria-label="Sponsored"></span>
                        let nsp = sp.nextSibling;
                        // note that this sibling is a "parent" ...
                        // .. sometimes it has a textNode (as firstChild) ...
                        if (nsp.tagName === "SPAN") {
                            if (nsp.firstChild.tagName === 'SPAN') {
                                // no immediate textNode (nothing to do)
                            }
                            else {
                                csr = window.getComputedStyle(nsp);
                                if (csr.position === 'relative' && csr.display === 'inline') {
                                    // visible ... (need both styles)
                                    // - ok, grab the textNode's value.
                                    daText += nsp.firstChild.textContent ;
                                }
                            }
                        }
                        //console.info("--::", daText);
                        // the "parent" has childNodes (spans) ...
                        nsp = nsp.firstChild;
                        do {
                            if (nsp.tagName === 'SPAN') {
                                csr = window.getComputedStyle(nsp);
                                if (csr.position === 'relative' && csr.display === 'inline') {
                                    // visible ... (need both styles)
                                    // - ok, grab the textNode's value.
                                    if (nsp.innerText.length === 1) {
                                        daText += nsp.firstChild.textContent ;
                                    }
                                }
                            }
                            nsp = nsp.nextSibling;
                        } while (nsp);
                        // console.info("--is Sponsored post:", daText, (SPONSORED_WORDS.indexOf(daText) > -1));
                        // do we hide this post?
                        if (SPONSORED_WORDS.indexOf(daText) > -1 ) {
                            hidePosts.push(sp);
                        }
                    });

                    // suggestions
                    if (suggestions) {
                        // scan the a tags
                        let els = Array.from(post.querySelectorAll('a'));
                        let skip = false;
                        for (let x = 0; x < els.length; x++) {
                            if (suggestions.includes(els[x].textContent)) {
                                hidePosts.push(els[x]);
                                skip = true;
                                break;
                            }
                        }
                        // scan the span tags
                        if (!skip) {
                            els = Array.from(post.querySelectorAll('span'));
                            for (let x = 0; x < els.length; x++) {
                                if (suggestions.includes(els[x].textContent)) {
                                    hidePosts.push(els[x]);
                                    break;
                                }
                            }
                        }
                    }
                }
            );
            return hidePosts;
        }

        function kill(element) {
            try {
                if(element) {
                    var limit = 0;
                    while(limit++ < 100) {
                        if(typeof element.getAttribute('data-pagelet') == "string")
                        {
                            if(element.getAttribute('data-pagelet').contains('FeedUnit'))
                            {
                                hide(element);
                                return;
                            }
                        }
                        element = element.parentNode;
                    }
                }
            } 
            catch (e) {
            }
        };

        findSponsoredPosts().forEach( e => kill(e) );

    };

    const callback = function () {
        try {
            doChanges();
        } catch (e) {
            console.warn(title, e);
        }
    };

    setInterval(callback, CHECK_RATE_MS);
})();