-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.js
152 lines (140 loc) · 5.71 KB
/
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// ==UserScript==
// @name AtCoder Submission User Colorizer
// @namespace https://github.com/morioprog
// @version 1.3
// @description 提出一覧のユーザ名を色付けします
// @author morio_prog
// @match https://atcoder.jp/contests/*/submissions*
// @grant none
// @license CC0
// @require https://unpkg.com/lscache/lscache.min.js
// ==/UserScript==
$(function() {
'use strict';
const lastUpdateKey = 'user-colorizer-ranking-last-update';
const rankingKey = 'user-colorizer-ranking';
const OUT_OF_RANK = Number.MAX_VALUE; // > 100
function getColor(rating) {
if (rating >= 2800) return '#FF0000';
if (rating >= 2400) return '#FF8000';
if (rating >= 2000) return '#C0C000';
if (rating >= 1600) return '#0000FF';
if (rating >= 1200) return '#00C0C0';
if (rating >= 800) return '#008000';
if (rating >= 400) return '#804000';
if (rating > 0) return '#808080';
return '#000000';
}
function getColorClass(rating) {
if (rating >= 2800) return 'user-red';
if (rating >= 2400) return 'user-orange';
if (rating >= 2000) return 'user-yellow';
if (rating >= 1600) return 'user-blue';
if (rating >= 1200) return 'user-cyan';
if (rating >= 800) return 'user-green';
if (rating >= 400) return 'user-brown';
if (rating > 0) return 'user-gray';
return 'user-unrated';
}
function getAchRate(rating) {
const base = Math.floor(rating / 400) * 400;
return ((rating - base) / 400) * 100;
}
function colorize(u, ranking, rating) {
/* */if (ranking <= 1) $(u).before('<img style="vertical-align: middle;" src="//img.atcoder.jp/assets/icon/crown_champion.png"> ');
else if (ranking <= 10) $(u).before('<img style="vertical-align: middle;" src="//img.atcoder.jp/assets/icon/crown_gold.png"> ');
else if (ranking <= 30) $(u).before('<img style="vertical-align: middle;" src="//img.atcoder.jp/assets/icon/crown_silver.png"> ');
else if (ranking <= 100) $(u).before('<img style="vertical-align: middle;" src="//img.atcoder.jp/assets/icon/crown_bronze.png"> ');
else if (rating > 0) {
const color = getColor(rating);
const achRate = getAchRate(rating);
$(u).before(`
<span style="
display: inline-block;
height: 12px;
width: 12px;
vertical-align: center;
border-radius: 50%;
border: solid 1px ${color};
background: -webkit-linear-gradient(
bottom,
${color} 0%,
${color} ${achRate}%,
rgba(255, 255, 255, 0.0) ${achRate}%,
rgba(255, 255, 255, 0.0) 100%);
"></span>
`);
}
$(u).addClass(getColorClass(rating));
}
function getRankingMap() {
return new Promise(function(callback) {
const currentTime = new Date().getTime();
const lastUpdateTime = localStorage.getItem(lastUpdateKey);
// Update every 3 hours
if (lastUpdateTime && currentTime < Number(lastUpdateTime) + 3 * 60 * 60 * 1000) {
callback(JSON.parse(localStorage.getItem(rankingKey)));
} else {
let ranking = {};
$.ajax({
url: "https://atcoder.jp/ranking",
type: 'GET',
dataType: 'html'
})
.done(function(data) {
$($.parseHTML(data)).find('.username > span').each(function(idx) {
const userName = $(this).text();
ranking[userName] = idx + 1;
});
})
.then(function() {
localStorage.setItem(lastUpdateKey, currentTime);
localStorage.setItem(rankingKey, JSON.stringify(ranking));
callback(ranking);
});
}
});
}
function getRanking(rankingMap, userName) {
if (userName in rankingMap) return rankingMap[userName];
return OUT_OF_RANK;
}
lscache.flushExpired();
getRankingMap().then((rankingMap) => {
let index = 0;
$('a[href*="/users"]').each(function(_, u) {
// Skip "My Profile"
if ($(u).find('span').length) return true;
const partUri = $(this).attr('href');
const userName = partUri.slice(7);
const lskey = "rating-" + userName;
const ranking = getRanking(rankingMap, userName);
let rating = lscache.get(lskey);
if (rating !== null) {
colorize(u, ranking, rating);
return;
}
index += 1;
setTimeout(function() {
$.ajax({
url: "https://atcoder.jp" + partUri + "/history/json",
type: 'GET',
dataType: 'json'
})
.done(function(data) {
const ratedCount = data.length;
if (ratedCount == 0) {
rating = 0;
} else {
rating = data[ratedCount - 1]["NewRating"];
}
// Update every 3 hours
lscache.set(lskey, rating, 3 * 60);
})
.then(function() {
colorize(u, ranking, rating);
});
}, index * 300);
});
});
});