Skip to content

Instantly share code, notes, and snippets.

@Cologler
Last active January 3, 2018 05:35
Show Gist options
  • Save Cologler/7891df3378eb77e2c908d76f43ba73e1 to your computer and use it in GitHub Desktop.
Save Cologler/7891df3378eb77e2c908d76f43ba73e1 to your computer and use it in GitHub Desktop.
#site:github #user_script
// ==UserScript==
// @name github-blocker
// @name:zh-CN github-blocker
// @namespace https://github.com/cologler/github-blocker
// @version 1.1.0.2
// @description block github user.
// @description:zh-CN 屏蔽某些国产 github 伸手党用户.
// @author cologler
// @match https://github.com/*/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @grant GM_info
// @grant GM_addStyle
// @grant GM_unregisterMenuCommand
// @grant GM_registerMenuCommand
// @grant GM_getResourceText
// @require https://greasyfork.org/scripts/32752/code/expirableStorage.js
// @require https://greasyfork.org/scripts/31497/code/StyleSwitcher.js
// @resource css-def https://gist.github.com/Cologler/7891df3378eb77e2c908d76f43ba73e1/raw/github-blocker.def.css
// @resource css-full https://gist.github.com/Cologler/7891df3378eb77e2c908d76f43ba73e1/raw/github-blocker.full.css
// ==/UserScript==
// this script was hosting on: https://gist.github.com/Cologler/7891df3378eb77e2c908d76f43ba73e1
// just let type script work.
(function() { function require(){}; require("greasemonkey"); })();
(async function() {
'use strict';
/* Copyright (c) 2017~2999 - cologler <skyoflw@gmail.com> */
let createDonePromise = (() => {
function createDonePromise(request) {
console.assert(request instanceof XMLHttpRequest);
return new Promise((resolve, reject) => {
request.onreadystatechange = () => {
if (request.readyState === XMLHttpRequest.DONE) {
resolve(request);
}
};
});
}
if (XMLHttpRequest.prototype.createDonePromise === undefined) {
XMLHttpRequest.prototype.createDonePromise = function () {
return createDonePromise(this);
};
}
return createDonePromise;
})();
/* Copyright (c) 2017~2999 - cologler <skyoflw@gmail.com> */
function parseLinkHeader(link) {
let parts = link.match(/<([^ ]+)>; rel="([^"]+)"/g);
let r = {};
parts.forEach(p => {
let m = p.match(/<([^ ]+)>; rel="([^"]+)"/);
r[m[2]] = m[1];
});
return r;
}
/* Copyright (c) 2017~2999 - cologler <skyoflw@gmail.com> */
class Logger {
constructor (name) {
this._name = name;
this._group = false;
}
get _headers() {
if (this._group) {
return [];
}
return [`[${this._name}]`]
}
group() {
console.group(this._name);
this._group = true;
}
end() {
console.groupEnd();
this._group = false;
}
debug() {
console.debug(...this._headers, ...arguments);
}
info() {
console.info(...this._headers, ...arguments);
}
warn() {
console.warn(...this._headers, ...arguments)
}
error() {
console.error(...this._headers, ...arguments)
}
}
const logger = new Logger('github-blocker');
// style
let sw = new StyleSwitcher();
sw.addStyle('def', GM_getResourceText('css-def'));
sw.addStyle('full', GM_getResourceText('css-full'));
sw.load();
// start script
let KEY_TOKEN = 'token';
GM_deleteValue('cache'); // remove old cache.
function buildTokenSaveButton(el) {
let tk = el.querySelector('.token').innerHTML;
let div = el.querySelector('.BtnGroup');
// create button
let a = document.createElement('a');
a.addEventListener('click', function(ev) {
console.log('Github-Blocker: saving token to ' + tk);
GM_setValue(KEY_TOKEN, tk);
});
a.innerText = 'use for Github-Blocker';
div.children[0].classList.forEach(function(z) {
a.classList.add(z);
});
div.insertBefore(a, div.firstChild);
}
if (location.href == 'https://github.com/settings/tokens') {
let tks = document.querySelectorAll('.access-token.new-token');
if (tks.length == 1) {
buildTokenSaveButton(tks[0]);
}
return;
}
if (/https:\/\/github.com\/settings/.test(location.href)) return;
let token = GM_getValue(KEY_TOKEN, null);
if (token === null) return;
const blockedUsers = new Set();
unsafeWindow.blockedUsers = blockedUsers;
const CLASS_NAME = 'blocked-user';
let resolveItems = function (root = null) {
if (root === null) root = document;
logger.group();
try {
if (root.querySelectorAll) {
if (/^\/.+\/.+\/issues$/.test(location.pathname)) {
document.querySelectorAll('.js-issue-row')
.forEach(z => {
if (z.classList.contains(CLASS_NAME)) return;
let username = z.querySelector('.opened-by a').textContent;
if (blockedUsers.has('https://github.com/' + username)) {
logger.debug(`${username} is blocked.`);
z.classList.add(CLASS_NAME);
} else {
logger.debug(`${username} is not blocked.`);
}
});
} else if (/^\/[^\/]+\/[^\/]+\/issues\/\d+$/.test(location.pathname)) {
document.querySelectorAll('.timeline-comment-wrapper.js-comment-container')
.forEach(z => {
if (z.classList.contains(CLASS_NAME)) return;
const a = z.querySelector('.avatar-parent-child.timeline-comment-avatar a');
if (a) {
let username = a.href.replace('https://github.com/', '');
if (blockedUsers.has(a.href)) {
logger.debug(`${username} is blocked.`);
z.classList.add(CLASS_NAME);
} else {
logger.debug(`${username} is not blocked.`);
}
}
});
}
}
} finally {
logger.end();
}
};
const cacheStorage = new ExpirableStorage(sessionStorage);
async function fetchBlockedData(url) {
url = url || 'https://api.github.com/user/blocks';
const entity = cacheStorage.getEntity(url) || {};
let cached = entity.content || null;
let result = null;
if (entity.isExpired === false) {
result = result = cached;
} else {
let req = new XMLHttpRequest();
req.open('GET', url);
req.setRequestHeader('Authorization', 'token ' + token);
req.setRequestHeader('Accept', 'application/vnd.github.giant-sentry-fist-preview+json');
if (cached && cached.etag) {
req.setRequestHeader('If-None-Match', cached.etag);
}
const awaitable = req.createDonePromise();
req.send();
await awaitable;
if (req.status == 200) {
result = {
etag: req.getResponseHeader('Etag'),
content: JSON.parse(req.responseText)
};
let link = req.getResponseHeader('Link');
if (link) {
let linkTable = parseLinkHeader(link);
if (linkTable.next) {
result.nexturl = linkTable.next;
}
}
} else if (req.status == 304) {
result = cached;
}
}
if (result) {
cacheStorage.setItemExpiresAfter(url, result, 15 * 60 * 1000);
result.content.forEach(z => blockedUsers.add(z.html_url));
if (result.nexturl) {
await fetchBlockedData(result.nexturl);
}
}
}
await fetchBlockedData();
resolveItems();
window.addEventListener('DOMNodeInserted', function (e) {
resolveItems(e.target);
});
})();
[
{
"login": "cfcboy",
"id": 590597,
"avatar_url": "https://avatars3.githubusercontent.com/u/590597?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/cfcboy",
"html_url": "https://github.com/cfcboy",
"followers_url": "https://api.github.com/users/cfcboy/followers",
"following_url": "https://api.github.com/users/cfcboy/following{/other_user}",
"gists_url": "https://api.github.com/users/cfcboy/gists{/gist_id}",
"starred_url": "https://api.github.com/users/cfcboy/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/cfcboy/subscriptions",
"organizations_url": "https://api.github.com/users/cfcboy/orgs",
"repos_url": "https://api.github.com/users/cfcboy/repos",
"events_url": "https://api.github.com/users/cfcboy/events{/privacy}",
"received_events_url": "https://api.github.com/users/cfcboy/received_events",
"type": "User",
"site_admin": false
}
]
.blocked-user .comment-body {
background: #D1D5DA;
padding: 0;
}
.blocked-user .comment-body * {
display:none;
}
.blocked-user .mt-1 {
margin-top: 0 !important;
}
.blocked-user span.labels, .blocked-user .js-navigation-open {
display:none;
}
.blocked-user .tooltipped {
visibility: hidden;
}
.blocked-user.timeline-comment-wrapper.js-comment-container {
display: none;
}
li.blocked-user.js-issue-row * {
display:none;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment