atcoder-virtual-remaining-time-display

バーチャルコンテストの残り時間を表示します。

  1. // ==UserScript==
  2. // @name atcoder-virtual-remaining-time-display
  3. // @namespace https://github.com/ilplrr
  4. // @version 1.0
  5. // @description バーチャルコンテストの残り時間を表示します。
  6. // @author ilplrr
  7. // @license MIT
  8. // @match https://atcoder.jp/contests/*
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. if (getServerTime() < endTime) return;
  16.  
  17. const createTimer = (data) => {
  18. if (!data.isVirtual) return;
  19. if (!(data.virtualStartTime && data.virtualEndTime)) return;
  20.  
  21. const timer = document.createElement('div');
  22. timer.id = 'virtual-timer';
  23. timer.style = `
  24. position: fixed;
  25. right: 170px;
  26. bottom: 0px;
  27. width: 160px;
  28. height: 80px;
  29. margin: 0;
  30. padding: 20px 0;
  31. background-image: url("//img.atcoder.jp/assets/contest/digitalclock.png");
  32. text-align: center;
  33. line-height: 20px;
  34. font-size: 15px;
  35. cursor: pointer;
  36. z-index: 50;
  37. `;
  38. document.body.appendChild(timer);
  39.  
  40. let intervalId = null;
  41. const update = () => {
  42. const serverTime = getServerTime();
  43. let s = '';
  44. if (serverTime.isAfter(data.virtualEndTime)) {
  45. s += 'バーチャル参加終了<br>'
  46. s += `<span style="color: #c00;">残り:${durationFormat(0)}</span>`;
  47. if (intervalId) {
  48. clearInterval(intervalId);
  49. intervalId = null;
  50. }
  51. } else if (serverTime.isAfter(data.virtualStartTime)) {
  52. s += 'バーチャル参加中<br>'
  53. s += `残り:${durationFormat(data.virtualEndTime.diff(serverTime))}`;
  54. } else {
  55. s += 'バーチャル参加まで<br>'
  56. s += `残り:${durationFormat(data.virtualStartTime.diff(serverTime))}`;
  57. }
  58. timer.innerHTML = s;
  59. };
  60. intervalId = setInterval(update, 100);
  61. };
  62.  
  63. const virtualStandingURL = `${location.origin}/contests/${contestScreenName}/standings/virtual`;
  64. fetch(virtualStandingURL).then((response) => {
  65. return response.text();
  66. }).then((text) => {
  67. const doc = new DOMParser().parseFromString(text, 'text/html');
  68. const data = {};
  69. doc.querySelectorAll('script').forEach((e) => {
  70. const s = e.innerHTML;
  71. const m = s.match(/(isVirtual|virtual(Start|End)Time)\s*=\s*[^\n]*/g);
  72. if (m) {
  73. m.forEach((s) => eval('data.' + s));
  74. }
  75. });
  76. createTimer(data);
  77. });
  78. })();