Geoguessrtips

A specific map is required to prompt. Press 1 to prompt for knowledge in plonkit, such as: plonkit novice guide, etc., or a question bank with tips keywords can be used.

  1. // ==UserScript==
  2. // @name Geoguessrtips
  3. // @namespace https://www.leonbrandt.com
  4. // @version 3.1
  5. // @description A specific map is required to prompt. Press 1 to prompt for knowledge in plonkit, such as: plonkit novice guide, etc., or a question bank with tips keywords can be used.
  6. // @author Leon Brandt
  7. // @homepage https://www.leonbrandt.com
  8. // @match https://www.geoguessr.com/*
  9. // @grant GM_xmlhttpRequest
  10. // @run-at document-idle
  11. // @connect nominatim.openstreetmap.org
  12. // @connect knowledgetips.fun
  13. // @connect cdn.nlark.com
  14. // ==/UserScript==
  15. (function() {
  16. 'use strict';
  17. let isMatch = true;
  18. const modalHTML = `
  19. <div id="customModal" style="
  20. cursor: move; /* 设置鼠标为可移动状态 */
  21. display: none; /* 初始设置为不显示,更改为block显示模态窗口 */
  22. position: fixed; /* 固定位置 */
  23. z-index: 1000; /* 设置堆叠顺序 */
  24. top: 10vh; /* 距离顶部10%的视口高度 */
  25. left: 10vw; /* 距离左侧10%的视口宽度 */
  26. background-color: #eee; /* 背景颜色 */
  27. padding: 5px; /* 内边距 */
  28. border-radius: 10px; /* 边框圆角 */
  29. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 盒子阴影 */
  30. width: 80vw; /* 宽度(这里可能是个错误,180vw可能过大) */
  31. max-width: 350px; /* 最大宽度 */
  32. transform: translate(0, 0); /* 移动转换(之前的负值已移除) */
  33. text-align: left; /* 文本对齐方式 */
  34. opacity: 0; /* 初始设置为透明,更改为1显示 */
  35. visibility: hidden; /* 初始设置为隐藏,更改为visible显示 */
  36. ">
  37. <div id="customModalHeader" style="cursor: move; padding: 10px; background-color: #eee;">
  38. <h2 style="cursor: move; user-select: none; margin-top: 0; margin-bottom: 20px; font-size: 1.5em; color: #333;">小技巧</h2>
  39. <!-- 图片模态窗口 -->
  40. <div id="imageModal" style="display:none;">
  41. <button id="toggleButton">地图打开/关闭</button>
  42. </div>
  43. <button id="pinModal" style="position: absolute; top: 3px; right: 30px; cursor: pointer;">📌</button>
  44. <div id="modalContent" style="user-select: text;">无提示</div>
  45. <!-- 新增文本输入框 -->
  46. <!-- 使用 textarea 替换原有的 input -->
  47. <textarea id="customInputBox" placeholder="在此输入内容..." style="
  48. width: 90%; /* 输入框宽度 */
  49. padding: 5px; /* 内边距 */
  50. margin: 10px 5%; /* 外边距,水平居中 */
  51. border: 1px solid #ccc; /* 边框 */
  52. border-radius: 5px; /* 边框圆角 */
  53. overflow-y: hidden; /* 隐藏垂直滚动条 */
  54. resize: none; /* 禁止用户手动调整大小 */
  55. "></textarea>
  56. <!-- 设置按钮 -->
  57. <div id="settingsPanel" style="display: none; padding: 10px; background-color: #f9f9f9; border-bottom: 1px solid #ccc;">
  58. <label for="countdownTime">设置倒计时(秒):</label>
  59. <input type="number" id="countdownTime" value="15" min="1" style="margin-right: 10px;">
  60. <button id="saveSettings">保存设置</button>
  61. </div>
  62. <!-- 新增按钮 -->
  63. <div style="text-align: center; margin-top: 10px;">
  64. <button id="addButton" style="padding: 5px 15px; border: none; border-radius: 5px; cursor: pointer;">新增</button>
  65. </div>
  66. <span id="modalClose" style="
  67. position: absolute;
  68. top: -4px;
  69. right: 8px;
  70. cursor: pointer;
  71. font-size: 1.5em;
  72. color: #333;
  73. ">&times;</span>
  74. </div>
  75. `;
  76. document.body.insertAdjacentHTML('beforeend', modalHTML);
  77. function updateModalPosition(x, y) {
  78. const modal = document.getElementById('customModal');
  79. modal.style.left = `${x}px`;
  80. modal.style.top = `${y}px`;
  81. localStorage.setItem('modalPosition', JSON.stringify({ x, y }));
  82. }
  83. function restoreModalPosition() {
  84. const modal = document.getElementById('customModal');
  85. const position = JSON.parse(localStorage.getItem('modalPosition'));
  86. if (position) {
  87. modal.style.left = `${position.x}px`;
  88. modal.style.top = `${position.y}px`;
  89. }
  90. }
  91. function createTagElement(text, index) {
  92. const tagContainer = document.createElement('div');
  93. tagContainer.classList.add('tag-container');
  94. const label = document.createElement('span');
  95. label.textContent = index !== undefined ? `${index + 1}. ` : '';
  96. label.classList.add('tag-label');
  97. const paragraph = document.createElement('p');
  98. paragraph.textContent = text;
  99. paragraph.contentEditable = "true";
  100. paragraph.id = index !== undefined ? `tag-${index}` : undefined;
  101. const placeholder = document.createElement('div');
  102. placeholder.style.display = 'none';
  103. const saveButton = document.createElement('button');
  104. saveButton.textContent = '保存';
  105. saveButton.classList.add('save-button');
  106. saveButton.onclick = index !== undefined ? () => saveTag(paragraph, index) : () => saveTag(paragraph);
  107. saveButton.style.display = 'none';
  108. applyButtonStyles(saveButton);
  109. let isEditable = false;
  110. paragraph.ondblclick = function() {
  111. if (isEditable) {
  112. makeEditable(paragraph, saveButton, placeholder);
  113. }
  114. };
  115. tagContainer.appendChild(label);
  116. tagContainer.appendChild(paragraph);
  117. tagContainer.appendChild(placeholder);
  118. tagContainer.appendChild(saveButton);
  119. return tagContainer;
  120. }
  121. function makeEditable(paragraph, saveButton, placeholder) {
  122. paragraph.contentEditable = "true";
  123. paragraph.focus();
  124. saveButton.style.display = 'inline-block';
  125. placeholder.style.display = 'block';
  126. }
  127. function applyButtonStyles(button) {
  128. button.style.minWidth = '50px';
  129. button.style.minHeight = '25px';
  130. button.style.overflow = 'hidden';
  131. button.style.backgroundColor = '#4CAF50';
  132. button.style.color = 'white';
  133. button.style.border = 'none';
  134. button.style.borderRadius = '5px';
  135. button.style.padding = '5px 5px';
  136. button.style.cursor = 'text';
  137. button.onmouseover = function() {
  138. button.style.backgroundColor = '#45a049';
  139. };
  140. button.onmouseout = function() {
  141. button.style.backgroundColor = '#4CAF50';
  142. };
  143. }
  144. function addCustomStyles() {
  145. const style = document.createElement('style');
  146. style.type = 'text/css';
  147. style.innerHTML = `
  148. .tag-container {
  149. display: flex;
  150. align-items: flex-start;
  151. margin-bottom: 10px;
  152. }
  153. .tag-label {
  154. margin-right: 8px;
  155. font-weight: bold;
  156. }
  157. .tag-container p {
  158. margin: 0;
  159. flex-grow: 1;
  160. margin-right: 8px;
  161. }
  162. .save-button {
  163. display: none;
  164. align-self: center;
  165. flex-shrink: 0;
  166. }
  167. @media (max-width: 600px) {
  168. .save-button {
  169. min-width: 40px;
  170. min-height: 20px;
  171. }
  172. }
  173. `;
  174. document.head.appendChild(style);
  175. }
  176. const customInputBox = document.getElementById('customInputBox');
  177. customInputBox.addEventListener('keyup', function(event) {
  178. if (event.key === 'f') {
  179. event.stopPropagation();
  180. }
  181. });
  182. customInputBox.addEventListener('input', function() {
  183. adjustTextareaHeight(this);
  184. });
  185. customInputBox.addEventListener('input', function() {
  186. adjustTextareaHeight(this);
  187. });
  188. function adjustTextareaHeight(textarea) {
  189. textarea.style.height = 'auto';
  190. textarea.style.height = textarea.scrollHeight + 'px';
  191. }
  192. function preventKeyPropagation() {
  193. const modal = document.getElementById('customModal');
  194. modal.addEventListener('keydown', function(event) {
  195. event.stopPropagation();
  196. });
  197. }
  198. window.addEventListener('load', function() {
  199. addCustomStyles();
  200. preventKeyPropagation();
  201. const savedPosition = localStorage.getItem('modalPosition');
  202. if (savedPosition) {
  203. const { x, y } = JSON.parse(savedPosition);
  204. const modal = document.getElementById('customModal');
  205. if (modal) {
  206. modal.style.left = x + 'px';
  207. modal.style.top = y + 'px';
  208. }
  209. }
  210. /* const storedTagsText = localStorage.getItem('tagsText');
  211. const storedImageUrls = JSON.parse(localStorage.getItem('imageUrls') || '[]');
  212. if (storedTagsText) {
  213. let modalContent = storedTagsText;
  214. if (!isModalContentSame(modalContent)) {
  215. showModal(modalContent);
  216. } else {
  217. }
  218. } else {
  219. }
  220. */
  221. document.getElementById('addButton').style.display = 'none';
  222. document.getElementById('customInputBox').style.display = 'none';
  223. });
  224. let countdownInterval;
  225. let shouldDisplayServerText = true;
  226. function showModal(serverText) {
  227. const modal = document.getElementById('customModal');
  228. const modalContent = document.getElementById('modalContent');
  229. modalContent.innerHTML = '倒计时: 15秒';
  230. const storedAddress = localStorage.getItem('address')
  231. || localStorage.getItem('state')
  232. || localStorage.getItem('city')
  233. || localStorage.getItem('region')
  234. || '地址信息未找到';
  235. const storedModalPosition = JSON.parse(localStorage.getItem('modalPosition'));
  236. if (storedModalPosition) {
  237. modal.style.left = storedModalPosition.x + 'px';
  238. modal.style.top = storedModalPosition.y + 'px';
  239. }
  240. modalContent.innerHTML = `<p>倒计时: 15秒</p><p>地址信息: ${storedAddress}</p>`;
  241. if (countdownInterval) {
  242. clearInterval(countdownInterval);
  243. }
  244. let countdown = 15;
  245. countdownInterval = setInterval(function() {
  246. countdown--;
  247. modalContent.innerHTML = `<p>倒计时: ${countdown}秒</p>`;
  248. if (countdown <= 0) {
  249. clearInterval(countdownInterval);
  250. modalContent.innerHTML = `<p>省份:${storedAddress}</p>`;
  251. const tags = serverText.split('; ');
  252. tags.forEach((tag, index) => {
  253. const tagElement = createTagElement(tag, index);
  254. modalContent.appendChild(tagElement);
  255. });
  256. }
  257. }, 1000);
  258. modalContent.innerHTML = '倒计时: 15秒';
  259. if (modal.style.display !== 'none') {
  260. modal.style.display = 'block';
  261. modal.style.opacity = '1';
  262. modal.style.visibility = 'visible';
  263. }
  264. }
  265. function closeModal() {
  266. const modal = document.getElementById('customModal');
  267. modal.style.opacity = '0';
  268. modal.style.visibility = 'hidden';
  269. setTimeout(() => modal.style.display = 'none', 100);
  270. }
  271. let isSaveTagActive = false;
  272. function saveTag(paragraph, index) {
  273. if (!isSaveTagActive) {
  274. return;
  275. }
  276. const editedText = paragraph.textContent.trim();
  277. paragraph.contentEditable = "false";
  278. let tags = [];
  279. tags = localStorage.getItem('tagsText') ? localStorage.getItem('tagsText').split('; ') : [];
  280. if (index !== undefined) {
  281. if (editedText === '') {
  282. tags.splice(index, 1);
  283. const tagContainer = paragraph.parentElement;
  284. if (tagContainer) {
  285. tagContainer.remove();
  286. }
  287. } else {
  288. tags[index] = editedText;
  289. }
  290. } else {
  291. if (editedText !== '') {
  292. tags.push(editedText);
  293. }
  294. }
  295. tags = tags.filter(tag => tag && tag.trim());
  296. const updatedTagsText = tags.join('; ');
  297. localStorage.setItem('tagsText', updatedTagsText);
  298. const storedCoordinates = JSON.parse(localStorage.getItem('coordinates'));
  299. const dataToSend = {
  300. mapsId: localStorage.getItem('mapsId'),
  301. coordinates: storedCoordinates,
  302. tagsText: updatedTagsText
  303. };
  304. const saveButton = paragraph.parentElement.querySelector('.save-button');
  305. if (saveButton) {
  306. saveButton.style.display = 'none';
  307. }
  308. GM_xmlhttpRequest({
  309. method: "POST",
  310. url: 'http://knowledgetips.fun:3000/save-data',
  311. data: JSON.stringify(dataToSend),
  312. headers: {
  313. "Content-Type": "application/json"
  314. },
  315. onload: function(response) {
  316. }
  317. });
  318. }
  319. isSaveTagActive = false;
  320. isSaveTagActive = true;
  321. //更新标签
  322. function updateTagNumbers() {
  323. const tags = document.querySelectorAll('.tag-container');
  324. tags.forEach((tag, index) => {
  325. const label = tag.querySelector('.tag-label');
  326. if (label) {
  327. label.textContent = `${index + 1}. `;
  328. }
  329. });
  330. }
  331. function addNewTag() {
  332. const inputBox = document.getElementById('customInputBox');
  333. const newText = inputBox.value.trim();
  334. if (newText) {
  335. const newTagElement = createTagElement(newText);
  336. const modalContent = document.getElementById('modalContent');
  337. modalContent.appendChild(newTagElement);
  338. saveTag(newTagElement.querySelector('p'));
  339. inputBox.value = '';
  340. updateTagNumbers();
  341. }
  342. const customInputBox = document.getElementById('customInputBox');
  343. customInputBox.style.height = '30px';
  344. }
  345. const addButton = document.getElementById('addButton');
  346. if (addButton) {
  347. } else {
  348. }
  349. addButton.addEventListener('click', addNewTag);
  350. let isPinned = false;
  351. function loadPinState() {
  352. const savedState = localStorage.getItem('isPinned');
  353. if (savedState !== null) {
  354. isPinned = savedState === 'true';
  355. }
  356. updatePinButton();
  357. }
  358. function updatePinButton() {
  359. const pinButton = document.getElementById('pinModal');
  360. pinButton.textContent = isPinned ? '📍' : '📌';
  361. }
  362. function togglePin() {
  363. isPinned = !isPinned;
  364. localStorage.setItem('isPinned', isPinned);
  365. updatePinButton();
  366. }
  367. document.getElementById('pinModal').addEventListener('click', function(event) {
  368. togglePin();
  369. event.stopPropagation();
  370. });
  371. window.addEventListener('load', loadPinState);
  372. //以上是置顶函数变量
  373. let isDragging = false;
  374. let dragStartX, dragStartY;
  375. let originalX, originalY;
  376. document.getElementById('customModalHeader').addEventListener('mousedown', function(e) {
  377. if (e.target !== this && e.target !== document.querySelector('#customModalHeader h2')) {
  378. return;
  379. }
  380. isDragging = true;
  381. dragStartX = e.clientX;
  382. dragStartY = e.clientY;
  383. const modal = document.getElementById('customModal');
  384. originalX = parseInt(window.getComputedStyle(modal).left, 10);
  385. originalY = parseInt(window.getComputedStyle(modal).top, 10);
  386. e.preventDefault();
  387. });
  388. document.addEventListener('mousemove', function(e) {
  389. if (!isDragging) return;
  390. let newX = originalX + e.clientX - dragStartX;
  391. let newY = originalY + e.clientY - dragStartY;
  392. updateModalPosition(newX, newY);
  393. });
  394. document.addEventListener('mouseup', function(e) {
  395. if (isDragging) {
  396. isDragging = false;
  397. let newX = originalX + e.clientX - dragStartX;
  398. let newY = originalY + e.clientY - dragStartY;
  399. updateModalPosition(newX, newY);
  400. localStorage.setItem('modalPosition', JSON.stringify({ x: newX, y: newY }));
  401. }
  402. });
  403. document.addEventListener('click', function(event) {
  404. const modal = document.getElementById('customModal');
  405. if (!isPinned && !modal.contains(event.target)) {
  406. closeModal();
  407. }
  408. });
  409. document.getElementById('modalClose').addEventListener('click', closeModal);
  410. function toggleModal() {
  411. const modal = document.getElementById('customModal');
  412. if (modal.style.opacity === '1' || modal.style.visibility === 'visible') {
  413. modal.style.opacity = '0';
  414. modal.style.visibility = 'hidden';
  415. modal.style.display = 'none';
  416. } else {
  417. modal.style.opacity = '1';
  418. modal.style.visibility = 'visible';
  419. modal.style.display = 'block';
  420. }
  421. }
  422. document.addEventListener("keyup", function(evt) {
  423. const targetTagName = (evt.target || evt.srcElement).tagName;
  424. if (evt.key === '1' && targetTagName !== 'INPUT' && targetTagName !== 'TEXTAREA') {
  425. toggleModal();
  426. }
  427. });
  428. const mapsIdMatch = window.location.href.match(/maps-start\?mapsId=(\d+)/);
  429. const mapsId = mapsIdMatch ? mapsIdMatch[1] : localStorage.getItem('mapsId') || '未找到ID';
  430. if (mapsIdMatch) {
  431. localStorage.setItem('mapsId', mapsId);
  432. }
  433. const mapsIdPattern = /maps\/([a-zA-Z0-9]+|famous-places)/;
  434. const addressPattern = /\[\["(.*?)","zh"\]\]|\[\[.*?,\["(.*?)","zh"\]\]\]/;
  435. const coordinatePattern = /\[\[null,null,(-?\d+\.\d+),(-?\d+\.\d+)\],\[\d+\.\d+\],\[\d+\.\d+,\d+\.\d+,\d+\.\d+\]\]|\[\s*null,\s*null,\s*(-?\d+\.\d+),\s*(-?\d+\.\d+)\s*\]/;
  436. var realSend = XMLHttpRequest.prototype.send;
  437. XMLHttpRequest.prototype.send = function(value) {
  438. let currentUrl = this._url;
  439. this.addEventListener("loadstart", function() {
  440. currentUrl = this._url;
  441. });
  442. this.addEventListener("load", function() {
  443. let previousMapsId = localStorage.getItem('previousMapsId');
  444. let currentMapsId = localStorage.getItem('mapsId');
  445. const currentUrlMapsIdMatch = mapsIdPattern.exec(window.location.href);
  446. if (currentUrlMapsIdMatch) {
  447. const newMapsId = currentUrlMapsIdMatch[1];
  448. if (newMapsId !== currentMapsId) {
  449. localStorage.setItem('previousMapsId', currentMapsId);
  450. localStorage.setItem('mapsId', newMapsId);
  451. }
  452. }
  453. currentMapsId = localStorage.getItem('mapsId');
  454. previousMapsId = localStorage.getItem('previousMapsId');
  455. if (currentMapsId !== previousMapsId) {
  456. } else {
  457. }
  458. if (currentUrl.includes('https://maps.googleapis.com/$rpc/google.internal.maps.mapsjs.v1.MapsJsInternalService/SingleImageSearch') ||
  459. currentUrl.includes('https://maps.googleapis.com/$rpc/google.internal.maps.mapsjs.v1.MapsJsInternalService/GetMetadata')) {
  460. /*
  461. https://maps.googleapis.com/$rpc/google.internal.maps.mapsjs.v1.MapsJsInternalService/GetMetadata
  462. https://maps.googleapis.com/$rpc/google.internal.maps.mapsjs.v1.MapsJsInternalService/SingleImageSearch
  463. */
  464. const responseText = this.responseText;
  465. let addressMatches;
  466. let isAddressFound = false;
  467. let loopCount = 0;
  468. while ((addressMatches = addressPattern.exec(responseText)) !== null && loopCount < 3) {
  469. loopCount++;
  470. isAddressFound = true;
  471. const address = addressMatches[1] || addressMatches[2];
  472. const storedAddress = localStorage.getItem('address');
  473. if (address !== storedAddress) {
  474. localStorage.setItem('address', address);
  475. } else {
  476. }
  477. break;
  478. }
  479. if (!isAddressFound) {
  480. localStorage.removeItem('address');
  481. }
  482. if (coordinatePattern.test(responseText)) {
  483. //
  484. let latitude, longitude;
  485. const matches = coordinatePattern.exec(responseText);
  486. if (matches) {
  487. //
  488. function confuse() {
  489. var seed = Math.random();
  490. return seed.toString(36).substring(2, 15);
  491. }
  492. var unused = confuse();
  493. var coordinateData = {lat: undefined, lon: undefined};
  494. if (matches[1] !== undefined && matches[2] !== undefined) {
  495. latitude = matches[1];
  496. longitude = matches[2];
  497. }
  498. else if (matches[3] !== undefined && matches[4] !== undefined) {
  499. latitude = matches[3];
  500. longitude = matches[4];
  501. }
  502. (function(){
  503. var fakeLat = Math.random() * 100;
  504. var fakeLon = Math.random() * 100;
  505. //
  506. })();
  507. if (latitude !== undefined && longitude !== undefined) {
  508. const storedCoordinatesString = localStorage.getItem('coordinates');
  509. let storedCoordinates = null;
  510. if (storedCoordinatesString) {
  511. storedCoordinates = JSON.parse(storedCoordinatesString);
  512. }else {
  513. }
  514. function removeAllMyImages() {
  515. let existingImages = document.querySelectorAll('#myImage');
  516. existingImages.forEach(function(img) {
  517. img.parentNode.removeChild(img);
  518. });
  519. }
  520. const tolerance = 0.005;
  521. if (!storedCoordinates || !isCoordinateCloseEnough(storedCoordinates, latitude, longitude, tolerance)) {
  522. localStorage.removeItem('tagsText');
  523. localStorage.removeItem('address');
  524. localStorage.removeItem('state');
  525. removeAllMyImages();
  526. const coordinates = { latitude, longitude };
  527. localStorage.setItem('coordinates', JSON.stringify(coordinates));
  528. function getAddress(lat, lon) {
  529. // console.log(`Fetching address for coordinates: Latitude = ${lat}, Longitude = ${lon}`);
  530. return new Promise((resolve) => { // 移除 reject 参数
  531. try {
  532. GM_xmlhttpRequest({
  533. method: "GET",
  534. url: `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lon}&format=json`,
  535. onload: function(response) {
  536. // console.log("Received response from OpenStreetMap API", response);
  537. if (response.status === 200) {
  538. // console.log("Successfully fetched address:", response.responseText);
  539. resolve(JSON.parse(response.responseText));
  540. } else {
  541. console.error(`无法获取地址。状态码: ${response.status}`);
  542. resolve({ error: `无法获取地址。状态码: ${response.status}`, lat, lon }); // 使用 resolve 代替 reject
  543. }
  544. },
  545. onerror: function(error) {
  546. console.error("在获取地址时发生错误:", error);
  547. resolve({ error: "在获取地址时发生错误", lat, lon }); // 使用 resolve 代替 reject
  548. }
  549. });
  550. } catch (error) {
  551. console.error("在获取地址时发生异常:", error);
  552. resolve({ error: "在获取地址时发生异常", lat, lon }); // 使用 resolve 代替 reject
  553. }
  554. });
  555. }
  556. getAddress(latitude, longitude)
  557. .then(addressData => {
  558. function processAddressData(data, key) {
  559. if (data && data.address && data.address[key]) {
  560. const fullString = data.address[key];
  561. const value = fullString.split('/')[0].trim();
  562. const storedValue = localStorage.getItem(key);
  563. if (storedValue !== null) {
  564. if (storedValue !== value) {
  565. localStorage.setItem(key, value);
  566. } else {
  567. localStorage.setItem(key, value);
  568. }
  569. } else {
  570. localStorage.setItem(key, value);
  571. }
  572. } else {
  573. }
  574. }
  575. if (addressData) {
  576. processAddressData(addressData, 'country');
  577. processAddressData(addressData, 'state');
  578. processAddressData(addressData, 'region');
  579. processAddressData(addressData, 'city');
  580. }
  581. const country = localStorage.getItem('country');
  582. const dataToSend = JSON.stringify({ mapsId, coordinates: `${latitude},${longitude}`,country });
  583. function checkAndSendRequest() {
  584. if (isMatch) {
  585. sendRequest();
  586. } else {
  587. }
  588. }
  589. let retryCount = 0;
  590. function sendRequest() {
  591. GM_xmlhttpRequest({
  592. method: "POST",
  593. url: 'http://knowledgetips.fun:3000/receive-data',
  594. data: JSON.stringify({ mapsId, coordinates: `${latitude},${longitude}`,country }),
  595. headers: {
  596. "Content-Type": "application/json"
  597. },
  598. onload: function(response) {
  599. const jsonResponse = JSON.parse(response.responseText);
  600. if (jsonResponse.hasOwnProperty('mymapsid')) {
  601. isMatch = jsonResponse.mymapsid;
  602. }
  603. if (jsonResponse.match && jsonResponse.tags) {
  604. const tagsText = jsonResponse.tags.join('; ');
  605. let imgTag = document.getElementById('uniqueImageId');
  606. if (!imgTag) {
  607. imgTag = document.createElement('img');
  608. imgTag.id = 'uniqueImageId';
  609. imgTag.style.height = "80vh";
  610. imgTag.style.width = 'auto' ;
  611. imgTag.style.position = 'absolute';
  612. imgTag.style.left = '30%';
  613. imgTag.style.top = '46%';
  614. imgTag.style.transform = 'translate(-50%, -50%)';
  615. imgTag.style.zIndex = 1200;
  616. imgTag.style.display = 'none';
  617. document.body.appendChild(imgTag);
  618. }
  619. if (!window.hasAddedKeyListener) {
  620. document.addEventListener('keyup', function(event) {
  621. if (event.key === '2') {
  622. if (imgTag.style.display === 'none') {
  623. let lastImageUrl = localStorage.getItem('lastImageUrl');
  624. if (lastImageUrl) {
  625. imgTag.src = lastImageUrl;
  626. }
  627. imgTag.style.display = 'block';
  628. } else {
  629. imgTag.style.display = 'none';
  630. }
  631. }
  632. });
  633. window.hasAddedKeyListener = true;
  634. }
  635. let lastImageUrl = localStorage.getItem('lastImageUrl');
  636. if (jsonResponse.images && jsonResponse.images.length > 0) {
  637. const imageUrl = jsonResponse.images[0];
  638. imgTag.src = imageUrl;
  639. localStorage.setItem('lastImageUrl', imageUrl);
  640. } else {
  641. }
  642. localStorage.setItem('tagsText', tagsText);
  643. //
  644. localStorage.setItem('coordinates', JSON.stringify(coordinates));
  645. const modal = document.getElementById('customModal');
  646. if (modal.style.display !== 'none') {
  647. const modalContent = document.getElementById('modalContent');
  648. modalContent.textContent = tagsText;
  649. }
  650. showModal(tagsText);
  651. } else {
  652. modalContent.innerHTML = '无提示';
  653. }
  654. //
  655. },
  656. onerror: function() {
  657. if (retryCount < 3) {
  658. retryCount++;
  659. setTimeout(SendRequest, 3000);
  660. } else {
  661. }
  662. },
  663. ontimeout: function() {
  664. }
  665. });
  666. }
  667. checkAndSendRequest();
  668. window.checkAndSendRequest = checkAndSendRequest;
  669. })
  670. .catch(errorData => {
  671. });
  672. } else {
  673. }
  674. function isCoordinateCloseEnough(storedCoordinates, latitude, longitude, tolerance) {
  675. const latDifference = Math.abs(storedCoordinates.latitude - latitude);
  676. const lonDifference = Math.abs(storedCoordinates.longitude - longitude);
  677. return latDifference <= tolerance && lonDifference <= tolerance;
  678. }
  679. }else {
  680. }
  681. } else {
  682. }
  683. if (latitude !== undefined && longitude !== undefined) {
  684. }
  685. }else {
  686. modalContent.innerHTML = '';
  687. //
  688. }
  689. }
  690. }, false);
  691. realSend.call(this, value);
  692. };
  693. XMLHttpRequest.prototype.realOpen = XMLHttpRequest.prototype.open;
  694. XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
  695. this._url = url;
  696. this.realOpen(method, url, async, user, pass);
  697. };
  698. if (XMLHttpRequest.prototype.send === XMLHttpRequest.prototype.realSend) {
  699. } else {
  700. }
  701. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址