mirror of
https://github.com/maxswa/osrs-json-hiscores.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7de2d9a95a | ||
![]() |
a143306519 | ||
![]() |
86b81abfd8 | ||
![]() |
8d065742d0 | ||
![]() |
eaa3d4a299 | ||
![]() |
a92fa7fffe | ||
![]() |
90f2939761 | ||
![]() |
12046246ef | ||
![]() |
adf73e59c4 | ||
![]() |
f2fcbad1c4 | ||
![]() |
0f47310814 | ||
![]() |
30530fde01 | ||
![]() |
2c0268939d | ||
![]() |
0142783d43 | ||
![]() |
468b43f66f | ||
![]() |
d5bbe2a169 | ||
![]() |
26d06da24b | ||
![]() |
582a5c01fd | ||
![]() |
0138dcd5fd | ||
![]() |
f1730d44ec | ||
![]() |
ae73fef5ed | ||
![]() |
8bf1f6cdbc | ||
![]() |
50d8365e87 | ||
![]() |
8f9c9777e5 | ||
![]() |
470d788327 | ||
![]() |
58e8eaad59 | ||
![]() |
6b6d561a1f | ||
![]() |
26aefe95a0 |
120
README.md
120
README.md
@@ -68,17 +68,17 @@ const topPage = await getSkillPage('overall');
|
||||
`getStats` will return a full player object with gamemode.
|
||||
`getStatsByGameMode` will return a stats object and accepts a gamemode parameter:
|
||||
|
||||
| Game mode | Param |
|
||||
| ---------------- | :----: |
|
||||
| Regular | `main` |
|
||||
| Ironman | `iron` |
|
||||
| Hardcore Ironman | `hc` |
|
||||
| Ultimate Ironman | `ult` |
|
||||
| Deadman Mode | `dmm` |
|
||||
| Seasonal Deadman | `sdmm` |
|
||||
| DMM Tournament | `dmmt` |
|
||||
| Game mode | Param |
|
||||
| ---------------- | :----------: |
|
||||
| Regular | `main` |
|
||||
| Ironman | `ironman` |
|
||||
| Hardcore Ironman | `hardcore` |
|
||||
| Ultimate Ironman | `ultimate` |
|
||||
| Deadman Mode | `deadman` |
|
||||
| Tournament | `tournament` |
|
||||
| Leagues | `seasonal` |
|
||||
|
||||
`getSkillPage` and `getActivityPage` require a skill/activity and optionally a gamemode and page:
|
||||
`getSkillPage` and `getActivityPage` require a skill / activity and optionally a gamemode and page:
|
||||
|
||||
```javascript
|
||||
hiscores
|
||||
@@ -87,27 +87,82 @@ hiscores
|
||||
.catch(err => console.error(err));
|
||||
```
|
||||
|
||||
Activities consist of all levels of clue scrolls as well as minigames:
|
||||
Activities consist of all levels of clue scrolls as well as minigames and bosses:
|
||||
|
||||
### Clue Scrolls
|
||||
|
||||
| Type | Param |
|
||||
| -------- | :-------------: |
|
||||
| All | `allclues` |
|
||||
| Beginner | `beginnerclues` |
|
||||
| Easy | `easyclues` |
|
||||
| Medium | `mediumclues` |
|
||||
| Hard | `hardclues` |
|
||||
| Elite | `eliteclues` |
|
||||
| Master | `masterclues` |
|
||||
| All | `allClues` |
|
||||
| Beginner | `beginnerClues` |
|
||||
| Easy | `easyClues` |
|
||||
| Medium | `mediumClues` |
|
||||
| Hard | `hardClues` |
|
||||
| Elite | `eliteClues` |
|
||||
| Master | `masterClues` |
|
||||
|
||||
### Minigames
|
||||
|
||||
| Minigame | Param |
|
||||
| ---------------------- | :--------: |
|
||||
| Bounty Hunter (Rogue) | `roguebh` |
|
||||
| Bounty Hunter (Hunter) | `hunterbh` |
|
||||
| Last Man Standing | `lms` |
|
||||
| Minigame | Param |
|
||||
| ---------------------- | :---------------: |
|
||||
| Bounty Hunter (Rogue) | `rogueBH` |
|
||||
| Bounty Hunter (Hunter) | `hunterBH` |
|
||||
| Last Man Standing | `lastManStanding` |
|
||||
|
||||
### Leagues
|
||||
|
||||
| Activity | Param |
|
||||
| ------------- | :------------: |
|
||||
| League Points | `leaguePoints` |
|
||||
|
||||
### Bosses
|
||||
|
||||
| Boss Name | Param |
|
||||
| -------------------------------- | :----------------------------: |
|
||||
| Abyssal Sire | `abyssalSire` |
|
||||
| Alchemical Hydra | `alchemicalHydra` |
|
||||
| Barrows Chests | `barrows` |
|
||||
| Bryophyta | `bryophyta` |
|
||||
| Callisto | `callisto` |
|
||||
| Cerberus | `cerberus` |
|
||||
| Chambers Of Xeric | `chambersOfXeric` |
|
||||
| Chambers Of Xeric Challenge Mode | `chambersOfXericChallengeMode` |
|
||||
| Chaos Elemental | `chaosElemental` |
|
||||
| Chaos Fanatic | `chaosFanatic` |
|
||||
| Commander Zilyana | `commanderZilyana` |
|
||||
| Corporeal Beast | `corporealBeast` |
|
||||
| Crazy Archaeologist | `crazyArchaeologist` |
|
||||
| Dagannoth Prime | `dagannothPrime` |
|
||||
| Dagannoth Rex | `dagannothRex` |
|
||||
| Dagannoth Supreme | `dagannothSupreme` |
|
||||
| Deranged Archaeologist | `derangedArchaeologist` |
|
||||
| General Graardor | `generalGraardor` |
|
||||
| Giant Mole | `giantMole` |
|
||||
| Grotesque Guardians | `grotesqueGuardians` |
|
||||
| Hespori | `hespori` |
|
||||
| Kalphite Queen | `kalphiteQueen` |
|
||||
| King Black Dragon | `kingBlackDragon` |
|
||||
| Kraken | `kraken` |
|
||||
| Kreearra | `kreeArra` |
|
||||
| K'ril Tsutsaroth | `krilTsutsaroth` |
|
||||
| Mimic | `mimic` |
|
||||
| The Nightmare of Ashihama | `nightmare` |
|
||||
| Obor | `obor` |
|
||||
| Sarachnis | `sarachnis` |
|
||||
| Scorpia | `scorpia` |
|
||||
| Skotizo | `skotizo` |
|
||||
| Gauntlet | `gauntlet` |
|
||||
| Corrupted Gauntlet | `corruptedGauntlet` |
|
||||
| Theatre Of Blood | `theatreOfBlood` |
|
||||
| Thermonuclear Smoke Devil | `thermonuclearSmokeDevil` |
|
||||
| TzKal-Zuk | `tzKalZuk` |
|
||||
| TzTok-Jad | `tzTokJad` |
|
||||
| Venenatis | `venenatis` |
|
||||
| Vetion | `vetion` |
|
||||
| Vorkath | `vorkath` |
|
||||
| Wintertodt | `wintertodt` |
|
||||
| Zalcano | `zalcano` |
|
||||
| Zulrah | `zulrah` |
|
||||
|
||||
## What you'll get
|
||||
|
||||
@@ -115,7 +170,7 @@ Activities consist of all levels of clue scrolls as well as minigames:
|
||||
|
||||
```javascript
|
||||
{
|
||||
rsn: 'Lynx Titan',
|
||||
name: 'Lynx Titan',
|
||||
mode: 'main',
|
||||
dead: false,
|
||||
deulted: false,
|
||||
@@ -128,8 +183,10 @@ Activities consist of all levels of clue scrolls as well as minigames:
|
||||
// ...
|
||||
},
|
||||
clues: {},
|
||||
bh: {},
|
||||
lms: {}
|
||||
leaguePoints: {},
|
||||
bountyHunter: {},
|
||||
lastManStanding: {},
|
||||
bosses: {}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -138,9 +195,18 @@ Activities consist of all levels of clue scrolls as well as minigames:
|
||||
|
||||
```javascript
|
||||
[
|
||||
{ rank: 1, rsn: 'Lynx Titan', level: 2277, xp: 4600000000, dead: false },
|
||||
{ rank: 1, name: 'Lynx Titan', level: 2277, xp: 4600000000, dead: false },
|
||||
{},
|
||||
{},
|
||||
// ...
|
||||
];
|
||||
```
|
||||
|
||||
## Helpful Extras
|
||||
|
||||
Get the properly formatted name of any skill, boss, clue or other activity:
|
||||
|
||||
```javascript
|
||||
// kril === "K'ril Tsutsaroth"
|
||||
const kril = FORMATTED_BOSS_NAMES['krilTsutsaroth'];
|
||||
```
|
||||
|
@@ -1,322 +1,404 @@
|
||||
import {
|
||||
parseStats,
|
||||
getRSNFormat,
|
||||
getSkillPage,
|
||||
getStats,
|
||||
getStatsByGamemode,
|
||||
getRSNFormat,
|
||||
Stats,
|
||||
} from '../src/index';
|
||||
import { PlayerSkillRow, Player, Stats } from '../src/types';
|
||||
import axios, { AxiosError } from 'axios';
|
||||
|
||||
test('Parse CSV to json', () => {
|
||||
const csv = `40258,2063,218035714
|
||||
20554, 99, 21102621
|
||||
39059, 99, 15364425
|
||||
14245, 99, 26556827
|
||||
19819, 99, 33511407
|
||||
27857, 99, 25774115
|
||||
44278, 91, 6081159
|
||||
40110, 99, 15128024
|
||||
178948, 90, 5347474
|
||||
175463, 81, 2355494
|
||||
138677, 90, 5356303
|
||||
77587, 91, 5904710
|
||||
158478, 85, 3570485
|
||||
93958, 83, 2684426
|
||||
39179, 88, 4425107
|
||||
138406, 77, 1591377
|
||||
33399, 90, 5866307
|
||||
1794, 99, 15057674
|
||||
45551, 91, 6363261
|
||||
121165, 90, 5748493
|
||||
89460, 88, 4624078
|
||||
53099, 80, 2008229
|
||||
169127, 73, 1067670
|
||||
115543, 82, 2546048
|
||||
-1, -1
|
||||
-1, -1
|
||||
32875, 500
|
||||
24817, 476
|
||||
212728, 1
|
||||
94827, 20
|
||||
59099, 74
|
||||
24642, 231
|
||||
5206, 99
|
||||
6293, 51`;
|
||||
const csv = `246,2277,1338203419
|
||||
615,99,77438259
|
||||
428,99,69176307
|
||||
425,99,115218641
|
||||
138,99,181425111
|
||||
160,99,169725807
|
||||
97,99,50666171
|
||||
144,99,93155913
|
||||
2108,99,53198880
|
||||
5750,99,19589494
|
||||
295,99,76386488
|
||||
1304,99,32252994
|
||||
847,99,54325931
|
||||
534,99,26379932
|
||||
7213,99,13246799
|
||||
2475,99,18161285
|
||||
1837,99,14746134
|
||||
668,99,23961670
|
||||
3841,99,17970837
|
||||
265,99,56230978
|
||||
821,99,62123353
|
||||
169,99,43127930
|
||||
810,99,37688883
|
||||
92,99,32005622
|
||||
-1,-1
|
||||
-1,-1
|
||||
-1,-1
|
||||
32,12148
|
||||
3105,76
|
||||
1997,505
|
||||
127,4259
|
||||
361,915
|
||||
392,250
|
||||
1,6143
|
||||
4814,898
|
||||
382,2780
|
||||
944,3000
|
||||
1981,1452
|
||||
4981,23
|
||||
888,1046
|
||||
613,4856
|
||||
102,4038
|
||||
156,334
|
||||
6240,133
|
||||
4569,250
|
||||
6893,603
|
||||
1,17798
|
||||
9320,125
|
||||
1030,2802
|
||||
4342,1655
|
||||
966,2951
|
||||
10151,1
|
||||
1288,2407
|
||||
377,4669
|
||||
545,1567
|
||||
6083,94
|
||||
264,2897
|
||||
4052,1277
|
||||
41643,1477
|
||||
625,2391
|
||||
120,2981
|
||||
1,109
|
||||
3,22666
|
||||
26,323
|
||||
201,1101
|
||||
82,3404
|
||||
5085,61
|
||||
63,375
|
||||
2870,6
|
||||
6984,138
|
||||
4043,2000
|
||||
489,8
|
||||
967,47
|
||||
11155,223
|
||||
1940,272
|
||||
8623,1340
|
||||
605,1694
|
||||
-1,-1
|
||||
3867,4583`;
|
||||
|
||||
expect(parseStats(csv)).toStrictEqual({
|
||||
const expectedOutput: Stats = {
|
||||
skills: {
|
||||
overall: { rank: 40258, level: 2063, xp: 218035714 },
|
||||
attack: { rank: 20554, level: 99, xp: 21102621 },
|
||||
defence: { rank: 39059, level: 99, xp: 15364425 },
|
||||
strength: { rank: 14245, level: 99, xp: 26556827 },
|
||||
hitpoints: { rank: 19819, level: 99, xp: 33511407 },
|
||||
ranged: { rank: 27857, level: 99, xp: 25774115 },
|
||||
prayer: { rank: 44278, level: 91, xp: 6081159 },
|
||||
magic: { rank: 40110, level: 99, xp: 15128024 },
|
||||
cooking: { rank: 178948, level: 90, xp: 5347474 },
|
||||
woodcutting: { rank: 175463, level: 81, xp: 2355494 },
|
||||
fletching: { rank: 138677, level: 90, xp: 5356303 },
|
||||
fishing: { rank: 77587, level: 91, xp: 5904710 },
|
||||
firemaking: { rank: 158478, level: 85, xp: 3570485 },
|
||||
crafting: { rank: 93958, level: 83, xp: 2684426 },
|
||||
smithing: { rank: 39179, level: 88, xp: 4425107 },
|
||||
mining: { rank: 138406, level: 77, xp: 1591377 },
|
||||
herblore: { rank: 33399, level: 90, xp: 5866307 },
|
||||
agility: { rank: 1794, level: 99, xp: 15057674 },
|
||||
thieving: { rank: 45551, level: 91, xp: 6363261 },
|
||||
slayer: { rank: 121165, level: 90, xp: 5748493 },
|
||||
farming: { rank: 89460, level: 88, xp: 4624078 },
|
||||
runecraft: { rank: 53099, level: 80, xp: 2008229 },
|
||||
hunter: { rank: 169127, level: 73, xp: 1067670 },
|
||||
construction: { rank: 115543, level: 82, xp: 2546048 },
|
||||
overall: { rank: 246, level: 2277, xp: 1338203419 },
|
||||
attack: { rank: 615, level: 99, xp: 77438259 },
|
||||
defence: { rank: 428, level: 99, xp: 69176307 },
|
||||
strength: { rank: 425, level: 99, xp: 115218641 },
|
||||
hitpoints: { rank: 138, level: 99, xp: 181425111 },
|
||||
ranged: { rank: 160, level: 99, xp: 169725807 },
|
||||
prayer: { rank: 97, level: 99, xp: 50666171 },
|
||||
magic: { rank: 144, level: 99, xp: 93155913 },
|
||||
cooking: { rank: 2108, level: 99, xp: 53198880 },
|
||||
woodcutting: { rank: 5750, level: 99, xp: 19589494 },
|
||||
fletching: { rank: 295, level: 99, xp: 76386488 },
|
||||
fishing: { rank: 1304, level: 99, xp: 32252994 },
|
||||
firemaking: { rank: 847, level: 99, xp: 54325931 },
|
||||
crafting: { rank: 534, level: 99, xp: 26379932 },
|
||||
smithing: { rank: 7213, level: 99, xp: 13246799 },
|
||||
mining: { rank: 2475, level: 99, xp: 18161285 },
|
||||
herblore: { rank: 1837, level: 99, xp: 14746134 },
|
||||
agility: { rank: 668, level: 99, xp: 23961670 },
|
||||
thieving: { rank: 3841, level: 99, xp: 17970837 },
|
||||
slayer: { rank: 265, level: 99, xp: 56230978 },
|
||||
farming: { rank: 821, level: 99, xp: 62123353 },
|
||||
runecraft: { rank: 169, level: 99, xp: 43127930 },
|
||||
hunter: { rank: 810, level: 99, xp: 37688883 },
|
||||
construction: { rank: 92, level: 99, xp: 32005622 },
|
||||
},
|
||||
bh: {
|
||||
leaguePoints: { rank: -1, score: -1 },
|
||||
bountyHunter: {
|
||||
rogue: { rank: -1, score: -1 },
|
||||
hunter: { rank: -1, score: -1 },
|
||||
},
|
||||
lms: { rank: 32875, score: 500 },
|
||||
lastManStanding: { rank: 4814, score: 898 },
|
||||
clues: {
|
||||
all: { rank: 24817, score: 476 },
|
||||
beginner: { rank: 212728, score: 1 },
|
||||
easy: { rank: 94827, score: 20 },
|
||||
medium: { rank: 59099, score: 74 },
|
||||
hard: { rank: 24642, score: 231 },
|
||||
elite: { rank: 5206, score: 99 },
|
||||
master: { rank: 6293, score: 51 },
|
||||
all: { rank: 32, score: 12148 },
|
||||
beginner: { rank: 3105, score: 76 },
|
||||
easy: { rank: 1997, score: 505 },
|
||||
medium: { rank: 127, score: 4259 },
|
||||
hard: { rank: 361, score: 915 },
|
||||
elite: { rank: 392, score: 250 },
|
||||
master: { rank: 1, score: 6143 },
|
||||
},
|
||||
bosses: {
|
||||
abyssalSire: { rank: 382, score: 2780 },
|
||||
alchemicalHydra: { rank: 944, score: 3000 },
|
||||
barrows: { rank: 1981, score: 1452 },
|
||||
bryophyta: { rank: 4981, score: 23 },
|
||||
callisto: { rank: 888, score: 1046 },
|
||||
cerberus: { rank: 613, score: 4856 },
|
||||
chambersOfXeric: { rank: 102, score: 4038 },
|
||||
chambersOfXericChallengeMode: { rank: 156, score: 334 },
|
||||
chaosElemental: { rank: 6240, score: 133 },
|
||||
chaosFanatic: { rank: 4569, score: 250 },
|
||||
commanderZilyana: { rank: 6893, score: 603 },
|
||||
corporealBeast: { rank: 1, score: 17798 },
|
||||
crazyArchaeologist: { rank: 9320, score: 125 },
|
||||
dagannothPrime: { rank: 1030, score: 2802 },
|
||||
dagannothRex: { rank: 4342, score: 1655 },
|
||||
dagannothSupreme: { rank: 966, score: 2951 },
|
||||
derangedArchaeologist: { rank: 10151, score: 1 },
|
||||
generalGraardor: { rank: 1288, score: 2407 },
|
||||
giantMole: { rank: 377, score: 4669 },
|
||||
grotesqueGuardians: { rank: 545, score: 1567 },
|
||||
hespori: { rank: 6083, score: 94 },
|
||||
kalphiteQueen: { rank: 264, score: 2897 },
|
||||
kingBlackDragon: { rank: 4052, score: 1277 },
|
||||
kraken: { rank: 41643, score: 1477 },
|
||||
kreeArra: { rank: 625, score: 2391 },
|
||||
krilTsutsaroth: { rank: 120, score: 2981 },
|
||||
mimic: { rank: 1, score: 109 },
|
||||
nightmare: { rank: 3, score: 22666 },
|
||||
obor: { rank: 26, score: 323 },
|
||||
sarachnis: { rank: 201, score: 1101 },
|
||||
scorpia: { rank: 82, score: 3404 },
|
||||
skotizo: { rank: 5085, score: 61 },
|
||||
gauntlet: { rank: 63, score: 375 },
|
||||
corruptedGauntlet: { rank: 2870, score: 6 },
|
||||
theatreOfBlood: { rank: 6984, score: 138 },
|
||||
thermonuclearSmokeDevil: { rank: 4043, score: 2000 },
|
||||
tzKalZuk: { rank: 489, score: 8 },
|
||||
tzTokJad: { rank: 967, score: 47 },
|
||||
venenatis: { rank: 11155, score: 223 },
|
||||
vetion: { rank: 1940, score: 272 },
|
||||
vorkath: { rank: 8623, score: 1340 },
|
||||
wintertodt: { rank: 605, score: 1694 },
|
||||
zalcano: { rank: -1, score: -1 },
|
||||
zulrah: { rank: 3867, score: 4583 },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('Get rsn format', async done => {
|
||||
const callback = (data: string) => {
|
||||
expect(data).toBe('Lynx Titan');
|
||||
done();
|
||||
};
|
||||
|
||||
getRSNFormat('lYnX tiTaN').then(callback);
|
||||
expect(parseStats(csv)).toStrictEqual(expectedOutput);
|
||||
});
|
||||
|
||||
test('Get attack top page', async done => {
|
||||
const callback = (data: PlayerSkillRow[]) => {
|
||||
expect(data).toMatchObject([
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 1,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 2,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{ rsn: 'Drakon', rank: 3, level: 99, xp: 200000000, dead: false },
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 4,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
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,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 10,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 11,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 12,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 13,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 14,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 15,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 16,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 17,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 18,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 19,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 20,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 21,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 22,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
rsn: expect.any(String),
|
||||
rank: 23,
|
||||
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();
|
||||
};
|
||||
|
||||
getSkillPage('attack').then(callback);
|
||||
test('Get name format', async () => {
|
||||
jest.setTimeout(30000);
|
||||
const data = await getRSNFormat('lYnX tiTaN');
|
||||
expect(data).toBe('Lynx Titan');
|
||||
});
|
||||
|
||||
test('Get non-existant player', async done => {
|
||||
const callback = (err: AxiosError) => {
|
||||
test('Get attack top page', async () => {
|
||||
jest.setTimeout(30000);
|
||||
const data = await getSkillPage('attack');
|
||||
expect(data).toMatchObject([
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 1,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 2,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{ name: 'Drakon', rank: 3, level: 99, xp: 200000000, dead: false },
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 4,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 5,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 6,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 7,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 8,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 9,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 10,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 11,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 12,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 13,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 14,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 15,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 16,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 17,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 18,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 19,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 20,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 21,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 22,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 23,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 24,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
{
|
||||
name: expect.any(String),
|
||||
rank: 25,
|
||||
level: 99,
|
||||
xp: 200000000,
|
||||
dead: false,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('Get non-existant player', async () => {
|
||||
jest.setTimeout(30000);
|
||||
getStats('fishy').catch(err => {
|
||||
if (err.response) {
|
||||
expect(err.response.status).toBe(404);
|
||||
}
|
||||
done();
|
||||
};
|
||||
|
||||
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);
|
||||
test('Get stats by gamemode', async () => {
|
||||
jest.setTimeout(30000);
|
||||
const { skills } = await getStatsByGamemode('Lynx Titan');
|
||||
expect(skills).toMatchObject({
|
||||
overall: { rank: expect.any(Number), level: 2277, xp: 4600000000 },
|
||||
attack: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
defence: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
strength: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
hitpoints: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
ranged: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
prayer: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
magic: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
cooking: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
woodcutting: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
fletching: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
fishing: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
firemaking: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
crafting: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
smithing: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
mining: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
herblore: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
agility: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
thieving: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
slayer: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
farming: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
runecraft: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
hunter: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
construction: { rank: expect.any(Number), level: 99, xp: 200000000 },
|
||||
});
|
||||
});
|
||||
|
@@ -3,5 +3,6 @@
|
||||
"^.+\\.(t|j)sx?$": "ts-jest"
|
||||
},
|
||||
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
|
||||
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"]
|
||||
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"],
|
||||
"testEnvironment": "node"
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "osrs-json-hiscores",
|
||||
"version": "1.2.1",
|
||||
"version": "2.2.0",
|
||||
"description": "The Oldschool Runescape API wrapper that does more!",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
@@ -10,6 +10,7 @@
|
||||
"scripts": {
|
||||
"dev": "watch 'yarn run build' src",
|
||||
"build": "tsc",
|
||||
"format": "prettier --write \"src/**/*.ts\"",
|
||||
"test": "jest --config jestconfig.json",
|
||||
"prepublish": "yarn run build",
|
||||
"release": "np"
|
||||
@@ -36,13 +37,14 @@
|
||||
"homepage": "https://github.com/maxswa/osrs-json-hiscores#readme",
|
||||
"dependencies": {
|
||||
"axios": "^0.19.0",
|
||||
"cheerio": "^1.0.0-rc.3"
|
||||
"jsdom": "^16.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cheerio": "^0.22.11",
|
||||
"@types/jest": "^24.0.14",
|
||||
"@types/jsdom": "^16.2.3",
|
||||
"jest": "^24.8.0",
|
||||
"np": "^5.0.3",
|
||||
"prettier": "^1.19.1",
|
||||
"ts-jest": "^24.0.2",
|
||||
"tslint": "^5.17.0",
|
||||
"tslint-config-airbnb": "^5.11.1",
|
||||
|
167
src/hiscores.ts
167
src/hiscores.ts
@@ -1,5 +1,4 @@
|
||||
import axios from 'axios';
|
||||
import * as cheerio from 'cheerio';
|
||||
import {
|
||||
Player,
|
||||
Activity,
|
||||
@@ -13,6 +12,7 @@ import {
|
||||
PlayerSkillRow,
|
||||
ActivityName,
|
||||
PlayerActivityRow,
|
||||
Bosses,
|
||||
} from './types';
|
||||
import {
|
||||
getStatsURL,
|
||||
@@ -26,7 +26,9 @@ import {
|
||||
numberFromElement,
|
||||
rsnFromElement,
|
||||
getActivityPageURL,
|
||||
BOSSES,
|
||||
} from './utils';
|
||||
import { JSDOM } from 'jsdom';
|
||||
|
||||
export async function getStats(rsn: string): Promise<Player> {
|
||||
if (typeof rsn !== 'string') {
|
||||
@@ -40,16 +42,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),
|
||||
getRSNFormat(rsn),
|
||||
axios(getStatsURL('ironman', rsn)).catch(err => err),
|
||||
axios(getStatsURL('hardcore', rsn)).catch(err => err),
|
||||
axios(getStatsURL('ultimate', rsn)).catch(err => err),
|
||||
getRSNFormat(rsn).catch(() => undefined),
|
||||
]);
|
||||
|
||||
const [ironRes, hcRes, ultRes, formattedName] = otherResponses;
|
||||
|
||||
const player: Player = {
|
||||
rsn: formattedName,
|
||||
name: formattedName || rsn,
|
||||
mode: 'main',
|
||||
dead: false,
|
||||
deulted: false,
|
||||
@@ -58,32 +60,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';
|
||||
}
|
||||
@@ -112,7 +124,7 @@ export async function getStatsByGamemode(
|
||||
if (response.status !== 200) {
|
||||
throw Error('Player not found');
|
||||
}
|
||||
const stats: Stats = parseStats(response.data);
|
||||
const stats = parseStats(response.data);
|
||||
|
||||
return stats;
|
||||
}
|
||||
@@ -132,21 +144,26 @@ export async function getSkillPage(
|
||||
const url = getSkillPageURL(mode, skill, page);
|
||||
|
||||
const response = await axios(url);
|
||||
const $ = cheerio.load(response.data);
|
||||
const playersHTML = $('.personal-hiscores__row').toArray();
|
||||
const dom = new JSDOM(response.data);
|
||||
const playersHTML = dom.window.document.querySelectorAll(
|
||||
'.personal-hiscores__row'
|
||||
);
|
||||
|
||||
const players: PlayerSkillRow[] = playersHTML.map(row => {
|
||||
const cells = row.children.filter(el => el.name === 'td');
|
||||
const [rankEl, nameCell, levelEl, xpEl] = cells;
|
||||
const [nameEl] = nameCell.children.filter(el => el.name === 'a');
|
||||
const players: PlayerSkillRow[] = [];
|
||||
playersHTML.forEach(row => {
|
||||
const rankEl = row.querySelector('td');
|
||||
const nameEl = row.querySelector('td a');
|
||||
const levelEl = row.querySelector('td.left + td');
|
||||
const xpEl = row.querySelector('td.left + td + td');
|
||||
const isDead = !!row.querySelector('td img');
|
||||
|
||||
return {
|
||||
rsn: rsnFromElement(nameEl),
|
||||
players.push({
|
||||
name: rsnFromElement(nameEl),
|
||||
rank: numberFromElement(rankEl),
|
||||
level: numberFromElement(levelEl),
|
||||
xp: numberFromElement(xpEl),
|
||||
dead: nameCell.children.length === 4,
|
||||
};
|
||||
dead: isDead,
|
||||
});
|
||||
});
|
||||
|
||||
return players;
|
||||
@@ -167,20 +184,24 @@ export async function getActivityPage(
|
||||
const url = getActivityPageURL(mode, activity, page);
|
||||
|
||||
const response = await axios(url);
|
||||
const $ = cheerio.load(response.data);
|
||||
const playersHTML = $('.personal-hiscores__row').toArray();
|
||||
const dom = new JSDOM(response.data);
|
||||
const playersHTML = dom.window.document.querySelectorAll(
|
||||
'.personal-hiscores__row'
|
||||
);
|
||||
|
||||
const players: PlayerActivityRow[] = playersHTML.map(row => {
|
||||
const cells = row.children.filter(el => el.name === 'td');
|
||||
const [rankEl, nameCell, scoreEl] = cells;
|
||||
const [nameEl] = nameCell.children.filter(el => el.name === 'a');
|
||||
const players: PlayerActivityRow[] = [];
|
||||
playersHTML.forEach(row => {
|
||||
const rankEl = row.querySelector('td');
|
||||
const nameEl = row.querySelector('td a');
|
||||
const scoreEl = row.querySelector('td.left + td');
|
||||
const isDead = !!row.querySelector('td img');
|
||||
|
||||
return {
|
||||
rsn: rsnFromElement(nameEl),
|
||||
players.push({
|
||||
name: rsnFromElement(nameEl),
|
||||
rank: numberFromElement(rankEl),
|
||||
score: numberFromElement(scoreEl),
|
||||
dead: nameCell.children.length === 4,
|
||||
};
|
||||
dead: isDead,
|
||||
});
|
||||
});
|
||||
|
||||
return players;
|
||||
@@ -198,10 +219,13 @@ export async function getRSNFormat(rsn: string): Promise<string> {
|
||||
const url = getPlayerTableURL('main', rsn);
|
||||
try {
|
||||
const response = await axios(url);
|
||||
const $ = cheerio.load(response.data);
|
||||
const rawName = $('[style="color:#AA0022;"]')[1].children[0].data;
|
||||
if (rawName) {
|
||||
return rawName.replace(/\uFFFD/g, ' ');
|
||||
const dom = new JSDOM(response.data);
|
||||
const spans = dom.window.document.querySelectorAll(
|
||||
'span[style="color:#AA0022;"]'
|
||||
);
|
||||
if (spans.length >= 2) {
|
||||
const nameSpan = spans[1];
|
||||
return rsnFromElement(nameSpan);
|
||||
}
|
||||
throw Error('Player not found');
|
||||
} catch {
|
||||
@@ -238,42 +262,43 @@ export function parseStats(csv: string): Stats {
|
||||
return activity;
|
||||
});
|
||||
|
||||
const [leaguePoints] = activityObjects.splice(0, 1);
|
||||
const bhObjects = activityObjects.splice(0, BH_MODES.length);
|
||||
const [lms] = activityObjects.splice(0, 1);
|
||||
const clueObjects = activityObjects.splice(0, CLUES.length);
|
||||
const [lastManStanding] = activityObjects.splice(0, 1);
|
||||
const bossObjects = activityObjects.splice(0, BOSSES.length);
|
||||
|
||||
const skills: Skills = skillObjects.reduce<Skills>(
|
||||
(prev, curr, index) => {
|
||||
const newSkills = { ...prev };
|
||||
newSkills[SKILLS[index]] = curr;
|
||||
return newSkills;
|
||||
},
|
||||
{} as Skills
|
||||
);
|
||||
const skills: Skills = skillObjects.reduce<Skills>((prev, curr, index) => {
|
||||
const newSkills = { ...prev };
|
||||
newSkills[SKILLS[index]] = curr;
|
||||
return newSkills;
|
||||
}, {} as Skills);
|
||||
|
||||
const bh: BH = bhObjects.reduce<BH>(
|
||||
(prev, curr, index) => {
|
||||
const newBH = { ...prev };
|
||||
newBH[BH_MODES[index]] = curr;
|
||||
return newBH;
|
||||
},
|
||||
{} as BH
|
||||
);
|
||||
const bountyHunter: BH = bhObjects.reduce<BH>((prev, curr, index) => {
|
||||
const newBH = { ...prev };
|
||||
newBH[BH_MODES[index]] = curr;
|
||||
return newBH;
|
||||
}, {} as BH);
|
||||
|
||||
const clues: Clues = clueObjects.reduce<Clues>(
|
||||
(prev, curr, index) => {
|
||||
const newClues = { ...prev };
|
||||
newClues[CLUES[index]] = curr;
|
||||
return newClues;
|
||||
},
|
||||
{} as Clues
|
||||
);
|
||||
const clues: Clues = clueObjects.reduce<Clues>((prev, curr, index) => {
|
||||
const newClues = { ...prev };
|
||||
newClues[CLUES[index]] = curr;
|
||||
return newClues;
|
||||
}, {} as Clues);
|
||||
|
||||
const bosses: Bosses = bossObjects.reduce<Bosses>((prev, curr, index) => {
|
||||
const newBosses = { ...prev };
|
||||
newBosses[BOSSES[index]] = curr;
|
||||
return newBosses;
|
||||
}, {} as Bosses);
|
||||
|
||||
const stats: Stats = {
|
||||
skills,
|
||||
bh,
|
||||
lms,
|
||||
leaguePoints,
|
||||
bountyHunter,
|
||||
lastManStanding,
|
||||
clues,
|
||||
bosses,
|
||||
};
|
||||
|
||||
return stats;
|
||||
|
@@ -2,5 +2,6 @@ import * as hiscores from './hiscores';
|
||||
|
||||
export * from './hiscores';
|
||||
export * from './types';
|
||||
export * from './utils';
|
||||
|
||||
export default hiscores;
|
||||
|
92
src/types.ts
92
src/types.ts
@@ -1,4 +1,11 @@
|
||||
export type Gamemode = 'main' | 'iron' | 'hc' | 'ult' | 'dmm' | 'sdmm' | 'dmmt';
|
||||
export type Gamemode =
|
||||
| 'main'
|
||||
| 'ironman'
|
||||
| 'ultimate'
|
||||
| 'hardcore'
|
||||
| 'deadman'
|
||||
| 'seasonal'
|
||||
| 'tournament';
|
||||
|
||||
export interface Skill {
|
||||
rank: number;
|
||||
@@ -54,29 +61,80 @@ export type BHType = 'rogue' | 'hunter';
|
||||
|
||||
export type BH = { [Type in BHType]: Activity };
|
||||
|
||||
export type Boss =
|
||||
| 'abyssalSire'
|
||||
| 'alchemicalHydra'
|
||||
| 'barrows'
|
||||
| 'bryophyta'
|
||||
| 'callisto'
|
||||
| 'cerberus'
|
||||
| 'chambersOfXeric'
|
||||
| 'chambersOfXericChallengeMode'
|
||||
| 'chaosElemental'
|
||||
| 'chaosFanatic'
|
||||
| 'commanderZilyana'
|
||||
| 'corporealBeast'
|
||||
| 'crazyArchaeologist'
|
||||
| 'dagannothPrime'
|
||||
| 'dagannothRex'
|
||||
| 'dagannothSupreme'
|
||||
| 'derangedArchaeologist'
|
||||
| 'generalGraardor'
|
||||
| 'giantMole'
|
||||
| 'grotesqueGuardians'
|
||||
| 'hespori'
|
||||
| 'kalphiteQueen'
|
||||
| 'kingBlackDragon'
|
||||
| 'kraken'
|
||||
| 'kreeArra'
|
||||
| 'krilTsutsaroth'
|
||||
| 'mimic'
|
||||
| 'nightmare'
|
||||
| 'obor'
|
||||
| 'sarachnis'
|
||||
| 'scorpia'
|
||||
| 'skotizo'
|
||||
| 'gauntlet'
|
||||
| 'corruptedGauntlet'
|
||||
| 'theatreOfBlood'
|
||||
| 'thermonuclearSmokeDevil'
|
||||
| 'tzKalZuk'
|
||||
| 'tzTokJad'
|
||||
| 'venenatis'
|
||||
| 'vetion'
|
||||
| 'vorkath'
|
||||
| 'wintertodt'
|
||||
| 'zalcano'
|
||||
| 'zulrah';
|
||||
|
||||
export type Bosses = { [Type in Boss]: Activity };
|
||||
|
||||
export type ActivityName =
|
||||
| 'hunterbh'
|
||||
| 'roguebh'
|
||||
| 'lms'
|
||||
| 'allclues'
|
||||
| 'beginnerclues'
|
||||
| 'easyclues'
|
||||
| 'mediumclues'
|
||||
| 'hardclues'
|
||||
| 'eliteclues'
|
||||
| 'masterclues';
|
||||
| 'leaguePoints'
|
||||
| '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 type Modes = { [M in Gamemode]?: Stats };
|
||||
|
||||
export interface Player extends Modes {
|
||||
rsn: string;
|
||||
name: string;
|
||||
mode: Gamemode;
|
||||
dead: boolean;
|
||||
deulted: boolean;
|
||||
@@ -84,11 +142,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;
|
||||
}
|
||||
|
@@ -1,16 +1,28 @@
|
||||
import { SkillName, ClueType, BHType, Gamemode } from '../types';
|
||||
import {
|
||||
BHType,
|
||||
Boss,
|
||||
ClueType,
|
||||
Gamemode,
|
||||
SkillName,
|
||||
ActivityName,
|
||||
} from '../types';
|
||||
|
||||
export const BASE_URL = 'http://services.runescape.com/m=hiscore_oldschool';
|
||||
export const BASE_URL = 'https://secure.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: '/',
|
||||
sdmm: '_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,24 +60,180 @@ 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 GAMEMODES: Gamemode[] = [
|
||||
'main',
|
||||
'iron',
|
||||
'hc',
|
||||
'ult',
|
||||
'dmm',
|
||||
'sdmm',
|
||||
'dmmt',
|
||||
'ironman',
|
||||
'hardcore',
|
||||
'ultimate',
|
||||
'deadman',
|
||||
'seasonal',
|
||||
'tournament',
|
||||
];
|
||||
export const BOSSES: Boss[] = [
|
||||
'abyssalSire',
|
||||
'alchemicalHydra',
|
||||
'barrows',
|
||||
'bryophyta',
|
||||
'callisto',
|
||||
'cerberus',
|
||||
'chambersOfXeric',
|
||||
'chambersOfXericChallengeMode',
|
||||
'chaosElemental',
|
||||
'chaosFanatic',
|
||||
'commanderZilyana',
|
||||
'corporealBeast',
|
||||
'crazyArchaeologist',
|
||||
'dagannothPrime',
|
||||
'dagannothRex',
|
||||
'dagannothSupreme',
|
||||
'derangedArchaeologist',
|
||||
'generalGraardor',
|
||||
'giantMole',
|
||||
'grotesqueGuardians',
|
||||
'hespori',
|
||||
'kalphiteQueen',
|
||||
'kingBlackDragon',
|
||||
'kraken',
|
||||
'kreeArra',
|
||||
'krilTsutsaroth',
|
||||
'mimic',
|
||||
'nightmare',
|
||||
'obor',
|
||||
'sarachnis',
|
||||
'scorpia',
|
||||
'skotizo',
|
||||
'gauntlet',
|
||||
'corruptedGauntlet',
|
||||
'theatreOfBlood',
|
||||
'thermonuclearSmokeDevil',
|
||||
'tzKalZuk',
|
||||
'tzTokJad',
|
||||
'venenatis',
|
||||
'vetion',
|
||||
'vorkath',
|
||||
'wintertodt',
|
||||
'zalcano',
|
||||
'zulrah',
|
||||
];
|
||||
export const ACTIVITIES: ActivityName[] = [
|
||||
'leaguePoints',
|
||||
'hunterBH',
|
||||
'rogueBH',
|
||||
'allClues',
|
||||
'beginnerClues',
|
||||
'easyClues',
|
||||
'mediumClues',
|
||||
'hardClues',
|
||||
'eliteClues',
|
||||
'masterClues',
|
||||
'lastManStanding',
|
||||
...BOSSES,
|
||||
];
|
||||
|
||||
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',
|
||||
nightmare: 'The Nightmare of Ashihama',
|
||||
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';
|
||||
|
@@ -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,19 +29,19 @@ export const getActivityPageURL = (
|
||||
activity: ActivityName,
|
||||
page: number
|
||||
) =>
|
||||
`${BASE_URL}${
|
||||
`${
|
||||
GAMEMODE_URL[gamemode]
|
||||
}${SCORES_URL}category_type=1&table=${ACTIVITIES.indexOf(
|
||||
activity
|
||||
)}&page=${page}`;
|
||||
|
||||
export const numberFromElement = (el: CheerioElement) => {
|
||||
const innerText = el.firstChild.data;
|
||||
const number = innerText ? innerText.replace(/[\n|,]/g, '') : '-1';
|
||||
export const numberFromElement = (el: Element | null) => {
|
||||
const { innerHTML } = el || {};
|
||||
const number = innerHTML?.replace(/[\n|,]/g, '') ?? '-1';
|
||||
return parseInt(number, 10);
|
||||
};
|
||||
|
||||
export const rsnFromElement = (el: CheerioElement) => {
|
||||
const innerText = el.firstChild.data;
|
||||
return innerText ? innerText.replace(/\uFFFD/g, ' ') : '';
|
||||
export const rsnFromElement = (el: Element | null) => {
|
||||
const { innerHTML } = el || {};
|
||||
return innerHTML?.replace(/\uFFFD/g, ' ') || '';
|
||||
};
|
||||
|
Reference in New Issue
Block a user