您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
12/8/2023, 9:09:51 PM
// ==UserScript== // @name GitHub: Redirect forked repo links to own repo // @namespace Violentmonkey Scripts // @match https://github.com/* // @grant none // @version 0.1.5 // @author CY Fung // @description 12/8/2023, 9:09:51 PM // @run-at document-start // @license MIT // ==/UserScript== /** * * This is to change links in markdown files from the original repo links to your forked repo links * **/ (() => { let rafPromise = null; const rafFn = (typeof webkitRequestAnimationFrame !== 'undefined' ? webkitRequestAnimationFrame : requestAnimationFrame).bind(window); // eslint-disable-line no-undef, no-constant-condition const getRafPromise = () => rafPromise || (rafPromise = new Promise(resolve => { rafFn(hRes => { rafPromise = null; resolve(hRes); }); })); const matcher = h => typeof h == 'string' && h.length > 19 && h.startsWith('https://github.com/') && /^https\:\/\/github\.com\/([\w\d\-\.]+)\/([\w\d\-\.]+)/.exec(h); const pageInfo = { ready: false, matched: false, owner: '', repo: '', repoUrl: '', originalOwner: '', originalRepo: '', originalRepoUrl: '', url: '', }; const PromiseExternal = ((resolve_, reject_) => { const h = (resolve, reject) => { resolve_ = resolve; reject_ = reject }; return class PromiseExternal extends Promise { constructor(cb = h) { super(cb); if (cb === h) { /** @type {(value: any) => void} */ this.resolve = resolve_; /** @type {(reason?: any) => void} */ this.reject = reject_; } } }; })(); let pageOriginalP = new PromiseExternal(); const obtainOriginalRepo = () => { if (pageInfo.ready && pageInfo.matched && pageInfo.url && !pageInfo.originalRepoUrl) { // Define the XPath expression var xpathExpression = "//span[contains(text(), 'forked from')]"; // Use document.evaluate to find the matching element var result = document.evaluate(xpathExpression, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); var spanElement = result.singleNodeValue; // Check if a matching element was found if (spanElement instanceof Element) { const a = spanElement.querySelector('a[href]'); if (a) { const h = a.href; let m = matcher(h); if (m) { pageInfo.originalOwner = m[1]; pageInfo.originalRepo = m[2]; pageInfo.originalRepoUrl = `https://github.com/${pageInfo.originalOwner}/${pageInfo.originalRepo}/`; pageOriginalP.resolve(); } } } } } document.addEventListener('DOMContentLoaded', () => { pageInfo.ready = false; pageInfo.matched = false; baseProcess(); obtainOriginalRepo(); }, false); let qk = 0; let ck = 0; const baseProcess = () => { let pageUrl = `${location.origin}${location.pathname}`; if (pageInfo.url !== pageUrl) { pageInfo.url = pageUrl; pageInfo.ready = false; pageInfo.matched = false; pageInfo.originalOwner = ''; pageInfo.originalRepo = ''; pageInfo.originalRepoUrl = ''; pageOriginalP = new PromiseExternal(); } if (!pageInfo.ready && pageInfo.url) { pageInfo.ready = true; let m = matcher(pageInfo.url); if (m) { pageInfo.matched = true; pageInfo.owner = m[1]; pageInfo.repo = m[2]; pageInfo.repoUrl = `https://github.com/${pageInfo.owner}/${pageInfo.repo}/`; } } if (pageInfo.ready && pageInfo.matched) { process(); } }; const process = async () => { let qt = ++qk; await pageOriginalP.then(); if (qt !== qk) return; let ct = ++ck; await getRafPromise().then(); if (ct !== ck) return; if (!pageInfo.ready || !pageInfo.matched) return; if (!pageInfo.repoUrl || !pageInfo.originalRepoUrl) return; for (const s of document.querySelectorAll(`a[href^="${pageInfo.originalRepoUrl}"]`)) { const h = s.getAttribute('href'); let m = matcher(h); if (m) { s.setAttribute('href', h.replace(`${pageInfo.originalRepoUrl}`, `${pageInfo.repoUrl}`)) } } } let dk = 0; const mo = new MutationObserver((entries) => { baseProcess(); if (pageInfo.ready && pageInfo.matched && pageInfo.url && !pageInfo.originalRepoUrl) { let dt = ++dk; getRafPromise().then(() => { if (dt === dk) setTimeout(obtainOriginalRepo, 80); }); } }); mo.observe(document, { subtree: true, childList: true }); })();