From 8b870474d7b150abb2a0c8d4a3400c0225e8f4a3 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Fri, 1 Oct 2021 02:57:41 +0200 Subject: [PATCH] Improvements in loading images --- Logic/Actors/SelectedFeatureHandler.ts | 2 +- Logic/ImageProviders/AllImageProviders.ts | 14 +++++++-- Logic/ImageProviders/ImageProvider.ts | 14 +++++++-- Logic/ImageProviders/Mapillary.ts | 31 ++++++++++++------- Logic/ImageProviders/WikidataImageProvider.ts | 4 +++ .../ImageProviders/WikimediaImageProvider.ts | 4 +-- UI/Image/AttributedImage.ts | 5 ++- UI/Image/ImageCarousel.ts | 2 -- css/index-tailwind-output.css | 16 +++++----- 9 files changed, 61 insertions(+), 31 deletions(-) diff --git a/Logic/Actors/SelectedFeatureHandler.ts b/Logic/Actors/SelectedFeatureHandler.ts index c76febd41..440115984 100644 --- a/Logic/Actors/SelectedFeatureHandler.ts +++ b/Logic/Actors/SelectedFeatureHandler.ts @@ -46,7 +46,7 @@ export default class SelectedFeatureHandler { // IF the selected element changes, set the hash correctly state.selectedElement.addCallback(feature => { if (feature === undefined) { - if (SelectedFeatureHandler._no_trigger_on.has(hash.data)) { + if (!SelectedFeatureHandler._no_trigger_on.has(hash.data)) { hash.setData("") } } diff --git a/Logic/ImageProviders/AllImageProviders.ts b/Logic/ImageProviders/AllImageProviders.ts index 18589f635..92818379f 100644 --- a/Logic/ImageProviders/AllImageProviders.ts +++ b/Logic/ImageProviders/AllImageProviders.ts @@ -16,7 +16,7 @@ export default class AllImageProviders { Mapillary.singleton, WikidataImageProvider.singleton, WikimediaImageProvider.singleton, - new GenericImageProvider([].concat(...Imgur.defaultValuePrefix, WikimediaImageProvider.commonsPrefix))] + new GenericImageProvider([].concat(...Imgur.defaultValuePrefix, WikimediaImageProvider.commonsPrefix, ...Mapillary.valuePrefixes))] private static _cache: Map> = new Map>() @@ -37,8 +37,18 @@ export default class AllImageProviders { this._cache.set(id, source) const allSources = [] for (const imageProvider of AllImageProviders.ImageAttributionSource) { + + let prefixes = imageProvider.defaultKeyPrefixes + if(imagePrefix !== undefined){ + prefixes = [...prefixes] + if(prefixes.indexOf("image") >= 0){ + prefixes.splice(prefixes.indexOf("image"), 1) + } + prefixes.push(imagePrefix) + } + const singleSource = imageProvider.GetRelevantUrls(tags, { - prefixes: imagePrefix !== undefined ? [imagePrefix] : undefined + prefixes: prefixes }) allSources.push(singleSource) singleSource.addCallbackAndRunD(_ => { diff --git a/Logic/ImageProviders/ImageProvider.ts b/Logic/ImageProviders/ImageProvider.ts index 67154d945..efce6aa92 100644 --- a/Logic/ImageProviders/ImageProvider.ts +++ b/Logic/ImageProviders/ImageProvider.ts @@ -8,7 +8,7 @@ export interface ProvidedImage { export default abstract class ImageProvider { - protected abstract readonly defaultKeyPrefixes : string[] + public abstract readonly defaultKeyPrefixes : string[] = ["mapillary", "image"] private _cache = new Map>() @@ -33,6 +33,9 @@ export default abstract class ImageProvider { prefixes?: string[] }):UIEventSource { const prefixes = options?.prefixes ?? this.defaultKeyPrefixes + if(prefixes === undefined){ + throw "The image provider"+this.constructor.name+" doesn't define `defaultKeyPrefixes`" + } const relevantUrls = new UIEventSource<{ url: string; key: string; provider: ImageProvider }[]>([]) const seenValues = new Set() allTags.addCallbackAndRunD(tags => { @@ -45,10 +48,15 @@ export default abstract class ImageProvider { continue } seenValues.add(value) - this.ExtractUrls(key, value).then(promises => { - for (const promise of promises) { + for (const promise of promises ?? []) { + if(promise === undefined){ + continue + } promise.then(providedImage => { + if(providedImage === undefined){ + return + } relevantUrls.data.push(providedImage) relevantUrls.ping() }) diff --git a/Logic/ImageProviders/Mapillary.ts b/Logic/ImageProviders/Mapillary.ts index 45342bc14..3fa25a534 100644 --- a/Logic/ImageProviders/Mapillary.ts +++ b/Logic/ImageProviders/Mapillary.ts @@ -5,24 +5,25 @@ import Svg from "../../Svg"; import {Utils} from "../../Utils"; import {LicenseInfo} from "./LicenseInfo"; import Constants from "../../Models/Constants"; +import {fail} from "assert"; export class Mapillary extends ImageProvider { - defaultKeyPrefixes = ["mapillary"] + defaultKeyPrefixes = ["mapillary","image"] public static readonly singleton = new Mapillary(); - - private static readonly v4_cached_urls = new Map>(); + private static readonly valuePrefix = "https://a.mapillary.com" + public static readonly valuePrefixes = [Mapillary.valuePrefix, "http://mapillary.com","https://mapillary.com"] private constructor() { super(); } - private static ExtractKeyFromURL(value: string): { + private static ExtractKeyFromURL(value: string, failIfNoMath = false): { key: string, isApiv4?: boolean } { - if (value.startsWith("https://a.mapillary.com")) { + if (value.startsWith(Mapillary.valuePrefix)) { const key = value.substring(0, value.lastIndexOf("?")).substring(value.lastIndexOf("/") + 1) return {key: key, isApiv4: !isNaN(Number(key))}; } @@ -47,8 +48,11 @@ export class Mapillary extends ImageProvider { if (matchApi !== null) { return {key: matchApi[1]}; } - - + + if(failIfNoMath){ + return undefined; + } + return {key: value, isApiv4: !isNaN(Number(value))}; } @@ -61,7 +65,12 @@ export class Mapillary extends ImageProvider { } private async PrepareUrlAsync(key: string, value: string): Promise { - const keyV = Mapillary.ExtractKeyFromURL(value) + const failIfNoMatch = key.indexOf("mapillary") < 0 + const keyV = Mapillary.ExtractKeyFromURL(value, failIfNoMatch) + if(keyV === undefined){ + return undefined; + } + if (!keyV.isApiv4) { const url = `https://images.mapillary.com/${keyV.key}/thumb-640.jpg?client_id=${Constants.mapillary_client_token_v3}` return { @@ -70,10 +79,8 @@ export class Mapillary extends ImageProvider { key: key } } else { - const key = keyV.key; - const metadataUrl = 'https://graph.mapillary.com/' + key + '?fields=thumb_1024_url&&access_token=' + Constants.mapillary_client_token_v4; - const source = new UIEventSource(undefined) - Mapillary.v4_cached_urls.set(key, source) + const mapillaryId = keyV.key; + const metadataUrl = 'https://graph.mapillary.com/' + mapillaryId + '?fields=thumb_1024_url&&access_token=' + Constants.mapillary_client_token_v4; const response = await Utils.downloadJson(metadataUrl) const url = response["thumb_1024_url"]; return { diff --git a/Logic/ImageProviders/WikidataImageProvider.ts b/Logic/ImageProviders/WikidataImageProvider.ts index 3bb7d3c91..8576de5d9 100644 --- a/Logic/ImageProviders/WikidataImageProvider.ts +++ b/Logic/ImageProviders/WikidataImageProvider.ts @@ -26,6 +26,10 @@ export class WikidataImageProvider extends ImageProvider { if (value.startsWith(wikidataUrl)) { value = value.substring(wikidataUrl.length) } + if(value.startsWith("http")){ + // Probably some random link in the image field - we skip it + return undefined + } if (!value.startsWith("Q")) { value = "Q" + value } diff --git a/Logic/ImageProviders/WikimediaImageProvider.ts b/Logic/ImageProviders/WikimediaImageProvider.ts index b8940a520..20f69a7e4 100644 --- a/Logic/ImageProviders/WikimediaImageProvider.ts +++ b/Logic/ImageProviders/WikimediaImageProvider.ts @@ -44,7 +44,7 @@ export class WikimediaImageProvider extends ImageProvider { if (continueParameter !== undefined) { url = `${url}&cmcontinue=${continueParameter}`; } - console.log("Loading a wikimedia category: ", url) + console.debug("Loading a wikimedia category: ", url) const response = await Utils.downloadJson(url) const members = response.query?.categorymembers ?? []; const imageOverview: string[] = members.map(member => member.title); @@ -55,7 +55,7 @@ export class WikimediaImageProvider extends ImageProvider { } if (maxLoad - imageOverview.length <= 0) { - console.log(`Recursive wikimedia category load stopped for ${categoryName}`) + console.debug(`Recursive wikimedia category load stopped for ${categoryName}`) return imageOverview; } diff --git a/UI/Image/AttributedImage.ts b/UI/Image/AttributedImage.ts index 919a9ac17..b0bb60d80 100644 --- a/UI/Image/AttributedImage.ts +++ b/UI/Image/AttributedImage.ts @@ -3,6 +3,7 @@ import Attribution from "./Attribution"; import Img from "../Base/Img"; import {ProvidedImage} from "../../Logic/ImageProviders/ImageProvider"; import BaseUIElement from "../BaseUIElement"; +import {Mapillary} from "../../Logic/ImageProviders/Mapillary"; export class AttributedImage extends Combine { @@ -10,7 +11,9 @@ export class AttributedImage extends Combine { constructor(imageInfo: ProvidedImage) { let img: BaseUIElement; let attr: BaseUIElement - img = new Img(imageInfo.url); + img = new Img(imageInfo.url, false, { + fallbackImage: imageInfo.provider === Mapillary.singleton ? "./assets/svg/blocked.svg" : undefined + }); attr = new Attribution(imageInfo.provider.GetAttributionFor(imageInfo.url), imageInfo.provider.SourceIcon(), ) diff --git a/UI/Image/ImageCarousel.ts b/UI/Image/ImageCarousel.ts index c20f52080..9932da616 100644 --- a/UI/Image/ImageCarousel.ts +++ b/UI/Image/ImageCarousel.ts @@ -13,9 +13,7 @@ export class ImageCarousel extends Toggle { const uiElements = images.map((imageURLS: { key: string, url: string, provider: ImageProvider }[]) => { const uiElements: BaseUIElement[] = []; for (const url of imageURLS) { - try { - let image = new AttributedImage(url) if (url.key !== undefined) { diff --git a/css/index-tailwind-output.css b/css/index-tailwind-output.css index 821461d81..4cbe196ae 100644 --- a/css/index-tailwind-output.css +++ b/css/index-tailwind-output.css @@ -912,14 +912,14 @@ video { margin-right: 0px; } -.mb-4 { - margin-bottom: 1rem; -} - .mb-1 { margin-bottom: 0.25rem; } +.mb-4 { + margin-bottom: 1rem; +} + .box-border { box-sizing: border-box; } @@ -1156,14 +1156,14 @@ video { animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; } -.cursor-wait { - cursor: wait; -} - .cursor-pointer { cursor: pointer; } +.cursor-wait { + cursor: wait; +} + .resize { resize: both; }