Geoguessr Team Duels Advanced Options

Adds extra options to team duel settings.

当前为 2023-03-08 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Geoguessr Team Duels Advanced Options
  3. // @description Adds extra options to team duel settings.
  4. // @version 0.2
  5. // @author macca#8949
  6. // @license MIT
  7. // @match https://www.geoguessr.com/*
  8. // @run-at document-start
  9. // @grant none
  10. // @namespace https://greasyfork.org/en/scripts/452579-geoguessr-team-duels-advanced-options
  11. // ==/UserScript==
  12.  
  13. let cachedGameMode = '';
  14. let cachedGameOptions = {};
  15.  
  16. const getGameId = () => {
  17. const scripts = document.getElementsByTagName('script');
  18. for (const script of scripts) {
  19. if (script.src.includes('_buildManifest.js')) {
  20. return script.src.split('/')[5];
  21. }
  22. }
  23. }
  24.  
  25. const gameMode = () => {
  26. const fullText = document.querySelector('.bars_root___G89E').textContent;
  27. return fullText.substring(0, fullText.lastIndexOf(' ')).toLowerCase();
  28. }
  29.  
  30. async function fetchWithCors(url, method, body) {
  31. return await fetch(url, {
  32. "headers": {
  33. "accept": "*/*",
  34. "accept-language": "en-US,en;q=0.8",
  35. "content-type": "application/json",
  36. "sec-fetch-dest": "empty",
  37. "sec-fetch-mode": "cors",
  38. "sec-fetch-site": "same-site",
  39. "sec-gpc": "1",
  40. "x-client": "web"
  41. },
  42. "referrer": "https://www.geoguessr.com/",
  43. "referrerPolicy": "strict-origin-when-cross-origin",
  44. "body": JSON.stringify(body),
  45. "method": method,
  46. "mode": "cors",
  47. "credentials": "same-origin"
  48. })
  49. }
  50.  
  51. window.modifySetting = (e, settingName) => {
  52. let newValue = e.value;
  53. if (settingName === 'multiplierIncrement') {
  54. newValue *= 10;
  55. newValue = Math.round(newValue);
  56. } else {
  57. newValue *= 1; // string to number conversion
  58. newValue = Math.round(newValue);
  59. }
  60.  
  61. // Fetch the game options
  62. fetchWithCors(`https://www.geoguessr.com/_next/data/${getGameId()}/en/party.json`, "GET")
  63. .then((response) => response.json())
  64. .then((data) => {
  65. let gameOptions = data.pageProps.party.gameSettings;
  66. gameOptions[settingName] = newValue;
  67. // Push the updated options
  68. fetchWithCors(`https://www.geoguessr.com/api/v4/parties/v2/game-settings`, "PUT", gameOptions);
  69. });
  70.  
  71. cachedGameMode = gameMode();
  72. cachedGameOptions[settingName] = e.value;
  73. }
  74.  
  75. let optionTextInputInnerHTML = (id, settingName, text, icon) =>
  76. `<div class="game-options_option__Dt26y"><div class="game-options_labelAndIcon__2fzCM"><div class="game-options_optionIcon__ZaJ8L"><img class="rule-icons_icon__dcLov" src="${icon}" alt="" width="48" height="48"></div><div class="game-options_optionLabel__APwH6">${text}</div></div><div><input type="text" id="${id}" onblur="modifySetting(this, '${settingName}')" style="text-align: center; background: rgba(255,255,255,0.1); color: white; border: none; border-radius: 5px; width: 60px;"></div></div>`;
  77.  
  78. function makeCustomTextInput(elt, id, settingName, text, icon) {
  79. elt.outerHTML = optionTextInputInnerHTML(id, settingName, text, icon);
  80. return elt;
  81. }
  82.  
  83. function updateValue(inputId, option, gameOptions) {
  84. if (document.querySelector(inputId)) {
  85. if (gameMode() == cachedGameMode && option in cachedGameOptions) {
  86. document.querySelector(inputId).value = cachedGameOptions[option];
  87. } else {
  88. if (option == 'multiplierIncrement') {
  89. document.querySelector(inputId).value = gameOptions[option] / 10;
  90. } else {
  91. document.querySelector(inputId).value = gameOptions[option];
  92. }
  93. }
  94. }
  95. }
  96.  
  97. let observer = new MutationObserver((mutations) => {
  98. if (window.location.href.includes('party') && (document.querySelector('.game-options_slider__AnQku') || document.querySelector('.game-options_roundButton__L0Tz5'))) {
  99. if (!gameMode().includes('battle royale')) {
  100. if (document.querySelector('.game-options_lives__S1iOt')) {
  101. let healthBox = document.querySelector('.game-options_lives__S1iOt').parentElement;
  102. makeCustomTextInput(healthBox, 'health-input', 'initialHealth', 'Health', '/_next/static/images/heart-eb251481d4679b6ee73413eff64d7eed.png');
  103. }
  104. if (document.querySelector('.game-options_lives__S1iOt')) {
  105. let multiplierIncrementBox = document.querySelector('.game-options_lives__S1iOt').parentElement;
  106. makeCustomTextInput(multiplierIncrementBox, 'increment-input', 'multiplierIncrement', 'Multiplier Increment', '/_next/static/images/multipliers-icon-94c4120e112cfbe8b287083d4e626842.svg');
  107. }
  108. }
  109.  
  110. if (document.querySelector('.game-options_roundTime__vWMWr') && gameMode() != 'bullseye') {
  111. let roundTimeBox = document.querySelector('.game-options_roundTime__vWMWr').parentElement;
  112. if (gameMode() == 'city streaks') {
  113. makeCustomTextInput(roundTimeBox, 'time-input', 'duration', 'Time', '/_next/static/images/time-limit-2f49a01869aca3e939cbaea0fccd590a.png');
  114. } else {
  115. makeCustomTextInput(roundTimeBox, 'time-input', 'roundTime', 'Time', '/_next/static/images/time-limit-2f49a01869aca3e939cbaea0fccd590a.png');
  116. }
  117. }
  118.  
  119. fetchWithCors(`https://www.geoguessr.com/_next/data/${getGameId()}/en/party.json`, "GET")
  120. .then((response) => response.json())
  121. .then((data) => {
  122. let gameOptions = data.pageProps.party.gameSettings;
  123.  
  124. updateValue('#health-input', 'initialHealth', gameOptions);
  125. updateValue('#increment-input', 'multiplierIncrement', gameOptions);
  126.  
  127. if (gameMode() != 'bullseye') {
  128. if (gameMode() == 'city streaks') {
  129. updateValue('#time-input', 'duration', gameOptions);
  130. } else {
  131. updateValue('#time-input', 'roundTime', gameOptions);
  132. }
  133. }
  134. });
  135. }
  136. });
  137.  
  138.  
  139. observer.observe(document.body, {
  140. characterDataOldValue: false,
  141. subtree: true,
  142. childList: true,
  143. characterData: false
  144. });
  145.  
  146. document.addEventListener('keydown', (event) => {
  147. if (event.key == 'Escape' && document.querySelector('.party-modal_heading__UqkX6')) {
  148. document.activeElement.blur();
  149. }
  150. });