您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Tag your street views by date and address
当前为
- // ==UserScript==
- // @name Geoguessr Map-Making Auto-Tag
- // @namespace http://tampermonkey.net/
- // @version 2.7
- // @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) {
- 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 UE(t, e) {
- try {
- const r = `https://maps.googleapis.com/$rpc/google.internal.maps.mapsjs.v1.MapsJsInternalService/${t}`;
- let payload=createPayload(t,e)
- const response = await fetch(r, {
- method: "POST",
- headers: {
- "content-type": "application/json+protobuf",
- "x-user-agent": "grpc-web-javascript/0.1"
- },
- body: payload,
- mode: "cors",
- credentials: "omit"
- });
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- } else {
- return await response.json();
- }
- } catch (error) {
- console.error(`There was a problem with the UE function: ${error.message}`);
- }
- }
- function createPayload(mode,coorData) {
- let payload;
- if (mode === 'GetMetadata') {
- payload = [["apiv3",null,null,null,"US",null,null,null,null,null,[[0]]],["en","US"],[[[2,coorData.panoId]]],[[1,2,3,4,8,6]]];
- } else if (mode === 'SingleImageSearch') {
- payload =[["apiv3",null,null,null,"US",null,null,null,null,null, [[0]]], [[null,null,coorData.lat,coorData.lng],50], [null,["en","US"],null,null,null,null,null,null,[2],null,[[[2,1,2],[3,1,2],[10,1,2]]]], [[1,2,3,4,8,6]]];
- } else {
- throw new Error("Invalid mode!");
- }
- return JSON.stringify(payload);
- }
- function getMetaData(svData) {
- let year = 'nodate';
- const match = svData.imageDate.match(/\d{4}/);
- if (match) {
- year = match[0];
- }
- let panoType = 'Unofficial';
- if (svData.copyright.includes('Google')) {
- panoType = 'Official';
- }
- let subdivision='nodata'
- let locality='nodata'
- if(svData.location.description){
- let parts = svData.location.description.split(',');
- if(parts.length > 1){
- subdivision = parts[parts.length-1].trim();
- locality = parts[parts.length-2].trim();
- } else {
- subdivision = svData.location.description;
- locality='nodata'
- }
- }
- return [year, panoType,subdivision,locality];
- }
- function getGeneration(svData,country) {
- if (svData && svData.tiles) {
- if (svData.tiles.worldSize.height === 1664) { // Gen 1
- return 'Gen1';
- } else if (svData.tiles.worldSize.height === 6656) { // Gen 2 or 3
- let lat;
- for (let key in svData.Sv) {
- lat = svData.Sv[key].lat;
- break;
- }
- const date = new Date(svData.imageDate);
- if ((country === 'BD' && (date >= new Date('2021-04'))) ||
- (country === 'EC' && (date >= new Date('2022-03'))) ||
- (country === 'FI' && (date >= new Date('2020-09'))) ||
- (country === 'IN' && (date >= new Date('2021-10'))) ||
- (country === 'LK' && (date >= new Date('2021-02'))) ||
- (country === 'NG' && (date >= new Date('2021-06'))) ||
- (country === 'US' && lat > 52 && (date >= new Date('2019-01')))) {
- return 'Shitcam';
- }
- if ((country === 'AU' )||(country === 'BR' )||(country === 'CA' )||(country === 'CL' )
- ||(country === 'JP' )||(country === 'GB' )||(country === 'IE' )||(country === 'NZ' )
- ||(country === 'MX' )||(country === 'RU' )||(country === 'US' )||(country === 'IT' )
- ||(country === 'DK' )||(country === 'GR' )||(country === 'RO' )||(country === 'PL' )
- ||(country === 'CZ' )||(country === 'CH' )||(country === 'SE' )||(country === 'FI' )
- ||(country === 'BE' )||(country === 'LU' )||(country === 'NL' )||(country === 'ZA' )
- ||(country === 'SG' )||(country === 'TW' )||(country === 'HK' )||(country === 'MO' )
- ||(country === 'MC' )||(country === 'SM' )||(country === 'AD' )||(country === 'IM' )
- ||(country === 'JE' ) ||(country === 'FR' )||(country === 'DE' )||(country === 'ES' )||
- (country === 'PT' )) {
- return 'Gen2or3';
- }
- return 'Gen3';
- } else if(svData.tiles.worldSize.height === 8192){
- return 'Gen4';
- }
- }
- return 'Unofficial';
- }
- var CHUNK_SIZE = 1000;
- var promises = [];
- async function processCoord(coord, tags, svData,ccData) {
- if (!coord.extra) {
- coord.extra = {};
- }
- if (!coord.extra.tags) {
- coord.extra.tags = [];
- }
- let meta=getMetaData(svData)
- let yearTag=meta[0]
- let typeTag=meta[1]
- let subdivisionTag=meta[2]
- let localityTag=meta[3]
- let countryTag
- let genTag
- let trekkerTag=svData.gn
- if(trekkerTag||typeTag === 'Unofficial'){
- subdivisionTag = 'nodata';
- localityTag = 'nodata'
- }
- if (ccData){try {
- countryTag = ccData[1][0][5][0][1][4];
- } catch (error) {
- try {
- countryTag = ccData[1][5][0][1][4];
- } catch (error) {
- countryTag='nodata'
- }
- }
- }
- genTag = getGeneration(svData,countryTag)
- if (tags.includes('generation')) {
- coord.extra.tags.push(genTag);
- }
- if (tags.includes('year')) {
- coord.extra.tags.push(yearTag);
- }
- if (tags.includes('type')) {
- coord.extra.tags.push(typeTag);
- }
- if (tags.includes('type')&& trekkerTag) {
- coord.extra.tags.push('trekker');
- }
- if (tags.includes('country')&& countryTag) {
- coord.extra.tags.push(countryTag);
- }
- if (tags.includes('subdivision')&& subdivisionTag) {
- coord.extra.tags.push(subdivisionTag);
- }
- if (tags.includes('locality')&& localityTag) {
- coord.extra.tags.push(localityTag);
- }
- 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;
- let ccData;
- if ((panoId || latLng)) {
- svData = await getSVData(service, panoId ? {pano: panoId} : {location: latLng, radius: 50});
- }
- if (!panoId && (tags.includes('generation')||('country'))) {
- ccData = await UE('SingleImageSearch', coord);
- } else if (panoId) {
- ccData = await UE('GetMetadata', coord);
- }
- await processCoord(coord, tags, svData,ccData)
- });
- await Promise.all(promises);
- }
- function getSVData(service, options, language) {
- 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';
- buttonContainer.style.display = 'none';
- document.body.appendChild(buttonContainer);
- function createCheckbox(text, tags) {
- var label = document.createElement('label');
- var checkbox = document.createElement('input');
- checkbox.type = 'checkbox';
- checkbox.value = text;
- checkbox.name = 'tags';
- checkbox.id = tags;
- label.appendChild(checkbox);
- label.appendChild(document.createTextNode(text));
- buttonContainer.appendChild(label);
- return checkbox;
- }
- var triggerButton = document.createElement('button');
- triggerButton.textContent = 'Star Tagging';
- triggerButton.addEventListener('click', function() {
- var checkboxes = document.getElementsByName('tags');
- var checkedTags = [];
- for (var i=0; i<checkboxes.length; i++) {
- if (checkboxes[i].checked) {
- checkedTags.push(checkboxes[i].id);
- }
- }
- runScript(checkedTags);
- });
- buttonContainer.appendChild(triggerButton);
- var mainButton = document.createElement('button');
- mainButton.textContent = 'Auto-Tag';
- mainButton.addEventListener('click', function() {
- if (buttonContainer.style.display === 'none') {
- buttonContainer.style.display = 'block';
- } else {
- buttonContainer.style.display = 'none';
- }
- });
- mainButtonContainer.appendChild(mainButton);
- createCheckbox('Year', 'year');
- createCheckbox('Type', 'type');
- createCheckbox('Country', 'country');
- createCheckbox('Subdivision', 'subdivision');
- createCheckbox('Locality', 'locality');
- createCheckbox('Generations', 'generation');
- })();