CF-Predictor

This extension predicts rating changes for Codeforces. It shows approximate deltas during and after the contest.

  1. // ==UserScript==
  2. // @name CF-Predictor
  3. // @version 1.3.2
  4. // @description This extension predicts rating changes for Codeforces. It shows approximate deltas during and after the contest.
  5. // @author Originally by WslF, Edited by ZZYSonny
  6. // @license Apache
  7. // @match *://codeforces.com/contest/*/standings*
  8. // @match *://codeforc.es/contest/*/standings*
  9. // @match *://codeforces.ml/contest/*/standings*
  10. // @connect cf-predictor-frontend.herokuapp.com
  11. // @connect cf-predictor.herokuapp.com
  12. // @grant GM_xmlhttpRequest
  13. // @namespace https://greatest.deepsurf.us/users/169007
  14. // ==/UserScript==
  15.  
  16. (function() {
  17. 'use strict';
  18. var partyNum = 0;
  19. var results = [];
  20. showDeltas();
  21.  
  22. function modifyPartyHtml(index, elem) {
  23. var delta = '?';
  24. var rank = ' ';
  25. var seed = ' ';
  26.  
  27. if (partyNum > 0) {
  28. var handle = $(elem).find("td:eq(1)").find("a").last().html();
  29. if (handle) {
  30. //next 2 lines - fix for legendary grandmaster
  31. handle = handle.replace('<span class="legendary-user-first-letter">','');
  32. handle = handle.replace('</span>','');
  33. if (handle in results) {
  34. delta = results[handle].delta;
  35. rank = results[handle].rank;
  36. seed = results[handle].seed;
  37. }
  38. }
  39. }
  40.  
  41. var darkClass = "";
  42. if (partyNum % 2 == 1) {
  43. darkClass = "dark ";
  44. }
  45. var text;
  46. if (partyNum == 0) {
  47. text = "<th class='top right' style='width: 4em;'><span title='Rating change''>&Delta;</span></th>";
  48. } else {
  49. if (delta > 0) {
  50. text = "<td class='" + darkClass + "right'><span style='color:green;font-weight:bold;'>+" + delta + "</span></td>";
  51. } else {
  52. text = "<td class='" + darkClass + "right'><span style='color:gray;font-weight:bold;'>" + delta + "</span></td>";
  53. }
  54. }
  55.  
  56. partyNum++;
  57. $(elem).append(text);
  58. /*
  59. text = "<td class='" + darkClass + "right'><span style='color:green;'>" + rank + "</span></td>";
  60. $(elem).append(text);
  61. text = "<td class='" + darkClass + "right'><span style='color:green;'>" + seed + "</span></td>";
  62. $(elem).append(text);
  63. */
  64. }
  65.  
  66. function showDeltas() {
  67. var count = $(".standings").find("tr").length;
  68. if (count > 2) {
  69. var contestId = document.location.href.replace(/\D+/ig, ',').substr(1).split(',')[0];
  70. var contestants = document.getElementsByClassName("contestant-cell");
  71. var contestantsHandles = Array.from(contestants).map(x => x.innerText.trim());
  72.  
  73. getDeltas(contestId, contestantsHandles, function() {
  74. $(".standings").find("tr").first().find("th").last().removeClass("right");
  75. $(".standings").find("tr").find("td").removeClass("right");
  76. $(".standings").find("tr").each(modifyPartyHtml);
  77. if (count % 2 == 0) {
  78. $(".standings").find("tr").last().find("td").last().replaceWith("<td class='smaller bottom right dark'>&Delta;</td>");
  79. } else {
  80. $(".standings").find("tr").last().find("td").last().replaceWith("<td class='smaller bottom right'>&Delta;</td>");
  81. }
  82. });
  83. }
  84. }
  85.  
  86. function parseDeltas(data, callback) {
  87. for (var i = 0; i < data.result.length; i++) {
  88. var handle = data.result[i].handle;
  89. var delta = data.result[i].newRating - data.result[i].oldRating;
  90. var rank = data.result[i].rank;
  91. var seed = data.result[i].seed;
  92.  
  93. var res = {
  94. delta : parseInt(delta),
  95. seed : parseInt(seed),
  96. rank : parseInt(rank)
  97. };
  98.  
  99. results[handle] = res;
  100. }
  101.  
  102. callback();
  103. }
  104.  
  105. function getDeltas(contestId, contestantsHandles, callback) {
  106. // var localServer = "http://localhost:8080/"
  107. var herokuServerOld = "https://cf-predictor-frontend.herokuapp.com/";
  108. var pageOld = "GetNextRatingServlet?contestId=" + contestId;
  109. var serverOld = herokuServerOld + pageOld;
  110.  
  111. var herokuServerNew = "https://cf-predictor.herokuapp.com/";
  112. var pageNew = "GetPartialRatingChangesServlet?contestId=" + contestId + "&handles="+contestantsHandles.join(",");
  113. var serverNew = herokuServerNew + pageNew;
  114.  
  115. try{
  116. GM_xmlhttpRequest({
  117. method: "GET",
  118. url: serverOld,
  119. onload: function(res) {
  120. var text = res.responseText;
  121. var data = JSON.parse(text);
  122. parseDeltas(data, callback);
  123. }
  124. });
  125. }catch(err){
  126. console.log(err);
  127. }
  128.  
  129. }
  130. })();