mirror of
https://github.com/maxswa/osrs-json-hiscores.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
58e8eaad59 | ||
![]() |
6b6d561a1f | ||
![]() |
26aefe95a0 | ||
![]() |
880679b9e6 | ||
![]() |
f679e2bde8 | ||
![]() |
06a176873b | ||
![]() |
553f4f5c36 | ||
![]() |
e95efb5cdf | ||
![]() |
68eb807657 | ||
![]() |
93d6961a4c | ||
![]() |
fbce22fd07 |
15
README.md
15
README.md
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[](https://www.npmjs.com/package/osrs-json-hiscores)
|
[](https://www.npmjs.com/package/osrs-json-hiscores)
|
||||||
[](https://npm-stat.com/charts.html?package=osrs-json-hiscores)
|
[](https://npm-stat.com/charts.html?package=osrs-json-hiscores)
|
||||||
[](https://github.com/maxswa/osrs-json-hiscores/src/types.ts)
|
[](https://github.com/maxswa/osrs-json-hiscores/blob/master/src/types.ts)
|
||||||
|
|
||||||
**The Oldschool Runescape API wrapper that does more!**
|
**The Oldschool Runescape API wrapper that does more!**
|
||||||
|
|
||||||
@@ -15,6 +15,14 @@ Additional functions are provided that screen-scrape the OSRS leaderboards and r
|
|||||||
|
|
||||||
`osrs-json-hiscores` has TypeScript support, with full definitions for all functions and custom data types.
|
`osrs-json-hiscores` has TypeScript support, with full definitions for all functions and custom data types.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Disclaimer
|
||||||
|
|
||||||
|
Jagex does not provide `Access-Control-Allow-Origin` headers in their responses. This means that [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) will block all browser requests to their hiscores API. In order to get around this, osrs-json-hiscores should be installed on the server side and exposed to the front end via a simple API. Here is an example of this in use: [codesandbox.io/s/osrs-json-hiscores-demo](https://codesandbox.io/s/osrs-json-hiscores-demo-qz656)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
With npm:
|
With npm:
|
||||||
@@ -41,7 +49,7 @@ Once you import it you can call the functions asynchronously:
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
hiscores
|
hiscores
|
||||||
.getStats('Lynx Titan', 'full')
|
.getStats('Lynx Titan')
|
||||||
.then(res => console.log(res))
|
.then(res => console.log(res))
|
||||||
.catch(err => console.error(err));
|
.catch(err => console.error(err));
|
||||||
```
|
```
|
||||||
@@ -57,7 +65,8 @@ const stats = await hiscores.getStats('Lynx Titan');
|
|||||||
const topPage = await getSkillPage('overall');
|
const topPage = await getSkillPage('overall');
|
||||||
```
|
```
|
||||||
|
|
||||||
`getStats` will return a `full` player object with game mode by default, but it will also accept any of the following game modes:
|
`getStats` will return a full player object with gamemode.
|
||||||
|
`getStatsByGameMode` will return a stats object and accepts a gamemode parameter:
|
||||||
|
|
||||||
| Game mode | Param |
|
| Game mode | Param |
|
||||||
| ---------------- | :----: |
|
| ---------------- | :----: |
|
||||||
|
@@ -1,5 +1,11 @@
|
|||||||
import { parseStats, getRSNFormat, getSkillPage, getStats } from '../src/index';
|
import {
|
||||||
import { PlayerSkillRow, Player } from '../src/types';
|
parseStats,
|
||||||
|
getRSNFormat,
|
||||||
|
getSkillPage,
|
||||||
|
getStats,
|
||||||
|
getStatsByGamemode,
|
||||||
|
} from '../src/index';
|
||||||
|
import { PlayerSkillRow, Player, Stats } from '../src/types';
|
||||||
import axios, { AxiosError } from 'axios';
|
import axios, { AxiosError } from 'axios';
|
||||||
|
|
||||||
test('Parse CSV to json', () => {
|
test('Parse CSV to json', () => {
|
||||||
@@ -93,10 +99,16 @@ test('Get rsn format', async done => {
|
|||||||
|
|
||||||
test('Get attack top page', async done => {
|
test('Get attack top page', async done => {
|
||||||
const callback = (data: PlayerSkillRow[]) => {
|
const callback = (data: PlayerSkillRow[]) => {
|
||||||
expect(data).toStrictEqual([
|
expect(data).toMatchObject([
|
||||||
{ rsn: 'Heur', rank: 1, level: 99, xp: 200000000, dead: false },
|
|
||||||
{
|
{
|
||||||
rsn: 'Unohdettu2',
|
rsn: expect.any(String),
|
||||||
|
rank: 1,
|
||||||
|
level: 99,
|
||||||
|
xp: 200000000,
|
||||||
|
dead: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rsn: expect.any(String),
|
||||||
rank: 2,
|
rank: 2,
|
||||||
level: 99,
|
level: 99,
|
||||||
xp: 200000000,
|
xp: 200000000,
|
||||||
@@ -104,105 +116,159 @@ test('Get attack top page', async done => {
|
|||||||
},
|
},
|
||||||
{ rsn: 'Drakon', rank: 3, level: 99, xp: 200000000, dead: false },
|
{ rsn: 'Drakon', rank: 3, level: 99, xp: 200000000, dead: false },
|
||||||
{
|
{
|
||||||
rsn: 'Ame Umehara',
|
rsn: expect.any(String),
|
||||||
rank: 4,
|
rank: 4,
|
||||||
level: 99,
|
level: 99,
|
||||||
xp: 200000000,
|
xp: 200000000,
|
||||||
dead: false,
|
dead: false,
|
||||||
},
|
},
|
||||||
{ rsn: 'Jakee', rank: 5, level: 99, xp: 200000000, dead: false },
|
|
||||||
{ rsn: 'Hitsuji', rank: 6, level: 99, xp: 200000000, dead: false },
|
|
||||||
{ rsn: 'Howson', rank: 7, level: 99, xp: 200000000, dead: false },
|
|
||||||
{ rsn: 'Dr PFAFF', rank: 8, level: 99, xp: 200000000, dead: false },
|
|
||||||
{
|
{
|
||||||
rsn: 'Malt Lickeys',
|
rsn: expect.any(String),
|
||||||
|
rank: 5,
|
||||||
|
level: 99,
|
||||||
|
xp: 200000000,
|
||||||
|
dead: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rsn: expect.any(String),
|
||||||
|
rank: 6,
|
||||||
|
level: 99,
|
||||||
|
xp: 200000000,
|
||||||
|
dead: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rsn: expect.any(String),
|
||||||
|
rank: 7,
|
||||||
|
level: 99,
|
||||||
|
xp: 200000000,
|
||||||
|
dead: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rsn: expect.any(String),
|
||||||
|
rank: 8,
|
||||||
|
level: 99,
|
||||||
|
xp: 200000000,
|
||||||
|
dead: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rsn: expect.any(String),
|
||||||
rank: 9,
|
rank: 9,
|
||||||
level: 99,
|
level: 99,
|
||||||
xp: 200000000,
|
xp: 200000000,
|
||||||
dead: false,
|
dead: false,
|
||||||
},
|
},
|
||||||
{ rsn: 'Burned', rank: 10, level: 99, xp: 200000000, dead: false },
|
|
||||||
{
|
{
|
||||||
rsn: 'Blue Limes',
|
rsn: expect.any(String),
|
||||||
|
rank: 10,
|
||||||
|
level: 99,
|
||||||
|
xp: 200000000,
|
||||||
|
dead: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rsn: expect.any(String),
|
||||||
rank: 11,
|
rank: 11,
|
||||||
level: 99,
|
level: 99,
|
||||||
xp: 200000000,
|
xp: 200000000,
|
||||||
dead: false,
|
dead: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rsn: 'Mini Finbarr',
|
rsn: expect.any(String),
|
||||||
rank: 12,
|
rank: 12,
|
||||||
level: 99,
|
level: 99,
|
||||||
xp: 200000000,
|
xp: 200000000,
|
||||||
dead: false,
|
dead: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rsn: 'Unohdettu3',
|
rsn: expect.any(String),
|
||||||
rank: 13,
|
rank: 13,
|
||||||
level: 99,
|
level: 99,
|
||||||
xp: 200000000,
|
xp: 200000000,
|
||||||
dead: false,
|
dead: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rsn: 'Eslihero',
|
rsn: expect.any(String),
|
||||||
rank: 14,
|
rank: 14,
|
||||||
level: 99,
|
level: 99,
|
||||||
xp: 200000000,
|
xp: 200000000,
|
||||||
dead: false,
|
dead: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rsn: 'Lynx Titan',
|
rsn: expect.any(String),
|
||||||
rank: 15,
|
rank: 15,
|
||||||
level: 99,
|
level: 99,
|
||||||
xp: 200000000,
|
xp: 200000000,
|
||||||
dead: false,
|
dead: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rsn: 'AndrewWigins',
|
rsn: expect.any(String),
|
||||||
rank: 16,
|
rank: 16,
|
||||||
level: 99,
|
level: 99,
|
||||||
xp: 200000000,
|
xp: 200000000,
|
||||||
dead: false,
|
dead: false,
|
||||||
},
|
},
|
||||||
{ rsn: 'iMelee', rank: 17, level: 99, xp: 200000000, dead: false },
|
|
||||||
{
|
{
|
||||||
rsn: 'Portuguese',
|
rsn: expect.any(String),
|
||||||
|
rank: 17,
|
||||||
|
level: 99,
|
||||||
|
xp: 200000000,
|
||||||
|
dead: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rsn: expect.any(String),
|
||||||
rank: 18,
|
rank: 18,
|
||||||
level: 99,
|
level: 99,
|
||||||
xp: 200000000,
|
xp: 200000000,
|
||||||
dead: false,
|
dead: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rsn: 'MarkoOSRS',
|
rsn: expect.any(String),
|
||||||
rank: 19,
|
rank: 19,
|
||||||
level: 99,
|
level: 99,
|
||||||
xp: 200000000,
|
xp: 200000000,
|
||||||
dead: false,
|
dead: false,
|
||||||
},
|
},
|
||||||
{ rsn: 'Cairo', rank: 20, level: 99, xp: 200000000, dead: false },
|
|
||||||
{
|
{
|
||||||
rsn: 'Hey Jase',
|
rsn: expect.any(String),
|
||||||
|
rank: 20,
|
||||||
|
level: 99,
|
||||||
|
xp: 200000000,
|
||||||
|
dead: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rsn: expect.any(String),
|
||||||
rank: 21,
|
rank: 21,
|
||||||
level: 99,
|
level: 99,
|
||||||
xp: 200000000,
|
xp: 200000000,
|
||||||
dead: false,
|
dead: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rsn: 'Sleighur',
|
rsn: expect.any(String),
|
||||||
rank: 22,
|
rank: 22,
|
||||||
level: 99,
|
level: 99,
|
||||||
xp: 200000000,
|
xp: 200000000,
|
||||||
dead: false,
|
dead: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rsn: 'KMSat200mALL',
|
rsn: expect.any(String),
|
||||||
rank: 23,
|
rank: 23,
|
||||||
level: 99,
|
level: 99,
|
||||||
xp: 200000000,
|
xp: 200000000,
|
||||||
dead: false,
|
dead: false,
|
||||||
},
|
},
|
||||||
{ rsn: 'Yumemi', rank: 24, level: 99, xp: 200000000, dead: false },
|
{
|
||||||
{ rsn: 'Fiiggy', rank: 25, level: 99, xp: 200000000, dead: false },
|
rsn: expect.any(String),
|
||||||
|
rank: 24,
|
||||||
|
level: 99,
|
||||||
|
xp: 200000000,
|
||||||
|
dead: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rsn: expect.any(String),
|
||||||
|
rank: 25,
|
||||||
|
level: 99,
|
||||||
|
xp: 200000000,
|
||||||
|
dead: false,
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
done();
|
done();
|
||||||
};
|
};
|
||||||
@@ -220,3 +286,37 @@ test('Get non-existant player', async done => {
|
|||||||
|
|
||||||
getStats('fishy').catch(callback);
|
getStats('fishy').catch(callback);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Get stats by gamemode', async done => {
|
||||||
|
const callback = (stats: Stats) => {
|
||||||
|
expect(stats.skills).toStrictEqual({
|
||||||
|
overall: { rank: 1, level: 2277, xp: 4600000000 },
|
||||||
|
attack: { rank: 15, level: 99, xp: 200000000 },
|
||||||
|
defence: { rank: 27, level: 99, xp: 200000000 },
|
||||||
|
strength: { rank: 18, level: 99, xp: 200000000 },
|
||||||
|
hitpoints: { rank: 7, level: 99, xp: 200000000 },
|
||||||
|
ranged: { rank: 7, level: 99, xp: 200000000 },
|
||||||
|
prayer: { rank: 11, level: 99, xp: 200000000 },
|
||||||
|
magic: { rank: 32, level: 99, xp: 200000000 },
|
||||||
|
cooking: { rank: 158, level: 99, xp: 200000000 },
|
||||||
|
woodcutting: { rank: 15, level: 99, xp: 200000000 },
|
||||||
|
fletching: { rank: 12, level: 99, xp: 200000000 },
|
||||||
|
fishing: { rank: 9, level: 99, xp: 200000000 },
|
||||||
|
firemaking: { rank: 49, level: 99, xp: 200000000 },
|
||||||
|
crafting: { rank: 4, level: 99, xp: 200000000 },
|
||||||
|
smithing: { rank: 3, level: 99, xp: 200000000 },
|
||||||
|
mining: { rank: 25, level: 99, xp: 200000000 },
|
||||||
|
herblore: { rank: 5, level: 99, xp: 200000000 },
|
||||||
|
agility: { rank: 24, level: 99, xp: 200000000 },
|
||||||
|
thieving: { rank: 12, level: 99, xp: 200000000 },
|
||||||
|
slayer: { rank: 2, level: 99, xp: 200000000 },
|
||||||
|
farming: { rank: 19, level: 99, xp: 200000000 },
|
||||||
|
runecraft: { rank: 7, level: 99, xp: 200000000 },
|
||||||
|
hunter: { rank: 4, level: 99, xp: 200000000 },
|
||||||
|
construction: { rank: 4, level: 99, xp: 200000000 },
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
|
||||||
|
getStatsByGamemode('Lynx Titan').then(callback);
|
||||||
|
});
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "osrs-json-hiscores",
|
"name": "osrs-json-hiscores",
|
||||||
"version": "1.2.0",
|
"version": "1.2.2",
|
||||||
"description": "The Oldschool Runescape API wrapper that does more!",
|
"description": "The Oldschool Runescape API wrapper that does more!",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
|
159
src/hiscores.ts
159
src/hiscores.ts
@@ -2,12 +2,11 @@ import axios from 'axios';
|
|||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
import {
|
import {
|
||||||
Player,
|
Player,
|
||||||
Mode,
|
|
||||||
Activity,
|
Activity,
|
||||||
Skill,
|
Skill,
|
||||||
Stats,
|
Stats,
|
||||||
Skills,
|
Skills,
|
||||||
BH as BHStats,
|
BH,
|
||||||
Clues,
|
Clues,
|
||||||
Gamemode,
|
Gamemode,
|
||||||
SkillName,
|
SkillName,
|
||||||
@@ -20,7 +19,6 @@ import {
|
|||||||
SKILLS,
|
SKILLS,
|
||||||
BH_MODES,
|
BH_MODES,
|
||||||
CLUES,
|
CLUES,
|
||||||
MODES,
|
|
||||||
getPlayerTableURL,
|
getPlayerTableURL,
|
||||||
getSkillPageURL,
|
getSkillPageURL,
|
||||||
GAMEMODES,
|
GAMEMODES,
|
||||||
@@ -30,92 +28,93 @@ import {
|
|||||||
getActivityPageURL,
|
getActivityPageURL,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
export async function getStats(
|
export async function getStats(rsn: string): Promise<Player> {
|
||||||
rsn: string,
|
|
||||||
mode: Mode = 'full'
|
|
||||||
): Promise<Player> {
|
|
||||||
if (typeof rsn !== 'string') {
|
if (typeof rsn !== 'string') {
|
||||||
throw Error('RSN must be a string');
|
throw Error('RSN must be a string');
|
||||||
} else if (!/^[a-zA-Z0-9 _]+$/.test(rsn)) {
|
} else if (!/^[a-zA-Z0-9 _]+$/.test(rsn)) {
|
||||||
throw Error('RSN contains invalid character');
|
throw Error('RSN contains invalid character');
|
||||||
} else if (rsn.length > 12 || rsn.length < 1) {
|
} else if (rsn.length > 12 || rsn.length < 1) {
|
||||||
throw Error('RSN must be between 1 and 12 characters');
|
throw Error('RSN must be between 1 and 12 characters');
|
||||||
} else if (!MODES.includes(mode)) {
|
|
||||||
throw Error('Invalid game mode');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode === 'full') {
|
const mainRes = await axios(getStatsURL('main', rsn));
|
||||||
const mainRes = await axios(getStatsURL('main', rsn));
|
if (mainRes.status === 200) {
|
||||||
if (mainRes.status === 200) {
|
const otherResponses = await Promise.all([
|
||||||
const otherResponses = await Promise.all([
|
axios(getStatsURL('iron', rsn)).catch(err => err),
|
||||||
axios(getStatsURL('iron', rsn)).catch(err => err),
|
axios(getStatsURL('hc', rsn)).catch(err => err),
|
||||||
axios(getStatsURL('hc', rsn)).catch(err => err),
|
axios(getStatsURL('ult', rsn)).catch(err => err),
|
||||||
axios(getStatsURL('ult', rsn)).catch(err => err),
|
getRSNFormat(rsn),
|
||||||
getRSNFormat(rsn),
|
]);
|
||||||
]);
|
|
||||||
|
|
||||||
const [ironRes, hcRes, ultRes, formattedName] = otherResponses;
|
const [ironRes, hcRes, ultRes, formattedName] = otherResponses;
|
||||||
|
|
||||||
const player: Player = {
|
|
||||||
rsn: formattedName,
|
|
||||||
mode: 'main',
|
|
||||||
dead: false,
|
|
||||||
deulted: false,
|
|
||||||
deironed: false,
|
|
||||||
};
|
|
||||||
player.main = parseStats(mainRes.data);
|
|
||||||
|
|
||||||
if (ironRes.status === 200) {
|
|
||||||
player.iron = 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.dead = true;
|
|
||||||
player.mode = 'iron';
|
|
||||||
}
|
|
||||||
if (player.main.skills.overall.xp !== player.iron.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.deulted = true;
|
|
||||||
player.mode = 'iron';
|
|
||||||
}
|
|
||||||
if (player.main.skills.overall.xp !== player.iron.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.deironed = true;
|
|
||||||
player.mode = 'main';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
throw Error('Player not found');
|
|
||||||
} else {
|
|
||||||
const response = await axios(getStatsURL(mode, rsn));
|
|
||||||
if (response.status !== 200) {
|
|
||||||
throw Error('Player not found');
|
|
||||||
}
|
|
||||||
const player: Player = {
|
const player: Player = {
|
||||||
rsn,
|
rsn: formattedName,
|
||||||
mode,
|
mode: 'main',
|
||||||
dead: false,
|
dead: false,
|
||||||
deulted: false,
|
deulted: false,
|
||||||
deironed: false,
|
deironed: false,
|
||||||
[mode]: parseStats(response.data),
|
|
||||||
};
|
};
|
||||||
|
player.main = parseStats(mainRes.data);
|
||||||
|
|
||||||
|
if (ironRes.status === 200) {
|
||||||
|
player.iron = 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.dead = true;
|
||||||
|
player.mode = 'iron';
|
||||||
|
}
|
||||||
|
if (player.main.skills.overall.xp !== player.iron.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.deulted = true;
|
||||||
|
player.mode = 'iron';
|
||||||
|
}
|
||||||
|
if (player.main.skills.overall.xp !== player.iron.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.deironed = true;
|
||||||
|
player.mode = 'main';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
throw Error('Player not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getStatsByGamemode(
|
||||||
|
rsn: string,
|
||||||
|
mode: Gamemode = 'main'
|
||||||
|
): Promise<Stats> {
|
||||||
|
if (typeof rsn !== 'string') {
|
||||||
|
throw Error('RSN must be a string');
|
||||||
|
} else if (!/^[a-zA-Z0-9 _]+$/.test(rsn)) {
|
||||||
|
throw Error('RSN contains invalid character');
|
||||||
|
} else if (rsn.length > 12 || rsn.length < 1) {
|
||||||
|
throw Error('RSN must be between 1 and 12 characters');
|
||||||
|
} else if (!GAMEMODES.includes(mode)) {
|
||||||
|
throw Error('Invalid game mode');
|
||||||
|
}
|
||||||
|
const response = await axios(getStatsURL(mode, rsn));
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw Error('Player not found');
|
||||||
|
}
|
||||||
|
const stats: Stats = parseStats(response.data);
|
||||||
|
|
||||||
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getSkillPage(
|
export async function getSkillPage(
|
||||||
@@ -219,10 +218,11 @@ export function parseStats(csv: string): Stats {
|
|||||||
const skillObjects: Skill[] = splitCSV
|
const skillObjects: Skill[] = splitCSV
|
||||||
.filter(stat => stat.length === 3)
|
.filter(stat => stat.length === 3)
|
||||||
.map(stat => {
|
.map(stat => {
|
||||||
|
const [rank, level, xp] = stat;
|
||||||
const skill: Skill = {
|
const skill: Skill = {
|
||||||
rank: parseInt(stat[0], 10),
|
rank: parseInt(rank, 10),
|
||||||
level: parseInt(stat[1], 10),
|
level: parseInt(level, 10),
|
||||||
xp: parseInt(stat[2], 10),
|
xp: parseInt(xp, 10),
|
||||||
};
|
};
|
||||||
return skill;
|
return skill;
|
||||||
});
|
});
|
||||||
@@ -230,9 +230,10 @@ export function parseStats(csv: string): Stats {
|
|||||||
const activityObjects: Activity[] = splitCSV
|
const activityObjects: Activity[] = splitCSV
|
||||||
.filter(stat => stat.length === 2)
|
.filter(stat => stat.length === 2)
|
||||||
.map(stat => {
|
.map(stat => {
|
||||||
|
const [rank, score] = stat;
|
||||||
const activity: Activity = {
|
const activity: Activity = {
|
||||||
rank: parseInt(stat[0], 10),
|
rank: parseInt(rank, 10),
|
||||||
score: parseInt(stat[1], 10),
|
score: parseInt(score, 10),
|
||||||
};
|
};
|
||||||
return activity;
|
return activity;
|
||||||
});
|
});
|
||||||
@@ -250,13 +251,13 @@ export function parseStats(csv: string): Stats {
|
|||||||
{} as Skills
|
{} as Skills
|
||||||
);
|
);
|
||||||
|
|
||||||
const bh: BHStats = bhObjects.reduce<BHStats>(
|
const bh: BH = bhObjects.reduce<BH>(
|
||||||
(prev, curr, index) => {
|
(prev, curr, index) => {
|
||||||
const newBH = { ...prev };
|
const newBH = { ...prev };
|
||||||
newBH[BH_MODES[index]] = curr;
|
newBH[BH_MODES[index]] = curr;
|
||||||
return newBH;
|
return newBH;
|
||||||
},
|
},
|
||||||
{} as BHStats
|
{} as BH
|
||||||
);
|
);
|
||||||
|
|
||||||
const clues: Clues = clueObjects.reduce<Clues>(
|
const clues: Clues = clueObjects.reduce<Clues>(
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
export type Gamemode = 'main' | 'iron' | 'hc' | 'ult' | 'dmm' | 'sdmm' | 'dmmt';
|
export type Gamemode = 'main' | 'iron' | 'hc' | 'ult' | 'dmm' | 'sdmm' | 'dmmt';
|
||||||
|
|
||||||
export type Mode = Gamemode | 'full';
|
|
||||||
|
|
||||||
export interface Skill {
|
export interface Skill {
|
||||||
rank: number;
|
rank: number;
|
||||||
level: number;
|
level: number;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { SkillName, ClueType, BHType, Gamemode, Mode } from '../types';
|
import { SkillName, ClueType, BHType, Gamemode } from '../types';
|
||||||
|
|
||||||
export const BASE_URL = 'http://services.runescape.com/m=hiscore_oldschool';
|
export const BASE_URL = 'http://services.runescape.com/m=hiscore_oldschool';
|
||||||
export const STATS_URL = 'index_lite.ws?player=';
|
export const STATS_URL = 'index_lite.ws?player=';
|
||||||
@@ -69,4 +69,3 @@ export const GAMEMODES: Gamemode[] = [
|
|||||||
'sdmm',
|
'sdmm',
|
||||||
'dmmt',
|
'dmmt',
|
||||||
];
|
];
|
||||||
export const MODES: Mode[] = [...GAMEMODES, 'full'];
|
|
||||||
|
@@ -3089,9 +3089,9 @@ lodash.zip@^4.2.0:
|
|||||||
integrity sha1-7GZi5IlkCO1KtsVCo5kLcswIACA=
|
integrity sha1-7GZi5IlkCO1KtsVCo5kLcswIACA=
|
||||||
|
|
||||||
lodash@^4.15.0, lodash@^4.17.11, lodash@^4.3.0:
|
lodash@^4.15.0, lodash@^4.17.11, lodash@^4.3.0:
|
||||||
version "4.17.11"
|
version "4.17.14"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba"
|
||||||
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
|
integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==
|
||||||
|
|
||||||
log-symbols@^1.0.2:
|
log-symbols@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
|
Reference in New Issue
Block a user