Facebook Hide Ads (a.k.a. sponsored posts)

Removes ads (a.k.a. sponsored posts) from feed and sidebar

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Facebook Hide Ads (a.k.a. sponsored posts)
// @namespace    https://openuserjs.org/users/burn
// @version      0.5.2
// @description  Removes ads (a.k.a. sponsored posts) from feed and sidebar
// @author       burn
// @copyright    2020, burn (https://openuserjs.org/users/burn)
// @license      MIT
// @match        https://www.facebook.com/*
// @match        https://web.facebook.com/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';
    let languages = { // thanks to Ciscoheat https://greasyfork.org/en/users/51960-ciscoheat
        'af':      ['Geborg'],
        'am':      ['የተከፈለበት ማስታወቂያ'],
        'ar':      ['إعلان مُموَّل'],
        'as':      ['পৃষ্ঠপোষকতা কৰা'],
        'ay':      ['Yatiyanaka'],
        'az':      ['Sponsor dəstəkli'],
        'be':      ['Рэклама'],
        'bg':      ['Спонсорирано'],
        'br':      ['Paeroniet'],
        'bs':      ['Sponzorirano'],
        'bn':      ['সৌজন্যে'],
        'ca':      ['Patrocinat'],
        'cb':      ['پاڵپشتیکراو'],
        'co':      ['Spunsurizatu'],
        'cs':      ['Sponzorováno'],
        'cx':      ['Giisponsoran'],
        'cy':      ['Noddwyd'],
        'da':      ['Sponsoreret'],
        'de':      ['Gesponsert'],
        'el':      ['Χορηγούμενη'],
        'en':      ['Sponsored', 'Chartered'],
        'eo':      ['Reklamo'],
        'es':      ['Publicidad', 'Patrocinado'],
        'et':      ['Sponsitud'],
        'eu':      ['Babestua'],
        'fa':      ['دارای پشتیبانی مالی'],
        'fi':      ['Sponsoroitu'],
        'fo':      ['Stuðlað'],
        'fr':      ['Commandité', 'Sponsorisé'],
        'fy':      ['Sponsore'],
        'ga':      ['Urraithe'],
        'gl':      ['Patrocinado'],
        'gn':      ['Oñepatrosinapyre'],
        'gx':      ['Χορηγούμενον'],
        'hi':      ['प्रायोजित'],
        'hu':      ['Hirdetés'],
        'id':      ['Bersponsor'],
        'it':      ['Sponsorizzata'],
        'ja':      ['広告'],
        'jv':      ['Disponsori'],
        'kk':      ['Демеушілік көрсеткен'],
        'km':      ['បានឧបត្ថម្ភ'],
        'lo':      ['ໄດ້ຮັບການສະໜັບສະໜູນ'],
        'mk':      ['Спонзорирано'],
        'ml':      ['സ്പോൺസർ ചെയ്തത്'],
        'mn':      ['Ивээн тэтгэсэн'],
        'mr':      ['प्रायोजित'],
        'ms':      ['Ditaja'],
        'ne':      ['प्रायोजित'],
        'nl':      ['Gesponsord'],
        'or':      ['ପ୍ରଯୋଜିତ'],
        'pa':      ['ਸਰਪ੍ਰਸਤੀ ਪ੍ਰਾਪਤ'],
        'pl':      ['Sponsorowane'],
        'ps':      ['تمويل شوي'],
        'pt':      ['Patrocinado'],
        'ru':      ['Реклама'],
        'sa':      ['प्रायोजितः |'],
        'si':      ['අනුග්‍රහය දක්වන ලද'],
        'so':      ['La maalgeliyey'],
        'sv':      ['Sponsrad'],
        'te':      ['స్పాన్సర్ చేసినవి'],
        'th':      ['ได้รับการสนับสนุน'],
        'tl':      ['May Sponsor'],
        'tr':      ['Sponsorlu'],
        'tz':      ['ⵉⴷⵍ'],
        'uk':      ['Реклама'],
        'ur':      ['تعاون کردہ'],
        'vi':      ['Được tài trợ'],
        'zh-Hans': ['赞助内容'],
        'zh-Hant': ['贊助']
    },
    qS = function (el, scope) {
      scope = (typeof scope == 'object') ? scope : document;
      return scope.querySelector(el) || false;
    },
    qSall = function (els, scope) {
      scope = (typeof scope == 'object') ? scope : document;
      return scope.querySelectorAll(els) || false;
    },
    targetNode = qS('body'),
    observerConfig = {
      attributes: false,
      childList: true,
      subtree: true
    },
    getParentEl = function (elmChild) {
        return elmChild.closest('[data-pagelet^="FeedUnit_"]') || false;
    },
    removeAdsInFeed = function (ads) {
        Array.prototype.forEach.call(ads, function (el) {
            let wrapper = getParentEl(el);
            if (wrapper !== false) {
                console.log("Found wrapper for " + el);
                if (wrapper.parentNode != null)
                    wrapper.parentNode.removeChild(wrapper);
                else {
                    const evt = new Event('mouseenter');
                    wrapper.dispatchEvent(evt);
                    //console.log("event dispatched");
                }
            }
        });
    },
    removeAbsoluteSpans = function (elm) {
        Array.prototype.forEach.call(qSall('span[style="position: absolute; top: 3em;"]', elm), function (el) {
            console.log("rimuovo " + el.tagName);
            el.parentNode.removeChild(el);
        });
    },
    callback = function (mutationsList, observer) {
      mutationsList.forEach(function (mutation) {
        var entry = {
          mutation: mutation,
          el: mutation.target,
          value: mutation.target.textContent,
          oldValue: mutation.oldValue
        };

        removeAbsoluteSpans(entry.el);

        // ads in right sidebar, old fb design
        let ego_wrapper = qS('#pagelet_ego_pane', entry.el);
        if (ego_wrapper) ego_wrapper.parentNode.removeChild(ego_wrapper);

        /* new fb 2020 design */
        let lang = languages[document.documentElement.lang] || languages.en;
        if (lang.indexOf(entry.value) >= 0) {
            //console.log("sponsored found for " + entry.el);
            removeAdsInFeed([entry.el]);
        }
      });
    };

    removeAbsoluteSpans(qS('body'));
    // ads in right sidebar, old fb design
    let ego_wrapper = qS('#pagelet_ego_pane');
    if (ego_wrapper) ego_wrapper.parentNode.removeChild(ego_wrapper);

    var observer = new MutationObserver(callback);
    observer.observe(targetNode, observerConfig);
})();