图寻pro插件(tuxun)

按3显示当前位置国家位置信息,新增每次点击显示距离正确地点的距离

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

    // ==UserScript==
    // @name         图寻pro插件(tuxun)
    // @namespace    https://tuxun.fun/
    // @version      1.1
    // @description  按3显示当前位置国家位置信息,新增每次点击显示距离正确地点的距离
    // @author       lemures
    // @match        https://tuxun.fun/*
    // @icon         https://s2.loli.net/2024/01/17/4nqsveVoH8A1mTB.png
    // @grant        GM_openInTab
    // ==/UserScript==

    (function() {
        'use strict';
        var currentLatitude = null;
        var currentLongitude = null;
        var newCoords;
        var randomDistance;
        var randomBearing;
        var realSend = XMLHttpRequest.prototype.send;
        XMLHttpRequest.prototype.send = function(value) {
            this.addEventListener("load", function() {
                var url = this._url;
                if (url.includes('https://tuxun.fun/api/v0/tuxun/mapProxy/getGooglePanoInfoPost')) {
                    handleGooglePanoInfo(this.responseText);
                } else if (url.includes('https://tuxun.fun/api/v0/tuxun/mapProxy/getPanoInfo?pano=')) {
                    handlePanoInfo(this.responseText);
                }
            }, false);
            realSend.call(this, 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);
        };

function createButtons() {
    var buttonContainer = document.createElement('div');
    buttonContainer.style.position = 'fixed';
    buttonContainer.style.top = '50px';
    buttonContainer.style.left = '20px';
    buttonContainer.style.zIndex = '10000';
    buttonContainer.style.display = 'flex';
    buttonContainer.style.flexDirection = 'column';
    document.body.appendChild(buttonContainer);

    var buttonsInfo = [
        /*{ text: '一键5K', action: () => simulateKeyPress('1'), bgColor: '#4CAF50', textColor: '#FFFFFF' },
        { text: '智能偏移', action: () => simulateKeyPress('2'), bgColor: '#008CBA', textColor: '#FFFFFF' },*/
        { text: '信息提示', action: () => simulateKeyPress('3'), bgColor: '#f44336', textColor: '#FFFFFF' },
        { text: '距离显示', action: toggleDistanceDisplay, bgColor: '#555555', textColor: '#FFFFFF' } // 新添加的按钮
    ];

    buttonsInfo.forEach(function(info) {
        var button = document.createElement('button');
        button.textContent = info.text;
        button.style.backgroundColor = info.bgColor;
        button.style.color = info.textColor;
        button.style.marginBottom = '5px';
        button.style.borderRadius = '5px';
        button.onclick = info.action;
        buttonContainer.appendChild(button);
    });
}

var distanceDisplayEnabled = false;

function toggleDistanceDisplay() {
    distanceDisplayEnabled = !distanceDisplayEnabled;
    showAlert(`距离显示${distanceDisplayEnabled ? '打开' : '关闭'}`);
    if (distanceDisplayEnabled) {
        XMLHttpRequest.prototype.realSend = XMLHttpRequest.prototype.send;
        XMLHttpRequest.prototype.send = function(value) {
            this.addEventListener("load", function() {
                if (this._url.includes('/pin?')) {
                    const params = new URLSearchParams(this._url.split('?')[1]);
                    const pinLat = parseFloat(params.get('lat'));
                    const pinLng = parseFloat(params.get('lng'));
                    const distance = calculateDistance(pinLat, pinLng, currentLatitude, currentLongitude);

                    showAlert(`距离正确位置: ${distance.toFixed(2)} km`);
                }
            }, false);
            XMLHttpRequest.prototype.realSend.call(this, value);
        };
    } else {
        XMLHttpRequest.prototype.send = XMLHttpRequest.prototype.realSend;
    }
}


function calculateDistance(lat1, lon1, lat2, lon2) {
    const R = 6371; // 地球半径km
    const dLat = toRadians(lat2-lat1);
    const dLon = toRadians(lon2-lon1);
    const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
              Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
              Math.sin(dLon/2) * Math.sin(dLon/2);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    return R * c;
}

function toRadians(degrees) {
    return degrees * Math.PI / 180;
}

createButtons();



        function simulateKeyPress(key) {
            var event = new KeyboardEvent('keydown', { key: key });
            document.dispatchEvent(event);
        }

        createButtons();

        document.addEventListener('keydown', function(event) {
            if (event.key === '') {
                randomDistance = 10 + Math.random() * 90;
                randomBearing = Math.random() * 360;
                newCoords = calculateNewCoords(currentLatitude, currentLongitude, randomDistance, randomBearing);
                guess(newCoords.latitude, newCoords.longitude);
            } else if (event.key === '') {
                generateNonSeaCoordinate();
            } else if (event.key === '3') {
                if (currentLatitude && currentLongitude) {
                    getAddressFromApi(currentLatitude, currentLongitude)
                        .then(addressInfo => {
                            if (addressInfo) {
                                showAlert(`${addressInfo.county}, ${addressInfo.state},${addressInfo.country}`);
                            } else {
                                showAlert('未能获取有效的地址信息');
                            }
                        })
                        .catch(error => {
                            console.error('Error:', error);
                            showAlert('发生错误');
                        });
                } else {
                    showAlert('未能获取有效的经纬度');
                }
            }
        });

        function generateNonSeaCoordinate() {
            randomDistance = 20000 + Math.random() * 200000;
            randomBearing = Math.random() * 360;
            newCoords = calculateNewCoords(currentLatitude, currentLongitude, randomDistance, randomBearing);
            isCoordinateOnLand(newCoords.latitude, newCoords.longitude, function(isOnLand) {
                if (isOnLand) {
                    guess(newCoords.latitude, newCoords.longitude);
                } else {
                    generateNonSeaCoordinate();
                }
            });
        }

        function isCoordinateOnLand(latitude, longitude, callback) {
            try {
                var apiUrl = 'https://nominatim.openstreetmap.org/reverse?format=json&lat=' + latitude + '&lon=' + longitude + '&addressdetails=1';
                fetch(apiUrl)
                    .then(response => response.json())
                    .then(data => {
                        callback(!!data.address);
                    })
                    .catch(error => {
                        console.error('Error checking land:', error);
                        callback(false);
                    });
            } catch (error) {
                console.error('Error checking land:', error);
                callback(false);
            }
        }

        function handleGooglePanoInfo(responseText) {
            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*\]/;
            const matches = coordinatePattern.exec(responseText);
            if (matches) {
                currentLatitude = parseFloat(matches[1] || matches[3]);
                currentLongitude = parseFloat(matches[2] || matches[4]);
            }
        }

        function handlePanoInfo(responseText) {
            try {
                const data = JSON.parse(responseText);
                const lat = data?.data?.lat;
                const lng = data?.data?.lng;

                if (lat && lng) {
                    currentLatitude = parseFloat(lat);
                    currentLongitude = parseFloat(lng);
                }
            } catch (error) {
                console.error('Error parsing PanoInfo JSON:', error);
            }
        }

        function getAddressFromApi(latitude, longitude) {
            return new Promise((resolve, reject) => {
                const apiUrl = `https://nominatim.openstreetmap.org/reverse?format=json&lat=${latitude}&lon=${longitude}&addressdetails=1`;

                fetch(apiUrl)
                    .then(response => response.json())
                    .then(data => {
                        const addressInfo = {
                            county: data?.address?.county || '',
                            state: data?.address?.state || '',
                            country: data?.address?.country || ''
                        };

                        resolve(addressInfo);
                    })
                    .catch(error => {
                        console.error('Error fetching address:', error);
                        reject(error);
                    });
            });
        }

        function calculateNewCoords(lat, lon, distance, bearing) {
            var R = 6371e3;
            var bearingRad = toRadians(bearing);
            var distRatio = distance / R;
            var distRatioSine = Math.sin(distRatio);
            var distRatioCosine = Math.cos(distRatio);
            var startLatRad = toRadians(lat);
            var startLonRad = toRadians(lon);

            var startLatCos = Math.cos(startLatRad);
            var startLatSin = Math.sin(startLatRad);

            var endLatRads = Math.asin((startLatSin * distRatioCosine) + (startLatCos * distRatioSine * Math.cos(bearingRad)));

            var endLonRads = startLonRad + Math.atan2(Math.sin(bearingRad) * distRatioSine * startLatCos, distRatioCosine - startLatSin * Math.sin(endLatRads));

            return {
                latitude: toDegrees(endLatRads),
                longitude: toDegrees(endLonRads)
            };
        }

        function toDegrees(radians) {
            return radians * 180 / Math.PI;
        }

        async function guess(latitude, longitude) {
            let gameId;

            if (window.location.href.includes('https://tuxun.fun/challenge/')) {
                gameId = await getGameIdFromChallengeURL();
            } else {
                gameId = getGameIdFromURL();
            }

            if (latitude && longitude && gameId) {
                let apiEndpoint, guessURL;

                if (window.location.href.includes('https://tuxun.fun/challenge/')) {
                    apiEndpoint = 'challenge/guess';
                } else if (window.location.href.includes('streak_game')) {
                    apiEndpoint = 'streak/guess';
                } else {
                    apiEndpoint = 'solo/guess';
                }

                guessURL = `https://tuxun.fun/api/v0/tuxun/${apiEndpoint}?gameId=${gameId}&lng=${longitude}&lat=${latitude}`;

                try {
                    const response = await fetch(guessURL);
                    showAlert('猜测成功!');
                } catch (error) {
                    console.error('Error making guess:', error);
                    showAlert('猜测失败,请重试。');
                }
            } else {
                showAlert('未能获取有效的经纬度或游戏ID');
            }
        }

        async function getGameIdFromChallengeURL() {
            const challengePattern = /tuxun\.fun\/challenge\/([a-f\d-]+)/;
            const matches = challengePattern.exec(window.location.href);
            const challengeId = matches && matches.length > 1 ? matches[1] : null;

            if (challengeId) {
                try {
                    const response = await fetch(`https://tuxun.fun/api/v0/tuxun/challenge/getGameInfo?challengeId=${challengeId}`);
                    const data = await response.json();
                    const gameId = data?.data?.id || null;
                    return gameId;
                } catch (error) {
                    console.error('Error fetching game info:', error);
                }
            }

            return null;
        }

        function getGameIdFromURL() {
            const oldUrlPattern = /tuxun\.fun\/solo_game\?gameId=([a-f\d-]+)/;
            const newUrlPattern = /tuxun\.fun\/solo\/([a-f\d-]+)/;
            const streakUrlPattern = /tuxun\.fun\/streak_game\?streakId=([a-f\d-]+)/;

            let matches = oldUrlPattern.exec(window.location.href);
            if (matches && matches.length > 1) {
                return matches[1];
            }

            matches = newUrlPattern.exec(window.location.href);
            if (matches && matches.length > 1) {
                return matches[1];
            }

            matches = streakUrlPattern.exec(window.location.href);
            if (matches && matches.length > 1) {
                return matches[1];
            }

            return null;
        }

        function showAlert(message) {
            var alertBox = document.createElement('div');
            alertBox.style.position = 'fixed';
            alertBox.style.top = '50%';
            alertBox.style.left = '50%';
            alertBox.style.transform = 'translate(-50%, -50%)';
            alertBox.style.padding = '20px';
            alertBox.style.borderRadius = '10px';
            alertBox.style.backdropFilter = 'blur(20px)';
            alertBox.style.background = 'rgba(94, 94, 94, 0.7)';
            alertBox.style.zIndex = '9999';
            alertBox.textContent = message;
            alertBox.style.color = 'white';
            alertBox.style.fontSize = '18px';

            document.body.appendChild(alertBox);

            setTimeout(function() {
                document.body.removeChild(alertBox);
            }, 2000);
        }

    })();