图寻pro插件(tuxun)

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

目前為 2024-07-16 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

    // ==UserScript==
    // @name         图寻pro插件(tuxun)
    // @namespace    https://tuxun.fun/
    // @version      1.2
    // @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);
        }

    })();