Greasy Fork

来自缓存

Greasy Fork is available in English.

Ads DOM Remover Runner

Library - Removes Ad Containers from DOM (doesn't replace adblocker extension, but blocks dynamic content which the adblocker fails to block by removing whole sections from the HTML DOM.)

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.greasyfork.icu/scripts/18490/983896/Ads%20DOM%20Remover%20Runner.js

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

You will need to install an extension such as Tampermonkey to install this script.

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Ads DOM Remover Runner
// @namespace    sagiegurari
// @version      0.14
// @author       Sagie Gur-Ari
// @description  Library - Removes Ad Containers from DOM (doesn't replace adblocker extension, but blocks dynamic content which the adblocker fails to block by removing whole sections from the HTML DOM.)
// @homepage     https://github.com/sagiegurari/userscripts-ads-dom-remover
// @supportURL   https://github.com/sagiegurari/userscripts-ads-dom-remover/issues
// @grant        none
// @license      MIT License
// ==/UserScript==

(function initADR() {
    'use strict';

    /**
     * This class invokes the ads removing process based on provided options.
     *
     * @author Sagie Gur-Ari
     * @class ADRService
     * @public
     * @param {object} $ - The jquery library
     * @param {object} [options] - The process options
     * @param {function} [options.getSelectorDefinitions] - Returns all selector definitions per host
     * @param {number} [options.loops=10] - The amount of loops to run (will be invoked twice)
     * @param {number} [options.interval=250] - Time in millies between each loop
     * @param {number} [options.secondLoopInterval=2500] - Time in millies between each bulk of loops
     * @param {function} [options.onDone] - Invoked at the end of all loops
     */
    var Service = function ($, options) {
        this.$ = $;
        options = options || {};
        this.loops = options.loops || 10;
        this.interval = options.interval || 250;
        this.secondLoopInterval = options.secondLoopInterval || 2500;
        this.onDone = options.onDone || this.noop;

        var hostname = document.location.hostname;
        if (window.adrRunner && window.adrRunner.mockHostname) {
            hostname = window.adrRunner.mockHostname;
        }

        var getSelectorDefinitions = options.getSelectorDefinitions || this.noop;
        this.selectorDefinitions = getSelectorDefinitions() || {};

        // find default selectors
        this.defaultSelectors = null;
        var index;
        var id;
        this.ids = Object.keys(this.selectorDefinitions);
        for (index = 0; index < this.ids.length; index++) {
            id = this.ids[index];

            this.selectorDefinitions[id].id = id;

            if (this.selectorDefinitions[id].hostNames === true) {
                this.defaultSelectors = this.selectorDefinitions[id];
            }
        }

        this.defaultSelectors = this.defaultSelectors || [];

        this.state = {
            intervalID: null,
            counter: 0,
            secondLoop: false
        };

        var selectors = this.getSelectors(hostname);
        if (selectors) {
            if ((!Array.isArray(selectors)) && selectors.selectors) {
                if (selectors.id) {
                    console.debug(
                        '[user script][Ads DOM Remover][hideElements] Using Selectors:',
                        selectors.id
                    );
                }

                if (selectors.options) {
                    this.loops = selectors.options.loops || this.loops;
                    this.interval = selectors.options.interval || this.interval;
                }

                selectors = selectors.selectors;
            }

            this.state.currentSelectors = selectors;
        }
    };

    /**
     * Empty function
     *
     * @function
     * @memberof! ADRService
     * @private
     * @returns {undefined} Always undefined
     */
    Service.prototype.noop = function () {
        return undefined;
    };

    /**
     * Returns the selectors to remove based on the provided host name.
     *
     * @function
     * @memberof! ADRService
     * @private
     * @param {string} hostName - The current host name
     * @returns {Array} Array of selectors (or objects) to remove from the DOM
     */
    Service.prototype.getSelectors = function (hostName) {
        var selectors;

        try {
            var definitionIndex;
            var hostNameIndex;
            var id;
            var hostNames;
            for (definitionIndex = 0; definitionIndex < this.ids.length; definitionIndex++) {
                id = this.ids[definitionIndex];
                hostNames = this.selectorDefinitions[id].hostNames;

                if ((typeof hostNames === 'string') && (hostName.indexOf(hostNames) !== -1)) {
                    selectors = this.selectorDefinitions[id];
                } else if (Array.isArray(hostNames)) {
                    for (hostNameIndex = 0; hostNameIndex < hostNames.length; hostNameIndex++) {
                        if (hostName.indexOf(hostNames[hostNameIndex]) !== -1) {
                            selectors = this.selectorDefinitions[id];
                            break;
                        }
                    }
                }

                if (selectors) {
                    break;
                }
            }
        } catch (error) {
            console.error(
                '[user script][Ads DOM Remover][getSelectors] Error:',
                error
            );
        }

        if (!selectors) {
            selectors = this.defaultSelectors;
        }

        return selectors || [];
    };

    /**
     * Hides the elements by removing them from the DOM completely.
     *
     * @function
     * @memberof! ADRService
     * @private
     * @returns {boolean} True if any element was removed during this invocation
     */
    Service.prototype.hideElements = function () {
        var self = this;
        var found = false;

        var selectors = self.state.currentSelectors || [];

        selectors.forEach(function (selector) {
            var selectorString = selector.selector || selector;

            var $element;
            try {
                $element = self.$(selectorString);
            } catch (error) {
                console.error(
                    '[user script][Ads DOM Remover][hideElements] Error while running selector:',
                    selectorString,
                    error
                );
            }

            if ($element && $element.length) {
                found = true;

                if (selector.fineTuneSelector && (typeof selector.fineTuneSelector === 'function')) {
                    $element = selector.fineTuneSelector($element);
                }

                if (selector.pre && (typeof selector.pre === 'function')) {
                    selector.pre($element);
                }

                var remove = true;
                if (selector.filter && (typeof selector.filter === 'function')) {
                    $element = selector.filter($element);
                    remove = !!$element.length;
                }

                if (remove) {
                    $element.removeAttr('style');
                    $element.css(
                        'display',
                        'none !important'
                    );

                    $element.remove();

                    console.debug(
                        '[user script][Ads DOM Remover][hideElements] Found:',
                        selector,
                        'count:',
                        $element.length,
                        'in website and removed it.'
                    );
                } else {
                    console.debug(
                        '[user script][Ads DOM Remover][hideElements] Found:',
                        selector,
                        'count:',
                        $element.length,
                        'in website but not removing.'
                    );
                }
            }
        });

        return found;
    };

    /**
     * Invoked each interval to run the main library logic.
     *
     * @function
     * @memberof! ADRService
     * @private
     */
    Service.prototype.actionLoop = function () {
        this.state.counter++;
        var stopInterval = this.state.intervalID && (this.state.counter > this.loops);
        console.debug(
            '[user script][Ads DOM Remover][actionLoop] Running loop:',
            this.state.counter,
            'state:',
            this.state,
            'stop interval:',
            stopInterval
        );

        this.hideElements();

        if (stopInterval) {
            console.debug(
                '[user script][Ads DOM Remover][actionLoop] Clearing interval ID:',
                this.state.intervalID
            );
            clearInterval(this.state.intervalID);
            this.state.intervalID = null;

            if (!this.state.secondLoop) {
                this.startActionLoop(
                    false,
                    this.secondLoopInterval
                );
            } else {
                this.onDone();
            }
        }
    };

    /**
     * Starts the interval invocations.
     *
     * @function
     * @memberof! ADRService
     * @private
     * @param {boolean} firstTime - If this function was called for the first time
     * @param {number} delay - The delay to wait before setting the interval
     */
    Service.prototype.startActionLoop = function (firstTime, delay) {
        var self = this;

        self.state.secondLoop = !firstTime;
        self.state.counter = 0;

        setTimeout(
            function () {
                self.state.intervalID = setInterval(
                    function () {
                        self.actionLoop();
                    },
                    self.interval
                );

                setTimeout(
                    function () {
                        self.hideElements();
                    },
                    15000
                );
            },
            delay
        );
    };

    /**
     * Starts the service run.
     *
     * @function
     * @memberof! ADRService
     * @private
     */
    Service.prototype.start = function () {
        this.startActionLoop(
            true,
            10
        );
    };

    /**
     * Starts the service run.
     *
     * @function
     * @namespace ADRRunner
     * @public
     * @param {object} $ - The jquery library
     * @param {object} options - The process options
     * @param {function} options.getSelectorDefinitions - Returns all selector definitions per host
     * @param {number} [options.loops=10] - The amount of loops to run (will be invoked twice)
     * @param {number} [options.interval=250] - Time in millies between each loop
     */
    window.adrRunner = function adrRunner($, options) {
        if ($ && (typeof $ === 'function') && options && options.getSelectorDefinitions && (typeof options.getSelectorDefinitions === 'function')) {
            var service = new Service(
                $,
                options
            );
            service.start();
        }
    };
}());