GitHub Repo Size Display

Display repository size on GitHub repository pages

// ==UserScript==
// @name         GitHub Repo Size Display
// @namespace    http://tampermonkey.net/
// @version      0.1
// @license      MIT
// @description  Display repository size on GitHub repository pages
// @author       RainbowBird
// @match        https://github.com/*
// @grant        GM_xmlhttpRequest
// @connect      api.github.com
// ==/UserScript==

(function() {
    'use strict';

    // 工具函数:转换文件大小为人类可读格式
    function convertSizeToHumanReadableFormat(bytes) {
        const units = ['B', 'KB', 'MB', 'GB', 'TB'];
        let size = bytes;
        let unitIndex = 0;

        while (size >= 1024 && unitIndex < units.length - 1) {
            size /= 1024;
            unitIndex++;
        }

        return {
            size: size.toFixed(1),
            measure: units[unitIndex]
        };
    }

    // 工具函数:从 URL 获取用户名和仓库名
    function getUsernameWithReponameFromGithubURL() {
        const pathnameParts = window.location.pathname.split('/').filter(Boolean);
        return {
            user: pathnameParts[0],
            repo: pathnameParts[1]
        };
    }

    // 添加仓库大小到页面
    function appendRepoSizeElement(repoSize) {
        // 移除已存在的仓库大小显示(如果有)
        const existingSize = document.querySelector('.eg-repo-size');
        if (existingSize) {
            existingSize.remove();
        }

        // 寻找插入位置
        const sidebarElement = document.querySelector('.Layout-sidebar .hide-sm.hide-md');
        if (!sidebarElement) return;

        const formattedFileSize = convertSizeToHumanReadableFormat(repoSize * 1024); // GitHub API 返回的大小单位是 KB

        const html = `
            <h3 class="sr-only">Repo Size</h3>
            <div class="mt-2 eg-repo-size">
                <a href="javascript:void(0);" data-view-component="true" class="Link Link--muted">
                    <svg class="octicon octicon-database mr-2" mr="2" aria-hidden="true" height="16" version="1.1" viewBox="0 0 12 16" width="16">
                        <path d="M6 15c-3.31 0-6-.9-6-2v-2c0-.17.09-.34.21-.5.67.86 3 1.5 5.79 1.5s5.12-.64 5.79-1.5c.13.16.21.33.21.5v2c0 1.1-2.69 2-6 2zm0-4c-3.31 0-6-.9-6-2V7c0-.11.04-.21.09-.31.03-.06.07-.13.12-.19C.88 7.36 3.21 8 6 8s5.12-.64 5.79-1.5c.05.06.09.13.12.19.05.1.09.21.09.31v2c0 1.1-2.69 2-6 2zm0-4c-3.31 0-6-.9-6-2V3c0-1.1 2.69-2 6-2s6 .9 6 2v2c0 1.1-2.69 2-6 2zm0-5c-2.21 0-4 .45-4 1s1.79 1 4 1 4-.45 4-1-1.79-1-4-1z"></path>
                    </svg>
                    <strong>${formattedFileSize.size}</strong>
                    <span>${formattedFileSize.measure}</span>
                </a>
            </div>
        `;

        sidebarElement.insertAdjacentHTML('beforeend', html);
    }

    // 获取仓库信息并显示大小
    function fetchRepoSizeAndDisplay() {
        const path = getUsernameWithReponameFromGithubURL();

        // 只在仓库主页执行
        if (!path.repo) return;

        const apiUrl = `https://api.github.com/repos/${path.user}/${path.repo}`;

        GM_xmlhttpRequest({
            method: 'GET',
            url: apiUrl,
            headers: {
                'Accept': 'application/vnd.github.v3+json'
            },
            onload: function(response) {
                if (response.status === 200) {
                    const data = JSON.parse(response.responseText);
                    if (data && data.size) {
                        appendRepoSizeElement(data.size);
                    }
                }
            }
        });
    }

    // 监听页面 URL 变化
    let lastUrl = location.href;
    new MutationObserver(() => {
        const url = location.href;
        if (url !== lastUrl) {
            lastUrl = url;
            fetchRepoSizeAndDisplay();
        }
    }).observe(document, { subtree: true, childList: true });

    // 初始加载
    fetchRepoSizeAndDisplay();
})();