forked from MapComplete/MapComplete
		
	Feat: add script to upload images to panoramax and remove 'imgur'-links
This commit is contained in:
		
							parent
							
								
									c1c2390694
								
							
						
					
					
						commit
						4233bd7618
					
				
					 5 changed files with 467 additions and 94 deletions
				
			
		
							
								
								
									
										362
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										362
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							|  | @ -65,7 +65,7 @@ | |||
|         "opening_hours": "^3.6.0", | ||||
|         "osm-auth": "^2.5.0", | ||||
|         "osmtogeojson": "^3.0.0-beta.5", | ||||
|         "panoramax-js": "^0.3.9", | ||||
|         "panoramax-js": "^0.3.10", | ||||
|         "panzoom": "^9.4.3", | ||||
|         "papaparse": "^5.3.1", | ||||
|         "pg": "^8.11.3", | ||||
|  | @ -4727,6 +4727,44 @@ | |||
|         "node-fetch": "^2.6.12" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@jeswr/prefixcc/node_modules/node-fetch": { | ||||
|       "version": "2.7.0", | ||||
|       "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", | ||||
|       "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", | ||||
|       "dependencies": { | ||||
|         "whatwg-url": "^5.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "4.x || >=6.0.0" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "encoding": "^0.1.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "encoding": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@jeswr/prefixcc/node_modules/tr46": { | ||||
|       "version": "0.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", | ||||
|       "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" | ||||
|     }, | ||||
|     "node_modules/@jeswr/prefixcc/node_modules/webidl-conversions": { | ||||
|       "version": "3.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", | ||||
|       "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" | ||||
|     }, | ||||
|     "node_modules/@jeswr/prefixcc/node_modules/whatwg-url": { | ||||
|       "version": "5.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", | ||||
|       "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", | ||||
|       "dependencies": { | ||||
|         "tr46": "~0.0.3", | ||||
|         "webidl-conversions": "^3.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@jridgewell/gen-mapping": { | ||||
|       "version": "0.1.1", | ||||
|       "dev": true, | ||||
|  | @ -8707,6 +8745,44 @@ | |||
|         "node-fetch": "^2.6.12" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/cross-fetch/node_modules/node-fetch": { | ||||
|       "version": "2.7.0", | ||||
|       "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", | ||||
|       "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", | ||||
|       "dependencies": { | ||||
|         "whatwg-url": "^5.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "4.x || >=6.0.0" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "encoding": "^0.1.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "encoding": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/cross-fetch/node_modules/tr46": { | ||||
|       "version": "0.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", | ||||
|       "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" | ||||
|     }, | ||||
|     "node_modules/cross-fetch/node_modules/webidl-conversions": { | ||||
|       "version": "3.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", | ||||
|       "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" | ||||
|     }, | ||||
|     "node_modules/cross-fetch/node_modules/whatwg-url": { | ||||
|       "version": "5.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", | ||||
|       "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", | ||||
|       "dependencies": { | ||||
|         "tr46": "~0.0.3", | ||||
|         "webidl-conversions": "^3.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/cross-spawn": { | ||||
|       "version": "7.0.3", | ||||
|       "dev": true, | ||||
|  | @ -10335,6 +10411,44 @@ | |||
|         "node-fetch": "^2.6.12" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/fetch-sparql-endpoint/node_modules/node-fetch": { | ||||
|       "version": "2.7.0", | ||||
|       "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", | ||||
|       "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", | ||||
|       "dependencies": { | ||||
|         "whatwg-url": "^5.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "4.x || >=6.0.0" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "encoding": "^0.1.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "encoding": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/fetch-sparql-endpoint/node_modules/tr46": { | ||||
|       "version": "0.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", | ||||
|       "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" | ||||
|     }, | ||||
|     "node_modules/fetch-sparql-endpoint/node_modules/webidl-conversions": { | ||||
|       "version": "3.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", | ||||
|       "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" | ||||
|     }, | ||||
|     "node_modules/fetch-sparql-endpoint/node_modules/whatwg-url": { | ||||
|       "version": "5.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", | ||||
|       "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", | ||||
|       "dependencies": { | ||||
|         "tr46": "~0.0.3", | ||||
|         "webidl-conversions": "^3.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/fflate": { | ||||
|       "version": "0.4.8", | ||||
|       "license": "MIT" | ||||
|  | @ -12030,6 +12144,44 @@ | |||
|         "node-fetch": "^2.6.12" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/jsonld-context-parser/node_modules/node-fetch": { | ||||
|       "version": "2.7.0", | ||||
|       "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", | ||||
|       "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", | ||||
|       "dependencies": { | ||||
|         "whatwg-url": "^5.0.0" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "4.x || >=6.0.0" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "encoding": "^0.1.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "encoding": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/jsonld-context-parser/node_modules/tr46": { | ||||
|       "version": "0.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", | ||||
|       "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" | ||||
|     }, | ||||
|     "node_modules/jsonld-context-parser/node_modules/webidl-conversions": { | ||||
|       "version": "3.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", | ||||
|       "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" | ||||
|     }, | ||||
|     "node_modules/jsonld-context-parser/node_modules/whatwg-url": { | ||||
|       "version": "5.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", | ||||
|       "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", | ||||
|       "dependencies": { | ||||
|         "tr46": "~0.0.3", | ||||
|         "webidl-conversions": "^3.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/jsonld-request": { | ||||
|       "version": "2.0.1", | ||||
|       "license": "BSD-3-Clause", | ||||
|  | @ -12256,22 +12408,6 @@ | |||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/ky-universal/node_modules/node-fetch": { | ||||
|       "version": "3.3.2", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "data-uri-to-buffer": "^4.0.0", | ||||
|         "fetch-blob": "^3.1.4", | ||||
|         "formdata-polyfill": "^4.0.10" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "^12.20.0 || ^14.13.1 || >=16.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/node-fetch" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/latlon2country": { | ||||
|       "version": "1.2.6", | ||||
|       "license": "GPL-3.0-or-later", | ||||
|  | @ -13300,37 +13436,20 @@ | |||
|       } | ||||
|     }, | ||||
|     "node_modules/node-fetch": { | ||||
|       "version": "2.7.0", | ||||
|       "license": "MIT", | ||||
|       "version": "3.3.2", | ||||
|       "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", | ||||
|       "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", | ||||
|       "dependencies": { | ||||
|         "whatwg-url": "^5.0.0" | ||||
|         "data-uri-to-buffer": "^4.0.0", | ||||
|         "fetch-blob": "^3.1.4", | ||||
|         "formdata-polyfill": "^4.0.10" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": "4.x || >=6.0.0" | ||||
|         "node": "^12.20.0 || ^14.13.1 || >=16.0.0" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "encoding": "^0.1.0" | ||||
|       }, | ||||
|       "peerDependenciesMeta": { | ||||
|         "encoding": { | ||||
|           "optional": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/node-fetch/node_modules/tr46": { | ||||
|       "version": "0.0.3", | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/node-fetch/node_modules/webidl-conversions": { | ||||
|       "version": "3.0.1", | ||||
|       "license": "BSD-2-Clause" | ||||
|     }, | ||||
|     "node_modules/node-fetch/node_modules/whatwg-url": { | ||||
|       "version": "5.0.0", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "tr46": "~0.0.3", | ||||
|         "webidl-conversions": "^3.0.0" | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/node-fetch" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/node-html-parser": { | ||||
|  | @ -16009,9 +16128,9 @@ | |||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/panoramax-js": { | ||||
|       "version": "0.3.9", | ||||
|       "resolved": "https://registry.npmjs.org/panoramax-js/-/panoramax-js-0.3.9.tgz", | ||||
|       "integrity": "sha512-CCXSmqwJxZYTxkru1LBAm2O+O/nnm3lwPX/8kLxYCIAZKQSFJsl1DoTkDqm/MLoo/dJOp3LmIVuK7nTM2NRgwA==", | ||||
|       "version": "0.3.10", | ||||
|       "resolved": "https://registry.npmjs.org/panoramax-js/-/panoramax-js-0.3.10.tgz", | ||||
|       "integrity": "sha512-ZI9gH98FB3RFWYy69Evsv6vWA+crwhlsdiY8KiZgXAdVYnW7C1YzuQg/Mls546ZHh8/WHj1GMwfe8w5UU6OcFg==", | ||||
|       "dependencies": { | ||||
|         "@ogcapi-js/features": "^1.1.1", | ||||
|         "@ogcapi-js/shared": "^1.1.1", | ||||
|  | @ -24630,6 +24749,33 @@ | |||
|           "requires": { | ||||
|             "node-fetch": "^2.6.12" | ||||
|           } | ||||
|         }, | ||||
|         "node-fetch": { | ||||
|           "version": "2.7.0", | ||||
|           "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", | ||||
|           "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", | ||||
|           "requires": { | ||||
|             "whatwg-url": "^5.0.0" | ||||
|           } | ||||
|         }, | ||||
|         "tr46": { | ||||
|           "version": "0.0.3", | ||||
|           "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", | ||||
|           "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" | ||||
|         }, | ||||
|         "webidl-conversions": { | ||||
|           "version": "3.0.1", | ||||
|           "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", | ||||
|           "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" | ||||
|         }, | ||||
|         "whatwg-url": { | ||||
|           "version": "5.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", | ||||
|           "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", | ||||
|           "requires": { | ||||
|             "tr46": "~0.0.3", | ||||
|             "webidl-conversions": "^3.0.0" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|  | @ -27338,6 +27484,35 @@ | |||
|       "version": "4.0.0", | ||||
|       "requires": { | ||||
|         "node-fetch": "^2.6.12" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "node-fetch": { | ||||
|           "version": "2.7.0", | ||||
|           "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", | ||||
|           "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", | ||||
|           "requires": { | ||||
|             "whatwg-url": "^5.0.0" | ||||
|           } | ||||
|         }, | ||||
|         "tr46": { | ||||
|           "version": "0.0.3", | ||||
|           "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", | ||||
|           "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" | ||||
|         }, | ||||
|         "webidl-conversions": { | ||||
|           "version": "3.0.1", | ||||
|           "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", | ||||
|           "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" | ||||
|         }, | ||||
|         "whatwg-url": { | ||||
|           "version": "5.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", | ||||
|           "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", | ||||
|           "requires": { | ||||
|             "tr46": "~0.0.3", | ||||
|             "webidl-conversions": "^3.0.0" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "cross-spawn": { | ||||
|  | @ -28401,6 +28576,33 @@ | |||
|           "requires": { | ||||
|             "node-fetch": "^2.6.12" | ||||
|           } | ||||
|         }, | ||||
|         "node-fetch": { | ||||
|           "version": "2.7.0", | ||||
|           "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", | ||||
|           "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", | ||||
|           "requires": { | ||||
|             "whatwg-url": "^5.0.0" | ||||
|           } | ||||
|         }, | ||||
|         "tr46": { | ||||
|           "version": "0.0.3", | ||||
|           "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", | ||||
|           "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" | ||||
|         }, | ||||
|         "webidl-conversions": { | ||||
|           "version": "3.0.1", | ||||
|           "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", | ||||
|           "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" | ||||
|         }, | ||||
|         "whatwg-url": { | ||||
|           "version": "5.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", | ||||
|           "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", | ||||
|           "requires": { | ||||
|             "tr46": "~0.0.3", | ||||
|             "webidl-conversions": "^3.0.0" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|  | @ -29513,6 +29715,33 @@ | |||
|           "requires": { | ||||
|             "node-fetch": "^2.6.12" | ||||
|           } | ||||
|         }, | ||||
|         "node-fetch": { | ||||
|           "version": "2.7.0", | ||||
|           "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", | ||||
|           "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", | ||||
|           "requires": { | ||||
|             "whatwg-url": "^5.0.0" | ||||
|           } | ||||
|         }, | ||||
|         "tr46": { | ||||
|           "version": "0.0.3", | ||||
|           "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", | ||||
|           "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" | ||||
|         }, | ||||
|         "webidl-conversions": { | ||||
|           "version": "3.0.1", | ||||
|           "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", | ||||
|           "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" | ||||
|         }, | ||||
|         "whatwg-url": { | ||||
|           "version": "5.0.0", | ||||
|           "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", | ||||
|           "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", | ||||
|           "requires": { | ||||
|             "tr46": "~0.0.3", | ||||
|             "webidl-conversions": "^3.0.0" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|  | @ -29659,16 +29888,6 @@ | |||
|       "requires": { | ||||
|         "abort-controller": "^3.0.0", | ||||
|         "node-fetch": "^3.2.10" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "node-fetch": { | ||||
|           "version": "3.3.2", | ||||
|           "requires": { | ||||
|             "data-uri-to-buffer": "^4.0.0", | ||||
|             "fetch-blob": "^3.1.4", | ||||
|             "formdata-polyfill": "^4.0.10" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "latlon2country": { | ||||
|  | @ -30370,24 +30589,13 @@ | |||
|       "version": "1.0.0" | ||||
|     }, | ||||
|     "node-fetch": { | ||||
|       "version": "2.7.0", | ||||
|       "version": "3.3.2", | ||||
|       "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", | ||||
|       "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", | ||||
|       "requires": { | ||||
|         "whatwg-url": "^5.0.0" | ||||
|       }, | ||||
|       "dependencies": { | ||||
|         "tr46": { | ||||
|           "version": "0.0.3" | ||||
|         }, | ||||
|         "webidl-conversions": { | ||||
|           "version": "3.0.1" | ||||
|         }, | ||||
|         "whatwg-url": { | ||||
|           "version": "5.0.0", | ||||
|           "requires": { | ||||
|             "tr46": "~0.0.3", | ||||
|             "webidl-conversions": "^3.0.0" | ||||
|           } | ||||
|         } | ||||
|         "data-uri-to-buffer": "^4.0.0", | ||||
|         "fetch-blob": "^3.1.4", | ||||
|         "formdata-polyfill": "^4.0.10" | ||||
|       } | ||||
|     }, | ||||
|     "node-html-parser": { | ||||
|  | @ -32104,9 +32312,9 @@ | |||
|       "version": "1.0.0" | ||||
|     }, | ||||
|     "panoramax-js": { | ||||
|       "version": "0.3.9", | ||||
|       "resolved": "https://registry.npmjs.org/panoramax-js/-/panoramax-js-0.3.9.tgz", | ||||
|       "integrity": "sha512-CCXSmqwJxZYTxkru1LBAm2O+O/nnm3lwPX/8kLxYCIAZKQSFJsl1DoTkDqm/MLoo/dJOp3LmIVuK7nTM2NRgwA==", | ||||
|       "version": "0.3.10", | ||||
|       "resolved": "https://registry.npmjs.org/panoramax-js/-/panoramax-js-0.3.10.tgz", | ||||
|       "integrity": "sha512-ZI9gH98FB3RFWYy69Evsv6vWA+crwhlsdiY8KiZgXAdVYnW7C1YzuQg/Mls546ZHh8/WHj1GMwfe8w5UU6OcFg==", | ||||
|       "requires": { | ||||
|         "@ogcapi-js/features": "^1.1.1", | ||||
|         "@ogcapi-js/shared": "^1.1.1", | ||||
|  |  | |||
|  | @ -138,7 +138,8 @@ | |||
|     "generate:buildDbScript": "vite-node scripts/osm2pgsql/generateBuildDbScript.ts", | ||||
|     "generate:summaryCache": "vite-node scripts/generateSummaryTileCache.ts", | ||||
|     "create:database": "vite-node scripts/osm2pgsql/createNewDatabase.ts", | ||||
|     "delete:database:old": "vite-node scripts/osm2pgsql/deleteOldDbs.ts" | ||||
|     "delete:database:old": "vite-node scripts/osm2pgsql/deleteOldDbs.ts", | ||||
|     "upload:panoramax": "vite-node scripts/ImgurToPanoramax.ts" | ||||
|   }, | ||||
|   "keywords": [ | ||||
|     "OpenStreetMap", | ||||
|  | @ -209,7 +210,7 @@ | |||
|     "opening_hours": "^3.6.0", | ||||
|     "osm-auth": "^2.5.0", | ||||
|     "osmtogeojson": "^3.0.0-beta.5", | ||||
|     "panoramax-js": "^0.3.9", | ||||
|     "panoramax-js": "^0.3.10", | ||||
|     "panzoom": "^9.4.3", | ||||
|     "papaparse": "^5.3.1", | ||||
|     "pg": "^8.11.3", | ||||
|  |  | |||
							
								
								
									
										156
									
								
								scripts/ImgurToPanoramax.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								scripts/ImgurToPanoramax.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,156 @@ | |||
| import Script from "./Script" | ||||
| import { Overpass } from "../src/Logic/Osm/Overpass" | ||||
| import { RegexTag } from "../src/Logic/Tags/RegexTag" | ||||
| import Constants from "../src/Models/Constants" | ||||
| import { BBox } from "../src/Logic/BBox" | ||||
| import { existsSync, readFileSync, writeFileSync } from "fs" | ||||
| import { PanoramaxUploader } from "../src/Logic/ImageProviders/Panoramax" | ||||
| import { Feature } from "geojson" | ||||
| import { LicenseInfo } from "../src/Logic/ImageProviders/LicenseInfo" | ||||
| import { GeoOperations } from "../src/Logic/GeoOperations" | ||||
| import { Tag } from "../src/Logic/Tags/Tag" | ||||
| import { Utils } from "../src/Utils" | ||||
| import ChangeTagAction from "../src/Logic/Osm/Actions/ChangeTagAction" | ||||
| import { And } from "../src/Logic/Tags/And" | ||||
| import { Changes } from "../src/Logic/Osm/Changes" | ||||
| import { ChangeDescription } from "../src/Logic/Osm/Actions/ChangeDescription" | ||||
| import OsmObjectDownloader from "../src/Logic/Osm/OsmObjectDownloader" | ||||
| import { OsmObject } from "../src/Logic/Osm/OsmObject" | ||||
| import { createReadStream } from "node:fs" | ||||
| import { File } from 'buffer'; | ||||
| import { open } from 'node:fs/promises'; | ||||
| import { UploadableTag } from "../src/Logic/Tags/TagTypes" | ||||
| 
 | ||||
| 
 | ||||
| export class ImgurToPanoramax extends Script { | ||||
| 
 | ||||
|     private readonly panoramax = new PanoramaxUploader(Constants.panoramax.url, Constants.panoramax.token) | ||||
| 
 | ||||
|     private _imageDirectory: string | ||||
|     private _licenseDirectory: string | ||||
| 
 | ||||
|     private readonly sequenceIds = { | ||||
|         test: "7f34cf53-27ff-46c9-ac22-78511fa8457a", | ||||
|         cc0: "f0d6f78a-ff95-4db1-8494-6eb44a17bb37", | ||||
|         ccby: "288a8052-b475-422c-811a-4f6f1a00015e", | ||||
|         ccbysa: "f3d02893-b4c1-4cd6-8b27-e27ab57eb59a", | ||||
|     } as const | ||||
| 
 | ||||
| 
 | ||||
|     constructor() { | ||||
|         super( | ||||
|             "Queries OSM for 'imgur'-images, uploads them to Panoramax and creates a changeset to update OSM", | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     async uploadImage(key: string, feat: Feature, sequences: ({ | ||||
|         id: string; | ||||
|         "stats:items": { count: number } | ||||
|     })[]): Promise<UploadableTag | undefined> { | ||||
|         const v = feat.properties[key] | ||||
|         if (!v) { | ||||
|             return undefined | ||||
|         } | ||||
|         const imageHash = v.split("/").at(-1).split(".").at(0) | ||||
|         let path: string = undefined | ||||
|         if (existsSync(this._imageDirectory + "/" + imageHash + ".jpg")) { | ||||
|             path = this._imageDirectory + "/" + imageHash + ".jpg" | ||||
|         } else if (existsSync(this._imageDirectory + "/" + imageHash + ".jpeg")) { | ||||
|             path = this._imageDirectory + "/" + imageHash + ".jpeg" | ||||
|         } | ||||
|         if (!path) { | ||||
|             return undefined | ||||
|         } | ||||
|         const licensePath = this._licenseDirectory + "/" + v.replaceAll(/[^a-zA-Z0-9]/g, "_") + ".json" | ||||
|         if (!existsSync(licensePath)) { | ||||
|             return undefined | ||||
|         } | ||||
|         const licenseText: LicenseInfo = JSON.parse(readFileSync(licensePath, "utf8")) | ||||
|         if (!licenseText.licenseShortName) { | ||||
|             console.log("No license found for", path, licenseText) | ||||
|             return undefined | ||||
|         } | ||||
|         const license = licenseText.licenseShortName.toLowerCase().split(" ")[0].replace(/-/g, "") | ||||
|         const sequence = this.sequenceIds[license] | ||||
|         const author = licenseText.artist | ||||
| 
 | ||||
| 
 | ||||
|         const handle = await open(path); | ||||
| 
 | ||||
|         const stat = await handle.stat(); | ||||
| 
 | ||||
|         class MyFile extends File { | ||||
|             // we should set correct size
 | ||||
|             // otherwise we will encounter UND_ERR_REQ_CONTENT_LENGTH_MISMATCH
 | ||||
|             size = stat.size; | ||||
|             stream = undefined | ||||
|         } | ||||
| 
 | ||||
|         const file = new MyFile([], path) | ||||
| 
 | ||||
|         file.stream = function() { | ||||
|             return handle.readableWebStream(); | ||||
|         }; | ||||
| 
 | ||||
|         console.log("Uploading", imageHash, sequence) | ||||
|         const result = await this.panoramax.uploadImage(<any> file, GeoOperations.centerpointCoordinates(feat), author, true, sequence) | ||||
|         await handle.close() | ||||
|         return new And([new Tag(key.replace("image", result.key), result.value), | ||||
|             new Tag(key,"")]) | ||||
|     } | ||||
| 
 | ||||
|     async main(args: string[]): Promise<void> { | ||||
|         this._imageDirectory = args[0] ?? "/home/pietervdvn/data/imgur-image-backup" | ||||
|         this._licenseDirectory = args[1] ?? "/home/pietervdvn/git/MapComplete-data/ImageLicenseInfo" | ||||
| 
 | ||||
|         const bounds = new BBox([[3.6984301050112833, 51.06715570450848], [3.7434328399847914, 51.039379568816145]]) | ||||
|         const maxcount = 100 | ||||
|         const filter = new RegexTag("image", /^https:\/\/i.imgur.com\/.*/) | ||||
|         const overpass = new Overpass(filter, [], Constants.defaultOverpassUrls[0]) | ||||
|         const features = (await overpass.queryGeoJson(bounds))[0].features | ||||
| 
 | ||||
|         let converted = 0 | ||||
| 
 | ||||
|         const pano = this.panoramax.panoramax | ||||
|         const sequences = await pano.mySequences() | ||||
|         const changes: ChangeDescription[] = [] | ||||
|         do { | ||||
|             const f = features.shift() | ||||
|             if (!f) { | ||||
|                 break | ||||
|             } | ||||
| 
 | ||||
|             const changedTags: (UploadableTag | undefined)[] = [] | ||||
|             for (const k of ["image", "image:menu", "image:streetsign"]) { | ||||
|                 changedTags.push(await this.uploadImage(k, f, sequences)) | ||||
|                 for (let i = 0; i < 20; i++) { | ||||
|                     changedTags.push( | ||||
|                         await this.uploadImage(k + ":" + i, f, sequences), | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|             const action = new ChangeTagAction(f.properties.id, new And(Utils.NoNull(changedTags)), | ||||
|                 f.properties, { | ||||
|                     theme: "image-mover", | ||||
|                     changeType: "link-image", | ||||
|                 }, | ||||
|             ) | ||||
|             changes.push(...await action.CreateChangeDescriptions()) | ||||
|             converted++ | ||||
|         } while (converted < maxcount) | ||||
| 
 | ||||
|         const modif: string[] = Utils.Dedup(changes.map(ch => ch.type + "/" + ch.id)) | ||||
|         const modifiedObjectsFresh = | ||||
|           <OsmObject[]>  (await Promise.all(modif.map(id => new OsmObjectDownloader().DownloadObjectAsync(id)))) | ||||
|                 .filter(m => m !== "deleted") | ||||
|         const modifiedObjects = Changes.createChangesetObjectsStatic( | ||||
|             changes, | ||||
|             modifiedObjectsFresh,false, []) | ||||
|         const cs = Changes.buildChangesetXML("0", modifiedObjects) | ||||
|         writeFileSync("imgur_to_panoramax.osc", cs, "utf8") | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| new ImgurToPanoramax().run() | ||||
|  | @ -45,9 +45,8 @@ export default class PanoramaxImageProvider extends ImageProvider { | |||
|      * @private | ||||
|      */ | ||||
|     private async getInfoFromMapComplete(id: string): Promise<{ data: ImageData, url: string }> { | ||||
|         const sequence = "6e702976-580b-419c-8fb3-cf7bd364e6f8" // We always reuse this sequence
 | ||||
|         const url = `https://panoramax.mapcomplete.org/` | ||||
|         const data = await PanoramaxImageProvider.defaultPanoramax.imageInfo(id, sequence) | ||||
|         const data = await PanoramaxImageProvider.defaultPanoramax.imageInfo(id) | ||||
|         return { url, data } | ||||
|     } | ||||
| 
 | ||||
|  | @ -163,27 +162,24 @@ export default class PanoramaxImageProvider extends ImageProvider { | |||
| } | ||||
| 
 | ||||
| export class PanoramaxUploader implements ImageUploader { | ||||
|     private readonly _panoramax: AuthorizedPanoramax | ||||
|     public readonly panoramax: AuthorizedPanoramax | ||||
|     maxFileSizeInMegabytes = 100 * 1000 * 1000 // 100MB
 | ||||
| 
 | ||||
|     constructor(url: string, token: string) { | ||||
|         this._panoramax = new AuthorizedPanoramax(url, token) | ||||
|         this.panoramax = new AuthorizedPanoramax(url, token) | ||||
|     } | ||||
| 
 | ||||
|     async uploadImage(blob: File, currentGps: [number, number], author: string,  noblur: boolean = false): Promise<{ | ||||
|     async uploadImage(blob: File, currentGps: [number, number], author: string,  noblur: boolean = false, sequenceId?: string ): Promise<{ | ||||
|         key: string; | ||||
|         value: string; | ||||
|         absoluteUrl: string | ||||
|     }> { | ||||
|         // https://panoramax.openstreetmap.fr/api/docs/swagger#/
 | ||||
| 
 | ||||
|         let hasDate = false | ||||
|         let hasGPS = false | ||||
|         let [lon, lat] = currentGps | ||||
|         let datetime = new Date().toISOString() | ||||
|         try { | ||||
|             const tags = await ExifReader.load(blob) | ||||
|             hasDate  = tags?.DateTime !== undefined | ||||
|             const [[latD], [latM], [latS, latSDenom]]  =<[[number,number],[number,number],[number,number]]> tags?.GPSLatitude.value | ||||
|             const [[lonD], [lonM], [lonS, lonSDenom]]  =<[[number,number],[number,number],[number,number]]> tags?.GPSLongitude.value | ||||
|             lat = latD + latM / 60 + latS / (3600 * latSDenom) | ||||
|  | @ -198,12 +194,12 @@ export class PanoramaxUploader implements ImageUploader { | |||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         const p = this._panoramax | ||||
|         const defaultSequence = (await p.mySequences())[0] | ||||
|         console.log("Upload options are", lon, lat, datetime) | ||||
|         const p = this.panoramax | ||||
|         const defaultSequence: {id: string, "stats:items":{count:number}} = (await p.mySequences()).find(s => s.id === (sequenceId ?? "6e702976-580b-419c-8fb3-cf7bd364e6f8")) | ||||
|         console.log("Upload options are", lon, lat, datetime, blob) | ||||
|         const img = <ImageData>await p.addImage(blob, defaultSequence, { | ||||
|             lon: Utils.Round7(lon), | ||||
|             lat: Utils.Round7(lat), | ||||
|             lon, | ||||
|             lat, | ||||
|             datetime, | ||||
|             isBlurred: noblur, | ||||
|             exifOverride: { | ||||
|  |  | |||
|  | @ -297,6 +297,18 @@ export class Changes { | |||
|         newObjects: OsmObject[] | ||||
|         modifiedObjects: OsmObject[] | ||||
|         deletedObjects: OsmObject[] | ||||
|     }{ | ||||
|         return Changes.createChangesetObjectsStatic(changes, downloadedOsmObjects, ignoreNoCreate, this.previouslyCreated) | ||||
|     } | ||||
|     public static createChangesetObjectsStatic( | ||||
|         changes: ChangeDescription[], | ||||
|         downloadedOsmObjects: OsmObject[], | ||||
|         ignoreNoCreate: boolean = false, | ||||
|         previouslyCreated : OsmObject[] | ||||
|     ): { | ||||
|         newObjects: OsmObject[] | ||||
|         modifiedObjects: OsmObject[] | ||||
|         deletedObjects: OsmObject[] | ||||
|     } { | ||||
|         /** | ||||
|          * This is a rather complicated method which does a lot of stuff. | ||||
|  | @ -322,7 +334,7 @@ export class Changes { | |||
|             states.set(o.type + "/" + o.id, "unchanged") | ||||
|         } | ||||
| 
 | ||||
|         for (const o of this.previouslyCreated) { | ||||
|         for (const o of previouslyCreated) { | ||||
|             objects.set(o.type + "/" + o.id, o) | ||||
|             states.set(o.type + "/" + o.id, "unchanged") | ||||
|         } | ||||
|  | @ -372,7 +384,7 @@ export class Changes { | |||
|                     throw "Hmm? This is a bug" | ||||
|                 } | ||||
|                 objects.set(id, osmObj) | ||||
|                 this.previouslyCreated.push(osmObj) | ||||
|                 previouslyCreated.push(osmObj) | ||||
|             } | ||||
| 
 | ||||
|             const state = states.get(id) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue