はじめに
これは、AtCoder関連サービス Advent Calendar 2018の18日目の記事です。今年作ったAtCoder向けのChrome拡張について書きます。
この拡張へのリンクはこちら。何かあったらフィードバックをもらえるとありがたいです。
※ 追記: この記事を公開した日にAtCoderのURLに変更が行われ、一時的にこの拡張が動かなくなってました。
機能
概要
どうして作ったのか
- 自分の前後のレーティングを見たい
- 過去のパフォーマンスがどの色のどのレベルなのか分かりやすくしたい
どうやって実現しているか
Chrome拡張部分
Chrome拡張とは
Chrome拡張は個人で書いて公開1することができ、それをインストールすることでChromeに機能を追加することができます。この拡張機能の様なDOMの操作だけでは無く、クライアントJSではできないようなChromeの用意しているAPIを利用した機能も実装できます。逆に、拡張機能のメニューが必要な場合は自作が必要になります。そして、Chromeで動けば良いため、ES6なども問題なく使用することができます。
公開方法としては、Tampermonkeyという拡張機能のスクリプトとして公開することもできます。こちらはユーザ登録派不要です。
manifest.json
"https://*.contest.atcoder.jp/*",
"http://*.contest.atcoder.jp/*",
"https://beta.atcoder.jp/contests/*",
"https://beta.atcoder.jp/users/*/history"
上記の4つのドメインを対象にしてます。betaの方がドメインが統一されていてloclstorageとか共有できて嬉しいです。
上記のページに対してCSS,JSを一個ずつ挿入してます。
表示部分
レーティングの円の表示はcanvas要素の挿入によって実現してます(canvasなのでinnerText
には無影響なはずなので、他の拡張に影響はおそらく無いはず)。表示内容はおそらくTopCoderと同じようになるようにレーティングの色2とその色の最大値と最小値を100%、0%にしたときにどの位置になるかを円で表しています。
canvasの円は上の3つの要素を組み合わせて描写しています。上の例は40%の場合の例で、まず左の円と真ん中の長方形の共通部分のみ描写します(source-in)。そうすると円の中身の部分だけ作れるので、それに右の円の輪郭を足し合わせるとTopCoderみたいな円が完成します。
取得部分
順位表にはユーザのレーティングは載っていないため、円を表示するにはそれを取得する必要があります。そのため、localstorageを確認して最新のデータが無かった場合に自前のサーバにレーティングのJSONを取得しに行っています。取得したJSONはlocalstorage3に取得時刻とともに記録し、無駄にデータを取ってこないようにしています(Chromeはサーバ側のキャッシュ用ヘッダを無視して取得しているように見える)。具体的には15分キャッシュします。
beta版を使用していない場合、コンテストごとにドメインが異なるのでlocalstorageにJSONがそれぞれ溜まってしまうという弊害はあります。
ユーザのコンテスト成績のページについてはレーティング値がページ内にあるのでそれを取得して表示しているだけでデータの取得・保存はしていません。
バックエンド部分
クライアント側でAtCoderのユーザページのJSONをたたくのも可能ですが、AtCoderとクライアント両方の負荷の負荷軽減のため自前のサーバでJSONを配布してます。
JSONは30分に一回AtCoderのランキングページをスクレイピングしてJSONを生成しています。ライブラリはjsdom
を利用してます。
手順は以下のとおり、
- ランキングページにアクセス
- ページャの右端からページ数を取得
- 各ページのテーブルの特定列からユーザとレーティングの関係を取得
- JSONにして保存
TODO
- beta版以外での無効化(JSONがかなり溜まるため)
- JSON取得・保存をサーバレス化する