| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  | import ImageProvider, { ProvidedImage } from "./ImageProvider" | 
					
						
							|  |  |  | import BaseUIElement from "../../UI/BaseUIElement" | 
					
						
							|  |  |  | import Svg from "../../Svg" | 
					
						
							|  |  |  | import Link from "../../UI/Base/Link" | 
					
						
							|  |  |  | import { Utils } from "../../Utils" | 
					
						
							|  |  |  | import { LicenseInfo } from "./LicenseInfo" | 
					
						
							|  |  |  | import Wikimedia from "../Web/Wikimedia" | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * This module provides endpoints for wikimedia and others | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export class WikimediaImageProvider extends ImageProvider { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |     public static readonly singleton = new WikimediaImageProvider() | 
					
						
							|  |  |  |     public static readonly commonsPrefixes = [ | 
					
						
							|  |  |  |         "https://commons.wikimedia.org/wiki/", | 
					
						
							|  |  |  |         "https://upload.wikimedia.org", | 
					
						
							|  |  |  |         "File:", | 
					
						
							|  |  |  |     ] | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |     private readonly commons_key = "wikimedia_commons" | 
					
						
							|  |  |  |     public readonly defaultKeyPrefixes = [this.commons_key, "image"] | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private constructor() { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         super() | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-09-30 00:26:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |     private static ExtractFileName(url: string) { | 
					
						
							|  |  |  |         if (!url.startsWith("http")) { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             return url | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         const path = new URL(url).pathname | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         return path.substring(path.lastIndexOf("/") + 1) | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |     private static PrepareUrl(value: string): string { | 
					
						
							|  |  |  |         if (value.toLowerCase().startsWith("https://commons.wikimedia.org/wiki/")) { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             return value | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         return `https://commons.wikimedia.org/wiki/Special:FilePath/${encodeURIComponent( | 
					
						
							|  |  |  |             value | 
					
						
							|  |  |  |         )}?width=500&height=400`
 | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private static startsWithCommonsPrefix(value: string): boolean { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         return WikimediaImageProvider.commonsPrefixes.some((prefix) => value.startsWith(prefix)) | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private static removeCommonsPrefix(value: string): string { | 
					
						
							|  |  |  |         if (value.startsWith("https://upload.wikimedia.org/")) { | 
					
						
							|  |  |  |             value = value.substring(value.lastIndexOf("/") + 1) | 
					
						
							|  |  |  |             value = decodeURIComponent(value) | 
					
						
							|  |  |  |             if (!value.startsWith("File:")) { | 
					
						
							|  |  |  |                 value = "File:" + value | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             return value | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const prefix of WikimediaImageProvider.commonsPrefixes) { | 
					
						
							|  |  |  |             if (value.startsWith(prefix)) { | 
					
						
							|  |  |  |                 let part = value.substr(prefix.length) | 
					
						
							|  |  |  |                 if (prefix.startsWith("http")) { | 
					
						
							|  |  |  |                     part = decodeURIComponent(part) | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 return part | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         return value | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |     SourceIcon(backlink: string): BaseUIElement { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         const img = Svg.wikimedia_commons_white_svg().SetStyle("width:2em;height: 2em") | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |         if (backlink === undefined) { | 
					
						
							|  |  |  |             return img | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         return new Link( | 
					
						
							|  |  |  |             Svg.wikimedia_commons_white_img, | 
					
						
							|  |  |  |             `https://commons.wikimedia.org/wiki/${backlink}`, | 
					
						
							|  |  |  |             true | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |     public PrepUrl(value: string): ProvidedImage { | 
					
						
							|  |  |  |         const hasCommonsPrefix = WikimediaImageProvider.startsWithCommonsPrefix(value) | 
					
						
							|  |  |  |         value = WikimediaImageProvider.removeCommonsPrefix(value) | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |         if (value.startsWith("File:")) { | 
					
						
							|  |  |  |             return this.UrlForImage(value) | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // We do a last effort and assume this is a file
 | 
					
						
							|  |  |  |         return this.UrlForImage("File:" + value) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public async ExtractUrls(key: string, value: string): Promise<Promise<ProvidedImage>[]> { | 
					
						
							|  |  |  |         const hasCommonsPrefix = WikimediaImageProvider.startsWithCommonsPrefix(value) | 
					
						
							|  |  |  |         if (key !== undefined && key !== this.commons_key && !hasCommonsPrefix) { | 
					
						
							|  |  |  |             return [] | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         value = WikimediaImageProvider.removeCommonsPrefix(value) | 
					
						
							|  |  |  |         if (value.startsWith("Category:")) { | 
					
						
							|  |  |  |             const urls = await Wikimedia.GetCategoryContents(value) | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             return urls | 
					
						
							|  |  |  |                 .filter((url) => url.startsWith("File:")) | 
					
						
							|  |  |  |                 .map((image) => Promise.resolve(this.UrlForImage(image))) | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (value.startsWith("File:")) { | 
					
						
							|  |  |  |             return [Promise.resolve(this.UrlForImage(value))] | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (value.startsWith("http")) { | 
					
						
							|  |  |  |             // PRobably an error
 | 
					
						
							|  |  |  |             return [] | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // We do a last effort and assume this is a file
 | 
					
						
							|  |  |  |         return [Promise.resolve(this.UrlForImage("File:" + value))] | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-13 00:51:53 +02:00
										 |  |  |     public async DownloadAttribution(filename: string): Promise<LicenseInfo> { | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |         filename = WikimediaImageProvider.ExtractFileName(filename) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (filename === "") { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             return undefined | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         const url = | 
					
						
							|  |  |  |             "https://en.wikipedia.org/w/" + | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |             "api.php?action=query&prop=imageinfo&iiprop=extmetadata&" + | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             "titles=" + | 
					
						
							|  |  |  |             filename + | 
					
						
							|  |  |  |             "&format=json&origin=*" | 
					
						
							|  |  |  |         const data = await Utils.downloadJsonCached(url, 365 * 24 * 60 * 60) | 
					
						
							|  |  |  |         const licenseInfo = new LicenseInfo() | 
					
						
							| 
									
										
										
										
											2021-10-07 22:06:47 +02:00
										 |  |  |         const pageInfo = data.query.pages[-1] | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |         if (pageInfo === undefined) { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             return undefined | 
					
						
							| 
									
										
										
										
											2021-10-07 22:06:47 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         const license = (pageInfo.imageinfo ?? [])[0]?.extmetadata | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |         if (license === undefined) { | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |             console.warn( | 
					
						
							|  |  |  |                 "The file", | 
					
						
							|  |  |  |                 filename, | 
					
						
							|  |  |  |                 "has no usable metedata or license attached... Please fix the license info file yourself!" | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             return undefined | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 22:06:47 +02:00
										 |  |  |         let title = pageInfo.title | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |         if (title.startsWith("File:")) { | 
					
						
							|  |  |  |             title = title.substr("File:".length) | 
					
						
							| 
									
										
										
										
											2021-10-07 22:06:47 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  |         if (title.endsWith(".jpg") || title.endsWith(".png")) { | 
					
						
							| 
									
										
										
										
											2021-10-07 22:06:47 +02:00
										 |  |  |             title = title.substring(0, title.length - 4) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-11-07 16:34:51 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 22:06:47 +02:00
										 |  |  |         licenseInfo.title = title | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         licenseInfo.artist = license.Artist?.value | 
					
						
							|  |  |  |         licenseInfo.license = license.License?.value | 
					
						
							|  |  |  |         licenseInfo.copyrighted = license.Copyrighted?.value | 
					
						
							|  |  |  |         licenseInfo.attributionRequired = license.AttributionRequired?.value | 
					
						
							|  |  |  |         licenseInfo.usageTerms = license.UsageTerms?.value | 
					
						
							|  |  |  |         licenseInfo.licenseShortName = license.LicenseShortName?.value | 
					
						
							|  |  |  |         licenseInfo.credit = license.Credit?.value | 
					
						
							|  |  |  |         licenseInfo.description = license.ImageDescription?.value | 
					
						
							|  |  |  |         licenseInfo.informationLocation = new URL("https://en.wikipedia.org/wiki/" + pageInfo.title) | 
					
						
							|  |  |  |         return licenseInfo | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-08 04:33:39 +02:00
										 |  |  |     private UrlForImage(image: string): ProvidedImage { | 
					
						
							| 
									
										
										
										
											2021-09-30 00:26:21 +02:00
										 |  |  |         if (!image.startsWith("File:")) { | 
					
						
							|  |  |  |             image = "File:" + image | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-09-08 21:40:48 +02:00
										 |  |  |         return { url: WikimediaImageProvider.PrepareUrl(image), key: undefined, provider: this } | 
					
						
							| 
									
										
										
										
											2021-09-29 23:56:59 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } |