open the link directly

点击链接直接跳转

目前為 2022-03-27 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         open the link directly
// @namespace    http://tampermonkey.net/
// @version      0.1.2
// @description  点击链接直接跳转
// @author       nediiii
// @match        *://*.csdn.net/*
// @match        *://*.gitee.com/*
// @match        *://*.uisdc.com/*
// @match        *://*.logonews.cn/*
// @match        *://*.afdian.net/*
// @match        *://*.tianyancha.com/*
// @match        *://*.oschina.net/*
// @match        *://*.pixiv.net/*
// @match        *://*.jianshu.com/*
// @match        *://*.juejin.cn/*
// @match        *://*.weibo.cn/*
// @match        *://*.weibo.com/*
// @match        *://*.yuque.com/*
// @match        *://*.segmentfault.com/*
// @match        *://*.zhihu.com/*
// @match        *://*.bookmarkearth.com/*
// @license      GPLv3 License
// @icon         https://www.google.com/s2/favicons?sz=64&domain=greasyfork.org
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function () {
    'use strict';

    const isValidURL = (url) => {
        try {
            new URL(url);
            return true;
        } catch (error) {
            return isValidURLWithBase(url);
        }
    }

    const isValidURLWithBase = (url) => {
        try {
            new URL(url, getCurrentURLBase());
            return true;
        } catch (error) {
            return false;
        }
    }

    const getCurrentURLBase = () => {
        return window.location.origin;
    }

    const urlReg = /\bhttps?:\/\/\S+/gi;

    const weiboResolver = async (href) => {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: href,
                onload: function (response) {
                    console.log({ response });
                    if (response.status != 200) {
                        reject(href);
                        return;
                    }

                    // weibo跳转会区分目标网址是否备案
                    // 未备案的, 中转
                    // 已备案的, 直跳
                    let realURI = href;
                    if (response.finalUrl === href) {
                        // 未备案, 中转网址
                        // 网址在html里
                        let doc = new DOMParser().parseFromString(response.responseText, "text/html");
                        let node = doc.querySelector('body > div > div:nth-child(2)');
                        let str = node.innerText;
                        console.log({ doc });
                        console.log({ node });
                        console.log({ str });

                        let extractURL = str.match(urlReg);
                        console.log({ extractURL });
                        if (extractURL) {
                            realURI = extractURL[0];
                        }
                    }
                    else {
                        // 已备案
                        // 网址在finalUrl里
                        let extractURL = response.finalUrl.match(urlReg);
                        if (extractURL) {
                            realURI = extractURL[0];
                        }
                    }

                    resolve(realURI)
                },
                onerror: function (error) {
                    console.log({ error });
                    reject(href)
                }
            });
        });
    }

    const segfaultResolver = async (href) => {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: href,
                onload: function (response) {
                    console.log({ response });
                    if (response.status == 200) {
                        let doc = new DOMParser().parseFromString(response.responseText, "text/html");
                        let node = doc.querySelector('body > p')
                        let str = node.innerText;
                        console.log({ doc });
                        console.log({ node });
                        console.log({ str });

                        let realURI = href;
                        let extractURL = str.match(urlReg);
                        console.log({ extractURL });
                        if (extractURL) {
                            realURI = extractURL[0];
                        }
                        resolve(realURI)
                    } else {
                        reject(href)
                    }
                },
                onerror: function (error) {
                    console.log({ error });
                    reject(href)
                }
            });
        });
    }

    const bmeResolver = async (href) => {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: href,
                onload: function (response) {
                    console.log({ response });
                    if (response.status == 200) {
                        let doc = new DOMParser().parseFromString(response.responseText, "text/html");
                        let node = doc.querySelector('body > div.row.box > div.col-lg-6.jump-box > div > div.content > p.link');
                        let str = node.innerText;
                        console.log({ doc });
                        console.log({ node });
                        console.log({ str });

                        let realURI = href;
                        let extractURL = str.match(urlReg);
                        console.log({ extractURL });
                        if (extractURL) {
                            realURI = extractURL[0];
                        }
                        resolve(realURI)
                    } else {
                        reject(href)
                    }
                },
                onerror: function (error) {
                    console.log({ error });
                    reject(href)
                }
            });
        });
    }

    const patter_match = {

        // 注意这里的pattern需要去看对应网站dom里的a标签的实际herf值, console也会打印日志, 可以自己添加正则来增加网站支持
        // https://link.zhihu.com/?target=https%3A//greasyfork.org/en/scripts/5029-yet-another-%25E8%2587%25AA%25E5%258F%25A4cb%25E5%2587%25BA%25E8%25AF%2584%25E8%25AE%25BA-sharing-plugin
        zhihu: { pattern: /https?:\/\/link\.zhihu\.com\/?\?target=(.+)$/ },

        // https://www.jianshu.com/p/a6a63a0c6e53
        // https://links.jianshu.com/go?to=https%3A%2F%2Fnpm.taobao.org%2Fmirrors%2Felectron
        jianshu2: { pattern: /https?:\/\/links\.jianshu\.com\/go\?to=(.+)$/ },

        // href="https://link.juejin.cn?target=https%3A%2F%2Fdeveloper.aliyun.com%2Fgroup%2Falisoftwaretech%2F"
        juejin: { pattern: /https?:\/\/link\.juejin\.cn\/?\?target=(.+)$/ },

        // https://gitee.com/meetqy/acss-dnd
        // href="https://gitee.com/link?target=https%3A%2F%2Fcuyang.me%2Facss-dnd%2F"
        gitee: { pattern: /https?:\/\/gitee\.com\/link\?target=(.+)$/ },

        // https://www.uisdc.com/build-b-end-grid-system
        // https://link.uisdc.com/?redirect=https%3A%2F%2Fuxdesign.cc%2Fresponsive-grids-and-how-to-actually-use-them-970de4c16e01
        uisdc: { pattern: /https?:\/\/link\.uisdc\.com\/?\?redirect=(.+)$/ },

        // https://www.logonews.cn/apple-sues-sex-topic-blog-for-logo-infringement.html
        // https://link.logonews.cn/?url=http://aasd.k12.wi.us/district
        logonews: { pattern: /https?:\/\/link\.logonews\.cn\/?\?url=(.+)$/ },

        // https://afdian.net/@AdventCirno
        // https://afdian.net/link?target=https%3A%2F%2Fwww.patreon.com%2Fuser%3Fu%3D6139561
        afdian: { pattern: /https?:\/\/afdian\.net\/link\?target=(.+)$/ },

        // https://www.tianyancha.com/company/28723141
        // https://www.tianyancha.com/security?target=https%3A%2F%2Fss.knet.cn%2Fverifyseal.dll%3Fsn%3De18042711010873571xsuv000000%26pa%3D111332
        tianyancha: { pattern: /https?:\/\/www\.tianyancha\.com\/security\?target=(.+)$/ },

        // https://www.pixiv.net/users/25237
        // href="/jump.php?url=https%3A%2F%2Ftwitter.com%2Fomiya_io"
        // href="/jump.php?https%3A%2F%2Finstagram.com%2Fsnatti89%2F"
        pixiv: { pattern: /\/jump\.php\?(?:url=)?(.+)$/ },

        // https://my.oschina.net/androiddevs/blog/5496556
        // https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmp.weixin.qq.com%2Fmp%2Fappmsgalbum%3F__biz%3DMzk0NDIwMTExNw%3D%3D%26action%3Dgetalbum%26album_id%3D1879128471667326981%23wechat_redirect
        // href="https://www.oschina.net/action/GoToLink?url=https%3A%2F%2Fmp.weixin.qq.com%2Fmp%2Fappmsgalbum%3F__biz%3DMzk0NDIwMTExNw%3D%3D%26action%3Dgetalbum%26album_id%3D1879128471667326981%23wechat_redirect"
        oschina: { pattern: /https?:\/\/www\.oschina\.net\/action\/GoToLink\?url=(.+)$/ },

        // https://weibo.cn/sinaurl?u=https%3A%2F%2Fwww.freebsd.org%2F
        // https://weibo.cn/sinaurl?toasturl=https%3A%2F%2Ftime.geekbang.org%2F
        // https://weibo.cn/sinaurl?luicode=10000011&lfid=230259&u=http%3A%2F%2Ft.cn%2FA6qHeVlf
        // https://weibo.cn/sinaurl?f=w&u=http%3A%2F%2Ft.cn%2FA66XY2gI&ep=LlAsNz3HD%2C1683963007%2CLlpkandl6%2C7276218544
        // href="https://weibo.cn/sinaurl?f=w&u=http%3A%2F%2Ft.cn%2FA66XY2gI&ep=LlAsNz3HD%2C1683963007%2CLlpkandl6%2C7276218544"
        weibo: { pattern: /https?:\/\/weibo\.cn\/sinaurl\?f=w&u=(.+)$/, resolver: weiboResolver },

        // http://t.cn/A66926Pm  未备案的, 跳转到中转网址,  response.finalUrl仍然还是http://t.cn/A66926Pm 目标网址出现在response.responseText里
        // http://t.cn/A669K964  已备案的, 直接跳转到目标网址, 出现在response.finalUrl里
        weibo2: { pattern: /(https?:\/\/t\.cn\/.+)$/, resolver: weiboResolver },


        // segmentfault对链接进行加密处理, 不知道如何decode, 所以只能写一个函数去单独处理
        // https://link.segmentfault.com/?enc=LZyRulLABKpXOHl2vbA%2F4w%3D%3D.MWhFMvjhyBk1ReIRoGxyxa0VxGtg%2Foyk0DMtfzZTJoKbsgoJFtGCPHe8%2BZ1HbRdcvNsGaVfll9oGQXLsZCHK7w%3D%3D
        segfault: { pattern: /https?:\/\/link\.segmentfault\.com\/?\?enc=(.+)$/, resolver: segfaultResolver },

        // https://www.bookmarkearth.com/detail/097c687c98974691b2174bc1e85103d4
        // https://show.bookmarkearth.com/view/801
        bookmarkearth: { pattern: /(https?:\/\/show\.bookmarkearth\.com\/view\/.+)$/, resolver: bmeResolver },


        // 以下网站a标签的herf未修改, 推测是js做的弹窗, 所以不需要匹配, 也匹配不出来
        // csdn https://link.csdn.net/?target=https%3A%2F%2Fdeveloper.mozilla.org%2Fzh-CN%2Fdocs%2FWeb%2FJavaScript%2FReference%2FGlobal_Objects%2FRegExp
        // 语雀 https://www.yuque.com/r/goto?url=https%3A%2F%2Fwww.canva.cn%2F
    }

    const resolveRealURI = async (href) => {
        const fallbackURI = href;

        for (let i in patter_match) {
            const matcher = href.match(patter_match[i].pattern);
            if (!matcher) {
                continue;
            }
            console.log({ matcher });

            if (patter_match[i].hasOwnProperty('resolver')) {
                // complex customize resolver
                console.log(patter_match[i].resolver)
                let realURI = await patter_match[i].resolver(href);
                return realURI;
            }

            const encodeURI = matcher[1];
            // simple reg resolver
            return decodeURIComponent(encodeURI);
        }
        return fallbackURI;
    }

    const getHref = (e) => {
        let target = e.target;
        while (target) {
            if (target.tagName.toLowerCase() === 'a' && target.hasAttribute('href')) {
                console.log("find element", { target })
                return target.getAttribute('href');
            }
            target = target.parentElement;
        }
        return null;
    }

    document.addEventListener('click', (e) => {
        console.log({ e })
        let href = getHref(e);
        if (href) {

            // 不是url, 则不做处理
            // 兼容如 href设置为 'javascript:void(0);' 等的情况
            if (!isValidURL(href)) {
                return;
            }

            e.stopPropagation();
            e.preventDefault();

            resolveRealURI(href).then((realURI) => {
                console.log({ realURI })
                window.open(realURI);
            }).catch(() => { window.open(href); })
        }
    }, { capture: true })

})();