Chess Compass Analysis for Chess.com

This plugin adds buttons next to the chess board allowing for a quick post-game analysis of the current game on screen

当前为 2020-12-27 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Chess Compass Analysis for Chess.com
  3. // @match https://www.chess.com/*
  4. // @run-at document-end
  5. // @grant none
  6. // @version 1.2
  7. // @author AndyVuj24
  8. // @description This plugin adds buttons next to the chess board allowing for a quick post-game analysis of the current game on screen
  9. // @supportURL https://github.com/andyvuj24/Chess-Compass-Analysis-for-Chess.com/issues
  10. // @homepageURL https://github.com/andyvuj24/Chess-Compass-Analysis-for-Chess.com
  11. // @namespace https://greasyfork.org/users/708710
  12. // ==/UserScript==
  13.  
  14. var counter = 0;
  15.  
  16. const $ = document.querySelector.bind(document);
  17. const $$ = document.querySelectorAll.bind(document);
  18.  
  19. const log = (message) => {
  20. console.log(`[Chess.com Plugin Log]: ${message}`);
  21. };
  22.  
  23. const addStyling = async () => {
  24. // button styling
  25. log("Adding styling to page for plugin buttons");
  26. const styleElement = document.createElement("style");
  27. styleElement.innerHTML = `.gf-chess-compass-button-container{margin:auto;display:flex;align-items:center;justify-content:center;border-radius:3px;color:#fff;font-size:16px}.gf-chess-compass-button-container>a{width:100%}.gf-chess-compass-button{background-color:#489e5d;width:100%;margin:auto;height:40px;display:flex;align-items:center;justify-content:center;border-radius:3px 3px 0 0;color:#fff;cursor:pointer;font-size:16px;font-weight:500;}.gf-chess-compass-button:hover{background-color:#57b26e}`;
  28. $("head")?.appendChild(styleElement);
  29. };
  30.  
  31. const addButtons = async (element) => {
  32. // for button element
  33. log("Adding buttons to sidebar");
  34. $(element)?.insertAdjacentHTML(
  35. "beforebegin",
  36. '<div><div id="btnPGN" class="gf-chess-compass-button-container"><button class="gf-chess-compass-button">Analyze PGN with Chess Compass</button></div></div>'
  37. );
  38. $(element)?.insertAdjacentHTML(
  39. "beforebegin",
  40. '<div><div id="btnFEN" class="gf-chess-compass-button-container"><button class="gf-chess-compass-button">Analyze FEN with Chess Compass</button></div></div>'
  41. );
  42. };
  43.  
  44. const setupButton = async (id) => {
  45. log(`Configuring button -> ${id}`);
  46. const btn = $(id);
  47. if (id.indexOf("PGN") !== -1) {
  48. btn.addEventListener("click", function () {
  49. const data =
  50. ($("chess-board")
  51. ?.game.getPGN?.()
  52. .replace(/\[[^\]]*\]|\{[^\}]*\}/g, "") ||
  53. [
  54. ...$$(
  55. "div.vertical-move-list-component span.vertical-move-list-column:not(.move-timestamps-component)"
  56. ),
  57. ]
  58. .map(({ innerText }) => innerText)
  59. .join(" ")
  60. .replace(/\[[^\]]*\]|\{[^\}]*\}/g, "")) ??
  61. null;
  62. if (!data) {
  63. log("Unable to find data for PGN");
  64. return;
  65. }
  66.  
  67. log("PGN: " + data);
  68. fetch("https://www.chesscompass.com/api/get_game_id", {
  69. method: "post",
  70. body: JSON.stringify({
  71. gameData: data,
  72. }),
  73. })
  74. .then((response) => {
  75. return response.json();
  76. })
  77. .then(({ gameId }) => {
  78. window.open(
  79. "https://www.chesscompass.com/analyze/" + gameId,
  80. "_blank"
  81. );
  82. });
  83. });
  84. }
  85.  
  86. if (id.indexOf("FEN") !== -1) {
  87. btn.addEventListener("click", function () {
  88. const data =
  89. ($("chess-board")?.game.getFEN?.() ||
  90. $("div.v-board")?.getChessboardInstance?.().state.selectedNode.fen) ??
  91. null;
  92. if (!data) {
  93. log("Unable to find data for FEN");
  94. return;
  95. }
  96. log("FEN: " + data);
  97. fetch("https://www.chesscompass.com/api/get_game_id", {
  98. method: "post",
  99. body: JSON.stringify({
  100. gameData: data,
  101. }),
  102. })
  103. .then((response) => {
  104. return response.json();
  105. })
  106. .then(({ gameId }) => {
  107. window.open(
  108. "https://www.chesscompass.com/analyze/" + gameId,
  109. "_blank"
  110. );
  111. });
  112. });
  113. }
  114. };
  115.  
  116. const waitForContainer = async () => {
  117. const existCondition = setInterval(function () {
  118. [
  119. ".sidebar-component",
  120. ".sidebar-v5-component",
  121. "vertical-move-list",
  122. ].forEach((element) => {
  123. if ($(element)) {
  124. clearInterval(existCondition);
  125. main(element);
  126. return;
  127. }
  128. if (counter > 600) {
  129. log("No sidebars found for us to use...");
  130. clearInterval(existCondition);
  131. }
  132. });
  133. counter++;
  134. }, 100); // check every 100ms
  135. };
  136.  
  137. const clearAds = async () => {
  138. log("Clearing ads...");
  139. const adsToRemove = [
  140. "#tall-sidebar-ad",
  141. "#adblocker-check",
  142. "#board-layout-ad",
  143. ];
  144. adsToRemove.forEach((selector) => {
  145. $$(selector).forEach((ele) => {
  146. ele.remove();
  147. });
  148. });
  149. log("Ads cleared!");
  150. };
  151.  
  152. async function main(element) {
  153. await addStyling();
  154. await addButtons(element);
  155. await setupButton("#btnPGN");
  156. await setupButton("#btnFEN");
  157. await clearAds();
  158. }
  159.  
  160. if (
  161. document.readyState === "complete" ||
  162. (document.readyState !== "loading" && !document.documentElement.doScroll)
  163. ) {
  164. waitForContainer();
  165. } else {
  166. document.addEventListener("DOMContentLoaded", waitForContainer);
  167. }