您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Tag your street views by date and address
当前为
- // ==UserScript==
- // @name Geoguessr Map-Making Auto-Tag
- // @namespace http://tampermonkey.net/
- // @version 2.5
- // @description Tag your street views by date and address
- // @author KaKa
- // @match https://map-making.app/maps/*
- // @grant GM_setValue
- // @grant GM_getValue
- // @grant GM_setClipboard
- // @license MIT
- // ==/UserScript==
- (function() {
- 'use strict';
- async function runScript(tags) {
- let api_key = GM_getValue("api_key");
- if (!api_key) {
- api_key = prompt("Please enter your Google API key");
- GM_setValue("api_key", api_key);
- }
- const option = confirm('Do you want to input data from the clipboard? If you click "Cancel", you will need to upload a JSON file.');
- let data;
- if (option) {
- const text = await navigator.clipboard.readText();
- try {
- data = JSON.parse(text);
- } catch (error) {
- alert('The input JSON data is invalid or incorrectly formatted.');
- return;
- }
- } else {
- const input = document.createElement('input');
- input.type = 'file';
- document.body.appendChild(input);
- data = await new Promise((resolve) => {
- input.addEventListener('change', async () => {
- const file = input.files[0];
- const reader = new FileReader();
- reader.onload = (event) => {
- try {
- const result = JSON.parse(event.target.result);
- resolve(result);
- document.body.removeChild(input);
- } catch (error) {
- alert('The input JSON data is invalid or incorrectly formatted.');
- }
- };
- reader.readAsText(file);
- });
- input.click();
- });
- }
- const newData = [];
- async function getMetaData(url) {
- try {
- const response = await fetch(url);
- const data = await response.json();
- if (data.status == "OK") {
- let year = 'nodate';
- const match = data.date.match(/\d{4}/);
- if (match) {
- year = match[0];
- }
- let panoType = 'unofficial';
- if (data.copyright.includes('Google')) {
- panoType = 'official';
- }
- return [year, panoType];
- } else {
- return ["nodata","nodata"];
- }
- } catch (error) {
- console.error(`Error fetching metadata: ${error}`);
- }
- }
- function get_Meta(id) {
- const url = `https://maps.googleapis.com/maps/api/streetview/metadata?pano=${id}&key=${api_key}`;
- return getMetaData(url);
- }
- function search_Meta(lat, lng) {
- const url = `https://maps.googleapis.com/maps/api/streetview/metadata?location=${lat},${lng}&key=${api_key}`;
- return getMetaData(url);
- }
- let last_token = null;
- let last_token_expiry = 0;
- async function get_Token(api_key) {
- let current_time = Date.now() / 1000;
- if (last_token && last_token_expiry > current_time) {
- return last_token;
- }
- let url = `https://tile.googleapis.com/v1/createSession?key=${api_key}`;
- let headers = {'Content-Type': 'application/json'};
- let data = { "mapType": "streetview",
- "language": "en-US",
- "region": "US"};
- let response = await fetch(url, {method: 'POST', headers: headers, body: JSON.stringify(data)});
- if (response.status == 200) {
- let token = (await response.json()).session;
- last_token_expiry = current_time + 5 * 60;
- last_token = token;
- return token;
- } else {
- alert(`Error: ${response.status}, ${await response.text()}`);
- }
- }
- async function getAddress(url) {
- let country = 'nodata';
- let subdivision = 'nodata';
- let locality = 'nodata';
- try {
- let response = await fetch(url);
- if (response.status == 200) {
- let data = await response.json();
- for (let add of data.addressComponents) {
- if (add.types.includes('country')) {
- country = add.longName;
- }
- if (add.types.includes('administrative_area_level_1')) {
- subdivision = add.longName;
- }
- if (add.types.includes('locality')) {
- locality = add.longName;
- }
- }
- }
- } catch (error) {
- console.log(error);
- }
- return [country, subdivision, locality];
- }
- async function get_add(id) {
- let tk = await get_Token(api_key);
- let url = `https://tile.googleapis.com/v1/streetview/metadata?session=${tk}&key=${api_key}&panoId=${id}`;
- return getAddress(url);
- }
- async function search_add(lat,lng) {
- let tk = await get_Token(api_key);
- let url = `https://tile.googleapis.com/v1/streetview/metadata?session=${tk}&key=${api_key}&lat=${lat}&lng=${lng}&radius=50`;
- return getAddress(url);
- }
- var CHUNK_SIZE = 1000;
- var promises = [];
- async function processCoord(coord, tags, svData) {
- if (!coord.extra) {
- coord.extra = {};
- }
- if (!coord.extra.tags) {
- coord.extra.tags = [];
- }
- var meta;
- var address;
- if (coord.panoId && (tags.includes('year') || tags.includes('type'))) {
- meta = await get_Meta(coord.panoId);
- } else if (tags.includes('year') || tags.includes('type')) {
- meta = await search_Meta(coord.lat, coord.lng);
- }
- if (coord.panoId && (tags.includes('country') || tags.includes('subdivision') || tags.includes('locality'))) {
- address= await get_add(coord.panoId);
- } else if (tags.includes('country') || tags.includes('subdivision') || tags.includes('locality')) {
- address= await search_add(coord.lat, coord.lng);
- }
- if (meta && meta.length >= 2) {
- var year_tag = meta[0];
- var type_tag = meta[1];
- if (tags.includes('year')) coord.extra.tags.push(year_tag);
- if (tags.includes('type')) coord.extra.tags.push(type_tag);
- }
- if (address && address.length >= 3) {
- var country_tag=address[0]
- var subdivision_tag=address[1]
- var locality_tag=address[2]
- if (tags.includes('country')) coord.extra.tags.push(country_tag);
- if (tags.includes('subdivision')) coord.extra.tags.push(subdivision_tag);
- if (tags.includes('locality')) coord.extra.tags.push(locality_tag);
- }
- if (svData) {
- let trekkerTag = (svData.hasOwnProperty('dn') && svData.dn) ? 'trekker' : null;
- if (tags.includes('type') && trekkerTag) {
- coord.extra.tags.push(trekkerTag);
- }
- }
- newData.push(coord);
- }
- async function processChunk(chunk, tags) {
- var service = new google.maps.StreetViewService();
- var promises = chunk.map(async coord => {
- let panoId = coord.panoId;
- let latLng = {lat: coord.lat, lng: coord.lng};
- let svData;
- if ((panoId || latLng) && tags.includes('type')) {
- svData = await getSVData(service, panoId ? {pano: panoId} : {location: latLng, radius: 50});
- }
- await processCoord(coord, tags, svData)
- });
- await Promise.all(promises);
- }
- function getSVData(service, options) {
- return new Promise(resolve => service.getPanorama(options, (data, status) => {
- resolve(data);
- }));
- }
- async function processData(tags) {
- try {
- for (let i = 0; i < data.customCoordinates.length; i += CHUNK_SIZE) {
- let chunk = data.customCoordinates.slice(i, i + CHUNK_SIZE);
- await processChunk(chunk, tags);
- }
- GM_setClipboard(JSON.stringify(newData));
- alert("New JSON data has been copied to the clipboard!");
- } catch (error) {
- alert("Invalid JSON data");
- console.error('Error processing JSON data:', error);
- }
- }
- processData(tags);
- }
- var mainButtonContainer = document.createElement('div');
- mainButtonContainer.style.position = 'fixed';
- mainButtonContainer.style.right = '20px';
- mainButtonContainer.style.bottom = '20px';
- document.body.appendChild(mainButtonContainer);
- var buttonContainer = document.createElement('div');
- buttonContainer.style.position = 'fixed';
- buttonContainer.style.right = '20px';
- buttonContainer.style.bottom = '60px';
- document.body.appendChild(buttonContainer);
- function createButton(text, tags) {
- var button = document.createElement('button');
- button.textContent = text;
- button.style.display = 'none';
- button.addEventListener('click', async function() { await runScript(tags); });
- buttonContainer.appendChild(button);
- return button;
- }
- var mainButton = document.createElement('button');
- mainButton.textContent = 'Auto-Tag';
- mainButton.addEventListener('click', function() {
- for (var i = 0; i < buttonContainer.children.length; i++) {
- var button = buttonContainer.children[i];
- if (button.style.display === 'none') {
- button.style.display = 'block';
- } else {
- button.style.display = 'none';
- }
- }
- });
- mainButtonContainer.appendChild(mainButton);
- createButton('Tag by Year', ['year']);
- createButton('Tag by Type',[ 'type']);
- createButton('Tag by Country', ['country']);
- createButton('Tag by Subdivision', ['subdivision']);
- createButton('Tag by Locality', ['locality']);
- })();