-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscript.js
253 lines (210 loc) · 10 KB
/
script.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
// ==UserScript==
// @name GeoGuessr Retry Hotkey
// @namespace https://www.geoguessr.com/
// @version 1.4
// @description Quickly resets the game by navigating to the last visited map and starting a new game.
// @author Shukaaa (aduchi nom)
// @match https://www.geoguessr.com/*
// @grant GM_setValue
// @grant GM_getValue
// @grant window.focus
// @license MIT
// @downloadURL https://update.greasyfork.org/scripts/524965/GeoGuessr%20Retry%20Hotkey.user.js
// @updateURL https://update.greasyfork.org/scripts/524965/GeoGuessr%20Retry%20Hotkey.meta.js
// ==/UserScript==
(function () {
'use strict';
// Constants for script metadata, storage keys
const SCRIPT_NAME = "GeoGuessr Retry Hotkey";
const LAST_VISITED_MAP_KEY = "lastVisitedMap";
const PLAY_TRIGGERED_KEY = "playTriggered";
const RESET_KEY_STORAGE = "resetKey";
const DELAY_STORAGE = "rh-delay";
// Retry Hotkey
let RESET_KEY = localStorage.getItem(RESET_KEY_STORAGE) || "p";
let DELAY = localStorage.getItem(DELAY_STORAGE) || 50;
// Helper: Logging function for consistent console outputs
const log = (message, level = "log") => {
const levels = {
log: console.log,
warn: console.warn
};
const logFunction = levels[level] || console.log;
logFunction(`[${SCRIPT_NAME}] ${message}`);
};
// Helper: Save to GM storage
const saveToStorage = (key, value) => GM_setValue(key, value);
// Helper: Load from GM storage
const loadFromStorage = (key, defaultValue = null) => GM_getValue(key, defaultValue);
// Handle keydown for resetting the game
const handleKeyDown = (event) => {
const currentURL = window.location.href;
// Trigger reset
if (currentURL.includes("/game/") && event.key === RESET_KEY) {
const lastVisitedMap = loadFromStorage(LAST_VISITED_MAP_KEY);
if (lastVisitedMap) {
log(`'${RESET_KEY.toUpperCase()}' key pressed. Navigating to: ${lastVisitedMap}`);
saveToStorage(PLAY_TRIGGERED_KEY, true); // Set playTriggered to true
window.location.href = lastVisitedMap; // Redirect to the map
} else {
log("No last map URL found. Reset aborted.", "warn");
}
}
if (!currentURL.includes("/game/")) {
log("Reset aborted: Not on a game page.", "warn");
}
};
// Automatically click the play button on the map page
const attemptPlay = () => {
const currentURL = window.location.href;
const playTriggered = loadFromStorage(PLAY_TRIGGERED_KEY, false);
if (currentURL.includes("/maps/") && playTriggered) {
log("Map page detected with playTriggered=true. Attempting to start a new game...");
// Try finding the play button container
const playButtonContainer = document.querySelector("div[class*='map-selector_playButtons']");
if (playButtonContainer) {
const playButton = playButtonContainer.querySelector("button");
if (playButton) {
saveToStorage(PLAY_TRIGGERED_KEY, false);
playButton.focus();
setTimeout(() => {
playButton.click();
}, DELAY);
} else {
log("'Play' button not found inside container.", "warn");
}
} else {
log("Play button container not found.", "warn");
}
}
};
// Save the current map URL if on a map page
const saveCurrentMap = () => {
const currentURL = window.location.href;
if (currentURL.includes("/maps/")) {
log(`Saving current map URL: ${currentURL}`);
saveToStorage(LAST_VISITED_MAP_KEY, currentURL);
}
};
// Check for URL Changes
const observeUrlChanges = () => {
let lastUrl = window.location.href;
const observer = new MutationObserver(() => {
const currentUrl = window.location.href;
if (currentUrl !== lastUrl) {
log(`URL changed: ${currentUrl}`);
lastUrl = currentUrl;
// Save the map URL if it's a map page
saveCurrentMap();
}
});
observer.observe(document.body, { childList: true, subtree: true });
};
const addConfigurationsToMenuOverlay = () => {
const SETTINGS_INITIALIZED_ATTR = "data-retry-hotkey-settings-initialized";
// Utility functions for creating reusable components made by geoguessr
const cloneComponent = (selector, modifier = (clone) => clone) => {
const component = document.querySelector(selector);
if (!component) return null;
const clone = component.cloneNode(true);
return modifier(clone);
};
const createTitle = (title) =>
cloneComponent("div[class*='game-menu_headerContainer']", (clone) => {
clone.childNodes[0].innerHTML = title;
return clone;
});
const createDivider = () => cloneComponent("div[class*='game-menu_divider']");
const createOptionContainer = (optionName) =>
cloneComponent("div[class*='game-menu_volumeContainer']", (clone) => {
clone.removeChild(clone.lastChild);
clone.childNodes[0].innerHTML = optionName;
return clone;
});
const createButton = (text, onClick) => {
const button = document.createElement("button");
button.style.cursor = "pointer";
button.style.color = "#fff";
button.style.border = ".0625rem solid var(--ds-color-white-80)";
button.style.padding = "0.75rem 1.5rem";
button.style.borderRadius = "3.75rem";
button.style.marginTop = "1em";
button.innerHTML = text;
if (onClick) button.onclick = onClick;
return button;
};
const createBlockquote = (text) => {
const blockquote = document.createElement("blockquote");
blockquote.style.borderLeft = ".333rem solid #ccc";
blockquote.style.color = "#ccc";
blockquote.style.marginLeft = "0";
blockquote.style.paddingLeft = "0.5em";
blockquote.innerHTML = text
return blockquote
}
const initializeSettingsMenu = () => {
const settingsContainer = document.querySelector("div[class*='game-menu_settingsContainer']");
if (!settingsContainer || settingsContainer.hasAttribute(SETTINGS_INITIALIZED_ATTR)) return;
settingsContainer.appendChild(createDivider());
settingsContainer.appendChild(createTitle("Retry Hotkey Settings"));
const switchHotkeySetting = createOptionContainer("Hotkey");
const updateHotkeyButton = createButton("Set new hotkey (Current Hotkey: " + RESET_KEY.toUpperCase() + ")", () => {
updateHotkeyButton.innerHTML = "Press a new key to set as the hotkey";
updateHotkeyButton.style.color = "#ccc";
updateHotkeyButton.disabled = true;
const handleNewKey = (event) => {
RESET_KEY = event.key;
localStorage.setItem(RESET_KEY_STORAGE, RESET_KEY);
log(`New hotkey set: ${RESET_KEY}`);
alert(`New hotkey set to: ${RESET_KEY.toUpperCase()}`);
updateHotkeyButton.disabled = false;
updateHotkeyButton.style.color = "#fff";
updateHotkeyButton.innerHTML = "Set new hotkey (Current Hotkey: " + RESET_KEY.toUpperCase() + ")";
document.removeEventListener("keydown", handleNewKey);
};
document.addEventListener("keydown", handleNewKey);
});
switchHotkeySetting.appendChild(updateHotkeyButton);
const changeDelaySetting = createOptionContainer("Delay");
const changeDelayInfoText = createBlockquote("When dealing with bad internet connection or bugs that the match won't automatically start, it can be helpful to increase the delay")
const changeDelayButton = createButton("Change Delay (Current Delay: " + DELAY + "ms)", () => {
const newDelay = prompt("Enter new delay in ms")
if (isNaN(newDelay)) {
alert("Input is not a number")
return
}
DELAY = Number(newDelay)
localStorage.setItem(DELAY_STORAGE, DELAY);
log(`New delay set: ${DELAY}`);
alert(`New delay set to: ${DELAY}`);
changeDelayButton.innerHTML = "Change Delay (Current Delay: " + DELAY + "ms)"
});
changeDelaySetting.appendChild(changeDelayInfoText);
changeDelaySetting.appendChild(changeDelayButton);
settingsContainer.appendChild(switchHotkeySetting);
settingsContainer.appendChild(changeDelaySetting);
settingsContainer.setAttribute(SETTINGS_INITIALIZED_ATTR, true);
};
initializeSettingsMenu();
};
const observeSettingsView = () => {
const observer = new MutationObserver(() => {
const settingsView = document.querySelector("div[class*='game-menu_inGameMenuOverlay']");
if (settingsView) {
log("Settings view loaded.");
addConfigurationsToMenuOverlay()
}
});
observer.observe(document.body, { childList: true, subtree: true });
};
// Initialize script
const initialize = () => {
document.addEventListener("keydown", handleKeyDown); // Add keydown listener
attemptPlay(); // Check if play needs to be triggered
saveCurrentMap(); // Save the map URL if relevant
observeUrlChanges(); // Start observing DOM and URL changes
observeSettingsView(); // Start observing the menu overlay view to add own settings
};
// Run the script
initialize();
})();