// ==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=gf.qytechs.cn
// @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//gf.qytechs.cn/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 })
})();