// ==UserScript==
// @name 图寻tips
// @namespace http://tampermonkey.net/
// @version 2.0
// @description 需要特定地图才能提示,按1键可以提示plonkit中的知识,比如:plonkit新手向等等,或者带有tips关键词的题库才能使用
// @supportURL https://sleazyfork.org/en/scripts/480332-图寻tips
// @author yukejun
// @match https://tuxun.fun/*
// @grant GM_xmlhttpRequest
// @connect knowledgetips.fun
// @license MIT
// ==/UserScript==
(function() {
'use strict';
const modalHTML = `
<div id="customModal" style="
cursor: move;
display: none;
position: fixed;
z-index: 1000;
top: 10vh;
left: 10vw;
background-color: #eee;
padding: 5px;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
width: 80vw;
max-width: 300px;
transform: translate(0, 0);
text-align: left;
opacity: 0;
visibility: hidden;
">
<div id="customModalHeader" style="cursor: move; padding: 10px; background-color: #eee;">
<h2 style="cursor: move; user-select: none; margin-top: 0; margin-bottom: 20px; font-size: 1.5em; color: #333;">小技巧</h2>
<button id="pinModal" style="position: absolute; top: 3px; right: 30px; cursor: pointer;">📌</button>
<div id="modalContent" style="user-select: text;">无提示</div>
<input type="text" id="customInputBox" placeholder="在此输入内容..." style="
width: 90%;
padding: 5px;
margin: 10px 5%;
border: 1px solid #ccc;
border-radius: 5px;
">
<div style="text-align: center; margin-top: 10px;">
<button id="addButton" style="padding: 5px 15px; border: none; border-radius: 5px; cursor: pointer;">新增</button>
</div>
<span id="modalClose" style="
position: absolute;
top: -4px;
right: 8px;
cursor: pointer;
font-size: 1.5em;
color: #333;
">×</span>
</div>
`;
document.body.insertAdjacentHTML('beforeend', modalHTML);
function updateModalPosition(x, y) {
const modal = document.getElementById('customModal');
modal.style.left = `${x}px`;
modal.style.top = `${y}px`;
localStorage.setItem('modalPosition', JSON.stringify({ x, y }));
}
function restoreModalPosition() {
const modal = document.getElementById('customModal');
const position = JSON.parse(localStorage.getItem('modalPosition'));
if (position) {
modal.style.left = `${position.x}px`;
modal.style.top = `${position.y}px`;
}
}
window.addEventListener('load', restoreModalPosition);
function createTagElement(text, index) {
const tagContainer = document.createElement('div');
tagContainer.classList.add('tag-container');
const label = document.createElement('span');
label.textContent = index !== undefined ? `${index + 1}. ` : '';
label.classList.add('tag-label');
const paragraph = document.createElement('p');
paragraph.textContent = text;
paragraph.contentEditable = "true";
paragraph.id = index !== undefined ? `tag-${index}` : undefined;
const placeholder = document.createElement('div');
placeholder.style.display = 'none';
const saveButton = document.createElement('button');
saveButton.textContent = '保存';
saveButton.classList.add('save-button');
saveButton.onclick = index !== undefined ? () => saveTag(paragraph, index) : () => saveTag(paragraph);
saveButton.style.display = 'none';
applyButtonStyles(saveButton);
paragraph.ondblclick = function() {
makeEditable(paragraph, saveButton, placeholder);
};
tagContainer.appendChild(label);
tagContainer.appendChild(paragraph);
tagContainer.appendChild(placeholder);
tagContainer.appendChild(saveButton);
return tagContainer;
}
function makeEditable(paragraph, saveButton, placeholder) {
/* paragraph.contentEditable = "true";
paragraph.focus();
saveButton.style.display = 'inline-block';
placeholder.style.display = 'block';
*/
}
function applyButtonStyles(button) {
button.style.minWidth = '50px';
button.style.minHeight = '25px';
button.style.overflow = 'hidden';
button.style.backgroundColor = '#4CAF50';
button.style.color = 'white';
button.style.border = 'none';
button.style.borderRadius = '5px';
button.style.padding = '5px 5px';
button.style.cursor = 'text';
button.onmouseover = function() {
button.style.backgroundColor = '#45a049';
};
button.onmouseout = function() {
button.style.backgroundColor = '#4CAF50';
};
}
function addCustomStyles() {
const style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = `
.tag-container {
display: flex;
align-items: flex-start;
margin-bottom: 10px;
}
.tag-label {
margin-right: 8px;
font-weight: bold;
}
.tag-container p {
margin: 0;
flex-grow: 1;
margin-right: 8px;
}
.save-button {
display: none;
align-self: center;
// 使用flex布局,适应内容大小
flex-shrink: 0;
}
@media (max-width: 600px) {
.save-button {
// 小屏幕上的特定样式
min-width: 40px;
min-height: 20px;
}
}
`;
document.head.appendChild(style);
}
function preventKeyPropagation() {
const modal = document.getElementById('customModal');
modal.addEventListener('keydown', function(event) {
event.stopPropagation();
// event.preventDefault();
});
}
window.addEventListener('load', function() {
restoreModalPosition();
addCustomStyles();
preventKeyPropagation();
document.getElementById('addButton').style.display = 'none';
document.getElementById('customInputBox').style.display = 'none';
});
let countdownInterval;
let shouldDisplayServerText = true;
function showModal(serverText) {
const modal = document.getElementById('customModal');
const modalContent = document.getElementById('modalContent');
modalContent.innerHTML = '倒计时: 15秒';
const storedAddress = localStorage.getItem('address') || '地址信息未找到';
modalContent.innerHTML = '<p>倒计时: 15秒</p>';
if (countdownInterval) {
clearInterval(countdownInterval);
}
let countdown = 15;
countdownInterval = setInterval(function() {
countdown--;
modalContent.innerHTML = `<p>倒计时: ${countdown}秒</p>`;
if (countdown <= 0) {
clearInterval(countdownInterval);
modalContent.innerHTML = `<p>省份:${storedAddress}</p>`;
const tags = serverText.split('; ');
tags.forEach((tag, index) => {
const tagElement = createTagElement(tag, index);
modalContent.appendChild(tagElement);
});
}
}, 1000);
modalContent.innerHTML = '倒计时: 15秒';
if (modal.style.display !== 'none') {
modal.style.display = 'block';
modal.style.opacity = '1';
modal.style.visibility = 'visible';
}
}
function closeModal() {
const modal = document.getElementById('customModal');
modal.style.opacity = '0';
modal.style.visibility = 'hidden';
setTimeout(() => modal.style.display = 'none', 100);
}
function saveTag(paragraph, index) {
const editedText = paragraph.textContent;
paragraph.contentEditable = "false";
let tags = localStorage.getItem('tagsText') ? localStorage.getItem('tagsText').split('; ') : [];
if (index !== undefined) {
tags[index] = editedText;
} else {
tags.push(editedText);
}
const updatedTagsText = tags.join('; ');
localStorage.setItem('tagsText', updatedTagsText);
const storedCoordinates = JSON.parse(localStorage.getItem('coordinates'));
const dataToSend = {
mapsId: localStorage.getItem('mapsId'),
coordinates: storedCoordinates,
tagsText: updatedTagsText
};
const saveButton = paragraph.parentElement.querySelector('.save-button');
if (saveButton) {
saveButton.style.display = 'none';
}
GM_xmlhttpRequest({
method: "POST",
url: 'knowledgetips.fun:3000/save-data',
data: JSON.stringify(dataToSend),
headers: {
"Content-Type": "application/json"
},
onload: function(response) {
}
});
}
function updateTagNumbers() {
const tags = document.querySelectorAll('.tag-container');
tags.forEach((tag, index) => {
const label = tag.querySelector('.tag-label');
if (label) {
label.textContent = `${index + 1}. `;
}
});
}
function addNewTag() {
const inputBox = document.getElementById('customInputBox');
const newText = inputBox.value.trim();
if (newText) {
const newTagElement = createTagElement(newText);
const modalContent = document.getElementById('modalContent');
modalContent.appendChild(newTagElement);
saveTag(newTagElement.querySelector('p'));
inputBox.value = '';
updateTagNumbers();
}
}
const addButton = document.getElementById('addButton');
if (addButton) {
} else {
}
addButton.addEventListener('click', addNewTag);
let isPinned = false;
function loadPinState() {
const savedState = localStorage.getItem('isPinned');
if (savedState !== null) {
isPinned = savedState === 'true';
}
updatePinButton();
}
function updatePinButton() {
const pinButton = document.getElementById('pinModal');
pinButton.textContent = isPinned ? '📍' : '📌';
}
function togglePin() {
isPinned = !isPinned;
localStorage.setItem('isPinned', isPinned);
updatePinButton();
}
document.getElementById('pinModal').addEventListener('click', function(event) {
togglePin();
event.stopPropagation();
});
window.addEventListener('load', loadPinState);
let isDragging = false;
let dragStartX, dragStartY;
let originalX, originalY;
document.getElementById('customModalHeader').addEventListener('mousedown', function(e) {
if (e.target !== this && e.target !== document.querySelector('#customModalHeader h2')) {
return;
}
isDragging = true;
dragStartX = e.clientX;
dragStartY = e.clientY;
const modal = document.getElementById('customModal');
originalX = parseInt(window.getComputedStyle(modal).left, 10);
originalY = parseInt(window.getComputedStyle(modal).top, 10);
e.preventDefault();
});
document.addEventListener('mousemove', function(e) {
if (!isDragging) return;
let newX = originalX + e.clientX - dragStartX;
let newY = originalY + e.clientY - dragStartY;
updateModalPosition(newX, newY);
});
document.addEventListener('mouseup', function(e) {
if (isDragging) {
isDragging = false;
let newX = originalX + e.clientX - dragStartX;
let newY = originalY + e.clientY - dragStartY;
updateModalPosition(newX, newY);
}
});
document.addEventListener('click', function(event) {
const modal = document.getElementById('customModal');
if (!isPinned && !modal.contains(event.target)) {
closeModal();
}
});
document.getElementById('modalClose').addEventListener('click', closeModal);
function toggleModal() {
const modal = document.getElementById('customModal');
if (modal.style.opacity === '1' || modal.style.visibility === 'visible') {
modal.style.opacity = '0';
modal.style.visibility = 'hidden';
modal.style.display = 'none';
} else {
modal.style.opacity = '1';
modal.style.visibility = 'visible';
modal.style.display = 'block';
}
}
document.addEventListener("keydown", function(evt) {
const targetTagName = (evt.target || evt.srcElement).tagName;
if (evt.key === '1' && targetTagName !== 'INPUT' && targetTagName !== 'TEXTAREA') {
toggleModal();
}
});
const mapsIdMatch = window.location.href.match(/maps-start\?mapsId=(\d+)/);
const mapsId = mapsIdMatch ? mapsIdMatch[1] : localStorage.getItem('mapsId') || '未找到ID';
if (mapsIdMatch) {
localStorage.setItem('mapsId', mapsId);
}
const mapsIdPattern = /mapsId=(-\d+)/;
const addressPattern = /\[\["(.*?)","zh"\]\]|\[\[.*?,\["(.*?)","zh"\]\]\]/;
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*\]/;
XMLHttpRequest.prototype.realSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function(value) {
let currentUrl = this._url;
this.addEventListener("loadstart", function() {
currentUrl = this._url;
});
this.addEventListener("load", function() {
if (this._url.includes('https://tuxun.fun/api/v0/tuxun/party/changeMaps')) {
const newMapsIdMatch = this._url.match(mapsIdPattern);
if (newMapsIdMatch) {
const newMapsId = newMapsIdMatch[1];
localStorage.setItem('mapsId', newMapsId);
localStorage.removeItem('address');
localStorage.removeItem('coordinates');
}
}
if (!currentUrl.includes('mapsId=')) {
const responseText = this.responseText;
const mapsIdMatches = mapsIdPattern.exec(responseText);
if (mapsIdMatches) {
const mapsId = mapsIdMatches[1];
localStorage.setItem('mapsId', mapsId);
localStorage.removeItem('address');
localStorage.removeItem('coordinates');
}
}
if (currentUrl.includes('https://tuxun.fun/api/v0/tuxun/mapProxy/getGooglePanoInfoPost')) {
const responseText = this.responseText;
let addressMatches;
let isAddressFound = false;
let loopCount = 0;
let dummyVar = Math.random();
function confuseFunction(data) {
return data.split('').reverse().join('');
}
while ((addressMatches = addressPattern.exec(responseText)) !== null && loopCount < 3) {
loopCount++;
isAddressFound = true;
const address = addressMatches[1] || addressMatches[2];
const encryptedAddress = confuseFunction(address);
const storedAddress = localStorage.getItem('address');
if (address !== storedAddress) {
localStorage.setItem('address', address);
} else {
}
break;
}
if (!isAddressFound) {
localStorage.removeItem('address');
}
if (coordinatePattern.test(responseText)) {
let latitude, longitude;
const matches = coordinatePattern.exec(responseText);
if (matches) {
function confuse() {
var seed = Math.random();
console.log('种子数:', seed);
return seed.toString(36).substring(2, 15);
}
var unused = confuse();
var coordinateData = {lat: undefined, lon: undefined};
if (matches[1] !== undefined && matches[2] !== undefined) {
latitude = matches[1];
longitude = matches[2];
}
else if (matches[3] !== undefined && matches[4] !== undefined) {
latitude = matches[3];
longitude = matches[4];
}
(function(){
var fakeLat = Math.random() * 100;
var fakeLon = Math.random() * 100;
})();
if (latitude !== undefined && longitude !== undefined) {
const storedCoordinatesString = localStorage.getItem('coordinates');
let storedCoordinates = null;
if (storedCoordinatesString) {
storedCoordinates = JSON.parse(storedCoordinatesString);
}
if (!storedCoordinates || storedCoordinates.latitude !== latitude || storedCoordinates.longitude !== longitude) {
const coordinates = { latitude, longitude };
localStorage.setItem('coordinates', JSON.stringify(coordinates));
GM_xmlhttpRequest({
method: "POST",
url: 'http://knowledgetips.fun:3000/receive-data',
data: JSON.stringify({ mapsId, coordinates: `${latitude},${longitude}` }),
headers: {
"Content-Type": "application/json"
},
onload: function(response) {
const jsonResponse = JSON.parse(response.responseText);
if (jsonResponse.match && jsonResponse.tags) {
const tagsText = jsonResponse.tags.join('; ');
localStorage.setItem('tagsText', tagsText);
localStorage.setItem('coordinates', JSON.stringify(coordinates));
const modal = document.getElementById('customModal');
if (modal.style.display !== 'none') {
const modalContent = document.getElementById('modalContent');
modalContent.textContent = tagsText;
}
showModal(tagsText);
} else{
modalContent.innerHTML = '暂无提示,等待加入';
}
},
});
} else {
const storedTagsText = localStorage.getItem('tagsText');
if (storedTagsText) {
showModal(storedTagsText);
}
}
}
}
if (latitude !== undefined && longitude !== undefined) {
}
}
}
}, false);
this.realSend(value);
};
XMLHttpRequest.prototype.realOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
this._url = url;
this.realOpen(method, url, async, user, pass);
};
if (XMLHttpRequest.prototype.send === XMLHttpRequest.prototype.realSend) {
} else {
}
})();