Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitattributes

This file was deleted.

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
*.mw-datamaps
*.png
*.tiled-session
*.tmx
node_modules
114 changes: 112 additions & 2 deletions extensions/includes/api.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { InterwikiDataImpl, MetadataImpl } from './metadata.mjs';
import { getStringProperty, getWikiUrl } from './util.mjs';

const USER_AGENT = `tiled-datamaps/1.0 (https://github.com/utdrwiki/maps; admin@undertale.wiki) tiled/${tiled.version}`;
Expand Down Expand Up @@ -28,13 +29,18 @@ export function getRestUrl(language = 'en') {
* @param {(value: any|PromiseLike<any>) => void} resolve Promise
* resolution function
* @param {(reason: any?) => void} reject Promise rejection function
* @param {boolean} isArrayBuffer Whether the request expects a binary response
* @returns {() => void} Ready state change handler
*/
const readyStateChange = (xhr, resolve, reject) => () => {
const readyStateChange = (xhr, resolve, reject, isArrayBuffer = false) => () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
try {
resolve(JSON.parse(xhr.responseText));
if (isArrayBuffer) {
resolve(xhr.response);
} else {
resolve(JSON.parse(xhr.responseText));
}
} catch (error) {
reject(new Error(`Failed to parse response: ${xhr.responseText}`));
}
Expand Down Expand Up @@ -160,3 +166,107 @@ export function edit(title, text, summary, accessToken, language = 'en') {
return response.edit;
});
}

/**
* Retrieves maps from the wiki under specific criteria.
* @param {object} options Options for retrieving maps
* @param {string} language Wiki language
* @returns {Promise<DataMap[]>} List of maps on the wiki
*/
function getMaps(options, language = 'en') {
return httpGet(getApiUrl(language), Object.assign({
action: 'query',
prop: 'revisions',
rvprop: 'ids|content',
rvslots: 'main',
format: 'json',
formatversion: '2',
}, options)).then(data => data.query.pages
.filter((/** @type {any} */ page) =>
page.revisions &&
page.revisions.length > 0 &&
page.revisions[0].slots &&
page.revisions[0].slots.main &&
page.revisions[0].slots.main.contentmodel === 'datamap'
)
.map((/** @type {any} */ page) => {
const {slots, revid} = page.revisions[0];
const /** @type {DataMap} */ datamap = JSON.parse(slots.main.content);
datamap.custom = datamap.custom || new MetadataImpl();
datamap.custom.interwiki = datamap.custom.interwiki || {};
datamap.custom.interwiki[language] = new InterwikiDataImpl({
mapName: page.title.split(':').slice(1).join(':'),
});
datamap.custom.interwiki[language].revision = revid;
return datamap;
})
.filter((/** @type {DataMap} */ datamap) => !datamap.$fragment)
);
}

/**
* Retrieves all maps from the wiki.
* @param {string} language Wiki language
* @returns {Promise<DataMap[]>} List of maps on the wiki
*/
export function getAllMaps(language = 'en') {
return getMaps({
generator: 'allpages',
gapnamespace: '2900',
gapfilterredir: 'nonredirects',
gaplimit: 'max',
}, language);
}

/**
* Retrieves a single map from the wiki.
* @param {string} name Map name
* @param {string} language Wiki language
* @returns {Promise<DataMap>} Specified map from the wiki
*/
export function getMap(name, language = 'en') {
return getMaps({
titles: `Map:${name}`
}, language).then(maps => maps[0]);
}

/**
* Returns the URLs of the given map files on the wiki.
* @param {string[]} filenames Map file names
* @param {string} language Wiki language
* @returns {Promise<string[]>} URLs of the given map files on the wiki
*/
export function getFileUrls(filenames, language = 'en') {
return httpGet(getApiUrl(language), {
action: 'query',
titles: filenames.map(name => `File:${name}`).join('|'),
prop: 'imageinfo',
iiprop: 'url',
format: 'json',
formatversion: '2'
}).then(data => filenames.map(filename => data.query.pages
.find((/** @type {any} */ page) => page.title === `File:${
data.query.normalized
?.find((/** @type {any} */ n) => n.from === filename)
?.to ||
filename
}`)
?.imageinfo[0].url)
.filter(Boolean));
}

/**
* Downloads a file from a URL and returns it as an ArrayBuffer.
* @param {string} url URL to download the file from
* @returns {Promise<ArrayBuffer>} Downloaded file data
*/
export function downloadFile(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.onreadystatechange = readyStateChange(xhr, resolve, reject, true);
xhr.setRequestHeader('User-Agent', USER_AGENT);
xhr.send();
});
}
Loading