| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  | 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" | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  | import PanoramaxImageProvider, { PanoramaxUploader } from "../src/Logic/ImageProviders/Panoramax" | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  | 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" | 
					
						
							| 
									
										
										
										
											2024-10-24 00:56:24 +02:00
										 |  |  | import { File } from "buffer" | 
					
						
							|  |  |  | import { open } from "node:fs/promises" | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  | import { UploadableTag } from "../src/Logic/Tags/TagTypes" | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  | import { Imgur } from "../src/Logic/ImageProviders/Imgur" | 
					
						
							|  |  |  | import { Or } from "../src/Logic/Tags/Or" | 
					
						
							|  |  |  | import ScriptUtils from "./ScriptUtils" | 
					
						
							|  |  |  | import { ImmutableStore } from "../src/Logic/UIEventSource" | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | export class ImgurToPanoramax extends Script { | 
					
						
							| 
									
										
										
										
											2024-10-24 00:56:24 +02:00
										 |  |  |     private readonly panoramax = new PanoramaxUploader( | 
					
						
							|  |  |  |         Constants.panoramax.url, | 
					
						
							| 
									
										
										
										
											2024-10-29 01:12:18 +01:00
										 |  |  |         Constants.panoramax.token | 
					
						
							| 
									
										
										
										
											2024-10-24 00:56:24 +02:00
										 |  |  |     ) | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |     private licenseChecker = new PanoramaxImageProvider() | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |     private readonly alreadyUploaded: Record<string, string> = this.readAlreadyUploaded() | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |     private readonly alreadyUploadedInv: Record<string, string> = Utils.transposeMapSimple( | 
					
						
							|  |  |  |         this.alreadyUploaded | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |     private _imageDirectory: string | 
					
						
							|  |  |  |     private _licenseDirectory: string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private readonly sequenceIds = { | 
					
						
							|  |  |  |         test: "7f34cf53-27ff-46c9-ac22-78511fa8457a", | 
					
						
							| 
									
										
										
										
											2024-11-14 18:31:36 +01:00
										 |  |  |         cc0: "e9bcb8c0-8ade-4ac9-bc9f-cfa464221fd6", // "1de6f4a1-73ac-4c75-ab7f-2a2aabddf50a", // "f0d6f78a-ff95-4db1-8494-6eb44a17bb37",
 | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |         ccby: "288a8052-b475-422c-811a-4f6f1a00015e", | 
					
						
							| 
									
										
										
										
											2024-11-28 12:00:23 +01:00
										 |  |  |         ccbysa: "f3d02893-b4c1-4cd6-8b27-e27ab57eb59a", | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |     } as const | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     constructor() { | 
					
						
							|  |  |  |         super( | 
					
						
							| 
									
										
										
										
											2024-10-29 01:12:18 +01:00
										 |  |  |             "Queries OSM for 'imgur'-images, uploads them to Panoramax and creates a changeset to update OSM" | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |         ) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |     private async getRawInfo(imgurUrl): Promise<{ description?: string; datetime: number }> { | 
					
						
							|  |  |  |         const fallbackpath = | 
					
						
							|  |  |  |             this._licenseDirectory + "/raw/" + imgurUrl.replaceAll(/[^a-zA-Z0-9]/g, "_") + ".json" | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         if (existsSync(fallbackpath)) { | 
					
						
							|  |  |  |             console.log("Loaded raw info from fallback path") | 
					
						
							|  |  |  |             return JSON.parse(readFileSync(fallbackpath, "utf8"))["data"] | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // No local data available; lets ask imgur themselves
 | 
					
						
							|  |  |  |         return new Promise((resolve) => { | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |             Imgur.singleton.DownloadAttribution({ url: imgurUrl }, (raw) => { | 
					
						
							|  |  |  |                 console.log("Writing fallback to", fallbackpath, "(via raw)") | 
					
						
							|  |  |  |                 writeFileSync(fallbackpath, JSON.stringify(raw), "utf8") | 
					
						
							|  |  |  |                 resolve(raw["data"]) | 
					
						
							|  |  |  |             }) | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private async getLicenseFor(imgurUrl: string): Promise<LicenseInfo> { | 
					
						
							|  |  |  |         const imageName = imgurUrl.split("/").at(-1) | 
					
						
							|  |  |  |         const licensePath: string = this._licenseDirectory + "/" + imageName | 
					
						
							|  |  |  |         if (existsSync(licensePath)) { | 
					
						
							|  |  |  |             const rawText = readFileSync(licensePath, "utf8") | 
					
						
							|  |  |  |             if (rawText?.toLowerCase() === "cc0" || rawText?.toLowerCase().startsWith("cc0")) { | 
					
						
							|  |  |  |                 return { licenseShortName: "CC0", artist: "Unknown" } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             try { | 
					
						
							|  |  |  |                 const licenseText: LicenseInfo = JSON.parse(rawText) | 
					
						
							|  |  |  |                 if (licenseText.licenseShortName) { | 
					
						
							|  |  |  |                     return licenseText | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 console.log("<<< No valid license found in text", rawText) | 
					
						
							|  |  |  |                 return undefined | 
					
						
							|  |  |  |             } catch (e) { | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |                 console.error( | 
					
						
							|  |  |  |                     "Could not read ", | 
					
						
							|  |  |  |                     rawText.slice(0, 20), | 
					
						
							|  |  |  |                     "as json for image", | 
					
						
							|  |  |  |                     imgurUrl, | 
					
						
							|  |  |  |                     "from", | 
					
						
							|  |  |  |                     licensePath | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // We didn't find the expected license in the expected location; search for the fallback (raw) license
 | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |         const fallbackpath = | 
					
						
							|  |  |  |             this._licenseDirectory + "/raw/" + imgurUrl.replaceAll(/[^a-zA-Z0-9]/g, "_") + ".json" | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         if (existsSync(fallbackpath)) { | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |             const fallbackRaw: string = JSON.parse(readFileSync(fallbackpath, "utf8"))["data"] | 
					
						
							|  |  |  |                 ?.description | 
					
						
							|  |  |  |             if ( | 
					
						
							|  |  |  |                 fallbackRaw?.toLowerCase()?.startsWith("cc0") || | 
					
						
							|  |  |  |                 fallbackRaw?.toLowerCase()?.indexOf("#cc0") >= 0 | 
					
						
							|  |  |  |             ) { | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |                 return { licenseShortName: "CC0", artist: "Unknown" } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |             const license = Imgur.parseLicense(fallbackRaw) | 
					
						
							|  |  |  |             if (license) { | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |                 return license | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |             console.log( | 
					
						
							|  |  |  |                 "No (fallback) license found for (but file exists), not uploading", | 
					
						
							|  |  |  |                 imgurUrl, | 
					
						
							|  |  |  |                 fallbackRaw | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |             return undefined | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // No local data available; lets ask imgur themselves
 | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |         const attr = await Imgur.singleton.DownloadAttribution({ url: imgurUrl }, (raw) => { | 
					
						
							|  |  |  |             console.log("Writing fallback to", fallbackpath) | 
					
						
							|  |  |  |             writeFileSync(fallbackpath, JSON.stringify(raw), "utf8") | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2024-11-14 02:08:10 +01:00
										 |  |  |         console.log("Got license via API:", attr?.licenseShortName) | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         await ScriptUtils.sleep(500) | 
					
						
							| 
									
										
										
										
											2024-11-14 02:08:10 +01:00
										 |  |  |         if (attr?.licenseShortName) { | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |             return attr | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return undefined | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |     async uploadImage(key: string, feat: Feature): Promise<UploadableTag | undefined> { | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |         const v = feat.properties[key] | 
					
						
							|  |  |  |         if (!v) { | 
					
						
							|  |  |  |             return undefined | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-11-17 22:56:10 +01:00
										 |  |  |         const isPng = v.endsWith(".png") | 
					
						
							| 
									
										
										
										
											2024-10-27 14:09:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         const imageHash = v.split("/").at(-1).split(".").at(0) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2024-10-27 14:09:58 +01:00
										 |  |  |             const panohash = this.alreadyUploaded[imageHash] | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |             if (panohash) { | 
					
						
							|  |  |  |                 console.log("Already uploaded", panohash) | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |                 return new And([ | 
					
						
							|  |  |  |                     new Tag(key.replace("image", "panoramax"), panohash), | 
					
						
							| 
									
										
										
										
											2024-11-28 12:00:23 +01:00
										 |  |  |                     new Tag(key, ""), | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |                 ]) | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2024-10-27 14:09:58 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |         let path: string = undefined | 
					
						
							| 
									
										
										
										
											2024-11-17 22:56:10 +01:00
										 |  |  |         if (isPng) { | 
					
						
							|  |  |  |             path = this._imageDirectory + "/../imgur_png_images/jpg/" + imageHash + ".jpg" | 
					
						
							|  |  |  |         } else if (existsSync(this._imageDirectory + "/" + imageHash + ".jpg")) { | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |             path = this._imageDirectory + "/" + imageHash + ".jpg" | 
					
						
							|  |  |  |         } else if (existsSync(this._imageDirectory + "/" + imageHash + ".jpeg")) { | 
					
						
							|  |  |  |             path = this._imageDirectory + "/" + imageHash + ".jpeg" | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!path) { | 
					
						
							|  |  |  |             return undefined | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-11-14 18:31:36 +01:00
										 |  |  |         let license: LicenseInfo | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |             license = await this.getLicenseFor(v) | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							|  |  |  |             console.error("Could not fetch license due to", e) | 
					
						
							| 
									
										
										
										
											2024-11-17 22:56:10 +01:00
										 |  |  |             if (e === 404) { | 
					
						
							| 
									
										
										
										
											2024-11-14 18:31:36 +01:00
										 |  |  |                 console.log("NOT FOUND") | 
					
						
							|  |  |  |                 return new Tag(key, "") | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             throw e | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         if (license === undefined) { | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |             return undefined | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         const sequence = this.sequenceIds[license.licenseShortName?.toLowerCase()] | 
					
						
							| 
									
										
										
										
											2024-11-28 12:00:23 +01:00
										 |  |  |         console.log("Reading ", path) | 
					
						
							|  |  |  |         if (!existsSync(path)) { | 
					
						
							| 
									
										
										
										
											2024-11-17 22:56:10 +01:00
										 |  |  |             return undefined | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-10-24 00:56:24 +02:00
										 |  |  |         const handle = await open(path) | 
					
						
							|  |  |  |         const stat = await handle.stat() | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         class MyFile extends File { | 
					
						
							|  |  |  |             // we should set correct size
 | 
					
						
							|  |  |  |             // otherwise we will encounter UND_ERR_REQ_CONTENT_LENGTH_MISMATCH
 | 
					
						
							| 
									
										
										
										
											2024-10-24 00:56:24 +02:00
										 |  |  |             size = stat.size | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |             stream = undefined | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const file = new MyFile([], path) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-28 12:00:23 +01:00
										 |  |  |         file.stream = function () { | 
					
						
							| 
									
										
										
										
											2024-10-24 00:56:24 +02:00
										 |  |  |             return handle.readableWebStream() | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         const licenseRaw = await this.getRawInfo(v) | 
					
						
							|  |  |  |         const date = new Date(licenseRaw.datetime * 1000) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |         console.log("Uploading", imageHash, sequence) | 
					
						
							| 
									
										
										
										
											2024-10-24 00:56:24 +02:00
										 |  |  |         const result = await this.panoramax.uploadImage( | 
					
						
							|  |  |  |             <any>file, | 
					
						
							|  |  |  |             GeoOperations.centerpointCoordinates(feat), | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |             license.artist, | 
					
						
							| 
									
										
										
										
											2024-10-24 00:56:24 +02:00
										 |  |  |             true, | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |             sequence, | 
					
						
							|  |  |  |             date.toISOString() | 
					
						
							| 
									
										
										
										
											2024-10-24 00:56:24 +02:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |         await handle.close() | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         this.alreadyUploaded[imageHash] = result.value | 
					
						
							|  |  |  |         this.writeAlreadyUploaded() | 
					
						
							| 
									
										
										
										
											2024-10-24 00:56:24 +02:00
										 |  |  |         return new And([new Tag(key.replace("image", result.key), result.value), new Tag(key, "")]) | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |     private writeAlreadyUploaded() { | 
					
						
							|  |  |  |         writeFileSync("uploaded_images.json", JSON.stringify(this.alreadyUploaded)) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private readAlreadyUploaded() { | 
					
						
							|  |  |  |         const uploaded = JSON.parse(readFileSync("uploaded_images.json", "utf8")) | 
					
						
							|  |  |  |         console.log("Detected ", Object.keys(uploaded).length, "previously uploaded images") | 
					
						
							|  |  |  |         return uploaded | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private async patchDate(panokey: string) { | 
					
						
							|  |  |  |         const imgurkey = this.alreadyUploadedInv[panokey] | 
					
						
							|  |  |  |         const license = await this.getRawInfo("https://i.imgur.com/" + imgurkey + ".jpg") | 
					
						
							|  |  |  |         const date = new Date(license.datetime * 1000) | 
					
						
							|  |  |  |         const panolicense = await this.panoramax.panoramax.search({ | 
					
						
							| 
									
										
										
										
											2024-11-28 12:00:23 +01:00
										 |  |  |             ids: [panokey], | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         }) | 
					
						
							|  |  |  |         const panodata = panolicense[0] | 
					
						
							|  |  |  |         const collection: string = panodata.collection | 
					
						
							|  |  |  |         console.log({ imgurkey, date, panodata, datetime: license.datetime }) | 
					
						
							|  |  |  |         const p = this.panoramax.panoramax | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |         const url = p.host + "/collections/" + collection + "/items/" + panokey | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         const result = await p.fetch(url, { | 
					
						
							|  |  |  |             method: "PATCH", | 
					
						
							|  |  |  |             headers: { "content-type": "application/json" }, | 
					
						
							|  |  |  |             body: JSON.stringify({ | 
					
						
							| 
									
										
										
										
											2024-11-28 12:00:23 +01:00
										 |  |  |                 ts: date.getTime(), | 
					
						
							|  |  |  |             }), | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         }) | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |         console.log( | 
					
						
							|  |  |  |             "Patched date of ", | 
					
						
							|  |  |  |             p.createViewLink({ | 
					
						
							| 
									
										
										
										
											2024-11-28 12:00:23 +01:00
										 |  |  |                 imageId: panokey, | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |             }), | 
					
						
							|  |  |  |             url, | 
					
						
							|  |  |  |             "result is", | 
					
						
							|  |  |  |             result.status, | 
					
						
							|  |  |  |             await result.text() | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |     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" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |         //  await this.panoramax.panoramax.createCollection("CC0 - part 2")
 | 
					
						
							|  |  |  |         //  return
 | 
					
						
							|  |  |  |         /*  for (const panohash in this.alreadyUploadedInv) { | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |             await this.patchDate(panohash) | 
					
						
							|  |  |  |             break | 
					
						
							|  |  |  |         }*/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-24 00:56:24 +02:00
										 |  |  |         const bounds = new BBox([ | 
					
						
							| 
									
										
										
										
											2024-11-28 12:00:23 +01:00
										 |  |  |             [-180, -90], | 
					
						
							|  |  |  |             [180, 90], | 
					
						
							| 
									
										
										
										
											2024-10-24 00:56:24 +02:00
										 |  |  |         ]) | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         const maxcount = 10000 | 
					
						
							|  |  |  |         const overpassfilters: RegexTag[] = [] | 
					
						
							|  |  |  |         const r = /^https:\/\/i.imgur.com\/.*/ | 
					
						
							|  |  |  |         for (const k of ["image", "image:menu", "image:streetsign"]) { | 
					
						
							|  |  |  |             overpassfilters.push(new RegexTag(k, r)) | 
					
						
							|  |  |  |             for (let i = 0; i < 20; i++) { | 
					
						
							|  |  |  |                 overpassfilters.push(new RegexTag(k + ":" + i, r)) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |         const overpass = new Overpass( | 
					
						
							|  |  |  |             new Or(overpassfilters), | 
					
						
							|  |  |  |             [], | 
					
						
							|  |  |  |             Constants.defaultOverpassUrls[0], | 
					
						
							|  |  |  |             new ImmutableStore(500) | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |         const features = (await overpass.queryGeoJson(bounds))[0].features | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         const featuresCopy = [...features] | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |         let converted = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         const total = features.length | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |         const changes: ChangeDescription[] = [] | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |         do { | 
					
						
							|  |  |  |             const f = features.shift() | 
					
						
							|  |  |  |             if (!f) { | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |             if (converted % 100 === 0) { | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |                 console.log( | 
					
						
							|  |  |  |                     "Converted:", | 
					
						
							|  |  |  |                     converted, | 
					
						
							|  |  |  |                     "total:", | 
					
						
							|  |  |  |                     total, | 
					
						
							|  |  |  |                     "progress:", | 
					
						
							|  |  |  |                     Math.round((converted * 100) / total) + "%" | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |             let changedTags: (UploadableTag | undefined)[] = [] | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |             console.log(converted + "/" + total, " handling " + f.properties.id) | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |             for (const k of ["image", "image:menu", "image:streetsign"]) { | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |                 changedTags.push(await this.uploadImage(k, f)) | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |                 for (let i = 0; i < 20; i++) { | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |                     changedTags.push(await this.uploadImage(k + ":" + i, f)) | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |             changedTags = Utils.NoNull(changedTags) | 
					
						
							|  |  |  |             if (changedTags.length > 0) { | 
					
						
							|  |  |  |                 const action = new ChangeTagAction( | 
					
						
							|  |  |  |                     f.properties.id, | 
					
						
							|  |  |  |                     new And(changedTags), | 
					
						
							|  |  |  |                     f.properties, | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         theme: "image-mover", | 
					
						
							| 
									
										
										
										
											2024-11-28 12:00:23 +01:00
										 |  |  |                         changeType: "link-image", | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 changes.push(...(await action.CreateChangeDescriptions())) | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |             converted++ | 
					
						
							|  |  |  |         } while (converted < maxcount) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         console.log("Uploaded images for", converted, "items; now creating the changeset") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-24 00:56:24 +02:00
										 |  |  |         const modif: string[] = Utils.Dedup(changes.map((ch) => ch.type + "/" + ch.id)) | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         const modifiedObjectsFresh: OsmObject[] = [] | 
					
						
							|  |  |  |         const dloader = new OsmObjectDownloader() | 
					
						
							|  |  |  |         for (let i = 0; i < modif.length; i++) { | 
					
						
							|  |  |  |             if (i % 100 === 0) { | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |                 console.log( | 
					
						
							|  |  |  |                     "Downloaded osm object", | 
					
						
							|  |  |  |                     i, | 
					
						
							|  |  |  |                     "/", | 
					
						
							|  |  |  |                     modif.length, | 
					
						
							|  |  |  |                     "(" + Math.round((i * 100) / modif.length) + "%)" | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |             const id = modif[i] | 
					
						
							|  |  |  |             const obj = await dloader.DownloadObjectAsync(id) | 
					
						
							|  |  |  |             if (obj === "deleted") { | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             modifiedObjectsFresh.push(obj) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |         const modifiedObjects = Changes.createChangesetObjectsStatic( | 
					
						
							|  |  |  |             changes, | 
					
						
							| 
									
										
										
										
											2024-10-24 00:56:24 +02:00
										 |  |  |             modifiedObjectsFresh, | 
					
						
							|  |  |  |             false, | 
					
						
							| 
									
										
										
										
											2024-10-29 01:12:18 +01:00
										 |  |  |             [] | 
					
						
							| 
									
										
										
										
											2024-10-24 00:56:24 +02:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |         const cs = Changes.buildChangesetXML("0", modifiedObjects) | 
					
						
							|  |  |  |         writeFileSync("imgur_to_panoramax.osc", cs, "utf8") | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |         const usernames = featuresCopy.map((f) => f.properties.user) | 
					
						
							|  |  |  |         const hist: Record<string, number> = {} | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         for (const username of usernames) { | 
					
						
							| 
									
										
										
										
											2024-11-14 02:21:10 +01:00
										 |  |  |             hist[username] = (hist[username] ?? 0) + 1 | 
					
						
							| 
									
										
										
										
											2024-11-10 23:51:41 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         console.log(hist) | 
					
						
							| 
									
										
										
										
											2024-10-23 18:41:32 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | new ImgurToPanoramax().run() |