Github anchor enhance

Enhance github repository link with badges

  1. // ==UserScript==
  2. // @name Github anchor enhance
  3. // @namespace https://github.com/NateScarlet/Scripts/tree/master/user-script
  4. // @description Enhance github repository link with badges
  5. // @grant GM.xmlHttpRequest
  6. // @run-at document-end
  7. // @include *
  8. // @version 2023.08.27+d1f0a919
  9. // ==/UserScript==
  10.  
  11. "use strict";
  12. (() => {
  13. var __async = (__this, __arguments, generator) => {
  14. return new Promise((resolve, reject) => {
  15. var fulfilled = (value) => {
  16. try {
  17. step(generator.next(value));
  18. } catch (e) {
  19. reject(e);
  20. }
  21. };
  22. var rejected = (value) => {
  23. try {
  24. step(generator.throw(value));
  25. } catch (e) {
  26. reject(e);
  27. }
  28. };
  29. var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
  30. step((generator = generator.apply(__this, __arguments)).next());
  31. });
  32. };
  33.  
  34. // src/github-anchor-enhance.user.ts
  35. var reservedUsername = /* @__PURE__ */ new Set([
  36. "topics",
  37. "search",
  38. "ghost",
  39. "pulls",
  40. "issues",
  41. "marketplace",
  42. "explore",
  43. "discover",
  44. "notifications",
  45. "new",
  46. "organizations",
  47. "settings",
  48. "site",
  49. "about",
  50. "contact",
  51. "pricing",
  52. "apps",
  53. "features",
  54. "password_reset",
  55. "trending",
  56. "collections",
  57. "events",
  58. "stars",
  59. "codespaces",
  60. "sponsors",
  61. "logout",
  62. "account"
  63. ]);
  64. var allBadgeClasses = ["added-stars-badge", "added-last-commit-badge"];
  65. var current = parseURL(location.href);
  66. function parseURL(rawURL) {
  67. const u = new URL(rawURL, document.baseURI);
  68. if (u.hostname !== "github.com") {
  69. return;
  70. }
  71. const match = /^\/([^/]+?)\/([^/]+?)(?:.git)?\/?$/.exec(u.pathname);
  72. if (!match) {
  73. return;
  74. }
  75. const owner = match[1];
  76. const repo = match[2];
  77. if (owner === (current == null ? void 0 : current.owner) && repo === current.repo) {
  78. return;
  79. }
  80. if (reservedUsername.has(owner)) {
  81. return;
  82. }
  83. return {
  84. owner,
  85. repo
  86. };
  87. }
  88. function appendBadge(el, className, url) {
  89. return __async(this, null, function* () {
  90. if (el.classList.contains(className)) {
  91. return;
  92. }
  93. return new Promise((resolve, reject) => {
  94. GM.xmlHttpRequest({
  95. method: "GET",
  96. url,
  97. onload: (resp) => {
  98. if (resp.status === 200) {
  99. if (!el.classList.contains(className)) {
  100. const img = document.createElement("img");
  101. img.src = `data:image/svg+xml;base64,${btoa(resp.response)}`;
  102. const containerClassNames = [
  103. "natescarlet-gmail-com",
  104. "badge-container"
  105. ];
  106. const selector = containerClassNames.map((i) => "." + i).join("");
  107. const container = el.querySelector(selector) || document.createElement("span");
  108. el.appendChild(container);
  109. container.classList.add(...containerClassNames);
  110. container.append(img);
  111. img.style.order = allBadgeClasses.indexOf(className).toString();
  112. container.style.display = "inline-flex";
  113. el.classList.add(className);
  114. }
  115. resolve();
  116. }
  117. reject(`${resp.status}: ${url}`);
  118. },
  119. onerror: reject
  120. });
  121. });
  122. });
  123. }
  124. function appendStarsBadge(el, res) {
  125. return __async(this, null, function* () {
  126. yield appendBadge(
  127. el,
  128. "added-stars-badge",
  129. `https://img.shields.io/github/stars/${res.owner}/${res.repo}.svg?style=social`
  130. );
  131. });
  132. }
  133. function appendLastCommitBadge(el, res) {
  134. return __async(this, null, function* () {
  135. yield appendBadge(
  136. el,
  137. "added-last-commit-badge",
  138. `https://img.shields.io/github/last-commit/${res.owner}/${res.repo}.svg`
  139. );
  140. });
  141. }
  142. (function() {
  143. return __async(this, null, function* () {
  144. document.addEventListener(
  145. "mouseover",
  146. (e) => __async(this, null, function* () {
  147. if (e.target instanceof HTMLAnchorElement) {
  148. const el = e.target;
  149. const res = parseURL(el.href);
  150. if (!res) {
  151. return;
  152. }
  153. try {
  154. yield Promise.all([
  155. appendStarsBadge(el, res),
  156. appendLastCommitBadge(el, res)
  157. ]);
  158. } catch (err) {
  159. console.error(err);
  160. }
  161. }
  162. }),
  163. {}
  164. );
  165. });
  166. })();
  167. })();