redirect 外链跳转

自动跳转(重定向)到目标链接,免去点击步骤。适配了简书、知乎、微博、QQ邮箱、QQPC、QQNT、印象笔记、贴吧、CSDN、YouTube、微信、企业微信、微信开放社区、开发者知识库、豆瓣、个人图书馆、Pixiv、搜狗、Google、站长之家、OSCHINA、掘金、腾讯文档、pc6下载站、爱发电、Gitee、天眼查、爱企查、企查查、优设网、51CTO、力扣、花瓣网、飞书、Epic、Steam、语雀、牛客网、哔哩哔哩、少数派、5ch、金山文档、石墨文档、urlshare、酷安、网盘分享、腾讯云开发者社区、腾讯兔小巢、云栖社区、NodeSeek、亿企查、异次元软件、HelloGitHub

  1. // ==UserScript==
  2. // @name redirect 外链跳转
  3. // @version 1.59.0
  4. // @description 自动跳转(重定向)到目标链接,免去点击步骤。适配了简书、知乎、微博、QQ邮箱、QQPC、QQNT、印象笔记、贴吧、CSDN、YouTube、微信、企业微信、微信开放社区、开发者知识库、豆瓣、个人图书馆、Pixiv、搜狗、Google、站长之家、OSCHINA、掘金、腾讯文档、pc6下载站、爱发电、Gitee、天眼查、爱企查、企查查、优设网、51CTO、力扣、花瓣网、飞书、Epic、Steam、语雀、牛客网、哔哩哔哩、少数派、5ch、金山文档、石墨文档、urlshare、酷安、网盘分享、腾讯云开发者社区、腾讯兔小巢、云栖社区、NodeSeek、亿企查、异次元软件、HelloGitHub
  5. // @author sakura-flutter
  6. // @namespace https://github.com/sakura-flutter/tampermonkey-scripts
  7. // @license GPL-3.0
  8. // @compatible chrome Latest
  9. // @compatible firefox Latest
  10. // @compatible edge Latest
  11. // @run-at document-start
  12. // @match *://www.jianshu.com/go-wild*
  13. // @match *://link.zhihu.com/*
  14. // @match *://t.cn/*
  15. // @match *://weibo.cn/sinaurl*
  16. // @match *://mail.qq.com/cgi-bin/*
  17. // @match *://wx.mail.qq.com/xmspamcheck/xmsafejump*
  18. // @match *://c.pc.qq.com/middlem.html*
  19. // @match *://c.pc.qq.com/middlect.html*
  20. // @match *://c.pc.qq.com/pc.html*
  21. // @match *://c.pc.qq.com/ios.html*
  22. // @match *://c.pc.qq.com/android.html*
  23. // @match *://app.yinxiang.com/OutboundRedirect.action*
  24. // @match *://jump.bdimg.com/safecheck/*
  25. // @match *://jump2.bdimg.com/safecheck/*
  26. // @match *://link.csdn.net/*
  27. // @match *://www.youtube.com/redirect*
  28. // @match *://weixin110.qq.com/cgi-bin/mmspamsupport-bin/newredirectconfirmcgi*
  29. // @match *://open.work.weixin.qq.com/wwopen/uriconfirm*
  30. // @match *://developers.weixin.qq.com/community/middlepage/href*
  31. // @match *://www.itdaan.com/link/*
  32. // @match *://www.douban.com/link2/*
  33. // @match *://www.360doc.com/content/*
  34. // @match *://www.pixiv.net/jump.php*
  35. // @match *://m.sogou.com/*/tc*
  36. // @match *://m.sogou.com*/tc*
  37. // @match *://www.chinaz.com/go.shtml*
  38. // @match *://www.oschina.net/action/GoToLink*
  39. // @match *://link.juejin.cn/*
  40. // @match *://docs.qq.com/scenario/link.html*
  41. // @match *://www.pc6.com/goread.html*
  42. // @match *://afdian.net/link*
  43. // @match *://afdian.com/link*
  44. // @match *://ifdian.net/link*
  45. // @match *://gitee.com/link*
  46. // @match *://www.tianyancha.com/security*
  47. // @match *://aiqicha.baidu.com/safetip*
  48. // @match *://www.qcc.com/web/transfer-link*
  49. // @match *://link.uisdc.com/*
  50. // @match *://blog.51cto.com/transfer*
  51. // @match *://leetcode.cn/link*
  52. // @match *://huaban.com/go*
  53. // @match *://security.feishu.cn/link/safety*
  54. // @match *://redirect.epicgames.com/*
  55. // @match *://steamcommunity.com/linkfilter/*
  56. // @match *://*.yuque.com/r/goto*
  57. // @match *://hd.nowcoder.com/link.html*
  58. // @match *://game.bilibili.com/linkfilter/*
  59. // @match *://sspai.com/link*
  60. // @match *://jump.5ch.net/*
  61. // @match *://www.kdocs.cn/office/link*
  62. // @match *://shimo.im/outlink/black*
  63. // @match *://google.urlshare.cn/umirror_url_check*
  64. // @match *://www.coolapk.com/link*
  65. // @match *://wpfx.org/go*
  66. // @match *://cloud.tencent.com/developer/tools/blog-entry*
  67. // @match *://support.qq.com/products/*/link-jump*
  68. // @match *://txc.qq.com/products/*/link-jump*
  69. // @match *://yq.aliyun.com/go/articleRenderRedirect*
  70. // @match *://www.nodeseek.com/jump*
  71. // @match *://www.yiqicha.com/thirdPage*
  72. // @match *://www.iplaysoft.com/link*
  73. // @match *://hellogithub.com/periodical/statistics/click*
  74. // @include /^https?:\/\/www\.google\..{2,7}url/
  75. // ==/UserScript==
  76.  
  77. /******/ (() => { // webpackBootstrap
  78. /******/ "use strict";
  79. /******/ // The require scope
  80. /******/ var __webpack_require__ = {};
  81. /******/
  82. /************************************************************************/
  83. /******/ /* webpack/runtime/define property getters */
  84. /******/ (() => {
  85. /******/ // define getter functions for harmony exports
  86. /******/ __webpack_require__.d = (exports, definition) => {
  87. /******/ for(var key in definition) {
  88. /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
  89. /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
  90. /******/ }
  91. /******/ }
  92. /******/ };
  93. /******/ })();
  94. /******/
  95. /******/ /* webpack/runtime/hasOwnProperty shorthand */
  96. /******/ (() => {
  97. /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
  98. /******/ })();
  99. /******/
  100. /******/ /* webpack/runtime/make namespace object */
  101. /******/ (() => {
  102. /******/ // define __esModule on exports
  103. /******/ __webpack_require__.r = (exports) => {
  104. /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
  105. /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  106. /******/ }
  107. /******/ Object.defineProperty(exports, '__esModule', { value: true });
  108. /******/ };
  109. /******/ })();
  110. /******/
  111. /************************************************************************/
  112. var __webpack_exports__ = {};
  113.  
  114. // NAMESPACE OBJECT: ./src/utils/ready-state.ts
  115. var ready_state_namespaceObject = {};
  116. __webpack_require__.r(ready_state_namespaceObject);
  117. __webpack_require__.d(ready_state_namespaceObject, {
  118. "DOMContentLoaded": () => (DOMContentLoaded),
  119. "complete": () => (complete),
  120. "interactive": () => (interactive),
  121. "load": () => (load),
  122. "loading": () => (loading)
  123. });
  124.  
  125. ;// CONCATENATED MODULE: ./src/utils/log.ts
  126. const isDebug = "production" !== 'production';
  127.  
  128. function warn(...args) {
  129. isDebug && warn.force(...args);
  130. }
  131.  
  132. warn.force = function (...args) {
  133. console.warn('%c warn ', 'background: #ffa500; padding: 1px; color: #fff;', ...args);
  134. };
  135.  
  136. function error(...args) {
  137. isDebug && error.force(...args);
  138. }
  139.  
  140. error.force = function (...args) {
  141. console.error('%c error ', 'background: red; padding: 1px; color: #fff;', ...args);
  142. };
  143.  
  144. function table(...args) {
  145. isDebug && console.table(...args);
  146. }
  147.  
  148.  
  149. ;// CONCATENATED MODULE: ./src/utils/ready-state.ts
  150. /**
  151. * readyState 因为脚本加载时机不一定监听到所有变化
  152. * 所以 pool 中的状态区分先后顺序
  153. * 靠后定义的会自动将靠前定义的但没有监听到的执行一次,但实际上不再是原来的状态
  154. */
  155.  
  156. const pool = new Map([['loading', []], ['interactive', []], ['DOMContentLoaded', []], // 扩展状态
  157. ['complete', []], ['load', []] // 扩展状态,不一定可以监听到
  158. ]);
  159. let currentState = document.readyState;
  160.  
  161. const execute = (readyState = currentState) => {
  162. currentState = readyState;
  163.  
  164. for (const [state, functions] of pool) {
  165. while (functions.length) {
  166. functions.shift()();
  167. }
  168.  
  169. if (readyState === state) break;
  170. }
  171. };
  172.  
  173. warn('document.readyState', currentState);
  174.  
  175. if (document.readyState !== 'complete') {
  176. document.addEventListener('readystatechange', () => execute(document.readyState));
  177. window.addEventListener('DOMContentLoaded', () => execute('DOMContentLoaded'));
  178. }
  179.  
  180. window.addEventListener('load', () => execute('load'));
  181.  
  182. const wrapper = (readyState, fn) => new Promise(resolve => {
  183. pool.get(readyState).push(function () {
  184. resolve(fn?.());
  185. }); // 立即检查一下
  186.  
  187. execute();
  188. });
  189.  
  190. const loading = fn => wrapper('loading', fn);
  191. const interactive = fn => wrapper('interactive', fn);
  192. const DOMContentLoaded = fn => wrapper('DOMContentLoaded', fn);
  193. const complete = fn => wrapper('complete', fn);
  194. const load = fn => wrapper('load', fn);
  195. ;// CONCATENATED MODULE: ./src/utils/querystring.ts
  196. /**
  197. * 解析 query
  198. * @param href 或 带有参数格式的 string;有 search 则不再 hash
  199. */
  200. function parse(href = location.href) {
  201. if (!href) return {};
  202. let search;
  203.  
  204. try {
  205. // 链接
  206. const url = new URL(href);
  207. ({
  208. search
  209. } = url); // 主要处理对hash的search
  210.  
  211. if (!search && url.hash.includes('?')) {
  212. search = url.hash.split('?')[1];
  213. }
  214. } catch {
  215. // 非链接,如:a=1&b=2、?a=1、/foo?a=1、/foo#bar?a=1
  216. if (href.includes('?')) {
  217. search = href.split('?')[1];
  218. } else {
  219. search = href;
  220. }
  221. }
  222.  
  223. return Object.fromEntries(new URLSearchParams(search));
  224. }
  225. function stringify(obj) {
  226. return Object.entries(obj) // 过滤 undefined,保留 null 且转成 ''
  227. .filter(([, value]) => value !== undefined).map(([key, value]) => `${key}=${value ?? ''}`).join('&');
  228. }
  229. ;// CONCATENATED MODULE: ./src/utils/selector.ts
  230. const $ = document.querySelector.bind(document);
  231. const $$ = document.querySelectorAll.bind(document);
  232. ;// CONCATENATED MODULE: ./src/scripts/redirect/sites/t-cn.ts
  233.  
  234. const weibo = async () => {
  235. let link = $('.open-url a[href]')?.href;
  236. link || (link = await fetch(location.href).then(response => response.headers.get('location')));
  237. return {
  238. link
  239. };
  240. };
  241. ;// CONCATENATED MODULE: ./src/scripts/redirect/sites/weixin110-qq-com.ts
  242. /* eslint-disable camelcase */
  243.  
  244. const {
  245. atob
  246. } = window;
  247. const weixin = () => {
  248. const {
  249. main_type,
  250. midpagecode
  251. } = parse();
  252. /**
  253. * main_type 貌似是旧的规则
  254. */
  255.  
  256. switch (main_type) {
  257. case '2':
  258. {
  259. const url = new URL(location.href); // 转为 1 可还原链接
  260.  
  261. url.searchParams.set('main_type', '1');
  262. location.replace(url.href);
  263. return {};
  264. }
  265.  
  266. case '1':
  267. break;
  268. }
  269. /**
  270. * midpagecode 似乎是新的规则
  271. */
  272.  
  273.  
  274. const MAGIC_KEY = atob(atob('Tmpjek56ZGhNbUZrWWpRMFpURTNZekZpTUdGa1lqSTBZalZqWmpKaVpERXlZek0wWkRsaU5UWmxNRFpqWTJRMlpHUTBZekk1TVdJME1qTmlOV0prTjJabU5tUmhZbVJqTlRVM1l6azVNbVkxWkRZd1pEZzVNbUkyT0Rjd1pqYzBOakV3TldNM05HRmhNalJqTXpBMk0yUTNOR1ExT1dJMFlXVTFOVFF6WldJM1lqSmtObVUwT1dOak1qYzNNMkZsTVRjM01UWTNNemcwTmpRM04ySmpOalppTTJNelltUTNPVE5sWkRJNFpEZGhaVE5rTnpZeE0yUm1ZVGRpWW1ReQ=='));
  275.  
  276. if (midpagecode && midpagecode !== MAGIC_KEY && !window.cgiData?.url) {
  277. const url = new URL(location.href); // 会还原链接
  278.  
  279. url.searchParams.set('midpagecode', MAGIC_KEY);
  280. location.replace(url.href);
  281. return {};
  282. }
  283.  
  284. return {
  285. // 如果解析得到,会出现在页面这里
  286. selector: '.weui-msg__text-area .ui-ellpisis-content p'
  287. };
  288. };
  289. ;// CONCATENATED MODULE: ./src/scripts/redirect/sites/www-360doc-com.ts
  290.  
  291.  
  292. const doc360 = () => {
  293. $('#artContent').addEventListener('click', event => {
  294. const {
  295. target
  296. } = event;
  297. const href = target.href;
  298. warn(target);
  299. if (target.nodeName !== 'A') return;
  300. if (!href) return; // 是否本站
  301.  
  302. if (new RegExp(location.host).test(new URL(href).host)) return;
  303. event.stopPropagation();
  304. window.open(href);
  305. }, true);
  306. return {};
  307. };
  308. ;// CONCATENATED MODULE: ./src/scripts/redirect/sites/www-pixiv-net.ts
  309.  
  310. const pixiv = () => {
  311. let link; // 链接居然是直接拼在url上的
  312. // https://www.pixiv.net/jump.php?https%3A%2F%2Fwww.huawei.com%2Fcn%2Fcorporate-information
  313.  
  314. for (const [key, value] of Object.entries(parse())) {
  315. try {
  316. link || (link = new URL(key).href);
  317. } catch {}
  318.  
  319. try {
  320. link || (link = new URL(value).href);
  321. } catch {}
  322. }
  323.  
  324. return {
  325. link
  326. };
  327. };
  328. ;// CONCATENATED MODULE: ./src/scripts/redirect/sites/index.ts
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335. const sites = [{
  336. name: '简书',
  337. test: 'www.jianshu.com/go-wild',
  338. use: () => ({
  339. query: 'url'
  340. })
  341. }, {
  342. name: '知乎',
  343. test: 'link.zhihu.com/',
  344. use: () => ({
  345. query: 'target'
  346. })
  347. }, {
  348. name: '微博',
  349. test: /^t\.cn\//,
  350. readyState: 'interactive',
  351. use: weibo
  352. }, {
  353. name: '微博',
  354. // 不同规则
  355. test: 'weibo.cn/sinaurl',
  356. use: () => ({
  357. link: parse().toasturl || parse().u
  358. })
  359. }, {
  360. name: 'QQ邮箱',
  361. test: ['mail.qq.com/cgi-bin/readtemplate', // 好像不用登录(不可用)也可以 gourl
  362. 'mail.qq.com/cgi-bin/mail_spam', // 需要登录(不可用)邮箱才可以,不过这里仍然可以帮忙跳转 url
  363. 'wx.mail.qq.com/xmspamcheck/xmsafejump' // url
  364. ],
  365. use: () => ({
  366. link: parse().gourl || parse().url
  367. })
  368. }, {
  369. name: 'QQPC',
  370. test: /^c\.pc\.qq\.com\/middle(m|ct).html/,
  371. use: () => ({
  372. query: 'pfurl'
  373. })
  374. }, {
  375. // 被阻止访问
  376. name: 'QQNT',
  377. test: /^c\.pc\.qq\.com\/(pc|ios|android)\.html/,
  378. use: () => ({
  379. query: 'url'
  380. })
  381. }, {
  382. name: '腾讯文档',
  383. test: 'docs.qq.com/scenario/link.html',
  384. use: () => ({
  385. query: 'url'
  386. })
  387. }, {
  388. name: '印象笔记',
  389. test: /^app\.yinxiang\.com\/OutboundRedirect/,
  390. use: () => ({
  391. query: 'dest'
  392. })
  393. }, {
  394. name: '贴吧',
  395. test: /^jump2?\.bdimg\.com\/safecheck/,
  396. // 以前的地址没有 2
  397. readyState: 'interactive',
  398. use: () => ({
  399. selector: '.warning_info a:nth-of-type(1)[href]',
  400. attr: 'href'
  401. })
  402. }, {
  403. name: 'CSDN',
  404. test: 'link.csdn.net/',
  405. use: () => ({
  406. query: 'target'
  407. })
  408. }, {
  409. name: 'YouTube',
  410. test: 'www.youtube.com/redirect',
  411. use: () => ({
  412. query: 'q'
  413. })
  414. }, {
  415. name: '微信',
  416. test: /^weixin110\.qq\.com\/cgi-bin\/mmspamsupport-bin\/newredirectconfirmcgi/,
  417. readyState: 'interactive',
  418. use: weixin
  419. }, {
  420. name: '企业微信',
  421. test: 'open.work.weixin.qq.com/wwopen/uriconfirm',
  422. use: () => ({
  423. query: 'uri'
  424. })
  425. }, {
  426. name: '微信开放社区',
  427. test: 'developers.weixin.qq.com/community/middlepage/href',
  428. use: () => ({
  429. query: 'href'
  430. })
  431. }, {
  432. name: '开发者知识库',
  433. test: /^www\.itdaan.com\/link\//,
  434. readyState: 'interactive',
  435. use: () => ({
  436. selector: '.safety-url'
  437. })
  438. }, {
  439. name: '豆瓣',
  440. test: 'www.douban.com/link2/',
  441. use: () => ({
  442. query: 'url'
  443. })
  444. }, {
  445. name: '个人图书馆',
  446. test: /^www\.360doc.com\/content\//,
  447. readyState: 'interactive',
  448. use: doc360
  449. }, {
  450. name: 'Pixiv',
  451. test: 'www.pixiv.net/jump.php',
  452. use: pixiv
  453. }, {
  454. name: '搜狗',
  455. test: /^m\.sogou\.com.*tc$/,
  456. use: () => ({
  457. query: 'url'
  458. })
  459. }, {
  460. name: 'Google',
  461. test: /^www\.google\..{2,7}url$/,
  462. use: () => ({
  463. link: parse().url || parse().q
  464. })
  465. }, {
  466. name: '站长之家',
  467. test: 'www.chinaz.com/go.shtml',
  468. use: () => ({
  469. query: 'url'
  470. })
  471. }, {
  472. name: 'OSCHINA',
  473. test: 'www.oschina.net/action/GoToLink',
  474. use: () => ({
  475. query: 'url'
  476. })
  477. }, {
  478. name: '掘金',
  479. test: 'link.juejin.cn/',
  480. use: () => ({
  481. query: 'target'
  482. })
  483. }, {
  484. name: 'pc6下载站',
  485. test: 'www.pc6.com/goread.html',
  486. use: () => ({
  487. query: 'gourl'
  488. })
  489. }, {
  490. name: '爱发电',
  491. test: ['afdian.net/link', 'afdian.com/link', 'ifdian.net/link'],
  492. use: () => ({
  493. query: 'target'
  494. })
  495. }, {
  496. name: 'Gitee',
  497. test: 'gitee.com/link',
  498. use: () => ({
  499. query: 'target'
  500. })
  501. }, {
  502. name: '天眼查',
  503. test: 'www.tianyancha.com/security',
  504. use: () => ({
  505. query: 'target'
  506. })
  507. }, {
  508. name: '爱企查',
  509. test: 'aiqicha.baidu.com/safetip',
  510. use: () => ({
  511. query: 'target'
  512. })
  513. }, {
  514. name: '企查查',
  515. test: 'www.qcc.com/web/transfer-link',
  516. use: () => ({
  517. query: 'link'
  518. })
  519. }, {
  520. name: '优设网',
  521. test: 'link.uisdc.com/',
  522. use: () => ({
  523. query: 'redirect'
  524. })
  525. }, {
  526. name: '51CTO',
  527. test: 'blog.51cto.com/transfer',
  528. use: () => ({
  529. link: location.search.slice(1)
  530. })
  531. }, {
  532. name: '力扣',
  533. test: 'leetcode.cn/link/',
  534. use: () => ({
  535. query: 'target'
  536. })
  537. }, {
  538. name: '花瓣网',
  539. test: 'huaban.com/go',
  540. readyState: 'interactive',
  541. use: () => {
  542. const nextData = JSON.parse($('#__NEXT_DATA__').textContent);
  543. return {
  544. link: nextData.props.pageProps?.data.link
  545. };
  546. }
  547. }, {
  548. name: '飞书',
  549. test: 'security.feishu.cn/link/safety',
  550. use: () => ({
  551. query: 'target'
  552. })
  553. }, {
  554. name: 'Epic',
  555. test: /^redirect\.epicgames\.com\//,
  556. use: () => ({
  557. query: 'redirectTo'
  558. })
  559. }, {
  560. name: 'Steam',
  561. test: 'steamcommunity.com/linkfilter/',
  562. use: () => ({
  563. link: parse().url || parse().u
  564. })
  565. }, {
  566. name: '语雀',
  567. test: /\.yuque\.com\/r\/goto(\/?)$/,
  568. use: () => ({
  569. query: 'url'
  570. })
  571. }, {
  572. name: '牛客网',
  573. test: 'hd.nowcoder.com/link.html',
  574. use: () => ({
  575. query: 'target'
  576. })
  577. }, {
  578. name: '哔哩哔哩',
  579. test: 'game.bilibili.com/linkfilter/',
  580. use: () => ({
  581. query: 'url'
  582. })
  583. }, {
  584. name: '少数派',
  585. test: 'sspai.com/link',
  586. use: () => ({
  587. query: 'target'
  588. })
  589. }, {
  590. name: '5ch',
  591. test: 'jump.5ch.net/',
  592. use: () => ({
  593. link: location.search.slice(1)
  594. })
  595. }, {
  596. name: '金山文档',
  597. test: 'www.kdocs.cn/office/link',
  598. use: () => ({
  599. query: 'target'
  600. })
  601. }, {
  602. name: '石墨文档',
  603. test: 'shimo.im/outlink/black',
  604. use: () => ({
  605. query: 'url'
  606. })
  607. }, {
  608. name: 'urlshare',
  609. test: 'google.urlshare.cn/umirror_url_check',
  610. use: () => ({
  611. query: 'url'
  612. })
  613. }, {
  614. name: '酷安',
  615. test: 'www.coolapk.com/link',
  616. use: () => ({
  617. query: 'url'
  618. })
  619. }, {
  620. name: '网盘分享',
  621. test: 'wpfx.org/go/',
  622. use: () => ({
  623. query: 'url'
  624. })
  625. }, {
  626. name: '腾讯云开发者社区',
  627. test: 'cloud.tencent.com/developer/tools/blog-entry',
  628. use: () => ({
  629. query: 'target'
  630. })
  631. }, {
  632. name: '腾讯兔小巢',
  633. // 两个域名
  634. test: /^(support|txc)\.qq\.com\/products\/\d+\/link-jump$/,
  635. use: () => ({
  636. query: 'jump'
  637. })
  638. }, {
  639. name: '云栖社区',
  640. test: 'yq.aliyun.com/go/articleRenderRedirect',
  641. use: () => ({
  642. query: 'url'
  643. })
  644. }, {
  645. name: 'NodeSeek',
  646. test: 'www.nodeseek.com/jump',
  647. use: () => ({
  648. query: 'to'
  649. })
  650. }, {
  651. name: '亿企查',
  652. test: 'www.yiqicha.com/thirdPage',
  653. use: () => ({
  654. query: 'link'
  655. })
  656. }, {
  657. name: '异次元软件',
  658. test: 'www.iplaysoft.com/link/',
  659. readyState: 'interactive',
  660. use: () => ({
  661. selector: '#targetUrl > a'
  662. })
  663. }, {
  664. name: 'HelloGitHub',
  665. test: 'hellogithub.com/periodical/statistics/click',
  666. use: () => ({
  667. query: 'target'
  668. })
  669. }];
  670. /* harmony default export */ const redirect_sites = (sites);
  671. ;// CONCATENATED MODULE: ./src/scripts/redirect/index.ts
  672. function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { throw new TypeError("attempted to use private field on non-instance"); } return receiver; }
  673.  
  674. var id = 0;
  675.  
  676. function _classPrivateFieldLooseKey(name) { return "__private_" + id++ + "_" + name; }
  677.  
  678.  
  679.  
  680.  
  681.  
  682.  
  683.  
  684. function hidePage() {
  685. interactive(() => {
  686. document.body.style.cssText = 'display:none !important;';
  687. });
  688. }
  689.  
  690. var _sites = /*#__PURE__*/_classPrivateFieldLooseKey("sites");
  691.  
  692. var _includes = /*#__PURE__*/_classPrivateFieldLooseKey("includes");
  693.  
  694. var _parse = /*#__PURE__*/_classPrivateFieldLooseKey("parse");
  695.  
  696. var _ensure = /*#__PURE__*/_classPrivateFieldLooseKey("ensure");
  697.  
  698. class App {
  699. constructor(sites) {
  700. Object.defineProperty(this, _ensure, {
  701. value: _ensure2
  702. });
  703. Object.defineProperty(this, _parse, {
  704. value: _parse2
  705. });
  706. Object.defineProperty(this, _includes, {
  707. value: _includes2
  708. });
  709. Object.defineProperty(this, _sites, {
  710. writable: true,
  711. value: void 0
  712. });
  713. _classPrivateFieldLooseBase(this, _sites)[_sites] = sites;
  714. }
  715.  
  716. boot() {
  717. const briefURL = location.host + location.pathname;
  718.  
  719. _classPrivateFieldLooseBase(this, _sites)[_sites].forEach(async site => {
  720. const {
  721. name,
  722. test,
  723. use
  724. } = site;
  725. if (!_classPrivateFieldLooseBase(this, _includes)[_includes](test, briefURL)) return;
  726. const {
  727. readyState: state
  728. } = site;
  729. if (state) await ready_state_namespaceObject[state]();
  730. const redirection = await _classPrivateFieldLooseBase(this, _parse)[_parse](use);
  731. table({
  732. name,
  733. briefURL,
  734. redirection
  735. });
  736. if (!redirection) return;
  737. location.replace(redirection); // 为什么要这样做?
  738. // 只是为了避免被问“哎!怎么好像没有跳转啊?!”的烦恼(实际上跳转了只是外链打开慢)(x_x)
  739.  
  740. hidePage();
  741. });
  742. }
  743.  
  744. }
  745.  
  746. function _includes2(test, url) {
  747. return [].concat(test).some(item => {
  748. if (typeof item === 'string') return item === url;
  749. if (item instanceof RegExp) return item.test(url);
  750. return false;
  751. });
  752. }
  753.  
  754. async function _parse2(use) {
  755. const {
  756. query,
  757. link,
  758. selector,
  759. attr
  760. } = await use();
  761. let redirection;
  762.  
  763. if (query) {
  764. redirection = parse()[query];
  765. } else if (link) {
  766. redirection = link;
  767. } else if (selector) {
  768. redirection = $(selector)?.[attr ?? 'innerText'];
  769. }
  770.  
  771. redirection && (redirection = _classPrivateFieldLooseBase(this, _ensure)[_ensure](redirection.trim()));
  772. return redirection;
  773. }
  774.  
  775. function _ensure2(url) {
  776. try {
  777. // eslint-disable-next-line no-new
  778. new URL(url);
  779. } catch (error) {
  780. warn(error); // 修复某些链接没有 protocol 导致跳转不正确
  781. // https://gf.qytechs.cn/zh-CN/scripts/416338-redirect-外链跳转/discussions/69178
  782.  
  783. const protocol = 'http:';
  784. url = protocol + '//' + url;
  785. }
  786.  
  787. return url;
  788. }
  789.  
  790. new App(redirect_sites).boot();
  791. /******/ })()
  792. ;

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址