Greasy Fork is available in English.

github-contribution-ratio (typescript)

查看Github项目的贡献比例

// ==UserScript==
// @name              github-contribution-ratio (typescript)
// @author            Axetroy
// @collaborator      Axetroy
// @description       查看Github项目的贡献比例
// @version           0.1.0
// @update            2017-04-06 21:28:02
// @grant             GM_xmlhttpRequest
// @include           https://github.com*
// @connect           *
// @compatible        chrome  完美运行
// @compatible        firefox  完美运行
// @supportURL        http://www.burningall.com
// @run-at            document-idle
// @contributionURL   troy450409405@gmail.com|alipay.com
// @namespace         https://greasyfork.org/zh-CN/users/3400-axetroy
// @license           The MIT License (MIT); http://opensource.org/licenses/MIT
// ==/UserScript==

// Github源码:https://github.com/axetroy/github-contribution-ratio


/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports;
/******/
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// identity function for calling harmony imports with the correct context
/******/ 	__webpack_require__.i = function(value) { return value; };
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, {
/******/ 				configurable: false,
/******/ 				enumerable: true,
/******/ 				get: getter
/******/ 			});
/******/ 		}
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 2);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var extend = __webpack_require__(1);
var Http = (function () {
    function Http(options) {
        this.options = options;
    }
    Http.prototype.request = function (method, url, body, headers) {
        if (headers === void 0) { headers = { 'Cookie': document.cookie }; }
        var options = extend({}, this.options, { method: method, url: url, data: body, headers: headers });
        if (options.url.indexOf('http') !== 0) {
            options.url = (options.base || '') + url;
        }
        options.url += '?client_id=b8257841dd7ca5eef2aa&client_secret=4da33dd6fcb0a01d395945ad18613ecf9c12079e';
        return new Promise(function (resolve, reject) {
            options.synchronous = true; // async
            options.onreadystatechange = function (response) {
                if (response.readyState !== 4)
                    return;
                response.status >= 200 && response.status < 400 ? resolve(response) : reject(response);
            };
            options.onerror = function (response) {
                console.error('http error');
                reject(response);
            };
            options.onabort = function (response) {
                console.error('http abort');
                reject(response);
            };
            options.ontimeout = function (response) {
                console.error('http timeout');
                reject(response);
            };
            GM_xmlhttpRequest(extend({}, options));
        });
    };
    Http.prototype.get = function (url, body, headers) {
        if (body === void 0) { body = null; }
        if (headers === void 0) { headers = {}; }
        return this.request('GET', url, body, headers);
    };
    Http.prototype.post = function (url, body, headers) {
        if (body === void 0) { body = null; }
        if (headers === void 0) { headers = {}; }
        return this.request('POST', url, body, headers);
    };
    return Http;
}());
var timeout = 5000;
exports.timeout = timeout;
var http = new Http({ timeout: timeout, base: 'https://api.github.com' });
exports.http = http;


/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var hasOwn = Object.prototype.hasOwnProperty;
var toStr = Object.prototype.toString;

var isArray = function isArray(arr) {
	if (typeof Array.isArray === 'function') {
		return Array.isArray(arr);
	}

	return toStr.call(arr) === '[object Array]';
};

var isPlainObject = function isPlainObject(obj) {
	if (!obj || toStr.call(obj) !== '[object Object]') {
		return false;
	}

	var hasOwnConstructor = hasOwn.call(obj, 'constructor');
	var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
	// Not own constructor property must be Object
	if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
		return false;
	}

	// Own properties are enumerated firstly, so to speed up,
	// if last one is own, then all properties are own.
	var key;
	for (key in obj) {/**/}

	return typeof key === 'undefined' || hasOwn.call(obj, key);
};

module.exports = function extend() {
	var options, name, src, copy, copyIsArray, clone,
		target = arguments[0],
		i = 1,
		length = arguments.length,
		deep = false;

	// Handle a deep copy situation
	if (typeof target === 'boolean') {
		deep = target;
		target = arguments[1] || {};
		// skip the boolean and the target
		i = 2;
	} else if ((typeof target !== 'object' && typeof target !== 'function') || target == null) {
		target = {};
	}

	for (; i < length; ++i) {
		options = arguments[i];
		// Only deal with non-null/undefined values
		if (options != null) {
			// Extend the base object
			for (name in options) {
				src = target[name];
				copy = options[name];

				// Prevent never-ending loop
				if (target !== copy) {
					// Recurse if we're merging plain objects or arrays
					if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) {
						if (copyIsArray) {
							copyIsArray = false;
							clone = src && isArray(src) ? src : [];
						} else {
							clone = src && isPlainObject(src) ? src : {};
						}

						// Never move original objects, clone them
						target[name] = extend(deep, clone, copy);

					// Don't bring in undefined values
					} else if (typeof copy !== 'undefined') {
						target[name] = copy;
					}
				}
			}
		}
	}

	// Return the modified object
	return target;
};



