redirect 外链跳转

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

目前为 2023-04-05 提交的版本。查看 最新版本

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

QingJ © 2025

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