rBlock

移除一些网站用于数据统计的跳转功能,加快访问目标地址的速度。包括谷歌、知乎等,并添加少量定制化。| Removes redirects of some sites, such as google, zhihu..., add some customization.

As of 2016-07-04. See the latest version.

// ==UserScript==
// @name         rBlock
// @description  移除一些网站用于数据统计的跳转功能,加快访问目标地址的速度。包括谷歌、知乎等,并添加少量定制化。| Removes redirects of some sites, such as google, zhihu..., add some customization.
// @namespace    https://greasyfork.org/zh-CN/scripts/20568-rblock
// @homepageURL  https://github.com/nonoroazoro/rBlock
// @author       nonoroazoro
// @include      /^https?\:\/\/(www|encrypted|news)\.google\./
// @include      /^https?\:\/\/(www|zhuanlan)\.zhihu\./
// @version      1.2.5
// @run-at       document-end
// @grant        none
// ==/UserScript==

if (typeof unsafeWindow === "undefined")
{
    unsafeWindow = window;
}

const rBlock = {

    _blockers: [],

    start: function ()
    {
        this.reset();
        for (let blocker of this._blockers)
        {
            blocker.start();
        }
    },

    reset: function ()
    {
        this._blockers = [];

        // 1. google
        this._blockers.push(
            {
                start: function ()
                {
                    if (/^https?\:\/\/(www|encrypted|news)\.google\./.test(unsafeWindow.location.href))
                    {
                        // 1. for static pages.
                        // when google instant predictions is disabled,
                        // this blocker will only be called once.
                        this._block();

                        // 2. for dynamic pages.
                        // when google instant predictions is enabled,
                        // this blocker will be call whenever the current page is updated.
                        _startMutationObserver(
                            {
                                "id":
                                [
                                    "search", // all/videos/news/shopping/books/apps
                                ],
                                "class":
                                [
                                    "irc_rit", // images
                                    "pspo-popout pspo-lpop", // shopping
                                ]
                            },
                            this._block
                        );
                    }
                },

                // block redirects of google
                _block: function ()
                {
                    const host = unsafeWindow.location.host;
                    if (host === "news.google.com")
                    {
                        // 1. news.google.com
                        const elems = document.querySelectorAll(`.content-pane-container a.article`);
                        for (let e of elems)
                        {
                            _removeListeners(e, "click mousedown");
                        }
                    }
                    else
                    {
                        const base = document.querySelector("div#search");
                        if (base)
                        {
                            // 1. all/videos/news/apps
                            let elems = base.querySelectorAll(`a[onmousedown^="return rwt("]`);
                            for (let e of elems)
                            {
                                _removeAttributes(e, "onmousedown");
                            }

                            // 2. images
                            elems = base.querySelectorAll(`a[class^="irc_"], a[class*=" irc_"]`);
                            for (let e of elems)
                            {
                                _removeListeners(e, "mousedown");
                            }

                            // 3. books
                            revealURL(
                                base.querySelectorAll(`a[href^="/aclk?"]`),
                                /\/aclk?.*url=(.*)/i
                            );

                            // 4. general
                            revealURL(
                                document.querySelectorAll(`a[href*="/url?"]`),
                                /(?:\/url\?.*url=)(.*?)(?:&usg=|$)/i
                            );

                            // 5. cached links
                            elems = document.querySelectorAll(`a[href^="http://webcache.googleusercontent."], a[href^="https://webcache.googleusercontent."]`);
                            let targets = document.querySelectorAll(`a.rblock-cached-link`);
                            if (elems.length != targets.length * 2)
                            {
                                // prevent duplication
                                let menuLink;
                                let cacheLink;
                                for (let elem of elems)
                                {
                                    elem.style.display = "inline";
                                    menuLink = elem.closest("div.action-menu.ab_ctl");

                                    cacheLink = document.createElement("a");
                                    cacheLink.setAttribute("href", elem.getAttribute("href").replace(/^http\:/, "https:"));
                                    cacheLink.setAttribute("class", "rblock-cached-link");
                                    cacheLink.target = "_blank";
                                    cacheLink.innerText = " Cached ";

                                    menuLink.parentNode.insertBefore(cacheLink, menuLink);
                                }
                            }
                        }
                    }
                }
            }
        );

        // 2. zhihu
        this._blockers.push(
            {
                start: function ()
                {
                    if (/^https?\:\/\/(www|zhuanlan)\.zhihu\./.test(unsafeWindow.location.href))
                    {
                        this._block();

                        _startMutationObserver(
                            {
                                "id":
                                [
                                    "js-home-feed-list", // 首页最新动态
                                    "zh-question-answer-wrap", // 具体内容
                                ],
                                "class":
                                [
                                    "zm-item-rich-text expandable js-collapse-body", // 首页、话题显示全部
                                    "zh-general-list clearfix", // 话题
                                ],
                                "data-type":
                                [
                                    "daily", // 发现
                                ]
                            },
                            this._block
                        );
                    }
                },

                _block: function ()
                {
                    // 1. general
                    revealURL(
                        document.querySelectorAll(`a[href^="http://link.zhihu.com"], a[href^="https://link.zhihu.com"], a[href^="//link.zhihu.com"]`),
                        /(?:https?\:)?\/\/link\.zhihu\.com\/\?target=(.*)/i
                    );

                    // 2. open in new tab
                    const elems = document.querySelectorAll(`a.internal`);
                    for (let elem of elems)
                    {
                        _openInNewTab(elem);
                    }
                }
            }
        );
    }
};

function _startMutationObserver(p_filter, p_handler)
{
    if (typeof p_handler === "function")
    {
        const filter = p_filter || {};
        const observer = new unsafeWindow.MutationObserver((p_mutations) =>
        {
            let needUpdate = false;
            for (let mutation of p_mutations)
            {
                for (let key in p_filter)
                {
                    if (p_filter[key].indexOf(mutation.target.getAttribute(key)) != -1)
                    {
                        needUpdate = true;
                        break;
                    }
                }

                if (needUpdate)
                {
                    break;
                }
            }

            if (needUpdate)
            {
                p_handler();
            }
        });
        observer.observe(document.body,
            {
                childList: true,
                subtree: true
            }
        );
    }
}

function _removeAttributes(p_element, p_attributes)
{
    if (p_element && typeof p_attributes === "string")
    {
        const attributes = p_attributes.split(/\W+/) || [];
        for (let attribute of attributes)
        {
            p_element.removeAttribute(attribute);
        }
    }
}

function _removeListeners(p_element, p_events)
{
    if (p_element && typeof p_events === "string")
    {
        const events = p_events.split(/\W+/) || [];
        for (let event of events)
        {
            p_element.removeEventListener(event, _preventDefaultAction, true);
            p_element.addEventListener(event, _preventDefaultAction, true);
        }
    }
}

function _preventDefaultAction(e)
{
    e.stopPropagation();
}

/**
 * reveal url
 */
function revealURL(p_elems, p_regex)
{
    if (p_elems && p_regex)
    {
        for (let e of p_elems)
        {
            // reveal url
            const m = e.getAttribute("href").match(p_regex);
            if (m && m[1])
            {
                e.setAttribute("href", decodeURIComponent(m[1]));
            }

            // open in new tab
            _openInNewTab(e);
        }
    }
}

function _openInNewTab(p_elem)
{
    if (p_elem && !p_elem.target)
    {
        p_elem.target = "_blank";
    }
}

rBlock.start();