|
| 1 | +import { InterwikiDataImpl, MetadataImpl } from './metadata.mjs'; |
1 | 2 | import { getStringProperty, getWikiUrl } from './util.mjs'; |
2 | 3 |
|
3 | 4 | const USER_AGENT = `tiled-datamaps/1.0 (https://github.com/utdrwiki/maps; admin@undertale.wiki) tiled/${tiled.version}`; |
@@ -28,13 +29,18 @@ export function getRestUrl(language = 'en') { |
28 | 29 | * @param {(value: any|PromiseLike<any>) => void} resolve Promise |
29 | 30 | * resolution function |
30 | 31 | * @param {(reason: any?) => void} reject Promise rejection function |
| 32 | + * @param {boolean} isArrayBuffer Whether the request expects a binary response |
31 | 33 | * @returns {() => void} Ready state change handler |
32 | 34 | */ |
33 | | -const readyStateChange = (xhr, resolve, reject) => () => { |
| 35 | +const readyStateChange = (xhr, resolve, reject, isArrayBuffer = false) => () => { |
34 | 36 | if (xhr.readyState === XMLHttpRequest.DONE) { |
35 | 37 | if (xhr.status === 200) { |
36 | 38 | try { |
37 | | - resolve(JSON.parse(xhr.responseText)); |
| 39 | + if (isArrayBuffer) { |
| 40 | + resolve(xhr.response); |
| 41 | + } else { |
| 42 | + resolve(JSON.parse(xhr.responseText)); |
| 43 | + } |
38 | 44 | } catch (error) { |
39 | 45 | reject(new Error(`Failed to parse response: ${xhr.responseText}`)); |
40 | 46 | } |
@@ -160,3 +166,107 @@ export function edit(title, text, summary, accessToken, language = 'en') { |
160 | 166 | return response.edit; |
161 | 167 | }); |
162 | 168 | } |
| 169 | + |
| 170 | +/** |
| 171 | + * Retrieves maps from the wiki under specific criteria. |
| 172 | + * @param {object} options Options for retrieving maps |
| 173 | + * @param {string} language Wiki language |
| 174 | + * @returns {Promise<DataMap[]>} List of maps on the wiki |
| 175 | + */ |
| 176 | +function getMaps(options, language = 'en') { |
| 177 | + return httpGet(getApiUrl(language), Object.assign({ |
| 178 | + action: 'query', |
| 179 | + prop: 'revisions', |
| 180 | + rvprop: 'ids|content', |
| 181 | + rvslots: 'main', |
| 182 | + format: 'json', |
| 183 | + formatversion: '2', |
| 184 | + }, options)).then(data => data.query.pages |
| 185 | + .filter((/** @type {any} */ page) => |
| 186 | + page.revisions && |
| 187 | + page.revisions.length > 0 && |
| 188 | + page.revisions[0].slots && |
| 189 | + page.revisions[0].slots.main && |
| 190 | + page.revisions[0].slots.main.contentmodel === 'datamap' |
| 191 | + ) |
| 192 | + .map((/** @type {any} */ page) => { |
| 193 | + const {slots, revid} = page.revisions[0]; |
| 194 | + const /** @type {DataMap} */ datamap = JSON.parse(slots.main.content); |
| 195 | + datamap.custom = datamap.custom || new MetadataImpl(); |
| 196 | + datamap.custom.interwiki = datamap.custom.interwiki || {}; |
| 197 | + datamap.custom.interwiki[language] = new InterwikiDataImpl({ |
| 198 | + mapName: page.title.split(':').slice(1).join(':'), |
| 199 | + }); |
| 200 | + datamap.custom.interwiki[language].revision = revid; |
| 201 | + return datamap; |
| 202 | + }) |
| 203 | + .filter((/** @type {DataMap} */ datamap) => !datamap.$fragment) |
| 204 | + ); |
| 205 | +} |
| 206 | + |
| 207 | +/** |
| 208 | + * Retrieves all maps from the wiki. |
| 209 | + * @param {string} language Wiki language |
| 210 | + * @returns {Promise<DataMap[]>} List of maps on the wiki |
| 211 | + */ |
| 212 | +export function getAllMaps(language = 'en') { |
| 213 | + return getMaps({ |
| 214 | + generator: 'allpages', |
| 215 | + gapnamespace: '2900', |
| 216 | + gapfilterredir: 'nonredirects', |
| 217 | + gaplimit: 'max', |
| 218 | + }, language); |
| 219 | +} |
| 220 | + |
| 221 | +/** |
| 222 | + * Retrieves a single map from the wiki. |
| 223 | + * @param {string} name Map name |
| 224 | + * @param {string} language Wiki language |
| 225 | + * @returns {Promise<DataMap>} Specified map from the wiki |
| 226 | + */ |
| 227 | +export function getMap(name, language = 'en') { |
| 228 | + return getMaps({ |
| 229 | + titles: `Map:${name}` |
| 230 | + }, language).then(maps => maps[0]); |
| 231 | +} |
| 232 | + |
| 233 | +/** |
| 234 | + * Returns the URLs of the given map files on the wiki. |
| 235 | + * @param {string[]} filenames Map file names |
| 236 | + * @param {string} language Wiki language |
| 237 | + * @returns {Promise<string[]>} URLs of the given map files on the wiki |
| 238 | + */ |
| 239 | +export function getFileUrls(filenames, language = 'en') { |
| 240 | + return httpGet(getApiUrl(language), { |
| 241 | + action: 'query', |
| 242 | + titles: filenames.map(name => `File:${name}`).join('|'), |
| 243 | + prop: 'imageinfo', |
| 244 | + iiprop: 'url', |
| 245 | + format: 'json', |
| 246 | + formatversion: '2' |
| 247 | + }).then(data => filenames.map(filename => data.query.pages |
| 248 | + .find((/** @type {any} */ page) => page.title === `File:${ |
| 249 | + data.query.normalized |
| 250 | + ?.find((/** @type {any} */ n) => n.from === filename) |
| 251 | + ?.to || |
| 252 | + filename |
| 253 | + }`) |
| 254 | + ?.imageinfo[0].url) |
| 255 | + .filter(Boolean)); |
| 256 | +} |
| 257 | + |
| 258 | +/** |
| 259 | + * Downloads a file from a URL and returns it as an ArrayBuffer. |
| 260 | + * @param {string} url URL to download the file from |
| 261 | + * @returns {Promise<ArrayBuffer>} Downloaded file data |
| 262 | + */ |
| 263 | +export function downloadFile(url) { |
| 264 | + return new Promise((resolve, reject) => { |
| 265 | + const xhr = new XMLHttpRequest(); |
| 266 | + xhr.open('GET', url, true); |
| 267 | + xhr.responseType = 'arraybuffer'; |
| 268 | + xhr.onreadystatechange = readyStateChange(xhr, resolve, reject, true); |
| 269 | + xhr.setRequestHeader('User-Agent', USER_AGENT); |
| 270 | + xhr.send(); |
| 271 | + }); |
| 272 | +} |
0 commit comments