/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t;
    return { next: verb(0), "throw": verb(1), "return": verb(2) };
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [0, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
Object.defineProperty(exports, "__esModule", { value: true });
var http_1 = __webpack_require__(0);
function getUserName() {
    var matcher = location.href.match(/https:\/\/github\.com\/(\w+)\??/);
    return matcher[1];
}
function shouldRun() {
    return /https:\/\/github\.com\/\w+\?/.test(location.href) && location.search.indexOf('tab=repositories') >= 0;
}
function getRepositories() {
    return [].slice.call(document.querySelectorAll('.js-repo-list>li'))
        .filter(function (li) { return !li.getAttribute('contribute-ratio'); })
        .map(function (li) {
        var a = li.querySelector('h3>a');
        var match = a.pathname.match(/([^\/]+)\/([^\/]+)/);
        li.setAttribute('repository-owner', match[1]);
        li.setAttribute('repository-name', match[2]);
        return li;
    });
}
function main() {
    return __awaiter(this, void 0, void 0, function () {
        var userName, lis;
        return __generator(this, function (_a) {
            if (!shouldRun())
                return [2 /*return*/];
            userName = getUserName();
            console.info("Stating " + userName + "'s contribution...");
            lis = getRepositories();
            if (!lis.length)
                return [2 /*return*/];
            clearInterval(timer);
            timer = void 0;
            lis.forEach(function (li) {
                var owner = li.getAttribute('repository-owner');
                var name = li.getAttribute('repository-name');
                http_1.http.get("/repos/" + owner + "/" + name + "/stats/contributors")
                    .then(function (res) {
                    var raw = res.response;
                    if (!raw)
                        return;
                    var response = JSON.parse(raw);
                    response = Object.keys(response).length === 0 ? [] : response;
                    var contributes = response.filter(function (v) { return v["author"]["login"] === userName; }).map(function (v) { return v; });
                    var totalAdditions = 0;
                    var totalDeletions = 0;
                    var additions = 0;
                    var deletions = 0;
                    contributes.forEach(function (contribute) {
                        contribute.weeks.forEach(function (week) { return (additions += week.a) && (deletions += week.d); });
                    });
                    response.forEach(function (contribute) {
                        contribute.weeks.forEach(function (week) { return (totalAdditions += week.a) && (totalDeletions += week.d); });
                    });
                    var contributeRatio = (((additions + deletions) / (totalAdditions + totalDeletions)) * 100) + '';
                    li.setAttribute('total-additions', totalAdditions);
                    li.setAttribute('total-deletions', totalDeletions);
                    li.setAttribute('additions', additions);
                    li.setAttribute('deletions', deletions);
                    li.setAttribute('contribute-ratio', parseInt(contributeRatio));
                    var percent = parseInt(contributeRatio) > 0 ? parseInt(contributeRatio) : 1;
                    var uncontribution = document.createElement('span');
                    var contribution = document.createElement('span');
                    var container = document.createElement('span');
                    container.setAttribute('aria-label', "Contribution " + percent + "%");
                    var width = 155;
                    container.classList.add('d-inline-block');
                    container.classList.add('tooltipped');
                    container.classList.add('tooltipped-s');
                    container.style.width = '155px';
                    var contributionWidth = width * percent / 100;
                    contribution.style.width = contributionWidth + 'px';
                    contribution.style.borderBottom = '2px solid #009688';
                    contribution.style.display = 'inline-block';
                    uncontribution.style.width = width - contributionWidth + 'px';
                    uncontribution.style.borderBottom = '2px solid #9E9E9E';
                    uncontribution.style.display = 'inline-block';
                    container.appendChild(contribution);
                    container.appendChild(uncontribution);
                    li.querySelector('.col-3.float-right.text-right').appendChild(container);
                })
                    .catch(function (err) {
                    console.error(err);
                });
            });
            return [2 /*return*/];
        });
    });
}
(function (history) {
    var pushState = history.pushState;
    history.pushState = function (state) {
        if (typeof history["onpushstate"] == "function") {
            history["onpushstate"]({ state: state });
        }
        setTimeout(function () {
            run();
        });
        return pushState.apply(history, arguments);
    };
})(window.history);
var timer;
function run() {
    if (!shouldRun())
        return;
    timer = setInterval(function () {
        main();
    }, 1500);
}
run();


/***/ })
/******/ ]);