From 570dacb89e0c3e9c757751d07516a92e160cda97 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Mon, 30 Sep 2024 00:59:25 +0200 Subject: [PATCH] Fix mastodon bot to work with panoramax --- package-lock.json | 63 +++++++++++++++++++++++++++++++++++++++-- package.json | 1 + src/ImageUploader.ts | 40 +++++++++++++++----------- src/ImgurAttribution.ts | 28 ------------------ src/Postbuilder.ts | 2 +- 5 files changed, 87 insertions(+), 47 deletions(-) delete mode 100644 src/ImgurAttribution.ts diff --git a/package-lock.json b/package-lock.json index 86928aa..c2159a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mastodon-bot", - "version": "0.0.1", + "version": "0.0.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "mastodon-bot", - "version": "0.0.1", + "version": "0.0.3", "license": "GPL", "dependencies": { "@types/node-fetch": "^2.6.2", @@ -20,6 +20,7 @@ "masto": "^5.4.0", "mocha": "^10.0.0", "node-fetch": "^3.3.0", + "panoramax-js": "^0.3.7", "showdown": "^2.1.0", "ts-node": "^10.7.0" }, @@ -227,6 +228,19 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/@ogcapi-js/features": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@ogcapi-js/features/-/features-1.1.1.tgz", + "integrity": "sha512-/w6kFvAXWO+F0/nLC5m11tuOw0LX+gVz/OCLiDkElXO9ko9F9OA3AbzKZxJaE5Buu0KUGn+TRxS6w1xhZc4KRA==", + "dependencies": { + "@ogcapi-js/shared": "^1.1.1" + } + }, + "node_modules/@ogcapi-js/shared": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@ogcapi-js/shared/-/shared-1.1.1.tgz", + "integrity": "sha512-EQ6T4iVXwIMnBcdpR2C0YnNNCxtNWHpWg0Hs9uEvH4BPZI2xT87gV+WRw8/hYAe8EtrK6j57iluBoSyHiAQweQ==" + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -252,6 +266,11 @@ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==" }, + "node_modules/@types/geojson": { + "version": "7946.0.14", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", + "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" + }, "node_modules/@types/mocha": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", @@ -1935,6 +1954,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/panoramax-js": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/panoramax-js/-/panoramax-js-0.3.7.tgz", + "integrity": "sha512-jkmHPaIsjfalwGG2CZxe24t4F8sY7phOFz5+nC4VnOY4T+6peXMLqZZ4u6d/pOmkf5OD2hk2mFL4pO1viLoWBA==", + "dependencies": { + "@ogcapi-js/features": "^1.1.1", + "@ogcapi-js/shared": "^1.1.1", + "@types/geojson": "^7946.0.14", + "json-schema": "^0.4.0" + } + }, "node_modules/param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -3041,6 +3071,19 @@ } } }, + "@ogcapi-js/features": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@ogcapi-js/features/-/features-1.1.1.tgz", + "integrity": "sha512-/w6kFvAXWO+F0/nLC5m11tuOw0LX+gVz/OCLiDkElXO9ko9F9OA3AbzKZxJaE5Buu0KUGn+TRxS6w1xhZc4KRA==", + "requires": { + "@ogcapi-js/shared": "^1.1.1" + } + }, + "@ogcapi-js/shared": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@ogcapi-js/shared/-/shared-1.1.1.tgz", + "integrity": "sha512-EQ6T4iVXwIMnBcdpR2C0YnNNCxtNWHpWg0Hs9uEvH4BPZI2xT87gV+WRw8/hYAe8EtrK6j57iluBoSyHiAQweQ==" + }, "@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -3066,6 +3109,11 @@ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==" }, + "@types/geojson": { + "version": "7946.0.14", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", + "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" + }, "@types/mocha": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", @@ -4366,6 +4414,17 @@ "p-limit": "^3.0.2" } }, + "panoramax-js": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/panoramax-js/-/panoramax-js-0.3.7.tgz", + "integrity": "sha512-jkmHPaIsjfalwGG2CZxe24t4F8sY7phOFz5+nC4VnOY4T+6peXMLqZZ4u6d/pOmkf5OD2hk2mFL4pO1viLoWBA==", + "requires": { + "@ogcapi-js/features": "^1.1.1", + "@ogcapi-js/shared": "^1.1.1", + "@types/geojson": "^7946.0.14", + "json-schema": "^0.4.0" + } + }, "param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", diff --git a/package.json b/package.json index df75d2b..a3f2a89 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "masto": "^5.4.0", "mocha": "^10.0.0", "node-fetch": "^3.3.0", + "panoramax-js": "^0.3.7", "showdown": "^2.1.0", "ts-node": "^10.7.0" }, diff --git a/src/ImageUploader.ts b/src/ImageUploader.ts index f33a4d3..9f5876b 100644 --- a/src/ImageUploader.ts +++ b/src/ImageUploader.ts @@ -1,9 +1,9 @@ import {ChangeSetData} from "./OsmCha"; import MastodonPoster from "./Mastodon"; import OsmUserInfo from "./OsmUserInfo"; -import ImgurAttribution from "./ImgurAttribution"; import Utils from "./Utils"; import Config from "./Config"; +import {ImageData, Panoramax, PanoramaxXYZ} from "panoramax-js"; export default class ImageUploader { private readonly _imageQueue: { image: string; changeset: ChangeSetData }[]; @@ -13,39 +13,38 @@ export default class ImageUploader { private readonly _globalConfig: Config - - constructor(imageQueue: {image: string, changeset: ChangeSetData}[], poster: MastodonPoster, config: Config) { + constructor(imageQueue: { image: string, changeset: ChangeSetData }[], poster: MastodonPoster, config: Config) { this._imageQueue = imageQueue; this._poster = poster; this._globalConfig = config } - public getCurrentAuthors(){ + public getCurrentAuthors() { return [...this._authors] } - - public async attemptToUpload(targetcount: number): Promise{ + + public async attemptToUpload(targetcount: number): Promise { const mediaIds = [] - while(mediaIds.length < targetcount && this._imageQueue.length >0){ + while (mediaIds.length < targetcount && this._imageQueue.length > 0) { const first = this._imageQueue[0] try { const id = await this.uploadFirstImage() mediaIds.push(id) - }catch (e) { + } catch (e) { console.error("Could not upload image! ", first.image, e) console.log("Trying again") try { const id = await this.uploadFirstImage() mediaIds.push(id) - }catch (e) { + } catch (e) { console.error("Retry could not upload image! ", first.image, e) } } } return mediaIds } - - private async uploadFirstImage(): Promise{ + + private async uploadFirstImage(): Promise { const image = this._imageQueue.shift() const cs = image.changeset.properties let authorName = cs.user @@ -61,11 +60,20 @@ export default class ImageUploader { return "dummy_id" } console.log("Fetching attribution for", image.image) - const attribution = await ImgurAttribution.DownloadAttribution(image.image) - const id = image.image.substring(image.image.lastIndexOf("/") + 1) - const path = this._globalConfig.cacheDir + "/image_" + id - await Utils.DownloadBlob(image.image, path) - const mediaId = await this._poster.uploadImage(path, "Image taken by " + authorName + ", available under " + attribution.license + ". It is made with the thematic map " + image.changeset.properties.theme + " in changeset https://openstreetmap.org/changeset/" + image.changeset.id) + let imageData: ImageData = undefined + try { + + const p = new Panoramax("https://panoramax.mapcomplete.org") + imageData = await p.imageInfo(image.image) + } catch (e) { + const p = new PanoramaxXYZ() + imageData = await p.imageInfo(image.image) + + } + const path = this._globalConfig.cacheDir + "/image_" + image.image + console.log("Fetching image:", imageData.assets.sd.href) + await Utils.DownloadBlob(imageData.assets.sd.href, path) + const mediaId = await this._poster.uploadImage(path, "Image taken by " + authorName + ", available under " + imageData.properties["geovisio:license"] + ". It is made with the thematic map " + image.changeset.properties.theme + " in changeset https://openstreetmap.org/changeset/" + image.changeset.id) this._authors.push(authorName) return mediaId diff --git a/src/ImgurAttribution.ts b/src/ImgurAttribution.ts deleted file mode 100644 index 8679a80..0000000 --- a/src/ImgurAttribution.ts +++ /dev/null @@ -1,28 +0,0 @@ -import Utils from "./Utils"; - -export default class ImgurAttribution { - - // MUST be private to prevent other people stealing this key! That I'll push this to github later on is not relevant - private static ImgurApiKey = "7070e7167f0a25a" - - /** - * Download the attribution from a given URL - */ - public static async DownloadAttribution(url: string): Promise<{license: string, author: string}> { - const hash = url.substr("https://i.imgur.com/".length).split(/.jpe?g/i)[0] - - const apiUrl = "https://api.imgur.com/3/image/" + hash - const response = await Utils.DownloadJson(apiUrl, { - Authorization: "Client-ID " + ImgurAttribution.ImgurApiKey, - }) - - const descr: string = response.data.description ?? "" - const data: any = {} - for (const tag of descr.split("\n")) { - const kv = tag.split(":") - const k = kv[0] - data[k] = kv[1]?.replace(/\r/g, "") - } - return data - } -} \ No newline at end of file diff --git a/src/Postbuilder.ts b/src/Postbuilder.ts index 3d78e63..f47ac6c 100644 --- a/src/Postbuilder.ts +++ b/src/Postbuilder.ts @@ -441,7 +441,7 @@ export class Postbuilder { const osmChangeset = await Utils.DownloadXml(url) const osmChangesetTags: { k: string, v: string }[] = Array.from(osmChangeset.getElementsByTagName("tag")) .map(tag => ({k: tag.getAttribute("k"), v: tag.getAttribute("v")})) - .filter(kv => kv.k.startsWith("image")) + .filter(kv => kv.k.startsWith("panoramax")) for (const kv of osmChangesetTags) { if (seenURLS.has(kv.v)) {