GitHub FileSize Viewer Revised

Show the file size next to it on the website

As of 08.10.2018. See ბოლო ვერსია.

  1. // ==UserScript==
  2. // @name GitHub FileSize Viewer Revised
  3. // @namespace https://github.com/mo-san/GitHub-FileSize-Viewer
  4. // @version 0.9.12.1
  5. // @description Show the file size next to it on the website
  6. // @author nmaxcom (Original)
  7. // @author Masaki(mo-san)
  8. // @match https://*.github.com/*
  9. // @grant GM_xmlhttpRequest
  10. // ==/UserScript==
  11.  
  12. (function () {
  13. var TEXT_COLOR = '#6a737d'; // Default github style
  14. // var TEXT_COLOR = '#888'; // my dark github style
  15. const SHOW_BYTES = false; // false: always KB, i.e. '>1 KB'; true: i.e. '180 B' when less than 1 KB
  16. const ABSOLUTE_DATE = true; // shows commit datetime absolutely, otherwise originally relatively.
  17.  
  18. var vars, response;
  19. const css = style => document.head.insertAdjacentHTML("beforeend", `<style>${style}</style>`);
  20. css(`
  21. td.filesize { color: ${TEXT_COLOR}; text-align: right; 'padding-right: 50px !important; }
  22. table.files td.message { max-width: 250px !important; }
  23. `)
  24. XMLHttpRequest.prototype.open = () => {
  25. this.addEventListener('loadend', () => tableCheckandGo());
  26. XMLHttpRequest.prototype.open.apply(this, arguments);
  27. };
  28. tableCheckandGo();
  29.  
  30.  
  31. /*
  32. * Order of business:
  33. * - Detect table, if present, launch async API call and insert new blank cells
  34. * - Detect necessary info to make the async API call
  35. * - When promised is successful, change the blanks for the numbers
  36. * done: detect page change since github does that youtube thing
  37. */
  38. function tableCheckandGo() {
  39. if (!document.querySelector('table.files')) return;
  40.  
  41. /*
  42. * GET must be implemented in the api: /repos/:owner/:repo/contents/:path?ref=branch
  43. * With this regex we capture the title: \w+(.*?)\sat\s(.*?)\s.*?(\w+)\/(\w+)
  44. * where (1) dir path, (2) branch, (3) owner, (4) repo;
  45. * That regex does not work in root
  46. */
  47. var title = document.title;
  48. // Root folder:
  49. var match3 = title.match(/.*?([\w\d.-]+)\/([\w\d.-]+):/i);
  50. // Non root folder, any branch:
  51. // Root folder, we'll extract branch from scrape
  52. var match2 = title.match(/.+?\/([\w\d.\/-]+).*?·\s([\w\d.-]+)\/([\w\d.\/-]+)/i);
  53. if (match3) {
  54. vars = {
  55. dir: "",
  56. owner: match3[1],
  57. repo: match3[2],
  58. branch: document.querySelector('.branch-select-menu button span').innerHTML
  59. };
  60. } else if (match2) {
  61. vars = {
  62. dir: match2[1],
  63. owner: match2[2],
  64. repo: match2[3],
  65. branch: document.querySelector('.branch-select-menu button span').innerHTML
  66. };
  67. };
  68.  
  69. callGitHub().then((resp) => {
  70. insertBlankCells();
  71. fillTheBlanks(JSON.parse(resp.responseText));
  72. })
  73. }
  74.  
  75. /*
  76. * API call
  77. * We're forced to use GM_xmlhttpRequest to avoid Same Origin Policy issues
  78. */
  79. function callGitHub() {
  80. return new Promise((resolve, reject) =>
  81. GM_xmlhttpRequest({
  82. method: "GET",
  83. url: `https://api.github.com/repos/${vars.owner}/${vars.repo}/contents/${vars.dir}?ref=${vars.branch}`,
  84. onload: (res) => resolve(res),
  85. onerror: (res) => reject(res)
  86. })
  87. );
  88. }
  89.  
  90. /*
  91. * - Directories get new cellmate too
  92. *
  93. */
  94. function insertBlankCells() {
  95. const filenameCells = document.querySelectorAll('tr[class~="js-navigation-item"] > td.content');
  96. for (let cell of filenameCells) {
  97. const newtd = document.createElement('td');
  98. newtd.className = 'filesize';
  99. cell.parentNode.insertBefore(newtd, cell.nextSibling);
  100. }
  101. }
  102.  
  103. /*
  104. * If we get the data, we insert it carefully so each filename gets matched
  105. * with the correct filesize.
  106. */
  107. function fillTheBlanks(JSONelements) {
  108. const nametds = document.querySelectorAll('tr[class~="js-navigation-item"] > td.content a');
  109. toploop:
  110. for (let element of JSONelements) {
  111. for (let td of nametds) {
  112. if (element.name !== td.innerHTML) continue;
  113. if (element.type !== 'file') continue;
  114. let sizeNumber = (element.size / 1024).toFixed(0);
  115. if (SHOW_BYTES) {
  116. sizeNumber = sizeNumber < 1 ? element.size + ' B' : sizeNumber + ' KB';
  117. } else {
  118. sizeNumber = sizeNumber < 1 ? '> 1 KB' : sizeNumber + ' KB';
  119. }
  120. td.parentNode.parentNode.nextSibling.innerHTML = sizeNumber;
  121. }
  122. }
  123. }
  124.  
  125.  
  126. /*
  127. * Shows commit time in absolute, instead of relative.
  128. */
  129. if (ABSOLUTE_DATE) {
  130. css(`
  131. table.files td.age {
  132. padding: 0;
  133. }
  134. table.files td.age span.css-truncate {
  135. display: block;
  136. }
  137. td.age time-ago,
  138. relative-time {
  139. font-size: 0;
  140. }
  141. td.age time-ago::before,
  142. relative-time::before {
  143. content: attr(title);
  144. font-size: 14px;
  145. }
  146. `)
  147. }
  148.  
  149. })();