CheatGuessr | WorldGuessr Cheat

Extremely customizable WorldGuessr cheating client. Click 3 to open the settings menu.

目前为 2025-03-17 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name CheatGuessr | WorldGuessr Cheat
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.5
  5. // @description Extremely customizable WorldGuessr cheating client. Click 3 to open the settings menu.
  6. // @author CheatGuessr
  7. // @match https://www.worldguessr.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=worldguessr.com
  9. // @grant none
  10. // @license GNU AGPLv3
  11. // ==/UserScript==
  12. (function() {
  13. 'use strict';
  14.  
  15. if (window.location.pathname === '/banned') {
  16. const handleBannedPage = () => {
  17. const backdrop = document.createElement('div');
  18. backdrop.style.position = 'fixed';
  19. backdrop.style.top = '0';
  20. backdrop.style.left = '0';
  21. backdrop.style.right = '0';
  22. backdrop.style.bottom = '0';
  23. backdrop.style.backgroundColor = 'rgba(0,0,0,0.5)';
  24. backdrop.style.zIndex = '10000';
  25. const modal = document.createElement('div');
  26. modal.style.position = 'fixed';
  27. modal.style.top = '50%';
  28. modal.style.left = '50%';
  29. modal.style.transform = 'translate(-50%, -50%)';
  30. modal.style.backgroundColor = '#1f2937';
  31. modal.style.padding = '20px';
  32. modal.style.borderRadius = '8px';
  33. modal.style.color = 'white';
  34. modal.style.zIndex = '10001';
  35. const message = document.createElement('p');
  36. message.textContent = 'The Cheat has been detected!\nPlease Enter 10-20 random characters to bypass the anti-cheat.\n\nExample (do not use the example):\ndf89aj3n4r98nd9';
  37. message.style.margin = '0 0 15px 0';
  38. const input = document.createElement('input');
  39. input.type = 'text';
  40. input.style.width = '100%';
  41. input.style.marginBottom = '15px';
  42. input.style.padding = '8px';
  43. input.style.borderRadius = '4px';
  44. input.style.border = '1px solid #4b5563';
  45. input.style.backgroundColor = '#374151';
  46. input.style.color = 'white';
  47. const submitButton = document.createElement('button');
  48. submitButton.textContent = 'Submit';
  49. submitButton.style.padding = '8px 16px';
  50. submitButton.style.backgroundColor = '#3b82f6';
  51. submitButton.style.color = 'white';
  52. submitButton.style.border = 'none';
  53. submitButton.style.borderRadius = '4px';
  54. submitButton.style.cursor = 'pointer';
  55. submitButton.onmouseenter = () => submitButton.style.backgroundColor = '#2563eb';
  56. submitButton.onmouseleave = () => submitButton.style.backgroundColor = '#3b82f6';
  57. submitButton.onclick = () => {
  58. const chars = input.value.trim();
  59. if (chars) {
  60. if (chars === 'df89aj3n4r98nd9') {
  61. alert('You cannot use the example!');
  62. return;
  63. }
  64.  
  65. localStorage.setItem('mapDivClass', chars);
  66. const history = JSON.parse(localStorage.getItem('mapDivClassHistory') || '[]');
  67. history.push(chars);
  68. localStorage.setItem('mapDivClassHistory', JSON.stringify(history));
  69. window.location.href = 'https://www.worldguessr.com/';
  70. }
  71. };
  72. modal.appendChild(message);
  73. modal.appendChild(input);
  74. modal.appendChild(submitButton);
  75. document.body.appendChild(backdrop);
  76. document.body.appendChild(modal);
  77. };
  78. handleBannedPage();
  79. return;
  80. }
  81. let googleMapsIframe = null;
  82. let lastLocation = null;
  83. let loadingIndicator = null;
  84. let dotInterval = null;
  85. let settings = null;
  86. let settingsModal = null;
  87. let mapDivClass = localStorage.getItem('mapDivClass') || 'map-div';
  88. const DEFAULT_SETTINGS = {
  89. keybinds: {
  90. toggleMap: '1',
  91. newTab: '2',
  92. settings: '3',
  93. detailedLocation: '4'
  94. },
  95. mapPosition: 'top-left',
  96. mapSize: {
  97. width: 400,
  98. height: 300
  99. },
  100. loadingPosition: 'bottom',
  101. refreshInterval: 1000,
  102. blockAds: true
  103. };
  104. const style = document.createElement('style');
  105. style.textContent = `
  106. .${mapDivClass} {
  107. position: fixed;
  108. z-index: 9999;
  109. border: 2px solid #333;
  110. border-radius: 4px;
  111. }
  112. .close-button {
  113. position: absolute;
  114. top: -15px;
  115. right: -15px;
  116. width: 30px;
  117. height: 30px;
  118. background: red;
  119. border: 2px solid white;
  120. border-radius: 50%;
  121. color: white;
  122. font-weight: bold;
  123. cursor: pointer;
  124. display: flex;
  125. align-items: center;
  126. justify-content: center;
  127. z-index: 10000;
  128. }
  129. .loading-indicator {
  130. position: fixed;
  131. left: 10px;
  132. padding: 5px 10px;
  133. background: rgba(0,0,0,0.7);
  134. color: white;
  135. border-radius: 4px;
  136. z-index: 9999;
  137. }
  138. .settings-modal {
  139. position: fixed;
  140. top: 50%;
  141. left: 50%;
  142. transform: translate(-50%, -50%);
  143. background: #1f2937;
  144. padding: 20px;
  145. border-radius: 8px;
  146. z-index: 10001;
  147. width: 600px;
  148. max-height: 80vh;
  149. overflow-y: auto;
  150. color: white;
  151. }
  152. .settings-backdrop {
  153. position: fixed;
  154. top: 0;
  155. left: 0;
  156. right: 0;
  157. bottom: 0;
  158. background: rgba(0,0,0,0.5);
  159. z-index: 10000;
  160. }
  161. .settings-grid {
  162. display: grid;
  163. grid-template-columns: 1fr 1fr;
  164. gap: 20px;
  165. }
  166. .settings-section {
  167. background: #374151;
  168. padding: 15px;
  169. border-radius: 6px;
  170. }
  171. .settings-row {
  172. margin: 10px 0;
  173. }
  174. .settings-row label {
  175. display: block;
  176. margin-bottom: 5px;
  177. color: #e5e7eb;
  178. }
  179. .settings-input {
  180. width: 100%;
  181. padding: 8px;
  182. border: 1px solid #4b5563;
  183. border-radius: 4px;
  184. background: #1f2937;
  185. color: white;
  186. }
  187. .settings-button {
  188. padding: 8px 16px;
  189. border: none;
  190. border-radius: 4px;
  191. cursor: pointer;
  192. margin: 5px;
  193. background: #3b82f6;
  194. color: white;
  195. }
  196. .settings-button:hover {
  197. background: #2563eb;
  198. }
  199. `;
  200. document.head.appendChild(style);
  201. function loadSettings() {
  202. try {
  203. const saved = localStorage.getItem('worldGuessrHelper');
  204. settings = saved ? JSON.parse(saved) : DEFAULT_SETTINGS;
  205. } catch (e) {
  206. settings = DEFAULT_SETTINGS;
  207. }
  208. }
  209. function saveSettings() {
  210. localStorage.setItem('worldGuessrHelper', JSON.stringify(settings));
  211. }
  212. function blockAds() {
  213. if (!settings.blockAds) return;
  214. const adSelectors = [
  215. '[id^="google_ads_iframe"]',
  216. '[id^="worldguessr-com_"]',
  217. '.video-ad'
  218. ];
  219. const removeAds = () => {
  220. adSelectors.forEach(selector => {
  221. document.querySelectorAll(selector).forEach(ad => {
  222. ad.remove();
  223. });
  224. });
  225. };
  226. removeAds();
  227. const observer = new MutationObserver(removeAds);
  228. observer.observe(document.body, {
  229. childList: true,
  230. subtree: true
  231. });
  232. }
  233. function createLoadingIndicator() {
  234. loadingIndicator = document.createElement('div');
  235. loadingIndicator.className = 'loading-indicator';
  236. loadingIndicator.style.display = 'none';
  237. document.body.appendChild(loadingIndicator);
  238. let dots = 0;
  239. if (dotInterval) clearInterval(dotInterval);
  240. dotInterval = setInterval(() => {
  241. dots = (dots + 1) % 4;
  242. if (loadingIndicator) {
  243. loadingIndicator.textContent = 'Loading location' + '.'.repeat(dots);
  244. }
  245. }, 500);
  246. }
  247. function toggleSettingsModal() {
  248. if (settingsModal) {
  249. settingsModal.backdrop.remove();
  250. settingsModal.modal.remove();
  251. settingsModal = null;
  252. return;
  253. }
  254. const backdrop = document.createElement('div');
  255. backdrop.className = 'settings-backdrop';
  256. const modal = document.createElement('div');
  257. modal.className = 'settings-modal';
  258. modal.innerHTML = `
  259. <h2 style="margin-bottom: 20px">WorldGuessr Helper Settings</h2>
  260. <div class="settings-grid">
  261. <div class="settings-section">
  262. <h3>Keybinds</h3>
  263. <div class="settings-row">
  264. <label>Toggle Map Key</label>
  265. <input type="text" class="settings-input" id="toggleMapKey" value="${settings.keybinds.toggleMap}">
  266. </div>
  267. <div class="settings-row">
  268. <label>New Tab Key</label>
  269. <input type="text" class="settings-input" id="newTabKey" value="${settings.keybinds.newTab}">
  270. </div>
  271. <div class="settings-row">
  272. <label>Settings Key</label>
  273. <input type="text" class="settings-input" id="settingsKey" value="${settings.keybinds.settings}">
  274. </div>
  275. <div class="settings-row">
  276. <label>Detailed Location Alert</label>
  277. <input type="text" class="settings-input" id="detailedLocation" value="${settings.keybinds.detailedLocation}">
  278. </div>
  279. </div>
  280. <div class="settings-section">
  281. <h3>Map Settings</h3>
  282. <div class="settings-row">
  283. <label>Map Position</label>
  284. <select class="settings-input" id="mapPosition">
  285. <option value="top-left" ${settings.mapPosition === 'top-left' ? 'selected' : ''}>Top Left</option>
  286. <option value="top-right" ${settings.mapPosition === 'top-right' ? 'selected' : ''}>Top Right</option>
  287. <option value="bottom-left" ${settings.mapPosition === 'bottom-left' ? 'selected' : ''}>Bottom Left</option>
  288. <option value="bottom-right" ${settings.mapPosition === 'bottom-right' ? 'selected' : ''}>Bottom Right</option>
  289. </select>
  290. </div>
  291. <div class="settings-row">
  292. <label>Map Width (px)</label>
  293. <input type="number" class="settings-input" id="mapWidth" value="${settings.mapSize.width}">
  294. </div>
  295. <div class="settings-row">
  296. <label>Map Height (px)</label>
  297. <input type="number" class="settings-input" id="mapHeight" value="${settings.mapSize.height}">
  298. </div>
  299. </div>
  300. </div>
  301. <div class="settings-section" style="margin-top: 20px">
  302. <h3>Additional Settings</h3>
  303. <div class="settings-row">
  304. <label>
  305. <input type="checkbox" id="blockAds" ${settings.blockAds ? 'checked' : ''}>
  306. Block Advertisements
  307. </label>
  308. </div>
  309. </div>
  310. <div style="text-align: right; margin-top: 20px">
  311. <button class="settings-button" id="closeSettings">Cancel</button>
  312. <button class="settings-button" id="saveSettings">Save</button>
  313. </div>
  314. `;
  315. document.body.appendChild(backdrop);
  316. document.body.appendChild(modal);
  317. settingsModal = { backdrop, modal };
  318. document.getElementById('saveSettings').onclick = () => {
  319. settings.keybinds.toggleMap = document.getElementById('toggleMapKey').value;
  320. settings.keybinds.newTab = document.getElementById('newTabKey').value;
  321. settings.keybinds.settings = document.getElementById('settingsKey').value;
  322. settings.keybinds.detailedLocation = document.getElementById('detailedLocation').value;
  323. settings.mapPosition = document.getElementById('mapPosition').value;
  324. settings.mapSize.width = parseInt(document.getElementById('mapWidth').value);
  325. settings.mapSize.height = parseInt(document.getElementById('mapHeight').value);
  326. settings.blockAds = document.getElementById('blockAds').checked;
  327. saveSettings();
  328. blockAds();
  329. toggleSettingsModal();
  330. };
  331. document.getElementById('closeSettings').onclick = toggleSettingsModal;
  332. }
  333. function showLoadingIndicator() {
  334. if (loadingIndicator) {
  335. loadingIndicator.style.display = 'block';
  336. loadingIndicator.style.bottom = settings.loadingPosition === 'bottom' ? '10px' : 'auto';
  337. loadingIndicator.style.top = settings.loadingPosition === 'top' ? '10px' : 'auto';
  338. }
  339. }
  340. function hideLoadingIndicator() {
  341. if (loadingIndicator) {
  342. loadingIndicator.style.display = 'none';
  343. }
  344. }
  345. function extractLocationFromIframe() {
  346. showLoadingIndicator();
  347. const iframe = document.querySelector('iframe[src^="/svEmbed"]');
  348. if (!iframe) {
  349. hideLoadingIndicator();
  350. return null;
  351. }
  352. const urlParams = new URLSearchParams(iframe.src.split('?')[1]);
  353. const lat = parseFloat(urlParams.get('lat'));
  354. const long = parseFloat(urlParams.get('long'));
  355. if (!isNaN(lat) && !isNaN(long)) {
  356. hideLoadingIndicator();
  357. return { lat, long, timestamp: new Date() };
  358. }
  359. hideLoadingIndicator();
  360. return null;
  361. }
  362. function updateMapPosition() {
  363. if (!googleMapsIframe) return;
  364. const pos = settings.mapPosition.split('-');
  365. googleMapsIframe.style.top = pos[0] === 'top' ? '10px' : 'auto';
  366. googleMapsIframe.style.bottom = pos[0] === 'bottom' ? '10px' : 'auto';
  367. googleMapsIframe.style.left = pos[1] === 'left' ? '10px' : 'auto';
  368. googleMapsIframe.style.right = pos[1] === 'right' ? '10px' : 'auto';
  369. googleMapsIframe.style.width = settings.mapSize.width + 'px';
  370. googleMapsIframe.style.height = settings.mapSize.height + 'px';
  371. }
  372. function toggleGoogleMapsIframe(location) {
  373. if (!location) return;
  374. if (googleMapsIframe) {
  375. googleMapsIframe.remove();
  376. googleMapsIframe = null;
  377. return;
  378. }
  379. try {
  380. const container = document.createElement('div');
  381. container.className = mapDivClass;
  382. const closeBtn = document.createElement('button');
  383. closeBtn.className = 'close-button';
  384. closeBtn.textContent = '×';
  385. closeBtn.onclick = () => {
  386. container.remove();
  387. googleMapsIframe = null;
  388. };
  389. const iframe = document.createElement('iframe');
  390. iframe.width = '100%';
  391. iframe.height = '100%';
  392. iframe.style.border = 'none';
  393. iframe.src = "https://www.google.com/maps?q=" + location.lat + "," + location.long + "&z=18&output=embed";
  394. container.appendChild(closeBtn);
  395. container.appendChild(iframe);
  396. document.body.appendChild(container);
  397. googleMapsIframe = container;
  398. updateMapPosition();
  399. } catch (error) {
  400. console.error('Error creating iframe:', error);
  401. }
  402. }
  403. async function fetchLocationDetails(lat, long) {
  404. try {
  405. const response = await fetch(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${long}`);
  406. if (!response.ok) {
  407. throw new Error('Failed to fetch location details');
  408. }
  409. const data = await response.json();
  410. const { address } = data;
  411. const locationDetails = `
  412. Area: ${address.neighbourhood || address.suburb || address.hamlet || 'N/A'}
  413. City: ${address.city || address.town || address.village || 'N/A'}
  414. State: ${address.state || 'N/A'}
  415. Country: ${address.country || 'N/A'}
  416. `;
  417. alert(locationDetails);
  418. } catch (error) {
  419. alert('Could not fetch location details: ' + error.message);
  420. }
  421. }
  422. window.addEventListener('keydown', function(event) {
  423. event.stopPropagation();
  424. const location = extractLocationFromIframe();
  425. if (!location) return;
  426. if (lastLocation && (lastLocation.lat !== location.lat || lastLocation.long !== location.long)) {
  427. if (googleMapsIframe) {
  428. toggleGoogleMapsIframe(location);
  429. toggleGoogleMapsIframe(location);
  430. }
  431. }
  432. lastLocation = location;
  433. if (event.key === settings.keybinds.toggleMap) {
  434. toggleGoogleMapsIframe(location);
  435. } else if (event.key === settings.keybinds.newTab) {
  436. window.open("https://www.google.com/maps?q=" + location.lat + "," + location.long, "_blank");
  437. } else if (event.key === settings.keybinds.settings) {
  438. if (googleMapsIframe) {
  439. toggleGoogleMapsIframe(location);
  440. }
  441. toggleSettingsModal();
  442. } else if (event.key === settings.keybinds.detailedLocation) {
  443. const { lat, long } = location;
  444. if (!lat || !long) {
  445. alert('Coordinates not yet available!');
  446. } else {
  447. fetchLocationDetails(lat, long);
  448. }
  449. }
  450. }, true);
  451. loadSettings();
  452. createLoadingIndicator();
  453. blockAds();
  454. setInterval(() => {
  455. const location = extractLocationFromIframe();
  456. if (!location || !lastLocation) return;
  457. if (lastLocation.lat !== location.lat || lastLocation.long !== location.long) {
  458. if (googleMapsIframe) {
  459. toggleGoogleMapsIframe(location);
  460. toggleGoogleMapsIframe(location);
  461. }
  462. lastLocation = location;
  463. }
  464. }, settings.refreshInterval);
  465. const observer = new MutationObserver(() => {
  466. if (!document.querySelector('iframe[src^="/svEmbed"]') && googleMapsIframe) {
  467. googleMapsIframe.remove();
  468. googleMapsIframe = null;
  469. }
  470. });
  471. observer.observe(document.body, { childList: true, subtree: true });
  472. })();