forked from MapComplete/MapComplete
Merge master
This commit is contained in:
commit
01483ab3f9
264 changed files with 15566 additions and 4192 deletions
|
@ -34,10 +34,10 @@ export default class AllImageProviders {
|
|||
AllImageProviders.genericImageProvider,
|
||||
]
|
||||
public static apiUrls: string[] = [].concat(
|
||||
...AllImageProviders.ImageAttributionSource.map((src) => src.apiUrls()),
|
||||
...AllImageProviders.ImageAttributionSource.map((src) => src.apiUrls())
|
||||
)
|
||||
public static defaultKeys = [].concat(
|
||||
AllImageProviders.ImageAttributionSource.map((provider) => provider.defaultKeyPrefixes),
|
||||
AllImageProviders.ImageAttributionSource.map((provider) => provider.defaultKeyPrefixes)
|
||||
)
|
||||
private static providersByName = {
|
||||
imgur: Imgur.singleton,
|
||||
|
@ -71,13 +71,12 @@ export default class AllImageProviders {
|
|||
*/
|
||||
public static LoadImagesFor(
|
||||
tags: Store<Record<string, string>>,
|
||||
tagKey?: string[],
|
||||
tagKey?: string[]
|
||||
): Store<ProvidedImage[]> {
|
||||
if (tags?.data?.id === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
|
||||
const source = new UIEventSource([])
|
||||
const allSources: Store<ProvidedImage[]>[] = []
|
||||
for (const imageProvider of AllImageProviders.ImageAttributionSource) {
|
||||
|
@ -86,11 +85,11 @@ export default class AllImageProviders {
|
|||
However, we override them if a custom image tag is set, e.g. 'image:menu'
|
||||
*/
|
||||
const prefixes = tagKey ?? imageProvider.defaultKeyPrefixes
|
||||
const singleSource = tags.bindD(tags => imageProvider.getRelevantUrls(tags, prefixes))
|
||||
const singleSource = tags.bindD((tags) => imageProvider.getRelevantUrls(tags, prefixes))
|
||||
allSources.push(singleSource)
|
||||
singleSource.addCallbackAndRunD((_) => {
|
||||
const all: ProvidedImage[] = [].concat(...allSources.map((source) => source.data))
|
||||
const dedup = Utils.DedupOnId(all, i => i?.id ?? i?.url)
|
||||
const dedup = Utils.DedupOnId(all, (i) => i?.id ?? i?.url)
|
||||
source.set(dedup)
|
||||
})
|
||||
}
|
||||
|
@ -103,7 +102,7 @@ export default class AllImageProviders {
|
|||
*/
|
||||
public static loadImagesFrom(urls: string[]): Store<ProvidedImage[]> {
|
||||
const tags = {
|
||||
id:"na"
|
||||
id: "na",
|
||||
}
|
||||
for (let i = 0; i < urls.length; i++) {
|
||||
const url = urls[i]
|
||||
|
|
|
@ -27,12 +27,14 @@ export default class GenericImageProvider extends ImageProvider {
|
|||
return undefined
|
||||
}
|
||||
|
||||
return [{
|
||||
key: key,
|
||||
url: value,
|
||||
provider: this,
|
||||
id: value,
|
||||
}]
|
||||
return [
|
||||
{
|
||||
key: key,
|
||||
url: value,
|
||||
provider: this,
|
||||
id: value,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
SourceIcon() {
|
||||
|
|
|
@ -9,15 +9,15 @@ export interface ProvidedImage {
|
|||
key: string
|
||||
provider: ImageProvider
|
||||
id: string
|
||||
date?: Date,
|
||||
date?: Date
|
||||
status?: string | "ready"
|
||||
/**
|
||||
* Compass angle of the taken image
|
||||
* 0 = north, 90° = East
|
||||
*/
|
||||
rotation?: number
|
||||
lat?: number,
|
||||
lon?: number,
|
||||
lat?: number
|
||||
lon?: number
|
||||
host?: string
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,10 @@ export default abstract class ImageProvider {
|
|||
|
||||
public abstract readonly name: string
|
||||
|
||||
public abstract SourceIcon(img?: {id: string, url: string, host?: string}, location?: { lon: number; lat: number }): BaseUIElement
|
||||
|
||||
public abstract SourceIcon(
|
||||
img?: { id: string; url: string; host?: string },
|
||||
location?: { lon: number; lat: number }
|
||||
): BaseUIElement
|
||||
|
||||
/**
|
||||
* Gets all the relevant URLS for the given tags and for the given prefixes;
|
||||
|
@ -35,12 +37,19 @@ export default abstract class ImageProvider {
|
|||
* @param tags
|
||||
* @param prefixes
|
||||
*/
|
||||
public async getRelevantUrlsFor(tags: Record<string, string>, prefixes: string[]): Promise<ProvidedImage[]> {
|
||||
public async getRelevantUrlsFor(
|
||||
tags: Record<string, string>,
|
||||
prefixes: string[]
|
||||
): Promise<ProvidedImage[]> {
|
||||
const relevantUrls: ProvidedImage[] = []
|
||||
const seenValues = new Set<string>()
|
||||
|
||||
for (const key in tags) {
|
||||
if (!prefixes.some((prefix) => key === prefix || key.match(new RegExp(prefix+":[0-9]+")))) {
|
||||
if (
|
||||
!prefixes.some(
|
||||
(prefix) => key === prefix || key.match(new RegExp(prefix + ":[0-9]+"))
|
||||
)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
const values = Utils.NoEmpty(tags[key]?.split(";")?.map((v) => v.trim()) ?? [])
|
||||
|
@ -50,10 +59,10 @@ export default abstract class ImageProvider {
|
|||
}
|
||||
seenValues.add(value)
|
||||
let images = this.ExtractUrls(key, value)
|
||||
if(!Array.isArray(images)){
|
||||
images = await images
|
||||
if (!Array.isArray(images)) {
|
||||
images = await images
|
||||
}
|
||||
if(images){
|
||||
if (images) {
|
||||
relevantUrls.push(...images)
|
||||
}
|
||||
}
|
||||
|
@ -61,12 +70,17 @@ export default abstract class ImageProvider {
|
|||
return relevantUrls
|
||||
}
|
||||
|
||||
public getRelevantUrls(tags: Record<string, string>, prefixes: string[]): Store<ProvidedImage[]> {
|
||||
public getRelevantUrls(
|
||||
tags: Record<string, string>,
|
||||
prefixes: string[]
|
||||
): Store<ProvidedImage[]> {
|
||||
return Stores.FromPromise(this.getRelevantUrlsFor(tags, prefixes))
|
||||
}
|
||||
|
||||
|
||||
public abstract ExtractUrls(key: string, value: string): undefined | ProvidedImage[] | Promise<ProvidedImage[]>
|
||||
public abstract ExtractUrls(
|
||||
key: string,
|
||||
value: string
|
||||
): undefined | ProvidedImage[] | Promise<ProvidedImage[]>
|
||||
|
||||
public abstract DownloadAttribution(providedImage: {
|
||||
url: string
|
||||
|
|
|
@ -28,7 +28,10 @@ export class ImageUploadManager {
|
|||
private readonly _osmConnection: OsmConnection
|
||||
private readonly _changes: Changes
|
||||
public readonly isUploading: Store<boolean>
|
||||
private readonly _reportError: (message: (string | Error | XMLHttpRequest), extramessage?: string) => Promise<void>
|
||||
private readonly _reportError: (
|
||||
message: string | Error | XMLHttpRequest,
|
||||
extramessage?: string
|
||||
) => Promise<void>
|
||||
|
||||
constructor(
|
||||
layout: ThemeConfig,
|
||||
|
@ -38,7 +41,10 @@ export class ImageUploadManager {
|
|||
changes: Changes,
|
||||
gpsLocation: Store<GeolocationCoordinates | undefined>,
|
||||
allFeatures: IndexedFeatureSource,
|
||||
reportError: (message: string | Error | XMLHttpRequest, extramessage?: string ) => Promise<void>
|
||||
reportError: (
|
||||
message: string | Error | XMLHttpRequest,
|
||||
extramessage?: string
|
||||
) => Promise<void>
|
||||
) {
|
||||
this._uploader = uploader
|
||||
this._featureProperties = featureProperties
|
||||
|
@ -56,7 +62,7 @@ export class ImageUploadManager {
|
|||
(startedCount) => {
|
||||
return startedCount > failed.data + done.data
|
||||
},
|
||||
[failed, done],
|
||||
[failed, done]
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -105,7 +111,7 @@ export class ImageUploadManager {
|
|||
file: File,
|
||||
tagsStore: UIEventSource<OsmTags>,
|
||||
targetKey: string,
|
||||
noblur: boolean,
|
||||
noblur: boolean
|
||||
): Promise<void> {
|
||||
const canBeUploaded = this.canBeUploaded(file)
|
||||
if (canBeUploaded !== true) {
|
||||
|
@ -130,10 +136,16 @@ export class ImageUploadManager {
|
|||
}
|
||||
const properties = this._featureProperties.getStore(featureId)
|
||||
|
||||
const action = new LinkImageAction(featureId, uploadResult. key, uploadResult . value, properties, {
|
||||
theme: tags?.data?.["_orig_theme"] ?? this._theme.id,
|
||||
changeType: "add-image",
|
||||
})
|
||||
const action = new LinkImageAction(
|
||||
featureId,
|
||||
uploadResult.key,
|
||||
uploadResult.value,
|
||||
properties,
|
||||
{
|
||||
theme: tags?.data?.["_orig_theme"] ?? this._theme.id,
|
||||
changeType: "add-image",
|
||||
}
|
||||
)
|
||||
|
||||
await this._changes.applyAction(action)
|
||||
}
|
||||
|
@ -153,34 +165,51 @@ export class ImageUploadManager {
|
|||
if (this._gps.data) {
|
||||
location = [this._gps.data.longitude, this._gps.data.latitude]
|
||||
}
|
||||
if (location === undefined || location?.some(l => l === undefined)) {
|
||||
if (location === undefined || location?.some((l) => l === undefined)) {
|
||||
const feature = this._indexedFeatures.featuresById.data.get(featureId)
|
||||
location = GeoOperations.centerpointCoordinates(feature)
|
||||
}
|
||||
try {
|
||||
({ key, value, absoluteUrl } = await this._uploader.uploadImage(blob, location, author, noblur))
|
||||
;({ key, value, absoluteUrl } = await this._uploader.uploadImage(
|
||||
blob,
|
||||
location,
|
||||
author,
|
||||
noblur
|
||||
))
|
||||
} catch (e) {
|
||||
this.increaseCountFor(this._uploadRetried, featureId)
|
||||
console.error("Could not upload image, trying again:", e)
|
||||
try {
|
||||
({ key, value , absoluteUrl} = await this._uploader.uploadImage(blob, location, author, noblur))
|
||||
;({ key, value, absoluteUrl } = await this._uploader.uploadImage(
|
||||
blob,
|
||||
location,
|
||||
author,
|
||||
noblur
|
||||
))
|
||||
this.increaseCountFor(this._uploadRetriedSuccess, featureId)
|
||||
} catch (e) {
|
||||
console.error("Could again not upload image due to", e)
|
||||
this.increaseCountFor(this._uploadFailed, featureId)
|
||||
await this._reportError(e, JSON.stringify({ctx:"While uploading an image in the Image Upload Manager", featureId, author, targetKey}))
|
||||
await this._reportError(
|
||||
e,
|
||||
JSON.stringify({
|
||||
ctx: "While uploading an image in the Image Upload Manager",
|
||||
featureId,
|
||||
author,
|
||||
targetKey,
|
||||
})
|
||||
)
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
console.log("Uploading image done, creating action for", featureId)
|
||||
key = targetKey ?? key
|
||||
if(targetKey){
|
||||
if (targetKey) {
|
||||
// This is a non-standard key, so we use the image link directly
|
||||
value = absoluteUrl
|
||||
}
|
||||
this.increaseCountFor(this._uploadFinished, featureId)
|
||||
return {key, absoluteUrl, value}
|
||||
|
||||
return { key, absoluteUrl, value }
|
||||
}
|
||||
|
||||
private getCounterFor(collection: Map<string, UIEventSource<number>>, key: string | "*") {
|
||||
|
|
|
@ -6,10 +6,14 @@ export interface ImageUploader {
|
|||
*/
|
||||
uploadImage(
|
||||
blob: File,
|
||||
currentGps: [number,number],
|
||||
currentGps: [number, number],
|
||||
author: string,
|
||||
noblur: boolean
|
||||
): Promise<UploadResult>
|
||||
}
|
||||
|
||||
export interface UploadResult{ key: string; value: string, absoluteUrl: string }
|
||||
export interface UploadResult {
|
||||
key: string
|
||||
value: string
|
||||
absoluteUrl: string
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ export class Imgur extends ImageProvider {
|
|||
return [Imgur.apiUrl]
|
||||
}
|
||||
|
||||
|
||||
SourceIcon(): BaseUIElement {
|
||||
return undefined
|
||||
}
|
||||
|
@ -32,7 +31,7 @@ export class Imgur extends ImageProvider {
|
|||
key: key,
|
||||
provider: this,
|
||||
id: value,
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
return undefined
|
||||
|
|
|
@ -118,7 +118,7 @@ export class Mapillary extends ImageProvider {
|
|||
}
|
||||
|
||||
SourceIcon(
|
||||
img: {id: string, url: string},
|
||||
img: { id: string; url: string },
|
||||
location?: {
|
||||
lon: number
|
||||
lat: number
|
||||
|
@ -182,7 +182,7 @@ export class Mapillary extends ImageProvider {
|
|||
key,
|
||||
rotation,
|
||||
lat: geometry.coordinates[1],
|
||||
lon: geometry.coordinates[0]
|
||||
lon: geometry.coordinates[0],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,9 +12,7 @@ import Panoramax_bw from "../../assets/svg/Panoramax_bw.svelte"
|
|||
import Link from "../../UI/Base/Link"
|
||||
import { Utils } from "../../Utils"
|
||||
|
||||
|
||||
export default class PanoramaxImageProvider extends ImageProvider {
|
||||
|
||||
public static readonly singleton = new PanoramaxImageProvider()
|
||||
private static readonly xyz = new PanoramaxXYZ()
|
||||
private static defaultPanoramax = new AuthorizedPanoramax(Constants.panoramax.url, Constants.panoramax.token, 3000)
|
||||
|
@ -22,17 +20,24 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
|||
public defaultKeyPrefixes: string[] = ["panoramax"]
|
||||
public readonly name: string = "panoramax"
|
||||
|
||||
private static knownMeta: Record<string, { data: ImageData, time: Date }> = {}
|
||||
private static knownMeta: Record<string, { data: ImageData; time: Date }> = {}
|
||||
|
||||
public SourceIcon(img?: { id: string, url: string, host?: string }, location?: {
|
||||
lon: number;
|
||||
lat: number;
|
||||
}): BaseUIElement {
|
||||
public SourceIcon(
|
||||
img?: { id: string; url: string; host?: string },
|
||||
location?: {
|
||||
lon: number
|
||||
lat: number
|
||||
}
|
||||
): BaseUIElement {
|
||||
const p = new Panoramax(img.host)
|
||||
return new Link(new SvelteUIElement(Panoramax_bw), p.createViewLink({
|
||||
imageId: img?.id,
|
||||
location,
|
||||
}), true)
|
||||
return new Link(
|
||||
new SvelteUIElement(Panoramax_bw),
|
||||
p.createViewLink({
|
||||
imageId: img?.id,
|
||||
location,
|
||||
}),
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
public addKnownMeta(meta: ImageData) {
|
||||
|
@ -44,25 +49,24 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
|||
* @param id
|
||||
* @private
|
||||
*/
|
||||
private async getInfoFromMapComplete(id: string): Promise<{ data: ImageData, url: string }> {
|
||||
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)
|
||||
return { url, data }
|
||||
}
|
||||
|
||||
private async getInfoFromXYZ(imageId: string): Promise<{ data: ImageData, url: string }> {
|
||||
private async getInfoFromXYZ(imageId: string): Promise<{ data: ImageData; url: string }> {
|
||||
const data = await PanoramaxImageProvider.xyz.imageInfo(imageId)
|
||||
return { data, url: "https://api.panoramax.xyz/" }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads a geovisio-somewhat-looking-like-geojson object and converts it to a provided image
|
||||
* @param meta
|
||||
* @private
|
||||
*/
|
||||
private featureToImage(info: { data: ImageData, url: string }) {
|
||||
private featureToImage(info: { data: ImageData; url: string }) {
|
||||
const meta = info?.data
|
||||
if (!meta) {
|
||||
return undefined
|
||||
|
@ -83,8 +87,9 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
|||
id: meta.id,
|
||||
url: makeAbsolute(meta.assets.sd.href),
|
||||
url_hd: makeAbsolute(meta.assets.hd.href),
|
||||
host: meta["links"].find(l => l.rel === "root")?.href,
|
||||
lon, lat,
|
||||
host: meta["links"].find((l) => l.rel === "root")?.href,
|
||||
lon,
|
||||
lat,
|
||||
key: "panoramax",
|
||||
provider: this,
|
||||
status: meta.properties["geovisio:status"],
|
||||
|
@ -93,14 +98,13 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
|||
}
|
||||
}
|
||||
|
||||
private async getInfoFor(id: string): Promise<{ data: ImageData, url: string }> {
|
||||
private async getInfoFor(id: string): Promise<{ data: ImageData; url: string }> {
|
||||
if (!id.match(/^[a-zA-Z0-9-]+$/)) {
|
||||
return undefined
|
||||
}
|
||||
const cached = PanoramaxImageProvider.knownMeta[id]
|
||||
if (cached) {
|
||||
if (new Date().getTime() - cached.time.getTime() < 1000) {
|
||||
|
||||
return { data: cached.data, url: undefined }
|
||||
}
|
||||
}
|
||||
|
@ -121,10 +125,9 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
|||
if (!Panoramax.isId(value)) {
|
||||
return undefined
|
||||
}
|
||||
return [await this.getInfoFor(value).then(r => this.featureToImage(<any>r))]
|
||||
return [await this.getInfoFor(value).then((r) => this.featureToImage(<any>r))]
|
||||
}
|
||||
|
||||
|
||||
getRelevantUrls(tags: Record<string, string>, prefixes: string[]): Store<ProvidedImage[]> {
|
||||
const source = UIEventSource.FromPromise(super.getRelevantUrlsFor(tags, prefixes))
|
||||
|
||||
|
@ -132,7 +135,10 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
|||
if (data === undefined) {
|
||||
return true
|
||||
}
|
||||
return data?.some(img => img?.status !== undefined && img?.status !== "ready" && img?.status !== "broken")
|
||||
return data?.some(
|
||||
(img) =>
|
||||
img?.status !== undefined && img?.status !== "ready" && img?.status !== "broken"
|
||||
)
|
||||
}
|
||||
|
||||
Stores.Chronic(1500, () =>
|
||||
|
@ -147,7 +153,10 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
|||
return Stores.ListStabilized( source)
|
||||
}
|
||||
|
||||
public async DownloadAttribution(providedImage: { url: string; id: string; }): Promise<LicenseInfo> {
|
||||
public async DownloadAttribution(providedImage: {
|
||||
url: string
|
||||
id: string
|
||||
}): Promise<LicenseInfo> {
|
||||
const meta = await this.getInfoFor(providedImage.id)
|
||||
|
||||
return {
|
||||
|
@ -170,9 +179,14 @@ export class PanoramaxUploader implements ImageUploader {
|
|||
this._panoramax = new AuthorizedPanoramax(url, token)
|
||||
}
|
||||
|
||||
async uploadImage(blob: File, currentGps: [number, number], author: string, noblur: boolean = false): Promise<{
|
||||
key: string;
|
||||
value: string;
|
||||
async uploadImage(
|
||||
blob: File,
|
||||
currentGps: [number, number],
|
||||
author: string,
|
||||
noblur: boolean = false
|
||||
): Promise<{
|
||||
key: string
|
||||
value: string
|
||||
absoluteUrl: string
|
||||
}> {
|
||||
// https://panoramax.openstreetmap.fr/api/docs/swagger#/
|
||||
|
@ -183,7 +197,7 @@ export class PanoramaxUploader implements ImageUploader {
|
|||
let datetime = new Date().toISOString()
|
||||
try {
|
||||
const tags = await ExifReader.load(blob)
|
||||
hasDate = tags?.DateTime !== undefined
|
||||
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)
|
||||
|
@ -197,10 +211,10 @@ export class PanoramaxUploader implements ImageUploader {
|
|||
console.error("Could not read EXIF-tags")
|
||||
}
|
||||
|
||||
const [lon, lat] = currentGps
|
||||
|
||||
const p = this._panoramax
|
||||
const defaultSequence = (await p.mySequences())[0]
|
||||
console.log("Upload options are", lon, lat, datetime)
|
||||
const defaultSequence = (await p.mySequences()).find(s => s.id === Constants.panoramax.sequence)
|
||||
const img = <ImageData>await p.addImage(blob, defaultSequence, {
|
||||
lon: Utils.Round7(lon),
|
||||
lat: Utils.Round7(lat),
|
||||
|
@ -209,7 +223,6 @@ export class PanoramaxUploader implements ImageUploader {
|
|||
exifOverride: {
|
||||
Artist: author,
|
||||
},
|
||||
|
||||
})
|
||||
PanoramaxImageProvider.singleton.addKnownMeta(img)
|
||||
return {
|
||||
|
@ -218,5 +231,4 @@ export class PanoramaxUploader implements ImageUploader {
|
|||
absoluteUrl: img.assets.hd.href,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,8 +11,10 @@ export class WikidataImageProvider extends ImageProvider {
|
|||
public static readonly singleton = new WikidataImageProvider()
|
||||
public readonly defaultKeyPrefixes = ["wikidata"]
|
||||
public readonly name = "Wikidata"
|
||||
private static readonly keyBlacklist: ReadonlySet<string> = new Set(
|
||||
["mapillary", ...Utils.Times(i => "mapillary:" + i, 10)])
|
||||
private static readonly keyBlacklist: ReadonlySet<string> = new Set([
|
||||
"mapillary",
|
||||
...Utils.Times((i) => "mapillary:" + i, 10),
|
||||
])
|
||||
|
||||
private constructor() {
|
||||
super()
|
||||
|
@ -26,7 +28,7 @@ export class WikidataImageProvider extends ImageProvider {
|
|||
return new SvelteUIElement(Wikidata_icon)
|
||||
}
|
||||
|
||||
public async ExtractUrls(key: string, value: string): Promise<ProvidedImage[]> {
|
||||
public async ExtractUrls(key: string, value: string): Promise<ProvidedImage[]> {
|
||||
if (WikidataImageProvider.keyBlacklist.has(key)) {
|
||||
return undefined
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ export class WikimediaImageProvider extends ImageProvider {
|
|||
return value
|
||||
}
|
||||
const baseUrl = `https://commons.wikimedia.org/wiki/Special:FilePath/${encodeURIComponent(
|
||||
value,
|
||||
value
|
||||
)}`
|
||||
if (useHd) {
|
||||
return baseUrl
|
||||
|
@ -106,7 +106,8 @@ export class WikimediaImageProvider extends ImageProvider {
|
|||
value = WikimediaImageProvider.removeCommonsPrefix(value)
|
||||
if (value.startsWith("Category:")) {
|
||||
const urls = await Wikimedia.GetCategoryContents(value)
|
||||
return urls.filter((url) => url.startsWith("File:"))
|
||||
return urls
|
||||
.filter((url) => url.startsWith("File:"))
|
||||
.map((image) => this.UrlForImage(image))
|
||||
}
|
||||
if (value.startsWith("File:")) {
|
||||
|
@ -117,7 +118,7 @@ export class WikimediaImageProvider extends ImageProvider {
|
|||
return undefined
|
||||
}
|
||||
// We do a last effort and assume this is a file
|
||||
return [(this.UrlForImage("File:" + value))]
|
||||
return [this.UrlForImage("File:" + value)]
|
||||
}
|
||||
|
||||
public async DownloadAttribution(img: { url: string }): Promise<LicenseInfo> {
|
||||
|
@ -147,7 +148,7 @@ export class WikimediaImageProvider extends ImageProvider {
|
|||
console.warn(
|
||||
"The file",
|
||||
filename,
|
||||
"has no usable metedata or license attached... Please fix the license info file yourself!",
|
||||
"has no usable metedata or license attached... Please fix the license info file yourself!"
|
||||
)
|
||||
return undefined
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue