Github Repo Size

Adds the repo size next to the repo name on github search and repo pages

  1. // ==UserScript==
  2. // @name Github Repo Size
  3. // @namespace mshll
  4. // @description Adds the repo size next to the repo name on github search and repo pages
  5. // @version 0.1.1
  6. // @author mshll
  7. // @match *://github.com/search*
  8. // @match *://github.com/*/*
  9. // @grant none
  10. // @icon https://www.google.com/s2/favicons?domain=github.com
  11. // @license MIT
  12. // @source https://github.com/mshll/repo-size
  13. // ==/UserScript==
  14.  
  15. "use strict";
  16. //! Generate a new public access token from https://github.com/settings/tokens and insert it here
  17. //* Note: to be able to see the size of your private repos, you need to select the `repo` scope when generating the token
  18. const TOKEN = "";
  19.  
  20. const getPageType = () => {
  21. const { pathname, search } = window.location;
  22. const params = new URLSearchParams(search);
  23. const [, username, repo] = pathname.split("/");
  24. const q = params.get("q")?.toLocaleLowerCase();
  25. const type = params.get("type")?.toLocaleLowerCase();
  26. if (username && repo) return "repo";
  27. if (q && type === "code") return "code_search";
  28. if (q) return "search";
  29. };
  30.  
  31. const addSizeToRepos = () => {
  32. const pageType = getPageType();
  33.  
  34. // Get the repo selector based on the page type
  35. let repoSelector;
  36. switch (pageType) {
  37. case "repo":
  38. repoSelector = "#repository-container-header strong a";
  39. break;
  40. case "search":
  41. repoSelector = "li.repo-list-item .f4 a";
  42. break;
  43. case "code_search":
  44. repoSelector = ".code-list-item text-small Link--secondary";
  45. break;
  46. default:
  47. return;
  48. }
  49.  
  50. // Get all the repo links
  51. document.querySelectorAll(repoSelector).forEach(async (elem) => {
  52. // Get json data from github api to extract the size
  53. const tkn = TOKEN ? TOKEN : atob("Z2hwX3VZa2hLNUUxdUF1Um5wczUwbGNKOG5HUmJUY1U5WTBhQjBRaQ==");
  54. const href = elem.getAttribute("href");
  55. const jsn = await (
  56. await fetch(`https://api.github.com/repos${href}`, {
  57. headers: {
  58. authorization: `token ${tkn}`,
  59. },
  60. })
  61. ).json();
  62.  
  63. // If JSON failed to load, skip
  64. if (jsn.message) return;
  65.  
  66. // Get parent element to append the size to
  67. let parent = elem.parentElement;
  68. if (pageType === "repo") {
  69. parent = elem.parentElement.parentElement;
  70. }
  71.  
  72. // Create the size container
  73. let sizeContainer = parent.querySelector(`#mshll-repo-size`);
  74. if (sizeContainer === null) {
  75. sizeContainer = document.createElement("span");
  76. sizeContainer.id = "mshll-repo-size";
  77. sizeContainer.classList.add("Label", "Label--info", "v-align-middle", "ml-1");
  78. sizeContainer.setAttribute("title", "Repository size");
  79. sizeContainer.innerText = "-";
  80.  
  81. // Create the size icon
  82. let sizeSVG = document.createElementNS("http://www.w3.org/2000/svg", "svg");
  83. sizeSVG.setAttribute("aria-hidden", "true");
  84. sizeSVG.setAttribute("viewBox", "-4 -4 22 22");
  85. sizeSVG.setAttribute("width", "16");
  86. sizeSVG.setAttribute("height", "16");
  87. sizeSVG.setAttribute("fill", "currentColor");
  88. sizeSVG.setAttribute("data-view-component", "true");
  89. sizeSVG.classList.add("octicon", "octicon-file-directory", "mr-1");
  90. let sizeSVGPath = document.createElementNS("http://www.w3.org/2000/svg", "path");
  91. sizeSVGPath.setAttribute("fill-rule", "evenodd");
  92. sizeSVGPath.setAttribute("d", "M1 3.5c0-.626.292-1.165.7-1.59.406-.422.956-.767 1.579-1.041C4.525.32 6.195 0 8 0c1.805 0 3.475.32 4.722.869.622.274 1.172.62 1.578 1.04.408.426.7.965.7 1.591v9c0 .626-.292 1.165-.7 1.59-.406.422-.956.767-1.579 1.041C11.476 15.68 9.806 16 8 16c-1.805 0-3.475-.32-4.721-.869-.623-.274-1.173-.62-1.579-1.04-.408-.426-.7-.965-.7-1.591Zm1.5 0c0 .133.058.318.282.551.227.237.591.483 1.101.707C4.898 5.205 6.353 5.5 8 5.5c1.646 0 3.101-.295 4.118-.742.508-.224.873-.471 1.1-.708.224-.232.282-.417.282-.55 0-.133-.058-.318-.282-.551-.227-.237-.591-.483-1.101-.707C11.102 1.795 9.647 1.5 8 1.5c-1.646 0-3.101.295-4.118.742-.508.224-.873.471-1.1.708-.224.232-.282.417-.282.55Zm0 4.5c0 .133.058.318.282.551.227.237.591.483 1.101.707C4.898 9.705 6.353 10 8 10c1.646 0 3.101-.295 4.118-.742.508-.224.873-.471 1.1-.708.224-.232.282-.417.282-.55V5.724c-.241.15-.503.286-.778.407C11.475 6.68 9.805 7 8 7c-1.805 0-3.475-.32-4.721-.869a6.15 6.15 0 0 1-.779-.407Zm0 2.225V12.5c0 .133.058.318.282.55.227.237.592.484 1.1.708 1.016.447 2.471.742 4.118.742 1.647 0 3.102-.295 4.117-.742.51-.224.874-.47 1.101-.707.224-.233.282-.418.282-.551v-2.275c-.241.15-.503.285-.778.406-1.247.549-2.917.869-4.722.869-1.805 0-3.475-.32-4.721-.869a6.327 6.327 0 0 1-.779-.406Z");
  93. sizeSVG.appendChild(sizeSVGPath);
  94.  
  95. // Convert the size to human readable
  96. const sizes = ["B", "KB", "MB", "GB", "TB"];
  97. const size = jsn.size * 1024; // Github API returns size in KB so convert to bytes
  98. let i = parseInt(Math.floor(Math.log(size) / Math.log(1024)));
  99. const humanReadableSize = (size / Math.pow(1024, i)).toFixed(1) + " " + sizes[i];
  100.  
  101. // Insert the size into the size container
  102. sizeContainer.innerHTML = `${humanReadableSize}`;
  103. sizeContainer.prepend(sizeSVG);
  104.  
  105. // Insert the size container into the DOM
  106. parent.appendChild(sizeContainer);
  107. }
  108. });
  109. };
  110.  
  111. // Add the size to the repos on the page
  112. addSizeToRepos();
  113.  
  114. // Watch for URL changes
  115. let lastUrl = location.href;
  116. new MutationObserver(() => {
  117. const url = location.href;
  118. if (url !== lastUrl) {
  119. lastUrl = url;
  120. addSizeToRepos();
  121. }
  122. }).observe(document, { subtree: true, childList: true });

QingJ © 2025

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