GitHub: Redirect forked repo links to own repo

12/8/2023, 9:09:51 PM

当前为 2023-12-08 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name GitHub: Redirect forked repo links to own repo
  3. // @namespace Violentmonkey Scripts
  4. // @match https://github.com/*
  5. // @grant none
  6. // @version 0.1.1
  7. // @author CY Fung
  8. // @description 12/8/2023, 9:09:51 PM
  9. // @run-at document-start
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. /**
  14. *
  15. * This is to change links in markdown files from the original repo links to your forked repo links
  16. *
  17. **/
  18.  
  19. (() => {
  20.  
  21.  
  22. let rafPromise = null;
  23. const rafFn = (typeof webkitRequestAnimationFrame !== 'undefined' ? webkitRequestAnimationFrame : requestAnimationFrame).bind(window); // eslint-disable-line no-undef, no-constant-condition
  24.  
  25. const getRafPromise = () => rafPromise || (rafPromise = new Promise(resolve => {
  26. rafFn(hRes => {
  27. rafPromise = null;
  28. resolve(hRes);
  29. });
  30. }));
  31.  
  32. const matcher = h => typeof h == 'string' && h.length > 19 && h.startsWith('https://github.com/') && /^https\:\/\/github\.com\/([\w\d\-\.]+)\/([\w\d\-\.]+)/.exec(h);
  33. const pageInfo = {
  34. ready: false,
  35. matched: false,
  36. owner: '',
  37. repo: '',
  38. originalOwner: '',
  39. originalRepo: '',
  40. url: '',
  41. };
  42.  
  43. const PromiseExternal = ((resolve_, reject_) => {
  44. const h = (resolve, reject) => { resolve_ = resolve; reject_ = reject };
  45. return class PromiseExternal extends Promise {
  46. constructor(cb = h) {
  47. super(cb);
  48. if (cb === h) {
  49. /** @type {(value: any) => void} */
  50. this.resolve = resolve_;
  51. /** @type {(reason?: any) => void} */
  52. this.reject = reject_;
  53. }
  54. }
  55. };
  56. })();
  57.  
  58. let pageOriginalP = new PromiseExternal();
  59.  
  60. document.addEventListener('DOMContentLoaded', () => {
  61.  
  62.  
  63. // Define the XPath expression
  64. var xpathExpression = "//span[contains(text(), 'forked from')]";
  65.  
  66. // Use document.evaluate to find the matching element
  67. var result = document.evaluate(xpathExpression, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
  68.  
  69. var spanElement = result.singleNodeValue;
  70. // Check if a matching element was found
  71. if (spanElement instanceof Element) {
  72. setTimeout(() => {
  73.  
  74. const a = spanElement.querySelector('a[href]');
  75. if (a) {
  76. const h = a.href;
  77. let m = matcher(h);
  78.  
  79. if (m) {
  80. pageInfo.originalOwner = m[1];
  81. pageInfo.originalRepo = m[2];
  82. pageInfo.originalRepoUrl = `https://github.com/${pageInfo.originalOwner}/${pageInfo.originalRepo}/`;
  83. pageOriginalP.resolve();
  84. }
  85.  
  86. }
  87. }, 1);
  88. }
  89.  
  90.  
  91. }, false);
  92.  
  93.  
  94.  
  95. let qk = 0;
  96. let ck = 0;
  97.  
  98. const process = async () => {
  99. let qt = ++qk;
  100. await pageOriginalP.then();
  101. if (qt !== qk) return;
  102. let ct = ++ck;
  103. await getRafPromise().then();
  104. if (ct !== ck) return;
  105.  
  106. for (const s of document.querySelectorAll(`a[href^="${pageInfo.originalRepoUrl}"]`)) {
  107. const h = s.getAttribute('href');
  108. let m = matcher(h);
  109. if (m) {
  110. s.setAttribute('href', h.replace(`${pageInfo.originalRepoUrl}`, `${pageInfo.repoUrl}`))
  111. }
  112. }
  113.  
  114. }
  115.  
  116. const mo = new MutationObserver((entries) => {
  117. if (!pageInfo.ready) {
  118. pageInfo.ready = true;
  119. let pageUrl = `${location.origin}${location.pathname}`;
  120. pageInfo.url = pageUrl;
  121. let m = matcher(pageUrl);
  122. if (m) {
  123. pageInfo.matched = true;
  124. pageInfo.owner = m[1];
  125. pageInfo.repo = m[2];
  126. pageInfo.repoUrl = `https://github.com/${pageInfo.owner}/${pageInfo.repo}/`;
  127. }
  128. }
  129. if (pageInfo.matched) {
  130. process();
  131. }
  132. });
  133.  
  134. mo.observe(document, { subtree: true, childList: true });
  135.  
  136. })();