-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathskip-redirect-inplace.user.js
104 lines (93 loc) · 4.13 KB
/
skip-redirect-inplace.user.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// ==UserScript==
// @name Skip Redirect Inplace
// @namespace https://github.com/Vinfall/UserScripts
// @version 1.0.1
// @author Vinfall
// @match https://acg.gamer.com.tw/*
// @match https://forum.gamer.com.tw/*
// @match https://gnn.gamer.com.tw/*
// @match https://m.gamer.com.tw/forum/*
// @match https://m.weibo.cn/detail/*
// @match https://m.weibo.cn/status/*
// @match https://m.weibo.cn/u/*
// @match https://sspai.com/*
// @match https://www.cnblogs.com/*
// @match https://www.gcores.com/*
// @match https://www.tiangal.com/*
// @exclude-match https://www.tiangal.com/question*
// @exclude-match https://www.tiangal.com/sign*
// @exclude-match https://www.tiangal.com/tougao*
// @exclude-match https://www.tiangal.com/wp-login.php*
// @run-at document-end
// @grant none
// @icon data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⏭️</text></svg>
// @description Skip stupid URL redirect before you ever click on it
// @description:zh-cn 文内替换外链跳转 URL
// ==/UserScript==
(function () {
'use strict';
const attributeShape = [
{ name: 'selector', type: 'string' },
{ name: 'regex', type: 'regexp' },
{ name: 'observer', type: 'boolean' },
];
// prettier-ignore
const simplifiedRules = [
['a[href*="https://sspai.com/link?target="]', /https:\/\/sspai.com\/link\?target=([^&]+)/, true],
['a[href*="https://weibo.cn/sinaurl?u="]', /https:\/\/weibo.cn\/sinaurl\?u=([^&]+)/, true],
['a[href*="https://hellogithub.com/periodical/statistics/click?target="]', /https:\/\/hellogithub.com\/periodical\/statistics\/click\?target=([^&]+)/, false],
['a[href*="https://www.gcores.com/link?target="]', /https:\/\/www\.gcores\.com\/link\?target=([^&]+)/, false],
['a[href*="//ref.gamer.com.tw/redir.php?url="]', /https:\/\/ref\.gamer\.com\.tw\/redir\.php\?url=([^&]+)/, false],
['a[href^="https://www.tiangal.com/go.html"]', /https:\/\/www.tiangal.com\/go.html\?url=([^&]+)/, false],
];
function convertToStructuredRules(simplifiedRules, attributeShape) {
return simplifiedRules.map((rule) => {
let structuredRule = {};
attributeShape.forEach((attr, index) => {
if (typeof rule[index] !== attr.type && !(attr.type === 'regexp' && rule[index] instanceof RegExp)) {
throw new Error(`Expected ${attr.type} at position ${index}, but got ${typeof rule[index]}`);
}
structuredRule[attr.name] = rule[index];
});
return structuredRule;
});
}
const rules = convertToStructuredRules(simplifiedRules, attributeShape);
function decodeAndReplaceLink(link, regex) {
const currentHref = link.href;
// Extract real URL as per regex
const urlMatch = currentHref.match(regex);
if (urlMatch && urlMatch[1]) {
// URL decode
const realUrl = decodeURIComponent(urlMatch[1]);
// Replace href attr
link.href = realUrl;
}
}
function processLinks(rules) {
rules.forEach((rule) => {
// Retrieve all elements as per selector rule
const links = document.querySelectorAll(rule.selector);
// Process each link
links.forEach((link) => decodeAndReplaceLink(link, rule.regex));
});
}
function setupMutationObserver(rules) {
rules.forEach((rule) => {
if (rule.observer) {
const observer = new MutationObserver(() => {
// Pass the individual rule to only re-run for this rule
processLinks([rule]);
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
}
});
}
// Initial run
processLinks(rules);
// Optionally, set up mutation observer to fix dynamic link
setupMutationObserver(rules);
})();