forked from MapComplete/MapComplete
Feat: check if the image was blurred, attempt to reload if it is done; refactoring of ImageProvider code
This commit is contained in:
parent
590591dd31
commit
4650170db4
14 changed files with 224 additions and 190 deletions
|
@ -6,6 +6,7 @@ import { Store, UIEventSource } from "../UIEventSource"
|
|||
import ImageProvider, { ProvidedImage } from "./ImageProvider"
|
||||
import { WikidataImageProvider } from "./WikidataImageProvider"
|
||||
import Panoramax from "./Panoramax"
|
||||
import { Utils } from "../../Utils"
|
||||
|
||||
/**
|
||||
* A generic 'from the interwebz' image picker, without attribution
|
||||
|
@ -45,10 +46,6 @@ export default class AllImageProviders {
|
|||
wikimedia: WikimediaImageProvider.singleton,
|
||||
panoramax: Panoramax.singleton
|
||||
}
|
||||
private static _cache: Map<string, UIEventSource<ProvidedImage[]>> = new Map<
|
||||
string,
|
||||
UIEventSource<ProvidedImage[]>
|
||||
>()
|
||||
|
||||
public static byName(name: string) {
|
||||
return AllImageProviders.providersByName[name.toLowerCase()]
|
||||
|
@ -76,42 +73,25 @@ export default class AllImageProviders {
|
|||
tags: Store<Record<string, string>>,
|
||||
tagKey?: string[]
|
||||
): Store<ProvidedImage[]> {
|
||||
if (tags.data.id === undefined) {
|
||||
if (tags?.data?.id === undefined) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const cacheKey = tags.data.id + tagKey
|
||||
const cached = this._cache.get(cacheKey)
|
||||
if (cached !== undefined) {
|
||||
return cached
|
||||
}
|
||||
|
||||
const source = new UIEventSource([])
|
||||
this._cache.set(cacheKey, source)
|
||||
const allSources: Store<ProvidedImage[]>[] = []
|
||||
for (const imageProvider of AllImageProviders.ImageAttributionSource) {
|
||||
|
||||
|
||||
const singleSource = imageProvider.GetRelevantUrls(tags, {
|
||||
/*
|
||||
By default, 'GetRelevantUrls' uses the defaultKeyPrefixes.
|
||||
However, we override them if a custom image tag is set, e.g. 'image:menu'
|
||||
*/
|
||||
prefixes: tagKey ?? imageProvider.defaultKeyPrefixes,
|
||||
})
|
||||
/*
|
||||
By default, 'GetRelevantUrls' uses the defaultKeyPrefixes.
|
||||
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))
|
||||
allSources.push(singleSource)
|
||||
singleSource.addCallbackAndRunD((_) => {
|
||||
const all: ProvidedImage[] = [].concat(...allSources.map((source) => source.data))
|
||||
const uniq = []
|
||||
const seen = new Set<string>()
|
||||
for (const img of all) {
|
||||
if (seen.has(img.url)) {
|
||||
continue
|
||||
}
|
||||
seen.add(img.url)
|
||||
uniq.push(img)
|
||||
}
|
||||
source.setData(uniq)
|
||||
const dedup = Utils.DedupOnId(all, i => i?.id ?? i?.url)
|
||||
source.set(dedup)
|
||||
})
|
||||
}
|
||||
return source
|
||||
|
|
|
@ -15,26 +15,24 @@ export default class GenericImageProvider extends ImageProvider {
|
|||
this._valuePrefixBlacklist = valuePrefixBlacklist
|
||||
}
|
||||
|
||||
async ExtractUrls(key: string, value: string): Promise<Promise<ProvidedImage>[]> {
|
||||
ExtractUrls(key: string, value: string): undefined | ProvidedImage[] {
|
||||
if (this._valuePrefixBlacklist.some((prefix) => value.startsWith(prefix))) {
|
||||
return []
|
||||
return undefined
|
||||
}
|
||||
|
||||
try {
|
||||
new URL(value)
|
||||
} catch (_) {
|
||||
// Not a valid URL
|
||||
return []
|
||||
return undefined
|
||||
}
|
||||
|
||||
return [
|
||||
Promise.resolve({
|
||||
key: key,
|
||||
url: value,
|
||||
provider: this,
|
||||
id: value,
|
||||
}),
|
||||
]
|
||||
return [{
|
||||
key: key,
|
||||
url: value,
|
||||
provider: this,
|
||||
id: value,
|
||||
}]
|
||||
}
|
||||
|
||||
SourceIcon() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Store, UIEventSource } from "../UIEventSource"
|
||||
import { Store, Stores, UIEventSource } from "../UIEventSource"
|
||||
import BaseUIElement from "../../UI/BaseUIElement"
|
||||
import { LicenseInfo } from "./LicenseInfo"
|
||||
import { Utils } from "../../Utils"
|
||||
|
@ -10,6 +10,7 @@ export interface ProvidedImage {
|
|||
provider: ImageProvider
|
||||
id: string
|
||||
date?: Date,
|
||||
status?: string | "ready"
|
||||
/**
|
||||
* Compass angle of the taken image
|
||||
* 0 = north, 90° = East
|
||||
|
@ -26,59 +27,45 @@ export default abstract class ImageProvider {
|
|||
|
||||
public abstract SourceIcon(id?: string, location?: { lon: number; lat: number }): BaseUIElement
|
||||
|
||||
|
||||
/**
|
||||
* Given a properties object, maps it onto _all_ the available pictures for this imageProvider.
|
||||
* This iterates over _all_ tags and matches _anything_ that might be an image
|
||||
* Gets all the relevant URLS for the given tags and for the given prefixes;
|
||||
* extracts the necessary information
|
||||
* @param tags
|
||||
* @param prefixes
|
||||
*/
|
||||
public GetRelevantUrls(
|
||||
allTags: Store<any>,
|
||||
options?: {
|
||||
prefixes?: string[]
|
||||
}
|
||||
): UIEventSource<ProvidedImage[]> {
|
||||
const prefixes = Utils.Dedup(options?.prefixes ?? this.defaultKeyPrefixes)
|
||||
if (prefixes === undefined) {
|
||||
throw "No `defaultKeyPrefixes` defined by this image provider"
|
||||
}
|
||||
const relevantUrls = new UIEventSource<
|
||||
{ id: string; url: string; key: string; provider: ImageProvider }[]
|
||||
>([])
|
||||
public async getRelevantUrlsFor(tags: Record<string, string>, prefixes: string[]): Promise<ProvidedImage[]> {
|
||||
const relevantUrls: ProvidedImage[] = []
|
||||
const seenValues = new Set<string>()
|
||||
allTags.addCallbackAndRunD((tags) => {
|
||||
for (const key in tags) {
|
||||
if(key === "panoramax"){
|
||||
console.log("Inspecting", key,"against", prefixes)
|
||||
}
|
||||
if (!prefixes.some((prefix) => key === prefix || key.match(new RegExp(prefix+":[0-9]+")))) {
|
||||
|
||||
for (const key in tags) {
|
||||
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()) ?? [])
|
||||
for (const value of values) {
|
||||
if (seenValues.has(value)) {
|
||||
continue
|
||||
}
|
||||
const values = Utils.NoEmpty(tags[key]?.split(";")?.map((v) => v.trim()) ?? [])
|
||||
for (const value of values) {
|
||||
if (seenValues.has(value)) {
|
||||
continue
|
||||
}
|
||||
seenValues.add(value)
|
||||
this.ExtractUrls(key, value).then((promises) => {
|
||||
for (const promise of promises ?? []) {
|
||||
if (promise === undefined) {
|
||||
continue
|
||||
}
|
||||
promise.then((providedImage) => {
|
||||
if (providedImage === undefined) {
|
||||
return
|
||||
}
|
||||
relevantUrls.data.push(providedImage)
|
||||
relevantUrls.ping()
|
||||
})
|
||||
}
|
||||
})
|
||||
seenValues.add(value)
|
||||
let images = this.ExtractUrls(key, value)
|
||||
if(!Array.isArray(images)){
|
||||
images = await images
|
||||
}
|
||||
if(images){
|
||||
relevantUrls.push(...images)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
return relevantUrls
|
||||
}
|
||||
|
||||
public abstract ExtractUrls(key: string, value: string): Promise<Promise<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 DownloadAttribution(providedImage: {
|
||||
url: string
|
||||
|
|
|
@ -24,18 +24,18 @@ export class Imgur extends ImageProvider {
|
|||
return undefined
|
||||
}
|
||||
|
||||
public async ExtractUrls(key: string, value: string): Promise<Promise<ProvidedImage>[]> {
|
||||
public ExtractUrls(key: string, value: string): undefined | ProvidedImage[] {
|
||||
if (Imgur.defaultValuePrefix.some((prefix) => value.startsWith(prefix))) {
|
||||
return [
|
||||
Promise.resolve({
|
||||
{
|
||||
url: value,
|
||||
key: key,
|
||||
provider: this,
|
||||
id: value,
|
||||
}),
|
||||
}
|
||||
]
|
||||
}
|
||||
return []
|
||||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -131,8 +131,9 @@ export class Mapillary extends ImageProvider {
|
|||
return new SvelteUIElement(MapillaryIcon, { url })
|
||||
}
|
||||
|
||||
async ExtractUrls(key: string, value: string): Promise<Promise<ProvidedImage>[]> {
|
||||
return [this.PrepareUrlAsync(key, value)]
|
||||
async ExtractUrls(key: string, value: string): Promise<ProvidedImage[]> {
|
||||
const img = await this.PrepareUrlAsync(key, value)
|
||||
return [img]
|
||||
}
|
||||
|
||||
public async DownloadAttribution(providedImage: { id: string }): Promise<LicenseInfo> {
|
||||
|
|
|
@ -1,35 +1,31 @@
|
|||
import { ImageUploader } from "./ImageUploader"
|
||||
import { AuthorizedPanoramax } from "panoramax-js/dist"
|
||||
import { AuthorizedPanoramax, PanoramaxXYZ, ImageData } from "panoramax-js/dist"
|
||||
import ExifReader from "exifreader"
|
||||
import ImageProvider, { ProvidedImage } from "./ImageProvider"
|
||||
import BaseUIElement from "../../UI/BaseUIElement"
|
||||
import { LicenseInfo } from "./LicenseInfo"
|
||||
import { Utils } from "../../Utils"
|
||||
import { Feature, FeatureCollection, Point } from "geojson"
|
||||
import { GeoOperations } from "../GeoOperations"
|
||||
import Constants from "../../Models/Constants"
|
||||
import { Store, Stores, UIEventSource } from "../UIEventSource"
|
||||
|
||||
type ImageData = Feature<Point, { "geovisio:producer": string, "geovisio:license": string, "datetime": string }> & {
|
||||
id: string,
|
||||
assets: { hd: { href: string }, sd: { href: string } },
|
||||
providers: {name: string}[]
|
||||
}
|
||||
|
||||
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)
|
||||
public defaultKeyPrefixes: string[] = ["panoramax"]
|
||||
public readonly name: string = "panoramax"
|
||||
|
||||
private static knownMeta: Record<string, ImageData> = {}
|
||||
private static knownMeta: Record<string, { data: ImageData, time: Date }> = {}
|
||||
|
||||
public SourceIcon(id?: string, location?: { lon: number; lat: number; }): BaseUIElement {
|
||||
return undefined
|
||||
}
|
||||
|
||||
public addKnownMeta(meta: ImageData){
|
||||
console.log("Adding known meta for", meta.id)
|
||||
PanoramaxImageProvider.knownMeta[meta.id] = meta
|
||||
public addKnownMeta(meta: ImageData) {
|
||||
PanoramaxImageProvider.knownMeta[meta.id] = { data: meta, time: new Date() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -39,16 +35,14 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
|||
*/
|
||||
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/api/collections/${sequence}/items/${id}`
|
||||
const data = <any> await Utils.downloadJsonCached(url, 60 * 60 * 1000)
|
||||
return {url, data}
|
||||
const url = `https://panoramax.mapcomplete.org/`
|
||||
const data = await PanoramaxImageProvider.defaultPanoramax.imageInfo(sequence, id)
|
||||
return { url, data }
|
||||
}
|
||||
|
||||
private async getInfoFromXYZ(imageId: string): Promise<{ data: ImageData, url: string }> {
|
||||
const url = "https://api.panoramax.xyz/api/search?limit=1&ids=" + imageId
|
||||
const metaAll = await Utils.downloadJsonCached<FeatureCollection<Point>>(url, 1000 * 60 * 60)
|
||||
const data= <any>metaAll.features[0]
|
||||
return {data, url}
|
||||
const data = await PanoramaxImageProvider.xyz.imageInfo(imageId)
|
||||
return { data, url: "https://api.panoramax.xyz/" }
|
||||
}
|
||||
|
||||
|
||||
|
@ -57,17 +51,18 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
|||
* @param meta
|
||||
* @private
|
||||
*/
|
||||
private featureToImage(info: {data: ImageData, url: string}) {
|
||||
const meta = info.data
|
||||
const url = info.url
|
||||
private featureToImage(info: { data: ImageData, url: string }) {
|
||||
const meta = info?.data
|
||||
if (!meta) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
function makeAbsolute(s: string){
|
||||
if(!s.startsWith("https://") && !s.startsWith("http://")){
|
||||
const parsed = new URL(url)
|
||||
return parsed.protocol+"//"+parsed.host+s
|
||||
const url = info.url
|
||||
|
||||
function makeAbsolute(s: string) {
|
||||
if (!s.startsWith("https://") && !s.startsWith("http://")) {
|
||||
const parsed = new URL(url)
|
||||
return parsed.protocol + "//" + parsed.host + s
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
@ -80,27 +75,64 @@ export default class PanoramaxImageProvider extends ImageProvider {
|
|||
lon, lat,
|
||||
key: "panoramax",
|
||||
provider: this,
|
||||
status: meta.properties["geovisio:status"],
|
||||
rotation: Number(meta.properties["view:azimuth"]),
|
||||
date: new Date(meta.properties.datetime),
|
||||
}
|
||||
}
|
||||
|
||||
private async getInfoFor(id: string): Promise<{ data: ImageData, url: string }> {
|
||||
const cached= PanoramaxImageProvider.knownMeta[id]
|
||||
console.log("Cached version", id, cached)
|
||||
if(cached){
|
||||
return {data: cached, url: undefined}
|
||||
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 }
|
||||
}
|
||||
}
|
||||
try {
|
||||
return await this.getInfoFromMapComplete(id)
|
||||
} catch (e) {
|
||||
return await this.getInfoFromXYZ(id)
|
||||
console.debug(e)
|
||||
}
|
||||
try {
|
||||
return await this.getInfoFromXYZ(id)
|
||||
} catch (e) {
|
||||
console.debug(e)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
|
||||
public async ExtractUrls(key: string, value: string): Promise<Promise<ProvidedImage>[]> {
|
||||
return [this.getInfoFor(value).then(r => this.featureToImage(<any>r))]
|
||||
public async ExtractUrls(key: string, value: string): Promise<ProvidedImage[]> {
|
||||
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))
|
||||
|
||||
function hasLoading(data: ProvidedImage[]) {
|
||||
if(data === undefined){
|
||||
return true
|
||||
}
|
||||
return data?.some(img => img?.status !== undefined && img?.status !== "ready" && img?.status !== "broken")
|
||||
}
|
||||
|
||||
Stores.Chronic(1500, () =>
|
||||
hasLoading(source.data),
|
||||
).addCallback(_ => {
|
||||
console.log("UPdating... ")
|
||||
super.getRelevantUrlsFor(tags, prefixes).then(data => {
|
||||
console.log("New panoramax data is", data, hasLoading(data))
|
||||
source.set(data)
|
||||
return !hasLoading(data)
|
||||
})
|
||||
})
|
||||
|
||||
return source
|
||||
}
|
||||
|
||||
public async DownloadAttribution(providedImage: { url: string; id: string; }): Promise<LicenseInfo> {
|
||||
|
@ -139,7 +171,7 @@ export class PanoramaxUploader implements ImageUploader {
|
|||
|
||||
const p = this._panoramax
|
||||
const defaultSequence = (await p.mySequences())[0]
|
||||
const img = <ImageData> await p.addImage(blob, defaultSequence, {
|
||||
const img = <ImageData>await p.addImage(blob, defaultSequence, {
|
||||
lat: !hasGPS ? lat : undefined,
|
||||
lon: !hasGPS ? lon : undefined,
|
||||
datetime: !hasDate ? new Date().toISOString() : undefined,
|
||||
|
@ -149,11 +181,10 @@ export class PanoramaxUploader implements ImageUploader {
|
|||
|
||||
})
|
||||
PanoramaxImageProvider.singleton.addKnownMeta(img)
|
||||
await Utils.waitFor(1250)
|
||||
return {
|
||||
key: "panoramax",
|
||||
value: img.id,
|
||||
absoluteUrl: img.assets.hd.href
|
||||
absoluteUrl: img.assets.hd.href,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import Wikidata from "../Web/Wikidata"
|
|||
import SvelteUIElement from "../../UI/Base/SvelteUIElement"
|
||||
import * as Wikidata_icon from "../../assets/svg/Wikidata.svelte"
|
||||
import { Utils } from "../../Utils"
|
||||
import { ImmutableStore, Store, Stores, UIEventSource } from "../UIEventSource"
|
||||
|
||||
export class WikidataImageProvider extends ImageProvider {
|
||||
public static readonly singleton = new WikidataImageProvider()
|
||||
|
@ -25,28 +26,28 @@ export class WikidataImageProvider extends ImageProvider {
|
|||
return new SvelteUIElement(Wikidata_icon)
|
||||
}
|
||||
|
||||
public async ExtractUrls(key: string, value: string): Promise<Promise<ProvidedImage>[]> {
|
||||
public async ExtractUrls(key: string, value: string): Promise<ProvidedImage[]> {
|
||||
if (WikidataImageProvider.keyBlacklist.has(key)) {
|
||||
return []
|
||||
return undefined
|
||||
}
|
||||
const entity = await Wikidata.LoadWikidataEntryAsync(value)
|
||||
if (entity === undefined) {
|
||||
return []
|
||||
return undefined
|
||||
}
|
||||
|
||||
const allImages: Promise<ProvidedImage>[] = []
|
||||
const allImages: Promise<ProvidedImage[]>[] = []
|
||||
// P18 is the claim 'depicted in this image'
|
||||
for (const img of Array.from(entity.claims.get("P18") ?? [])) {
|
||||
const promises = await WikimediaImageProvider.singleton.ExtractUrls(undefined, img)
|
||||
allImages.push(...promises)
|
||||
const promises = WikimediaImageProvider.singleton.ExtractUrls(undefined, img)
|
||||
allImages.push(promises)
|
||||
}
|
||||
// P373 is 'commons category'
|
||||
for (let cat of Array.from(entity.claims.get("P373") ?? [])) {
|
||||
if (!cat.startsWith("Category:")) {
|
||||
cat = "Category:" + cat
|
||||
}
|
||||
const promises = await WikimediaImageProvider.singleton.ExtractUrls(undefined, cat)
|
||||
allImages.push(...promises)
|
||||
const promises = WikimediaImageProvider.singleton.ExtractUrls(undefined, cat)
|
||||
allImages.push(promises)
|
||||
}
|
||||
|
||||
const commons = entity.commons
|
||||
|
@ -54,10 +55,11 @@ export class WikidataImageProvider extends ImageProvider {
|
|||
commons !== undefined &&
|
||||
(commons.startsWith("Category:") || commons.startsWith("File:"))
|
||||
) {
|
||||
const promises = await WikimediaImageProvider.singleton.ExtractUrls(undefined, commons)
|
||||
allImages.push(...promises)
|
||||
const promises = WikimediaImageProvider.singleton.ExtractUrls(undefined, commons)
|
||||
allImages.push(promises)
|
||||
}
|
||||
return allImages
|
||||
const resolved = await Promise.all(Utils.NoNull(allImages))
|
||||
return [].concat(...resolved)
|
||||
}
|
||||
|
||||
public DownloadAttribution(_): Promise<any> {
|
||||
|
|
|
@ -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
|
||||
|
@ -97,28 +97,27 @@ export class WikimediaImageProvider extends ImageProvider {
|
|||
return this.UrlForImage("File:" + value)
|
||||
}
|
||||
|
||||
public async ExtractUrls(key: string, value: string): Promise<Promise<ProvidedImage>[]> {
|
||||
public async ExtractUrls(key: string, value: string): undefined | Promise<ProvidedImage[]> {
|
||||
const hasCommonsPrefix = WikimediaImageProvider.startsWithCommonsPrefix(value)
|
||||
if (key !== undefined && key !== this.commons_key && !hasCommonsPrefix) {
|
||||
return []
|
||||
return undefined
|
||||
}
|
||||
|
||||
value = WikimediaImageProvider.removeCommonsPrefix(value)
|
||||
if (value.startsWith("Category:")) {
|
||||
const urls = await Wikimedia.GetCategoryContents(value)
|
||||
return urls
|
||||
.filter((url) => url.startsWith("File:"))
|
||||
.map((image) => Promise.resolve(this.UrlForImage(image)))
|
||||
return urls.filter((url) => url.startsWith("File:"))
|
||||
.map((image) => this.UrlForImage(image))
|
||||
}
|
||||
if (value.startsWith("File:")) {
|
||||
return [Promise.resolve(this.UrlForImage(value))]
|
||||
return [this.UrlForImage(value)]
|
||||
}
|
||||
if (value.startsWith("http")) {
|
||||
// PRobably an error
|
||||
return []
|
||||
// Probably an error
|
||||
return undefined
|
||||
}
|
||||
// We do a last effort and assume this is a file
|
||||
return [Promise.resolve(this.UrlForImage("File:" + value))]
|
||||
return [(this.UrlForImage("File:" + value))]
|
||||
}
|
||||
|
||||
public async DownloadAttribution(img: { url: string }): Promise<LicenseInfo> {
|
||||
|
@ -148,7 +147,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