Fix mastodon bot to work with panoramax

This commit is contained in:
Pieter Vander Vennet 2024-09-30 00:59:25 +02:00
parent ddd8566efc
commit 570dacb89e
5 changed files with 87 additions and 47 deletions

63
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "mastodon-bot", "name": "mastodon-bot",
"version": "0.0.1", "version": "0.0.3",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "mastodon-bot", "name": "mastodon-bot",
"version": "0.0.1", "version": "0.0.3",
"license": "GPL", "license": "GPL",
"dependencies": { "dependencies": {
"@types/node-fetch": "^2.6.2", "@types/node-fetch": "^2.6.2",
@ -20,6 +20,7 @@
"masto": "^5.4.0", "masto": "^5.4.0",
"mocha": "^10.0.0", "mocha": "^10.0.0",
"node-fetch": "^3.3.0", "node-fetch": "^3.3.0",
"panoramax-js": "^0.3.7",
"showdown": "^2.1.0", "showdown": "^2.1.0",
"ts-node": "^10.7.0" "ts-node": "^10.7.0"
}, },
@ -227,6 +228,19 @@
"webidl-conversions": "^3.0.0" "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": { "node_modules/@tsconfig/node10": {
"version": "1.0.9", "version": "1.0.9",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", "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", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz",
"integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==" "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": { "node_modules/@types/mocha": {
"version": "9.1.1", "version": "9.1.1",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz",
@ -1935,6 +1954,17 @@
"url": "https://github.com/sponsors/sindresorhus" "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": { "node_modules/param-case": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", "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": { "@tsconfig/node10": {
"version": "1.0.9", "version": "1.0.9",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", "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", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz",
"integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==" "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": { "@types/mocha": {
"version": "9.1.1", "version": "9.1.1",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz",
@ -4366,6 +4414,17 @@
"p-limit": "^3.0.2" "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": { "param-case": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",

View file

@ -32,6 +32,7 @@
"masto": "^5.4.0", "masto": "^5.4.0",
"mocha": "^10.0.0", "mocha": "^10.0.0",
"node-fetch": "^3.3.0", "node-fetch": "^3.3.0",
"panoramax-js": "^0.3.7",
"showdown": "^2.1.0", "showdown": "^2.1.0",
"ts-node": "^10.7.0" "ts-node": "^10.7.0"
}, },

View file

@ -1,9 +1,9 @@
import {ChangeSetData} from "./OsmCha"; import {ChangeSetData} from "./OsmCha";
import MastodonPoster from "./Mastodon"; import MastodonPoster from "./Mastodon";
import OsmUserInfo from "./OsmUserInfo"; import OsmUserInfo from "./OsmUserInfo";
import ImgurAttribution from "./ImgurAttribution";
import Utils from "./Utils"; import Utils from "./Utils";
import Config from "./Config"; import Config from "./Config";
import {ImageData, Panoramax, PanoramaxXYZ} from "panoramax-js";
export default class ImageUploader { export default class ImageUploader {
private readonly _imageQueue: { image: string; changeset: ChangeSetData }[]; private readonly _imageQueue: { image: string; changeset: ChangeSetData }[];
@ -13,7 +13,6 @@ export default class ImageUploader {
private readonly _globalConfig: Config 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._imageQueue = imageQueue;
this._poster = poster; this._poster = poster;
@ -61,11 +60,20 @@ export default class ImageUploader {
return "dummy_id" return "dummy_id"
} }
console.log("Fetching attribution for", image.image) console.log("Fetching attribution for", image.image)
const attribution = await ImgurAttribution.DownloadAttribution(image.image) let imageData: ImageData = undefined
const id = image.image.substring(image.image.lastIndexOf("/") + 1) try {
const path = this._globalConfig.cacheDir + "/image_" + id
await Utils.DownloadBlob(image.image, path) const p = new Panoramax("https://panoramax.mapcomplete.org")
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) 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) this._authors.push(authorName)
return mediaId return mediaId

View file

@ -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
}
}

View file

@ -441,7 +441,7 @@ export class Postbuilder {
const osmChangeset = await Utils.DownloadXml(url) const osmChangeset = await Utils.DownloadXml(url)
const osmChangesetTags: { k: string, v: string }[] = Array.from(osmChangeset.getElementsByTagName("tag")) const osmChangesetTags: { k: string, v: string }[] = Array.from(osmChangeset.getElementsByTagName("tag"))
.map(tag => ({k: tag.getAttribute("k"), v: tag.getAttribute("v")})) .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) { for (const kv of osmChangesetTags) {
if (seenURLS.has(kv.v)) { if (seenURLS.has(kv.v)) {