Rename properties for clarity, add formatted names

This commit is contained in:
maxswa
2020-01-05 17:47:13 -05:00
parent ae73fef5ed
commit f1730d44ec
9 changed files with 426 additions and 511 deletions

View File

@@ -14,7 +14,6 @@ import {
ActivityName,
PlayerActivityRow,
Bosses,
LeagueStats,
Boss,
} from './types';
import {
@@ -44,16 +43,16 @@ export async function getStats(rsn: string): Promise<Player> {
const mainRes = await axios(getStatsURL('main', rsn));
if (mainRes.status === 200) {
const otherResponses = await Promise.all([
axios(getStatsURL('iron', rsn)).catch(err => err),
axios(getStatsURL('hc', rsn)).catch(err => err),
axios(getStatsURL('ult', rsn)).catch(err => err),
axios(getStatsURL('ironman', rsn)).catch(err => err),
axios(getStatsURL('hardcore', rsn)).catch(err => err),
axios(getStatsURL('ultimate', rsn)).catch(err => err),
getRSNFormat(rsn),
]);
const [ironRes, hcRes, ultRes, formattedName] = otherResponses;
const player: Player = {
rsn: formattedName,
name: formattedName,
mode: 'main',
dead: false,
deulted: false,
@@ -62,32 +61,42 @@ export async function getStats(rsn: string): Promise<Player> {
player.main = parseStats(mainRes.data);
if (ironRes.status === 200) {
player.iron = parseStats(ironRes.data);
player.ironman = parseStats(ironRes.data);
if (hcRes.status === 200) {
player.mode = 'hc';
player.hc = parseStats(hcRes.data);
if (player.iron.skills.overall.xp !== player.hc.skills.overall.xp) {
player.mode = 'hardcore';
player.hardcore = parseStats(hcRes.data);
if (
player.ironman.skills.overall.xp !== player.hardcore.skills.overall.xp
) {
player.dead = true;
player.mode = 'iron';
player.mode = 'ironman';
}
if (player.main.skills.overall.xp !== player.iron.skills.overall.xp) {
if (
player.main.skills.overall.xp !== player.ironman.skills.overall.xp
) {
player.deironed = true;
player.mode = 'main';
}
} else if (ultRes.status === 200) {
player.mode = 'ult';
player.ult = parseStats(ultRes.data);
if (player.iron.skills.overall.xp !== player.ult.skills.overall.xp) {
player.mode = 'ultimate';
player.ultimate = parseStats(ultRes.data);
if (
player.ironman.skills.overall.xp !== player.ultimate.skills.overall.xp
) {
player.deulted = true;
player.mode = 'iron';
player.mode = 'ironman';
}
if (player.main.skills.overall.xp !== player.iron.skills.overall.xp) {
if (
player.main.skills.overall.xp !== player.ironman.skills.overall.xp
) {
player.deironed = true;
player.mode = 'main';
}
} else {
player.mode = 'iron';
if (player.main.skills.overall.xp !== player.iron.skills.overall.xp) {
player.mode = 'ironman';
if (
player.main.skills.overall.xp !== player.ironman.skills.overall.xp
) {
player.deironed = true;
player.mode = 'main';
}
@@ -99,10 +108,10 @@ export async function getStats(rsn: string): Promise<Player> {
throw Error('Player not found');
}
export async function getStatsByGamemode<T extends Gamemode = 'main'>(
export async function getStatsByGamemode(
rsn: string,
mode: T = 'main' as T
): Promise<T extends 'leagues' ? LeagueStats : Stats> {
mode: Gamemode = 'main'
): Promise<Stats> {
if (typeof rsn !== 'string') {
throw Error('RSN must be a string');
} else if (!/^[a-zA-Z0-9 _]+$/.test(rsn)) {
@@ -116,7 +125,7 @@ export async function getStatsByGamemode<T extends Gamemode = 'main'>(
if (response.status !== 200) {
throw Error('Player not found');
}
const stats = parseStats(response.data, mode);
const stats = parseStats(response.data);
return stats;
}
@@ -145,7 +154,7 @@ export async function getSkillPage(
const [nameEl] = nameCell.children.filter(el => el.name === 'a');
return {
rsn: rsnFromElement(nameEl),
name: rsnFromElement(nameEl),
rank: numberFromElement(rankEl),
level: numberFromElement(levelEl),
xp: numberFromElement(xpEl),
@@ -180,7 +189,7 @@ export async function getActivityPage(
const [nameEl] = nameCell.children.filter(el => el.name === 'a');
return {
rsn: rsnFromElement(nameEl),
name: rsnFromElement(nameEl),
rank: numberFromElement(rankEl),
score: numberFromElement(scoreEl),
dead: nameCell.children.length === 4,
@@ -213,10 +222,7 @@ export async function getRSNFormat(rsn: string): Promise<string> {
}
}
export function parseStats<T extends Gamemode = 'main'>(
csv: string,
mode: T = 'main' as T
): T extends 'leagues' ? LeagueStats : Stats {
export function parseStats(csv: string): Stats {
const splitCSV = csv
.split('\n')
.filter(entry => !!entry)
@@ -245,10 +251,10 @@ export function parseStats<T extends Gamemode = 'main'>(
return activity;
});
const [lp] = activityObjects.splice(0, 1);
const [leaguePoints] = activityObjects.splice(0, 1);
const bhObjects = activityObjects.splice(0, BH_MODES.length);
const clueObjects = activityObjects.splice(0, CLUES.length);
const [lms] = activityObjects.splice(0, 1);
const [lastManStanding] = activityObjects.splice(0, 1);
const bossObjects = activityObjects.splice(0, BOSSES.length);
const skills: Skills = skillObjects.reduce<Skills>((prev, curr, index) => {
@@ -257,7 +263,7 @@ export function parseStats<T extends Gamemode = 'main'>(
return newSkills;
}, {} as Skills);
const bh: BH = bhObjects.reduce<BH>((prev, curr, index) => {
const bountyHunter: BH = bhObjects.reduce<BH>((prev, curr, index) => {
const newBH = { ...prev };
newBH[BH_MODES[index]] = curr;
return newBH;
@@ -278,36 +284,29 @@ export function parseStats<T extends Gamemode = 'main'>(
const bosses: Bosses = bossObjects.reduce<Bosses>((prev, curr, index) => {
const newBosses = { ...prev };
newBosses[TEMPBOSSES[index]] = brokenBosses.includes(BOSSES[index])
? { rank: -1, score: -1 }
: curr;
// TODO Remove as soon as Jagex's API is fixed
if (BOSSES[index] === brokenBosses[0]) {
brokenBosses.forEach(broken => {
newBosses[broken] = {
rank: -1,
score: -1,
};
});
}
newBosses[TEMPBOSSES[index]] = curr;
return newBosses;
}, {} as Bosses);
// TODO Remove as soon as Jagex's API is fixed
brokenBosses.forEach(broken => {
bosses[broken] = {
rank: -1,
score: -1,
};
});
const stats: Stats = {
skills,
bh,
lms,
leaguePoints,
bountyHunter,
lastManStanding,
clues,
bosses,
};
const leagueStats: LeagueStats = {
skills,
lp,
clues,
bosses,
};
return (mode === 'leagues' ? leagueStats : stats) as T extends 'leagues'
? LeagueStats
: Stats;
return stats;
}

View File

@@ -2,5 +2,6 @@ import * as hiscores from './hiscores';
export * from './hiscores';
export * from './types';
export * from './utils';
export default hiscores;

View File

@@ -1,11 +1,11 @@
export type Gamemode =
| 'main'
| 'iron'
| 'hc'
| 'ult'
| 'dmm'
| 'dmmt'
| 'leagues';
| 'ironman'
| 'ultimate'
| 'hardcore'
| 'deadman'
| 'seasonal'
| 'tournament';
export interface Skill {
rank: number;
@@ -62,43 +62,43 @@ export type BHType = 'rogue' | 'hunter';
export type BH = { [Type in BHType]: Activity };
export type Boss =
| 'abyssalsire'
| 'alchemicalhydra'
| 'barrowschests'
| 'abyssalSire'
| 'alchemicalHydra'
| 'barrows'
| 'bryophyta'
| 'callisto'
| 'cerberus'
| 'chambersofxeric'
| 'chambersofxericchallengemode'
| 'chaoselemental'
| 'chaosfanatic'
| 'commanderzilyana'
| 'corporealbeast'
| 'crazyarchaeologist'
| 'dagannothprime'
| 'dagannothrex'
| 'dagannothsupreme'
| 'derangedarchaeologist'
| 'generalgraardor'
| 'giantmole'
| 'grotesqueguardians'
| 'chambersOfXeric'
| 'chambersOfXericChallengeMode'
| 'chaosElemental'
| 'chaosFanatic'
| 'commanderZilyana'
| 'corporealBeast'
| 'crazyArchaeologist'
| 'dagannothPrime'
| 'dagannothRex'
| 'dagannothSupreme'
| 'derangedArchaeologist'
| 'generalGraardor'
| 'giantMole'
| 'grotesqueGuardians'
| 'hespori'
| 'kalphitequeen'
| 'kingblackdragon'
| 'kalphiteQueen'
| 'kingBlackDragon'
| 'kraken'
| 'kreearra'
| 'kriltsutsaroth'
| 'kreeArra'
| 'krilTsutsaroth'
| 'mimic'
| 'obor'
| 'sarachnis'
| 'scorpia'
| 'skotizo'
| 'gauntlet'
| 'corruptedgauntlet'
| 'theatreofblood'
| 'thermonuclearsmokedevil'
| 'tzkalzuk'
| 'tztokjad'
| 'corruptedGauntlet'
| 'theatreOfBlood'
| 'thermonuclearSmokeDevil'
| 'tzKalZuk'
| 'tzTokJad'
| 'venenatis'
| 'vetion'
| 'vorkath'
@@ -109,34 +109,30 @@ export type Boss =
export type Bosses = { [Type in Boss]: Activity };
export type ActivityName =
| 'hunterbh'
| 'roguebh'
| 'lms'
| 'allclues'
| 'beginnerclues'
| 'easyclues'
| 'mediumclues'
| 'hardclues'
| 'eliteclues'
| 'masterclues'
| 'hunterBH'
| 'rogueBH'
| 'lastManStanding'
| 'allClues'
| 'beginnerClues'
| 'easyClues'
| 'mediumClues'
| 'hardClues'
| 'eliteClues'
| 'masterClues'
| Boss;
export interface Stats {
skills: Skills;
clues: Clues;
bh: BH;
lms: Activity;
leaguePoints: Activity;
bountyHunter: BH;
lastManStanding: Activity;
bosses: Bosses;
}
export interface LeagueStats extends Omit<Stats, 'bh' | 'lms'> {
lp: Activity;
}
export type Modes = { [M in Gamemode]?: Stats };
export interface Player extends Modes {
rsn: string;
name: string;
mode: Gamemode;
dead: boolean;
deulted: boolean;
@@ -144,11 +140,11 @@ export interface Player extends Modes {
}
export interface PlayerSkillRow extends Skill {
rsn: string;
name: string;
dead: boolean;
}
export interface PlayerActivityRow extends Activity {
rsn: string;
name: string;
dead: boolean;
}

View File

@@ -1,16 +1,28 @@
import { SkillName, ClueType, BHType, Gamemode, Boss } from '../types';
import {
BHType,
Boss,
ClueType,
Gamemode,
SkillName,
ActivityName,
} from '../types';
export const BASE_URL = 'http://services.runescape.com/m=hiscore_oldschool';
export const STATS_URL = 'index_lite.ws?player=';
export const SCORES_URL = 'overall.ws?';
export const GAMEMODE_URL = {
dmm: '_deadman/',
dmmt: '_tournament/',
hc: '_hardcore_ironman/',
iron: '_ironman/',
main: '/',
leagues: '_seasonal/',
ult: '_ultimate/',
export type GamemodeUrl = {
[key in Gamemode]: string;
};
export const GAMEMODE_URL: GamemodeUrl = {
main: `${BASE_URL}/`,
ironman: `${BASE_URL}_ironman`,
hardcore: `${BASE_URL}_hardcore_ironman`,
ultimate: `${BASE_URL}_ultimate`,
deadman: `${BASE_URL}_deadman`,
seasonal: `${BASE_URL}_seasonal`,
tournament: `${BASE_URL}_tournament`,
};
export const SKILLS: SkillName[] = [
'overall',
@@ -48,65 +60,65 @@ export const CLUES: ClueType[] = [
'master',
];
export const BH_MODES: BHType[] = ['rogue', 'hunter'];
export const ACTIVITIES = [
'hunterbh',
'roguebh',
'lms',
'allclues',
'beginnerclues',
'easyclues',
'mediumclues',
'hardclues',
'eliteclues',
'masterclues',
export const ACTIVITIES: ActivityName[] = [
'hunterBH',
'rogueBH',
'lastManStanding',
'allClues',
'beginnerClues',
'easyClues',
'mediumClues',
'hardClues',
'eliteClues',
'masterClues',
];
export const GAMEMODES: Gamemode[] = [
'main',
'iron',
'hc',
'ult',
'dmm',
'dmmt',
'leagues',
'ironman',
'hardcore',
'ultimate',
'deadman',
'seasonal',
'tournament',
];
export const BOSSES: Boss[] = [
'abyssalsire',
'alchemicalhydra',
'barrowschests',
'abyssalSire',
'alchemicalHydra',
'barrows',
'bryophyta',
'chambersofxeric',
'chambersofxericchallengemode',
'callisto',
'cerberus',
'chaoselemental',
'chaosfanatic',
'commanderzilyana',
'corporealbeast',
'crazyarchaeologist',
'dagannothprime',
'dagannothrex',
'dagannothsupreme',
'derangedarchaeologist',
'generalgraardor',
'giantmole',
'grotesqueguardians',
'chambersOfXeric',
'chambersOfXericChallengeMode',
'chaosElemental',
'chaosFanatic',
'commanderZilyana',
'corporealBeast',
'crazyArchaeologist',
'dagannothPrime',
'dagannothRex',
'dagannothSupreme',
'derangedArchaeologist',
'generalGraardor',
'giantMole',
'grotesqueGuardians',
'hespori',
'kalphitequeen',
'kingblackdragon',
'kalphiteQueen',
'kingBlackDragon',
'kraken',
'kreearra',
'kriltsutsaroth',
'kreeArra',
'krilTsutsaroth',
'mimic',
'obor',
'sarachnis',
'scorpia',
'skotizo',
'gauntlet',
'corruptedgauntlet',
'theatreofblood',
'thermonuclearsmokedevil',
'tzkalzuk',
'tztokjad',
'corruptedGauntlet',
'theatreOfBlood',
'thermonuclearSmokeDevil',
'tzKalZuk',
'tzTokJad',
'venenatis',
'vetion',
'vorkath',
@@ -114,3 +126,110 @@ export const BOSSES: Boss[] = [
'zalcano',
'zulrah',
];
export type FormattedBossNames = {
[key in Boss]: string;
};
export const FORMATTED_BOSS_NAMES: FormattedBossNames = {
abyssalSire: 'Abyssal Sire',
alchemicalHydra: 'Alchemical Hydra',
barrows: 'Barrows Chests',
bryophyta: 'Bryophyta',
callisto: 'Callisto',
cerberus: 'Cerberus',
chambersOfXeric: 'Chambers of Xeric',
chambersOfXericChallengeMode: 'Chambers of Xeric: Challenge Mode',
chaosElemental: 'Chaos Elemental',
chaosFanatic: 'Chaos Fanatic',
commanderZilyana: 'Commander Zilyana',
corporealBeast: 'Corporeal Beast',
crazyArchaeologist: 'Crazy Archaeologist',
dagannothPrime: 'Dagannoth Prime',
dagannothRex: 'Dagannoth Rex',
dagannothSupreme: 'Dagannoth Supreme',
derangedArchaeologist: 'Deranged Archaeologist',
generalGraardor: 'General Graardor',
giantMole: 'Giant Mole',
grotesqueGuardians: 'Grotesque Guardians',
hespori: 'Hespori',
kalphiteQueen: 'Kalphite Queen',
kingBlackDragon: 'King Black Dragon',
kraken: 'Kraken',
kreeArra: "Kree'Arra",
krilTsutsaroth: "K'ril Tsutsaroth",
mimic: 'Mimic',
obor: 'Obor',
sarachnis: 'Sarachnis',
scorpia: 'Scorpia',
skotizo: 'Skotizo',
gauntlet: 'The Gauntlet',
corruptedGauntlet: 'The Corrupted Gauntlet',
theatreOfBlood: 'Theatre of Blood',
thermonuclearSmokeDevil: 'Thermonuclear Smoke Devil',
tzKalZuk: 'TzKal-Zuk',
tzTokJad: 'TzTok-Jad',
venenatis: 'Venenatis',
vetion: "Vet'ion",
vorkath: 'Vorkath',
wintertodt: 'Wintertodt',
zalcano: 'Zalcano',
zulrah: 'Zulrah',
};
export type FormattedSkillNames = {
[key in SkillName]: string;
};
export const FORMATTED_SKILL_NAMES: FormattedSkillNames = {
overall: 'Overall',
attack: 'Attack',
defence: 'Defence',
strength: 'Strength',
hitpoints: 'Hitpoints',
ranged: 'Ranged',
prayer: 'Prayer',
magic: 'Magic',
cooking: 'Cooking',
woodcutting: 'Woodcutting',
fletching: 'Fletching',
fishing: 'Fishing',
firemaking: 'Firemaking',
crafting: 'Crafting',
smithing: 'Smithing',
mining: 'Mining',
herblore: 'Herblore',
agility: 'Agility',
thieving: 'Thieving',
slayer: 'Slayer',
farming: 'Farming',
runecraft: 'Runecraft',
hunter: 'Hunter',
construction: 'Construction',
};
export type FormattedClueNames = {
[key in ClueType]: string;
};
export const FORMATTED_CLUE_NAMES: FormattedClueNames = {
all: 'Clue Scrolls (all)',
beginner: 'Clue Scrolls (beginner)',
easy: 'Clue Scrolls (easy)',
medium: 'Clue Scrolls (medium)',
hard: 'Clue Scrolls (hard)',
elite: 'Clue Scrolls (elite)',
master: 'Clue Scrolls (master)',
};
export type FormattedBHNames = {
[key in BHType]: string;
};
export const FORMATTED_BH_NAMES: FormattedBHNames = {
rogue: 'Bounty Hunter - Rogue',
hunter: 'Bounty Hunter - Hunter',
};
export const FORMATTED_LMS = 'Last Man Standing';
export const FORMATTED_LEAGUE_POINTS = 'League Points';

View File

@@ -1,6 +1,5 @@
import { Gamemode, SkillName, ActivityName } from '../types';
import {
BASE_URL,
GAMEMODE_URL,
STATS_URL,
SCORES_URL,
@@ -9,19 +8,19 @@ import {
} from './constants';
export const getStatsURL = (gamemode: Gamemode, rsn: string) =>
`${BASE_URL}${GAMEMODE_URL[gamemode]}${STATS_URL}${encodeURIComponent(rsn)}`;
`${GAMEMODE_URL[gamemode]}${STATS_URL}${encodeURIComponent(rsn)}`;
export const getPlayerTableURL = (gamemode: Gamemode, rsn: string) =>
`${BASE_URL}${
GAMEMODE_URL[gamemode]
}${SCORES_URL}table=0&user=${encodeURIComponent(rsn)}`;
`${GAMEMODE_URL[gamemode]}${SCORES_URL}table=0&user=${encodeURIComponent(
rsn
)}`;
export const getSkillPageURL = (
gamemode: Gamemode,
skill: SkillName,
page: number
) =>
`${BASE_URL}${GAMEMODE_URL[gamemode]}${SCORES_URL}table=${SKILLS.indexOf(
`${GAMEMODE_URL[gamemode]}${SCORES_URL}table=${SKILLS.indexOf(
skill
)}&page=${page}`;
@@ -30,7 +29,7 @@ export const getActivityPageURL = (
activity: ActivityName,
page: number
) =>
`${BASE_URL}${
`${
GAMEMODE_URL[gamemode]
}${SCORES_URL}category_type=1&table=${ACTIVITIES.indexOf(
activity