您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Show the file size next to it on the website
- // ==UserScript==
- // @name GitHub FileSize Viewer
- // @namespace http://tampermonkey.net/
- // @version 0.9.12
- // @description Show the file size next to it on the website
- // @author nmaxcom
- // @match https://*.github.com/*
- // @grant GM_xmlhttpRequest
- // ==/UserScript==
- // TODO: try document.addEventListener("pjax:start", function(){...}) and pjax:end as triggers
- (function(){
- /****************
- * Options:
- ****************/
- const DEBUG_MODE = true; // in production mode should be false
- const SHOW_BYTES = false; // false: always KB, i.e. '>1 KB', true: i.e. '180 B' when less than 1 KB
- /****************/
- var textColor = '#6a737d'; // Default github style
- // var textColor = '#888'; // my dark github style
- createStyles();
- var origXHROpen = XMLHttpRequest.prototype.open;
- XMLHttpRequest.prototype.open = function(){
- this.addEventListener('loadend', function(){
- if(DEBUG_MODE) console.log('%cStart: ' + document.title, 'color:white;background-color:#20A6E8;padding:3px');
- tableCheckandGo();
- });
- origXHROpen.apply(this, arguments);
- };
- var vars = {}, response;
- tableCheckandGo();
- /**
- * Order of business:
- * - Detect table, if present, launch async API call and insert new blank cells
- * - Detect necessary info to make the async API call
- * - When promised is successful, change the blanks for the numbers
- * done: detect page change since github does that youtube thing
- */
- function tableCheckandGo(){
- if(document.querySelector('table.files')){
- if(setVars()){
- var callPromise = callGitHub();
- callPromise
- .then(function(resp){
- response = resp;
- if(DEBUG_MODE) console.info('GitHub call went through');
- if(DEBUG_MODE) console.info(resp.responseText);
- insertBlankCells();
- fillTheBlanks(JSON.parse(resp.responseText));
- recheckAndFix();
- })
- .catch(function(fail){
- if(DEBUG_MODE) console.error(fail);
- });
- } else {
- if(DEBUG_MODE) console.info('setVars() failed. Vars: ', vars);
- }
- } else {
- if(DEBUG_MODE) console.info('No data table detected, nothing to do');
- }
- }
- /**
- * API call
- */
- function callGitHub(){
- return new Promise(function(resolve, reject){
- // I'm forced to use GM_xmlhttpRequest to avoid Same Origin Policy issues
- GM_xmlhttpRequest({
- method : "GET",
- url : getAPIurl(),
- onload : function(res){
- resolve(res);
- },
- onerror: function(res){
- reject(res);
- }
- });
- });
- }
- function getAPIurl(){
- // .../repos/:owner/:repo/contents/:path?ref=branch
- vars.dir = vars.dir || '';
- return "https://api.github.com/repos/" +
- vars.owner + "/" +
- vars.repo +
- "/contents/" +
- vars.dir + "?ref=" + vars.branch;
- }
- /**
- * - Directories get new cellmate too
- *
- */
- function insertBlankCells(){
- var filenameCells = document.querySelectorAll('tr[class~="js-navigation-item"] > td.content');
- for(var i = 0, len = filenameCells.length; i < len; i++){
- var newtd = document.createElement('td');
- newtd.className = 'filesize';
- filenameCells[i].parentNode.insertBefore(newtd, filenameCells[i].nextSibling);
- }
- if(DEBUG_MODE) console.info(`Inserted ${i} cells`);
- }
- /**
- * If we get the data, we insert it carefully so each filename gets matched
- * with the correct filesize.
- */
- function fillTheBlanks(JSONelements){
- if(!document.querySelectorAll('td.filesize').length){
- debugger;
- }
- var nametds = document.querySelectorAll('tr[class~="js-navigation-item"] > td.content a');
- var i, len;
- toploop:
- for(i = 0, len = JSONelements.length; i < len; i++){
- for(var cellnum in nametds){
- if(nametds.hasOwnProperty(cellnum) && JSONelements[i].name === nametds[cellnum].innerHTML){
- if(JSONelements[i].type === 'file'){
- var sizeNumber = (JSONelements[i].size / 1024).toFixed(0);
- if(SHOW_BYTES){
- sizeNumber = sizeNumber < 1 ? JSONelements[i].size + ' B' : sizeNumber + ' KB';
- } else {
- sizeNumber = sizeNumber < 1 ? '> 1 KB' : sizeNumber + ' KB';
- }
- nametds[cellnum].parentNode.parentNode.nextSibling.innerHTML = sizeNumber;
- }
- continue toploop;
- }
- }
- }
- if(DEBUG_MODE) console.info(`Processed ${i} of ${len} elements`);
- // if(DEBUG_MODE) console.info('Dumping json y nodes:');
- // if(DEBUG_MODE) console.log(JSONelements.forEach(function(e,i){if(DEBUG_MODE) console.log(JSONelements[i].name)}));
- // if(DEBUG_MODE) console.log(nametds.forEach(function(e,i){if(DEBUG_MODE) console.log(nametds[i].innerHTML)}));
- }
- function createStyles(){
- var css = 'td.filesize { color: ' + textColor + ';' +
- 'text-align: right;' +
- 'padding-right: 50px !important; }' +
- 'table.files td.message { max-width: 250px !important;',
- head = document.head || document.getElementsByTagName('head')[0],
- style = document.createElement('style');
- style.type = 'text/css';
- if(style.styleSheet){
- style.styleSheet.cssText = css;
- } else {
- style.appendChild(document.createTextNode(css));
- }
- head.appendChild(style);
- }
- /**
- * Hay que satisfacer en la api el GET /repos/:owner/:repo/contents/:path?ref=branch
- * Con este regex capturamos del título \w+(.*?)\sat\s(.*?)\s.*?(\w+)\/(\w+)
- * 1) dir path, 2) branch, 3) owner, 4) repo
- * Ese regex no funciona en el root
- */
- function setVars(){
- var title = document.title;
- // Root folder:
- var match3 = title.match(/.*?([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+):/);
- // Non root folder, any branch:
- //var match1 = title.match(/([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+)\sat\s([a-zA-Z0-9._-]+)\s·\s([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+)/);
- // Root folder, we'll extract branch from scrape
- var match2 = title.match(/.+?\/([a-zA-Z0-9._\/-]+).*?·\s([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._\/-]+)/);
- if(match3){
- vars = {owner: match3[1], repo: match3[2]};
- vars.branch = document.querySelector('.branch-select-menu button span').innerHTML;
- }/*else if(match1) {
- vars = {repo: match1[1], dir: match1[2], branch: match1[3], owner: match1[4]};
- } */ else if(match2){
- vars = {dir: match2[1], owner: match2[2], repo: match2[3]};
- vars.branch = document.querySelector('.branch-select-menu button span').innerHTML;
- } else if(DEBUG_MODE) console.log(getAPIurl());
- return 1;
- }
- /**
- * Sometimes, even though data has been correctly recieved, the DOM doesn't play well
- * for whatever reason. This function will quickly check if the data is indeed
- * there and if it's not will repaint the data again with the original functions.
- * TODO: finish this part
- */
- function recheckAndFix(){
- // Count td.filesize and compare to total rows
- let filesizes = document.querySelectorAll('td.filesize').length;
- let ages = document.querySelectorAll('td.age').length;
- if(filesizes === ages){
- if(DEBUG_MODE) console.info(`Good empty check: ${filesizes} of ${ages}`);
- } else {
- if(DEBUG_MODE) console.info(`Bad empty check: ${filesizes} of ${ages}. Repainting`);
- }
- // Count non-empty td.filesize and compare to number of files from response
- if(DEBUG_MODE) console.info(`Say something...`);
- }
- })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址