Google谷歌搜索页面dq.tieba.com贴吧链接替换 dq.tieba.com to tieba.baidu.com for Google results

最近访问dq.tieba.com老是出现 “您好,该页面正在维护中。” 于是就写了这个。为什么要在Google搜索页面替换呢?这是因为当你按dq.tieba.com时服务器就给你的浏览器发个HTTP 302重定向到维护页面,脚本都来不及执行

// ==UserScript==
// @name                 Google谷歌搜索页面dq.tieba.com贴吧链接替换 dq.tieba.com to tieba.baidu.com for Google results
// @name:zh-CN           Google谷歌搜索页面dq.tieba.com贴吧链接替换
// @name:zh-TW           Google谷歌搜索頁面dq.tieba.com貼吧鏈接替換
// @version              0.22
// @include              *://www.google.*
// @description          最近访问dq.tieba.com老是出现 “您好,该页面正在维护中。” 于是就写了这个。为什么要在Google搜索页面替换呢?这是因为当你按dq.tieba.com时服务器就给你的浏览器发个HTTP 302重定向到维护页面,脚本都来不及执行
// @description:zh-CN    最近访问dq.tieba.com老是出现 “您好,该页面正在维护中。” 于是就写了这个。为什么要在Google搜索页面替换呢?这是因为当你按dq.tieba.com时服务器就给你的浏览器发个HTTP 302重定向到维护页面,脚本都来不及执行
// @description:zh-TW    最近訪問dq.tieba.com老是出現 “您好,该页面正在维护中。” 於是就寫了這個。為什麼要在Google搜索頁面替換呢?這是因為當你按dq.tieba.com時服務器就給你的瀏覽器發個HTTP 302轉址到維護頁面,脚本都來不及執行
// @author               Jiaxing Peng
// @namespace            bjxpen
// @grant                none
// ==/UserScript==

(function() {
    'use strict';

    const URL_PATTERNS = [
        'jump*.bdimg.com',      // matches jump.bdimg.com, jump2.bdimg.com, ...
        'wapp.baidu.*/mo/q',    // matches wapp.baidu.com/mo/q, wapp.baidu.cn/mo/q, ...
        'wefan.baidu.*',
        'c.tieba.baidu.*',
        'tieba.baidu.*',
        'dq.tieba.*',
        'post.baidu.*',
        'xingqu.baidu.*',
        'www.tieba.*'
    ];

    const REPLACE_BY = 'tieba.baidu.com';

    const URL_REGEXPS = URL_PATTERNS.map(p => {
        return new RegExp(p.replace(/[\/.]/g, '\\$&').replace(/\*/g, '[^.\\/]*'));
    });

    const REDIRECT_URL_REGEXP = /^[^:]*:\/\/www\.google\.[^\/]*\/url\?.*$/,
        REDIRECT_QUERY_PARAM_Q = 'q',
        REDIRECT_QUERY_PARAM_URL = 'url';

    const WEBLIGHT_REGEXP = /^[^:]*:\/\/www\.google\.[^\/]*\/url\?.*(?=q=)q=http:\/\/googleweblight\.[^\/]*\/%3Flite_url%3D.*/;

    const HTTP_PROC_REGEXP = /^http:\/\//,
        HTTPS_PROC = 'https://';

    const NULL_RESULT = { matchedUrlPattern: null };

    const getUrlQueryParam = function (cache, url, name) {
        // cache URL instances; URL is not available in IE
        return (cache[url] = cache[url] || new URL(url)).searchParams.get(name) || null
    }.bind(null, {});

    function setup () {
        const testFn = RegExp.prototype.test;

        RegExp.prototype.test = function (str) { 
            this.cache = this.cache || {};
            return this.cache[str] = this.cache[str] || testFn.call(this, str);
        }

        return function teardown () { RegExp.prototype.test = testFn; };
    }

    function longestMatchPattern (strLikedArr) {
        return strLikedArr.length === 0 ? null : strLikedArr.reduce((a, b) => {
            return b.toString().length > a.toString().length ? b : a;
        });
    }

    function baseCase (a) {
        return {
            a: a,
            matchedUrlPattern: longestMatchPattern(URL_REGEXPS.filter(r => {
                var queryIndex = a.href.indexOf('?');
                var urlNoQuery = queryIndex === -1 ? a.href : a.href.slice(0, queryIndex);
                return r.test(urlNoQuery);
            })),
            url: a.href,
        };
    }

    function redirectionCase (redirectUrlQueryParamName, a) {
        try {
            const redirectUrl = getUrlQueryParam(a.href, redirectUrlQueryParamName) || '';
            const isRedirectUrl = REDIRECT_URL_REGEXP.test(a.href) && redirectUrl !== '' && !WEBLIGHT_REGEXP.test(a.href);

            return {
                a: a,
                url: redirectUrl,
                matchedUrlPattern: isRedirectUrl ? longestMatchPattern(URL_REGEXPS.filter(r => r.test(redirectUrl))) : null,
            };
        } catch (err) {
            return NULL_RESULT;
        }
    }

    function weblightCase(a) {
        try {
            const isWebLightUrl = WEBLIGHT_REGEXP.test(a.href);
            const level1Url = isWebLightUrl ? getUrlQueryParam(a.href, 'q') : '';
            const level2Url = isWebLightUrl ? decodeURIComponent(getUrlQueryParam(level1Url, 'lite_url')) : '';

            return {
                a: a,
                url: level2Url,
                matchedUrlPattern: isWebLightUrl ? longestMatchPattern(URL_REGEXPS.filter(r => r.test(level2Url))) : null,
            };
        } catch (err) {
            return NULL_RESULT;
        }
    }

    const teardown = setup();
    [
        baseCase,
        redirectionCase.bind(null, REDIRECT_QUERY_PARAM_Q),
        redirectionCase.bind(null, REDIRECT_QUERY_PARAM_URL),
        weblightCase
    ].forEach(fn => {
        [].slice.call(document.getElementsByTagName('a')).map(fn).forEach(res => {
            if (res.matchedUrlPattern) {
                res.a.href = res.url.replace(res.matchedUrlPattern, REPLACE_BY).replace(HTTP_PROC_REGEXP, HTTPS_PROC);
            }
        })
    })
    teardown();
})();