ブログに競プロのレーティングを表示するようにした(その2)
以前の記事でプログのサイドバーに競プロのレーティング(と色)を表示するjavascriptを紹介しました。 意外にも多くの方に使って頂けているようで嬉しいです。
以前紹介したスクリプトではAtCoderのレーティング取得がYQLに依存していましたが、 残念ながらYQLは2019年1月でサービス終了してしまいました。 それに伴って、AtCoderのレーティング取得ができなくなっていました。
この問題に対応するために、簡易的なAPIサーバー的なもの(Kyopro-Ratingsと命名)を作成し、Heroku上で動かすことにしました。
※追記 2022/11/05
Herokuの無料枠の終了に合わせてHerokuに設置していたAPIサーバを停止します。
今後は以下のURLで@su8ruさんにホストしていただけることになりました。
http://kyopro-ratings.jp1.su8.run/json
既にブログなどに設置している方は、以下のように変更していただくことで引き続き利用できます。
- xhr.open('GET', 'https://kyopro-ratings.herokuapp.com/json?' + query_str, true); + xhr.open('GET', 'http://kyopro-ratings.jp1.su8.run/json?' + query_str, true);
デモ
機能
旧バージョンと同じです。
- レーティング
- 色付け
- ユーザーページへのリンク
Kyopro-Ratings
サーバー側でレーティングを取得して、jsonでフロント側に送っています。
スクレイピングしている関係上、高頻度でリクエストが来た場合にエラーを返すようになっています。とりあえず200ms以内に複数のリクエストが来た場合に弾くようにしました。
※追記 2020/05/05 一日に1回だけフェッチしてサーバ側でキャッシュするようにしました。200msの制限が無くなった代わりにレーティングの更新が最大1日遅れます。
ソースコード
こちらをサイドバーなどに設置しています。適当に改変して使ってください。
(htmlのtwitter・AOJの部分、jsのatcoder_user
, codeforces_user
, topcoder_algorithm_user
の部分を自分のユーザー名に書き換えてください。)
なお、予告なくサーバーを停止するなどして動かなくなるかもしれませんので、その点はご了承ください。
<p> Twitter : <a id="twitter" href="https://twitter.com/algon_320" target="_blank" style="text-decoration:none;font-weight:bold;color:black;">@algon_320</a><br> AtCoder : <a id="atcoder_rating" target="_blank" style="text-decoration:none;font-weight:bold;">loading</a><br> Codeforces : <a id="codeforces_rating" target="_blank" style="text-decoration:none;font-weight:bold;">loading</a><br> TopCoder SRM : <a id="topcoder_algorithm_rating" target="_blank" style="text-decoration:none;font-weight:bold;">loading</a><br> AOJ : <a id="aoj" href="http://judge.u-aizu.ac.jp/onlinejudge/user.jsp?id=algon#1" target="_blank" style="text-decoration:none;font-weight:bold;color:black;">algon</a><br> </p> <script type="text/javascript"> (function () { class User { constructor(service, handle) { this.service = service; this.handle = handle; this.rating = 0; this.color = '#000'; // デフォルトの色 } } class Service { constructor(name, url) { this.name = name; this.url = url; } } let atcoder = new Service('atcoder', 'https://atcoder.jp/user/'); let codeforces = new Service('codeforces', 'http://codeforces.com/profile/'); let topcoder_algorithm = new Service('topcoder_algorithm', 'https://www.topcoder.com/members/'); let atcoder_user = new User(atcoder, 'algon'); let codeforces_user = new User(codeforces, 'algon_320'); let topcoder_algorithm_user = new User(topcoder_algorithm, 'algon_320'); let accounts = [atcoder_user, codeforces_user, topcoder_algorithm_user]; // ユーザーページへのリンクのみ function set_html_without_rating(user) { let a = document.getElementById(user.service.name + '_rating'); a.href = user.service.url + user.handle; a.innerHTML = user.handle; a.setAttribute('style', 'text-decoration:none;font-weight:bold;color:' + user.color); } // ユーザーページへのリンク + レーティング表示 + 色 function set_html(user) { let a = document.getElementById(user.service.name + '_rating'); a.href = user.service.url + user.handle; a.innerHTML = user.handle + ' (' + user.rating.toString() + ')'; a.setAttribute('style', 'text-decoration:none;font-weight:bold;color:' + user.color); } function fetch_ratings() { let query_str = ''; accounts.forEach(user => { query_str += user.service.name + "=" + user.handle + '&'; }); function error() { accounts.forEach(user => set_html_without_rating(user)); } let xhr = new XMLHttpRequest(); xhr.open('GET', 'http://kyopro-ratings.jp1.su8.run/json?' + query_str, true); xhr.onload = function (e) { if (xhr.readyState === 4) { if (xhr.status === 200) { json = JSON.parse(xhr.responseText); // console.log(json); if ('error' in json) { error(); } else { accounts.forEach(user => { let service_name = user.service.name; if (json[service_name]['status'] == 'success') { user.rating = json[service_name]['rating']; user.color = json[service_name]['color']; set_html(user); } else { set_html_without_rating(user); } }); } } } }; xhr.onerror = function (e) { error(); }; xhr.ontimeout = function (e) { error(); }; xhr.timeout = 10000; xhr.send(null); } fetch_ratings(); })(); </script>
はてなブログの場合、管理画面のデザイン→サイドバー→カスタマイズから設置することが出来ます。