Skip to content

Instantly share code, notes, and snippets.

@Scoder12
Created March 16, 2021 20:44
Show Gist options
  • Save Scoder12/aa2154713786f169bf75b97514af45fb to your computer and use it in GitHub Desktop.
Save Scoder12/aa2154713786f169bf75b97514af45fb to your computer and use it in GitHub Desktop.
Fantasy geopolitics leaderboard compositor. Finds top scoring countries and displays their owner names.
/**
* @author Scoder12 <https://scoder12.ml>
* @description A script to combine multiple fanschool data sources into one table.
* Finds top scoring countries and displays their owner names.
* Useful for finding high-scoring, untaken countries.
* API responses are cached as api_<endpoint> keys on window so that re-running the
* script will not re-request the data.
* @url https://app.fanschool.org/
* @license AGPL-3.0-or-later
* @tutorial Open your fasnschool dashboard and paste this script into the console.
*/
/*
Copyright (C) 2021 Scoder12
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
(async function () {
const m = /\/league\/(\d+)\/game\/(\d+)\/([a-zA-Z0-9]+)/gm.exec(
window.location.pathname
);
if (!m) return alert("Unexpected URL. Are you on fanschool?");
const [_, leagueId, gameId] = m;
const apiDom = "https://api.fanschool.org/v1";
const apiBase = apiDom + `/leagues/${leagueId}/games/${gameId}/`;
const token = sessionStorage.getItem("token");
if (!token) return alert("Missing token, are you logged in?");
async function requestApi(url) {
const r = await fetch(url, { headers: { "authentication-token": token } });
if (r.status != 200) {
console.log(r);
try {
console.log(await r.text());
} catch (e) {
console.error(e);
}
throw new Error("Error while fetching data");
}
const t = await r.text();
try {
data = JSON.parse(t);
} catch (e) {
console.error("JSON decode error with text:");
console.log(t);
throw e;
}
return data;
}
async function cachedReq(keyName, optendpoint) {
const endpoint = optendpoint || apiBase + keyName;
const k = "api_" + keyName;
if (window[k]) {
return window[k];
}
console.log("Fetching " + endpoint);
const d = await requestApi(endpoint);
window[k] = d;
return d;
}
const rankingData = await cachedReq("rankings");
const trends = await cachedReq("trends");
const userData = await cachedReq("users", apiDom + "/users");
const leagues = userData.leagues.filter(
(i) => i && i.id.toString() === leagueId
);
if (leagues.length != 1) return alert("League not found!");
const league = leagues[0];
const playerData = new Map();
for (const p of league.players) {
if (p && p.id) playerData.set(p.id, { name: p.full_name, email: p.email });
}
// rankingData but its a Map indexed by player_id
const rankings = new Map();
// Country name => player ID
const ownedCountries = new Map();
for (const p of rankingData.values) {
for (const c of p.active_items) {
ownedCountries.set(c.name, p.player_id);
}
rankings.set(p.player_id, p);
}
const bestCountries = trends.sort((a, b) => b.total - a.total).slice(0, 50);
const table = bestCountries.reduce((acc, c, i) => {
const ownerId = ownedCountries.get(c.name);
const owner = ownerId ? playerData.get(ownerId) : null;
acc["#" + (i + 1)] = {
name: c.name,
points: c.total,
owner: owner ? owner.name : null,
};
return acc;
}, {});
console.table(table);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment