User:Dagger/Widget drafts/API cache.js
From Guild Wars 2 Wiki
Jump to navigationJump to search
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
var API = {
key: localStorage.getItem("api-key"),
perms: localStorage.getItem("api-key-permissions"),
cacheTime: localStorage.getItem("api-cachetime") || 300 * 1000 /* 5 minutes */,
updates: {},
endpoints: {
"characters": {
url: "https://api.guildwars2.com/v2/characters?wiki=1&page=0&page_size=200",
requiresAuth: true,
requiresPerms: ["characters"],
postProcessing: function (data) {
data.forEach(function (character, index) {
// Pre-calculate a list of active crafting disciplines on this character.
data[index].activeCrafting = [];
character.crafting.forEach(function (craft) {
if (craft.active)
data[index].activeCrafting.push(craft.discipline.toLowerCase());
});
});
// Sort characters by play time. This is probably roughly what people want.
return data.sort(function(a, b) { return a.age < b.age; });
},
},
"account/skins": {
url: "https://api.guildwars2.com/v2/account/skins?wiki=1",
requiresAuth: true,
requiresPerms: ["unlocks"],
},
"account/dyes": {
url: "https://api.guildwars2.com/v2/account/dyes?wiki=1",
requiresAuth: true,
requiresPerms: ["unlocks"],
},
"account/minis": {
url: "https://api.guildwars2.com/v2/account/minis?wiki=1",
requiresAuth: true,
requiresPerms: ["unlocks"],
},
"account/materials": {
url: "https://api.guildwars2.com/v2/account/materials?wiki=1",
requiresAuth: true,
requiresPerms: ["inventories"],
postProcessing: function(data) {
// Reshape the response so we can look up materials by ID rather
// than having to iterate through the whole array to find them.
var items = {};
data.forEach(function(item) { items[item.id] = item; });
return items;
},
},
"account/bank": {
url: "https://api.guildwars2.com/v2/account/bank?wiki=1",
requiresAuth: true,
requiresPerms: ["inventories"],
},
"account/wallet": {
url: "https://api.guildwars2.com/v2/account/wallet?wiki=1",
requiresAuth: true,
requiresPerms: ["wallet"],
postProcessing: function(data) {
// Reshape the response so we can look up currencies by ID rather
// than having to iterate through the whole array to find them.
var currencies = {};
data.forEach(function(currency) {
currencies[currency.id] = currency.value;
});
return currencies;
},
},
},
fetch: function API_fetchAPI(name) {
var endpoint = this.endpoints[name];
// If this endpoint has already been requested, return the first request.
if (this.updates[name]) { return this.updates[name]; }
var dfr = new $.Deferred();
this.updates[name] = dfr.promise();
// If the API is disabled, don't resolve the promise -- just hang.
// This exists to make testing code changes easier.
if (localStorage.getItem("api-disabled")) { return this.updates[name]; }
// If there's no API key set then don't do any queries.
if (!API.key) { return dfr.reject("No API key set."); }
// Check if our key has the required permissions for this query. No sense
// in hitting the API endpoint constantly if it's just going to reject us.
if (endpoint.requiresPerms && endpoint.requiresPerms.some(function(perm) { return API.perms.indexOf(perm) == -1 })) {
return dfr.reject("API key is missing at least one necessary permission. Please set a new key.");
}
// Return the cached response if it's recent enough.
var cacheKey = "api-cache-" + name;
var cachedResponse = localStorage.getItem(cacheKey);
var cachedResponseAge = new Date() - new Date(localStorage.getItem(cacheKey + "-updated"));
if (cachedResponse && cachedResponseAge < API.cacheTime) {
API.log("Using cached response for " + name);
dfr.resolve(JSON.parse(cachedResponse));
} else {
// It's not recent. Time to fetch from the API.
var url = endpoint.url;
if (endpoint.requiresAuth) {
url += (url.indexOf('?') > -1 ? "&" : "?");
url += "access_token=" + this.key;
}
API.log("Querying API: " + url);
$.getJSON(url).then(function(data) {
if (endpoint.postProcessing) data = endpoint.postProcessing(data);
localStorage.setItem(cacheKey, JSON.stringify(data));
localStorage.setItem(cacheKey + "-updated", new Date().toISOString());
dfr.resolve(data);
}, function onFail(reason) { dfr.reject(reason); });
}
return this.updates[name];
},
log: function API_log() {
if (console && console.log) console.log.apply(console, arguments);
},
}
// If a key is set, show all API-related elements.
if (API.key) $(".api.hide").removeClass("hide");
// Load the other scripts. If we don't do this from this page, these scripts end up racing this one...
importScript("User:Dagger/Widget drafts/API recipe unlocks.js");
importScript("User:Dagger/Widget drafts/API item counts.js");
importScript("User:Dagger/Widget drafts/API mini unlocks.js");
importScript("User:Dagger/Widget drafts/API dye unlocks.js");
importScript("User:Dagger/Widget drafts/API skin unlocks.js");
importScript("User:Dagger/Widget drafts/API wallet.js");
importScript("User:Dagger/Widget drafts/API preferences.js");
// This should be in a <style> element in the final widget.
var style = document.createElement("style");
document.querySelector("head").appendChild(style);
style.sheet.insertRule(".api-craftinginactive { opacity: 0.5; }", 0);