您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Integrate location spoofing with Sniffies' existing Travel Mode button using natural language inputs.
当前为
// ==UserScript== // @name Sniffies Integrated Location Spoofer // @namespace https://sniffies.com/ // @version 1.3 // @description Integrate location spoofing with Sniffies' existing Travel Mode button using natural language inputs. // @author Your Name // @match https://sniffies.com/* // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; // Configuration const STORAGE_KEY = 'sniffiesLocationSpoofer'; const GEOCODING_API_URL = 'https://nominatim.openstreetmap.org/search'; // Utility Functions function getStoredLocation() { const data = localStorage.getItem(STORAGE_KEY); return data ? JSON.parse(data) : { enabled: false, locationName: '', latitude: 37.7749, longitude: -122.4194 }; // Default: San Francisco } function setStoredLocation(locationData) { localStorage.setItem(STORAGE_KEY, JSON.stringify(locationData)); } // Geocoding Function async function geocodeLocation(locationName) { const params = new URLSearchParams({ q: locationName, format: 'json', limit: 1 }); try { const response = await fetch(`${GEOCODING_API_URL}?${params.toString()}`, { method: 'GET', headers: { 'Accept': 'application/json' } }); if (!response.ok) { throw new Error(`Geocoding API error: ${response.statusText}`); } const data = await response.json(); if (data.length === 0) { throw new Error('Location not found. Please try a different query.'); } return { latitude: parseFloat(data[0].lat), longitude: parseFloat(data[0].lon) }; } catch (error) { throw new Error(`Failed to geocode location: ${error.message}`); } } // Override Geolocation API function overrideGeolocation(spoofedLocation) { const originalGeolocation = navigator.geolocation; const spoofedGeolocation = { getCurrentPosition: function (success, error, options) { success({ coords: { latitude: spoofedLocation.latitude, longitude: spoofedLocation.longitude, altitude: null, accuracy: 100, altitudeAccuracy: null, heading: null, speed: null }, timestamp: Date.now() }); }, watchPosition: function (success, error, options) { // For simplicity, behave like getCurrentPosition return originalGeolocation.watchPosition.call(navigator.geolocation, success, error, options); }, clearWatch: function (id) { originalGeolocation.clearWatch.call(navigator.geolocation, id); } }; Object.defineProperty(navigator, 'geolocation', { get: function () { return spoofedGeolocation; } }); } // UI Elements // Create Modal Dialog function createModal() { // Overlay const overlay = document.createElement('div'); overlay.id = 'spoofModalOverlay'; overlay.style.position = 'fixed'; overlay.style.top = '0'; overlay.style.left = '0'; overlay.style.width = '100%'; overlay.style.height = '100%'; overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; overlay.style.display = 'none'; overlay.style.alignItems = 'center'; overlay.style.justifyContent = 'center'; overlay.style.zIndex = '10000'; // Modal Container const modal = document.createElement('div'); modal.id = 'spoofModal'; modal.style.width = '90%'; modal.style.maxWidth = '400px'; modal.style.backgroundColor = '#fff'; modal.style.borderRadius = '8px'; modal.style.padding = '20px'; modal.style.boxShadow = '0 5px 15px rgba(0,0,0,0.3)'; modal.style.position = 'relative'; // Close Button const closeButton = document.createElement('span'); closeButton.innerHTML = '×'; closeButton.style.position = 'absolute'; closeButton.style.top = '10px'; closeButton.style.right = '15px'; closeButton.style.fontSize = '24px'; closeButton.style.cursor = 'pointer'; closeButton.style.color = '#aaa'; closeButton.style.transition = 'color 0.3s'; closeButton.addEventListener('mouseover', () => { closeButton.style.color = '#000'; }); closeButton.addEventListener('mouseout', () => { closeButton.style.color = '#aaa'; }); modal.appendChild(closeButton); // Title const title = document.createElement('h2'); title.textContent = 'Location Spoofer'; title.style.marginTop = '0'; title.style.textAlign = 'center'; modal.appendChild(title); // Enable Checkbox const enableLabel = document.createElement('label'); enableLabel.style.display = 'block'; enableLabel.style.marginBottom = '15px'; enableLabel.style.cursor = 'pointer'; const enableCheckbox = document.createElement('input'); enableCheckbox.type = 'checkbox'; enableCheckbox.id = 'spoofEnableCheckbox'; enableCheckbox.style.marginRight = '8px'; enableLabel.appendChild(enableCheckbox); const enableText = document.createElement('span'); enableText.textContent = 'Enable Location Spoofing'; enableLabel.appendChild(enableText); modal.appendChild(enableLabel); // Location Name Input const locationLabel = document.createElement('label'); locationLabel.textContent = 'Enter Location:'; locationLabel.style.display = 'block'; locationLabel.style.marginBottom = '5px'; modal.appendChild(locationLabel); const locationInput = document.createElement('input'); locationInput.type = 'text'; locationInput.id = 'spoofLocationName'; locationInput.placeholder = 'e.g., Washington DC, London, Tokyo'; locationInput.style.width = '100%'; locationInput.style.padding = '10px'; locationInput.style.marginBottom = '15px'; locationInput.style.border = '1px solid #ccc'; locationInput.style.borderRadius = '4px'; modal.appendChild(locationInput); // Preset Locations const presetLabel = document.createElement('label'); presetLabel.textContent = 'Or Select a Preset Location:'; presetLabel.style.display = 'block'; presetLabel.style.marginBottom = '5px'; modal.appendChild(presetLabel); const presetSelect = document.createElement('select'); presetSelect.id = 'spoofPresetSelect'; presetSelect.style.width = '100%'; presetSelect.style.padding = '10px'; presetSelect.style.marginBottom = '15px'; presetSelect.style.border = '1px solid #ccc'; presetSelect.style.borderRadius = '4px'; const presets = { 'Select a preset...': '', 'New York City, NY, USA': 'New York City, NY, USA', 'Los Angeles, CA, USA': 'Los Angeles, CA, USA', 'London, UK': 'London, UK', 'Tokyo, Japan': 'Tokyo, Japan', 'Sydney, Australia': 'Sydney, Australia', 'Paris, France': 'Paris, France', 'Berlin, Germany': 'Berlin, Germany', 'Toronto, Canada': 'Toronto, Canada', 'São Paulo, Brazil': 'São Paulo, Brazil', 'Cape Town, South Africa': 'Cape Town, South Africa', 'Washington DC, USA': 'Washington DC, USA' }; for (const [name, query] of Object.entries(presets)) { const option = document.createElement('option'); option.value = query; option.textContent = name; presetSelect.appendChild(option); } modal.appendChild(presetSelect); // Save Button const saveButton = document.createElement('button'); saveButton.textContent = 'Save & Apply'; saveButton.style.width = '100%'; saveButton.style.padding = '10px'; saveButton.style.backgroundColor = '#007bff'; saveButton.style.color = '#fff'; saveButton.style.border = 'none'; saveButton.style.borderRadius = '4px'; saveButton.style.cursor = 'pointer'; saveButton.style.fontSize = '16px'; saveButton.style.transition = 'background-color 0.3s'; saveButton.addEventListener('mouseover', () => { saveButton.style.backgroundColor = '#0069d9'; }); saveButton.addEventListener('mouseout', () => { saveButton.style.backgroundColor = '#007bff'; }); modal.appendChild(saveButton); // Status Message const statusMsg = document.createElement('div'); statusMsg.id = 'spoofStatusMsg'; statusMsg.style.marginTop = '15px'; statusMsg.style.fontSize = '14px'; statusMsg.style.textAlign = 'center'; modal.appendChild(statusMsg); overlay.appendChild(modal); document.body.appendChild(overlay); return { overlay, modal, closeButton, enableCheckbox, locationInput, presetSelect, saveButton, statusMsg }; } // Initialize Modal and Event Listeners function initializeUI() { const { overlay, modal, closeButton, enableCheckbox, locationInput, presetSelect, saveButton, statusMsg } = createModal(); // Function to open modal function openModal() { overlay.style.display = 'flex'; } // Function to close modal function closeModal() { overlay.style.display = 'none'; } // Attach event listeners to close modal closeButton.addEventListener('click', closeModal); overlay.addEventListener('click', (e) => { if (e.target === overlay) { closeModal(); } }); // Handle Preset Selection presetSelect.addEventListener('change', function () { const selected = presetSelect.value; if (selected) { locationInput.value = selected; } }); // Handle Save Button Click saveButton.addEventListener('click', async function () { const enabled = enableCheckbox.checked; const locationName = locationInput.value.trim(); if (enabled && locationName === '') { statusMsg.textContent = 'Please enter a location name or select a preset.'; statusMsg.style.color = 'red'; return; } if (enabled) { statusMsg.textContent = 'Resolving location...'; statusMsg.style.color = '#ffc107'; // Amber try { const coords = await geocodeLocation(locationName); setStoredLocation({ enabled: true, locationName: locationName, latitude: coords.latitude, longitude: coords.longitude }); statusMsg.textContent = 'Location spoofed successfully!'; statusMsg.style.color = '#28a745'; // Green // Override Geolocation overrideGeolocation({ latitude: coords.latitude, longitude: coords.longitude }); // Optionally, reload the page to apply changes setTimeout(() => { window.location.reload(); }, 1500); } catch (error) { statusMsg.textContent = error.message; statusMsg.style.color = 'red'; } } else { setStoredLocation({ enabled: false, locationName: '', latitude: 37.7749, longitude: -122.4194 }); statusMsg.textContent = 'Location spoofing disabled.'; statusMsg.style.color = '#6c757d'; // Gray // Restore original Geolocation setTimeout(() => { window.location.reload(); }, 1000); } }); // Observe DOM changes to target the existing button const observer = new MutationObserver((mutations, obs) => { const targetButton = document.querySelector('i[data-testid="travelModeIcon"]'); if (targetButton) { const parentButton = targetButton.closest('.lower-map-icon.travel-on-map'); if (parentButton) { // Prevent multiple initializations if (!parentButton.dataset.spoofInitialized) { parentButton.dataset.spoofInitialized = 'true'; // Modify button appearance to indicate spoofing functionality targetButton.classList.remove('fa-plane'); targetButton.classList.add('fa-map-marker-alt'); // Change icon to map marker parentButton.title = 'Enable Location Spoofing'; parentButton.setAttribute('aria-label', 'Enable Location Spoofing'); // Attach click event to open spoofing modal parentButton.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); openModal(); }); // Optionally, disable original functionality if needed // For example, remove existing click listeners // This depends on how Sniffies implements the original button } } // Once the button is found and initialized, disconnect the observer if (targetButton) { obs.disconnect(); } } }); // Start observing the body for added nodes observer.observe(document.body, { childList: true, subtree: true }); // Initialize UI with stored values const storedLocation = getStoredLocation(); if (storedLocation.enabled) { overrideGeolocation({ latitude: storedLocation.latitude, longitude: storedLocation.longitude }); } } // Presets for checking preset selection const presets = { 'Select a preset...': '', 'New York City, NY, USA': 'New York City, NY, USA', 'Los Angeles, CA, USA': 'Los Angeles, CA, USA', 'London, UK': 'London, UK', 'Tokyo, Japan': 'Tokyo, Japan', 'Sydney, Australia': 'Sydney, Australia', 'Paris, France': 'Paris, France', 'Berlin, Germany': 'Berlin, Germany', 'Toronto, Canada': 'Toronto, Canada', 'São Paulo, Brazil': 'São Paulo, Brazil', 'Cape Town, South Africa': 'Cape Town, South Africa', 'Washington DC, USA': 'Washington DC, USA' }; // Initialize the script function init() { initializeUI(); } // Wait for the DOM to load window.addEventListener('load', init); })();