Scripts: add script that moves wikimedia-files from image to Wikimedia

This commit is contained in:
Pieter Vander Vennet 2025-09-06 23:28:15 +02:00
parent 0d24f23177
commit 8d678008b7
2 changed files with 101 additions and 6 deletions

View file

@ -0,0 +1,95 @@
import Script from "../Script"
import { Overpass } from "../../src/Logic/Osm/Overpass"
import Constants from "../../src/Models/Constants"
import { BBox } from "../../src/Logic/BBox"
import { RegexTag } from "../../src/Logic/Tags/RegexTag"
import { Tag } from "../../src/Logic/Tags/Tag"
import { Feature, FeatureCollection } from "geojson"
import { existsSync, readFileSync, writeFileSync } from "fs"
import { Changes } from "../../src/Logic/Osm/Changes"
import ChangeTagAction from "../../src/Logic/Osm/Actions/ChangeTagAction"
import { And } from "../../src/Logic/Tags/And"
import { Lists } from "../../src/Utils/Lists"
export class FixWikimediaInImageTag extends Script {
constructor() {
super("For the given bbox, queries all `image=http(s)://commons.wikimedia.org` tags and replaces it with `commons`-tagging")
}
private handleFeature(f: Feature): ChangeTagAction {
const p = f.properties
const existingCommons = p["wikimedia_commons"]
const img = p["image"]
const id = p.id
if (!img) {
return undefined
}
const extractedCommons: string = img.match(/^https?:\/\/commons.wikimedia.org\/wiki\/(.*)$/)[1]
console.log("Feature " + p.id + ": " + img + ", extr " + extractedCommons + ", old: " + existingCommons)
if (existingCommons === extractedCommons) {
return new ChangeTagAction(id,
new Tag("image", ""),
p,
{
changeType: "cleanup",
theme: "/"
}
)
}
if (existingCommons) {
return undefined
}
if (!extractedCommons.startsWith("File:")) {
return undefined
}
return new ChangeTagAction(id,
new And([new Tag("image", ""), new Tag("wikimedia_commons", decodeURIComponent(extractedCommons))]),
p,
{
changeType: "cleanup",
theme: "/"
}
)
}
private async fetchData(bbox: BBox): Promise<FeatureCollection> {
const pth = "fix_wikimedia_" + bbox.toLngLatFlat().join("_") + ".geojson"
if (existsSync(pth)) {
return JSON.parse(readFileSync(pth, "utf-8"))
}
const overpass = new Overpass(Constants.defaultOverpassUrls[0],
new RegexTag("image", /https?:\/\/commons.wikimedia.org/)
)
const [feats] = await overpass.queryGeoJson(bbox)
writeFileSync(pth, JSON.stringify(feats), "utf8")
return feats
}
async main(args: string[]): Promise<void> {
if (args.length < 1) {
this.printHelp()
//return
}
const bbox = new BBox([3.632100582083325,
51.11343904784337, 3.8584183481742116,
50.99383861993195])
const feats = await this.fetchData(bbox)
const actions = Lists.noNull(feats.features.map(f => this.handleFeature(f)))
const xml = await Changes.createChangesetXMLForJosm(actions)
const pth = "move_image_to_wikimedia_commons_" + bbox.toLngLatFlat().join("_") + ".osc"
writeFileSync(pth, xml, "utf-8")
console.log("Written xml to file://" + pth)
}
}
new FixWikimediaInImageTag().run()

View file

@ -3,7 +3,7 @@ import { Utils } from "../../Utils"
import { ImmutableStore, Store } from "../UIEventSource" import { ImmutableStore, Store } from "../UIEventSource"
import { BBox } from "../BBox" import { BBox } from "../BBox"
import osmtogeojson from "osmtogeojson" import osmtogeojson from "osmtogeojson"
import { Feature } from "geojson" import { Feature, FeatureCollection } from "geojson"
("use strict") ("use strict")
/** /**
@ -37,7 +37,7 @@ export class Overpass {
this._includeMeta = includeMeta this._includeMeta = includeMeta
} }
public async queryGeoJson<T extends Feature>(bounds: BBox): Promise<[{features: T[]}, Date]> { public async queryGeoJson<T extends Feature>(bounds: BBox): Promise<[{ features: T[] } & FeatureCollection, Date]> {
const bbox = const bbox =
"[bbox:" + "[bbox:" +
bounds.getSouth() + bounds.getSouth() +
@ -49,16 +49,16 @@ export class Overpass {
bounds.getEast() + bounds.getEast() +
"]" "]"
const query = this.buildScript(bbox) const query = this.buildScript(bbox)
return await this.ExecuteQuery<T>(query) return await this.executeQuery<T>(query)
} }
public buildUrl(query: string) { public buildUrl(query: string) {
return `${this._interpreterUrl}?data=${encodeURIComponent(query)}` return `${this._interpreterUrl}?data=${encodeURIComponent(query)}`
} }
private async ExecuteQuery<T extends Feature>( private async executeQuery<T extends Feature>(
query: string query: string
): Promise<[{features: T[]}, Date]> { ): Promise<[{ features: T[] } & FeatureCollection, Date]> {
const json = await Utils.downloadJson<{ const json = await Utils.downloadJson<{
elements: [] elements: []
remark remark
@ -73,7 +73,7 @@ export class Overpass {
console.warn("No features for", this.buildUrl(query)) console.warn("No features for", this.buildUrl(query))
} }
const geojson = <{features: T[]}> <any> osmtogeojson(json) const geojson = <{ features: T[] } & FeatureCollection><any>osmtogeojson(json)
const osmTime = new Date(json.osm3s.timestamp_osm_base) const osmTime = new Date(json.osm3s.timestamp_osm_base)
return [geojson, osmTime] return [geojson, osmTime]
} }