GitHubReleasesCount

To show download counter for each attachment from Releases page on GitHub.com

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        GitHubReleasesCount
// @description To show download counter for each attachment from Releases page on GitHub.com
// @namespace   net.r_eg.GitHubReleasesCount
// @version     0.4
// @grant       none
// @include     https://github.com/*/*/releases*
// @require     https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
// @author      https://github.com/3F
// @license     MIT
// ==/UserScript==

/* 
 Here's sandbox as the main page of this script at this time:
 - https://github.com/3F/sandbox/tree/master/javascript/_user_scripts/GitHubReleasesCount
 
 Tested via: 
    - Firefox 61.0.2 + Greasemonkey 4.6
    - Firefox 59.0.2 + Greasemonkey 4.3
    - Firefox 55.0.3 & 54.0.1 + Greasemonkey 3.11
    
 Changes:
     * 0.4: Fixed the work with modern GitHub Releases ~ Aug 2018
     * 0.3: Fixed the work with modern GitHub Releases ~(Jan 2018 - Apr 2018)
     * 0.2: individual tags & multi-pages support (+async).
     * 0.1: first idea.
*/
(function()
{
    'use strict';

    class GhrCounter extends function(){ this.constructor.prototype.$ =
    {
        /** assets from the releases page */
        pageFiles: ".release-header + :first-of-type li a",

        /** 'user/project' from url */
        usrprj: /^\/([^/]+)\/([^/]+)/g,

        apiserver: 'api.github.com',

        out: {
            class: 'Label Label--outline Label--outline-green text-gray',
            style: 'margin-right: 3px;',
        },

        debug: false,

        /* --------------- */ }}{ /* --------------- */

        showCount(elem, count)
        {
            let _= this;
            if(_.isNull(elem) || _.isNull(count)) {
                throw new GhrcNullException('elem', 'count'); 
            }

            elem.prepend("<span class='" + _.$.out.class + "' style='" + _.$.out.style 
                            + "'>" + count + "</span>");
        }

        process()
        {
            let _= this;
            _.dbg('started for: ' + location.pathname);

            let url = _.getInfoAPI();
            _.dbg('get info: ' + url);

            $.get(url, function(apidata)
            {
                $(_.$.pageFiles).each(function()
                {
                    let root = $(this);
                    let durl = root.attr('href');

                    if(durl.indexOf('releases/download') == -1) {
                        return true; // means 'continue' statement
                    }

                    for(let idx in apidata)
                    for(let asset in apidata[idx].assets)
                    {
                        let lnk = apidata[idx].assets[asset];

                        if(!lnk.browser_download_url.endsWith(durl)) {
                            continue;
                        };
                        
                        _.dbg('insert data for #' + lnk.id + ': ' + durl);
                        _.showCount(root, lnk.download_count);
                    }
                });
            });
        }

        constructor(debug)
        {
            super();

            this.$.debug = debug;
            this.process();
        }

        getInfoAPI()
        {
            let l = this.$.usrprj.exec(location.pathname);
            return location.protocol 
                    + '//' + this.$.apiserver + '/repos/' + l[1] + '/' + l[2] + '/releases';
        }

        dbg(msg, ...args)
        {
            if(!this.$.debug) {
                return;
            }

            let stamp = new Date().toISOString().substr(11, 12) + '] ';
            if(this.isNull(args) || args.length < 1) {
                console.log(stamp + msg);
            }
            else {
                console.log(stamp + msg, args);
            }
        }

        isNull(val)
        {
            return val == null || val === undefined;
        }
    };

    class GhrcException
    {
        constructor(message, arg)
        {
            this.message    = message;
            this.arg        = arg;
        }
    }

    class GhrcNullException extends GhrcException
    {
        constructor(...args)
        {
            super("'" + args + "' cannot be null.", null);
        }
    }


    // ...

    let ghrс = new GhrCounter(false);

    // when async loading
    $(window).bind('pjax:success', function() { ghrс.process(); });

})();