mirror of
https://github.com/maxswa/osrs-json-hiscores.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
52 Commits
v1.2.0
...
bh-order-f
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d67837c161 | ||
![]() |
4aa6ad2752 | ||
![]() |
2f788fabf6 | ||
![]() |
0f5aea795c | ||
![]() |
7acb84e310 | ||
![]() |
9619bd2a2b | ||
![]() |
55abd9f800 | ||
![]() |
cf8a4cc26e | ||
![]() |
0f68c1995c | ||
![]() |
ae47df31f1 | ||
![]() |
7a3f3a0800 | ||
![]() |
b16e8ace6e | ||
![]() |
09f7805fd4 | ||
![]() |
939f4d2721 | ||
![]() |
a4577ffb2c | ||
![]() |
19ba7e2916 | ||
![]() |
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 | ||
![]() |
880679b9e6 | ||
![]() |
f679e2bde8 | ||
![]() |
06a176873b | ||
![]() |
553f4f5c36 | ||
![]() |
e95efb5cdf | ||
![]() |
68eb807657 | ||
![]() |
93d6961a4c | ||
![]() |
fbce22fd07 |
18
.github/workflows/main.yml
vendored
Normal file
18
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: borales/actions-yarn@v2.0.0
|
||||||
|
with:
|
||||||
|
cmd: install
|
||||||
|
- uses: borales/actions-yarn@v2.0.0
|
||||||
|
with:
|
||||||
|
cmd: build
|
||||||
|
- uses: borales/actions-yarn@v2.0.0
|
||||||
|
with:
|
||||||
|
cmd: test
|
137
README.md
137
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,19 +65,20 @@ 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 |
|
||||||
| ---------------- | :----: |
|
| ---------------- | :----------: |
|
||||||
| Regular | `main` |
|
| Regular | `main` |
|
||||||
| Ironman | `iron` |
|
| Ironman | `ironman` |
|
||||||
| Hardcore Ironman | `hc` |
|
| Hardcore Ironman | `hardcore` |
|
||||||
| Ultimate Ironman | `ult` |
|
| Ultimate Ironman | `ultimate` |
|
||||||
| Deadman Mode | `dmm` |
|
| Deadman Mode | `deadman` |
|
||||||
| Seasonal Deadman | `sdmm` |
|
| Tournament | `tournament` |
|
||||||
| DMM Tournament | `dmmt` |
|
| 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
|
```javascript
|
||||||
hiscores
|
hiscores
|
||||||
@@ -78,27 +87,83 @@ hiscores
|
|||||||
.catch(err => console.error(err));
|
.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
|
### Clue Scrolls
|
||||||
|
|
||||||
| Type | Param |
|
| Type | Param |
|
||||||
| -------- | :-------------: |
|
| -------- | :-------------: |
|
||||||
| All | `allclues` |
|
| All | `allClues` |
|
||||||
| Beginner | `beginnerclues` |
|
| Beginner | `beginnerClues` |
|
||||||
| Easy | `easyclues` |
|
| Easy | `easyClues` |
|
||||||
| Medium | `mediumclues` |
|
| Medium | `mediumClues` |
|
||||||
| Hard | `hardclues` |
|
| Hard | `hardClues` |
|
||||||
| Elite | `eliteclues` |
|
| Elite | `eliteClues` |
|
||||||
| Master | `masterclues` |
|
| Master | `masterClues` |
|
||||||
|
|
||||||
### Minigames
|
### Minigames
|
||||||
|
|
||||||
| Minigame | Param |
|
| Minigame | Param |
|
||||||
| ---------------------- | :--------: |
|
| ---------------------- | :---------------: |
|
||||||
| Bounty Hunter (Rogue) | `roguebh` |
|
| Bounty Hunter (Rogue) | `rogueBH` |
|
||||||
| Bounty Hunter (Hunter) | `hunterbh` |
|
| Bounty Hunter (Hunter) | `hunterBH` |
|
||||||
| Last Man Standing | `lms` |
|
| Last Man Standing | `lastManStanding` |
|
||||||
|
| Soul Wars Zeal | `soulWarsZeal` |
|
||||||
|
|
||||||
|
### 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
|
## What you'll get
|
||||||
|
|
||||||
@@ -106,7 +171,7 @@ Activities consist of all levels of clue scrolls as well as minigames:
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
rsn: 'Lynx Titan',
|
name: 'Lynx Titan',
|
||||||
mode: 'main',
|
mode: 'main',
|
||||||
dead: false,
|
dead: false,
|
||||||
deulted: false,
|
deulted: false,
|
||||||
@@ -119,8 +184,11 @@ Activities consist of all levels of clue scrolls as well as minigames:
|
|||||||
// ...
|
// ...
|
||||||
},
|
},
|
||||||
clues: {},
|
clues: {},
|
||||||
bh: {},
|
leaguePoints: {},
|
||||||
lms: {}
|
bountyHunter: {},
|
||||||
|
lastManStanding: {},
|
||||||
|
soulWarsZeal: {},
|
||||||
|
bosses: {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -129,9 +197,18 @@ Activities consist of all levels of clue scrolls as well as minigames:
|
|||||||
|
|
||||||
```javascript
|
```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,222 +1,406 @@
|
|||||||
import { parseStats, getRSNFormat, getSkillPage, getStats } from '../src/index';
|
import {
|
||||||
import { PlayerSkillRow, Player } from '../src/types';
|
parseStats,
|
||||||
import axios, { AxiosError } from 'axios';
|
getSkillPage,
|
||||||
|
getStats,
|
||||||
|
getStatsByGamemode,
|
||||||
|
getRSNFormat,
|
||||||
|
Stats,
|
||||||
|
} from '../src/index';
|
||||||
|
|
||||||
test('Parse CSV to json', () => {
|
test('Parse CSV to json', () => {
|
||||||
const csv = `40258,2063,218035714
|
const csv = `246,2277,1338203419
|
||||||
20554, 99, 21102621
|
615,99,77438259
|
||||||
39059, 99, 15364425
|
428,99,69176307
|
||||||
14245, 99, 26556827
|
425,99,115218641
|
||||||
19819, 99, 33511407
|
138,99,181425111
|
||||||
27857, 99, 25774115
|
160,99,169725807
|
||||||
44278, 91, 6081159
|
97,99,50666171
|
||||||
40110, 99, 15128024
|
144,99,93155913
|
||||||
178948, 90, 5347474
|
2108,99,53198880
|
||||||
175463, 81, 2355494
|
5750,99,19589494
|
||||||
138677, 90, 5356303
|
295,99,76386488
|
||||||
77587, 91, 5904710
|
1304,99,32252994
|
||||||
158478, 85, 3570485
|
847,99,54325931
|
||||||
93958, 83, 2684426
|
534,99,26379932
|
||||||
39179, 88, 4425107
|
7213,99,13246799
|
||||||
138406, 77, 1591377
|
2475,99,18161285
|
||||||
33399, 90, 5866307
|
1837,99,14746134
|
||||||
1794, 99, 15057674
|
668,99,23961670
|
||||||
45551, 91, 6363261
|
3841,99,17970837
|
||||||
121165, 90, 5748493
|
265,99,56230978
|
||||||
89460, 88, 4624078
|
821,99,62123353
|
||||||
53099, 80, 2008229
|
169,99,43127930
|
||||||
169127, 73, 1067670
|
810,99,37688883
|
||||||
115543, 82, 2546048
|
92,99,32005622
|
||||||
-1, -1
|
23423,478
|
||||||
-1, -1
|
99831,23
|
||||||
32875, 500
|
89912,37
|
||||||
24817, 476
|
32,12148
|
||||||
212728, 1
|
3105,76
|
||||||
94827, 20
|
1997,505
|
||||||
59099, 74
|
127,4259
|
||||||
24642, 231
|
361,915
|
||||||
5206, 99
|
392,250
|
||||||
6293, 51`;
|
1,6143
|
||||||
|
4814,898
|
||||||
|
37,225
|
||||||
|
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: {
|
skills: {
|
||||||
overall: { rank: 40258, level: 2063, xp: 218035714 },
|
overall: { rank: 246, level: 2277, xp: 1338203419 },
|
||||||
attack: { rank: 20554, level: 99, xp: 21102621 },
|
attack: { rank: 615, level: 99, xp: 77438259 },
|
||||||
defence: { rank: 39059, level: 99, xp: 15364425 },
|
defence: { rank: 428, level: 99, xp: 69176307 },
|
||||||
strength: { rank: 14245, level: 99, xp: 26556827 },
|
strength: { rank: 425, level: 99, xp: 115218641 },
|
||||||
hitpoints: { rank: 19819, level: 99, xp: 33511407 },
|
hitpoints: { rank: 138, level: 99, xp: 181425111 },
|
||||||
ranged: { rank: 27857, level: 99, xp: 25774115 },
|
ranged: { rank: 160, level: 99, xp: 169725807 },
|
||||||
prayer: { rank: 44278, level: 91, xp: 6081159 },
|
prayer: { rank: 97, level: 99, xp: 50666171 },
|
||||||
magic: { rank: 40110, level: 99, xp: 15128024 },
|
magic: { rank: 144, level: 99, xp: 93155913 },
|
||||||
cooking: { rank: 178948, level: 90, xp: 5347474 },
|
cooking: { rank: 2108, level: 99, xp: 53198880 },
|
||||||
woodcutting: { rank: 175463, level: 81, xp: 2355494 },
|
woodcutting: { rank: 5750, level: 99, xp: 19589494 },
|
||||||
fletching: { rank: 138677, level: 90, xp: 5356303 },
|
fletching: { rank: 295, level: 99, xp: 76386488 },
|
||||||
fishing: { rank: 77587, level: 91, xp: 5904710 },
|
fishing: { rank: 1304, level: 99, xp: 32252994 },
|
||||||
firemaking: { rank: 158478, level: 85, xp: 3570485 },
|
firemaking: { rank: 847, level: 99, xp: 54325931 },
|
||||||
crafting: { rank: 93958, level: 83, xp: 2684426 },
|
crafting: { rank: 534, level: 99, xp: 26379932 },
|
||||||
smithing: { rank: 39179, level: 88, xp: 4425107 },
|
smithing: { rank: 7213, level: 99, xp: 13246799 },
|
||||||
mining: { rank: 138406, level: 77, xp: 1591377 },
|
mining: { rank: 2475, level: 99, xp: 18161285 },
|
||||||
herblore: { rank: 33399, level: 90, xp: 5866307 },
|
herblore: { rank: 1837, level: 99, xp: 14746134 },
|
||||||
agility: { rank: 1794, level: 99, xp: 15057674 },
|
agility: { rank: 668, level: 99, xp: 23961670 },
|
||||||
thieving: { rank: 45551, level: 91, xp: 6363261 },
|
thieving: { rank: 3841, level: 99, xp: 17970837 },
|
||||||
slayer: { rank: 121165, level: 90, xp: 5748493 },
|
slayer: { rank: 265, level: 99, xp: 56230978 },
|
||||||
farming: { rank: 89460, level: 88, xp: 4624078 },
|
farming: { rank: 821, level: 99, xp: 62123353 },
|
||||||
runecraft: { rank: 53099, level: 80, xp: 2008229 },
|
runecraft: { rank: 169, level: 99, xp: 43127930 },
|
||||||
hunter: { rank: 169127, level: 73, xp: 1067670 },
|
hunter: { rank: 810, level: 99, xp: 37688883 },
|
||||||
construction: { rank: 115543, level: 82, xp: 2546048 },
|
construction: { rank: 92, level: 99, xp: 32005622 },
|
||||||
},
|
},
|
||||||
bh: {
|
leaguePoints: { rank: 23423, score: 478 },
|
||||||
rogue: { rank: -1, score: -1 },
|
bountyHunter: {
|
||||||
hunter: { rank: -1, score: -1 },
|
hunter: { rank: 99831, score: 23 },
|
||||||
|
rogue: { rank: 89912, score: 37 },
|
||||||
},
|
},
|
||||||
lms: { rank: 32875, score: 500 },
|
lastManStanding: { rank: 4814, score: 898 },
|
||||||
|
soulWarsZeal: { rank: 37, score: 225 },
|
||||||
clues: {
|
clues: {
|
||||||
all: { rank: 24817, score: 476 },
|
all: { rank: 32, score: 12148 },
|
||||||
beginner: { rank: 212728, score: 1 },
|
beginner: { rank: 3105, score: 76 },
|
||||||
easy: { rank: 94827, score: 20 },
|
easy: { rank: 1997, score: 505 },
|
||||||
medium: { rank: 59099, score: 74 },
|
medium: { rank: 127, score: 4259 },
|
||||||
hard: { rank: 24642, score: 231 },
|
hard: { rank: 361, score: 915 },
|
||||||
elite: { rank: 5206, score: 99 },
|
elite: { rank: 392, score: 250 },
|
||||||
master: { rank: 6293, score: 51 },
|
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 => {
|
test('Get name format', async () => {
|
||||||
const callback = (data: PlayerSkillRow[]) => {
|
jest.setTimeout(30000);
|
||||||
expect(data).toStrictEqual([
|
const data = await getRSNFormat('lYnX tiTaN');
|
||||||
{ rsn: 'Heur', rank: 1, level: 99, xp: 200000000, dead: false },
|
expect(data).toBe('Lynx Titan');
|
||||||
{
|
|
||||||
rsn: 'Unohdettu2',
|
|
||||||
rank: 2,
|
|
||||||
level: 99,
|
|
||||||
xp: 200000000,
|
|
||||||
dead: false,
|
|
||||||
},
|
|
||||||
{ rsn: 'Drakon', rank: 3, level: 99, xp: 200000000, dead: false },
|
|
||||||
{
|
|
||||||
rsn: 'Ame Umehara',
|
|
||||||
rank: 4,
|
|
||||||
level: 99,
|
|
||||||
xp: 200000000,
|
|
||||||
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',
|
|
||||||
rank: 9,
|
|
||||||
level: 99,
|
|
||||||
xp: 200000000,
|
|
||||||
dead: false,
|
|
||||||
},
|
|
||||||
{ rsn: 'Burned', rank: 10, level: 99, xp: 200000000, dead: false },
|
|
||||||
{
|
|
||||||
rsn: 'Blue Limes',
|
|
||||||
rank: 11,
|
|
||||||
level: 99,
|
|
||||||
xp: 200000000,
|
|
||||||
dead: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rsn: 'Mini Finbarr',
|
|
||||||
rank: 12,
|
|
||||||
level: 99,
|
|
||||||
xp: 200000000,
|
|
||||||
dead: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rsn: 'Unohdettu3',
|
|
||||||
rank: 13,
|
|
||||||
level: 99,
|
|
||||||
xp: 200000000,
|
|
||||||
dead: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rsn: 'Eslihero',
|
|
||||||
rank: 14,
|
|
||||||
level: 99,
|
|
||||||
xp: 200000000,
|
|
||||||
dead: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rsn: 'Lynx Titan',
|
|
||||||
rank: 15,
|
|
||||||
level: 99,
|
|
||||||
xp: 200000000,
|
|
||||||
dead: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rsn: 'AndrewWigins',
|
|
||||||
rank: 16,
|
|
||||||
level: 99,
|
|
||||||
xp: 200000000,
|
|
||||||
dead: false,
|
|
||||||
},
|
|
||||||
{ rsn: 'iMelee', rank: 17, level: 99, xp: 200000000, dead: false },
|
|
||||||
{
|
|
||||||
rsn: 'Portuguese',
|
|
||||||
rank: 18,
|
|
||||||
level: 99,
|
|
||||||
xp: 200000000,
|
|
||||||
dead: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rsn: 'MarkoOSRS',
|
|
||||||
rank: 19,
|
|
||||||
level: 99,
|
|
||||||
xp: 200000000,
|
|
||||||
dead: false,
|
|
||||||
},
|
|
||||||
{ rsn: 'Cairo', rank: 20, level: 99, xp: 200000000, dead: false },
|
|
||||||
{
|
|
||||||
rsn: 'Hey Jase',
|
|
||||||
rank: 21,
|
|
||||||
level: 99,
|
|
||||||
xp: 200000000,
|
|
||||||
dead: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rsn: 'Sleighur',
|
|
||||||
rank: 22,
|
|
||||||
level: 99,
|
|
||||||
xp: 200000000,
|
|
||||||
dead: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rsn: 'KMSat200mALL',
|
|
||||||
rank: 23,
|
|
||||||
level: 99,
|
|
||||||
xp: 200000000,
|
|
||||||
dead: false,
|
|
||||||
},
|
|
||||||
{ rsn: 'Yumemi', rank: 24, level: 99, xp: 200000000, dead: false },
|
|
||||||
{ rsn: 'Fiiggy', rank: 25, level: 99, xp: 200000000, dead: false },
|
|
||||||
]);
|
|
||||||
done();
|
|
||||||
};
|
|
||||||
|
|
||||||
getSkillPage('attack').then(callback);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Get non-existant player', async done => {
|
test('Get attack top page', async () => {
|
||||||
const callback = (err: AxiosError) => {
|
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) {
|
if (err.response) {
|
||||||
expect(err.response.status).toBe(404);
|
expect(err.response.status).toBe(404);
|
||||||
}
|
}
|
||||||
done();
|
});
|
||||||
};
|
});
|
||||||
|
|
||||||
getStats('fishy').catch(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"
|
"^.+\\.(t|j)sx?$": "ts-jest"
|
||||||
},
|
},
|
||||||
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
|
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
|
||||||
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"]
|
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"],
|
||||||
|
"testEnvironment": "node"
|
||||||
}
|
}
|
||||||
|
17
package.json
17
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "osrs-json-hiscores",
|
"name": "osrs-json-hiscores",
|
||||||
"version": "1.2.0",
|
"version": "2.3.1",
|
||||||
"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",
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "watch 'yarn run build' src",
|
"dev": "watch 'yarn run build' src",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
|
"format": "prettier --write \"src/**/*.ts\"",
|
||||||
"test": "jest --config jestconfig.json",
|
"test": "jest --config jestconfig.json",
|
||||||
"prepublish": "yarn run build",
|
"prepublish": "yarn run build",
|
||||||
"release": "np"
|
"release": "np"
|
||||||
@@ -35,15 +36,17 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/maxswa/osrs-json-hiscores#readme",
|
"homepage": "https://github.com/maxswa/osrs-json-hiscores#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.19.0",
|
"axios": "^0.21.1",
|
||||||
"cheerio": "^1.0.0-rc.3"
|
"jsdom": "^16.3.0",
|
||||||
|
"useragent-generator": "^1.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/cheerio": "^0.22.11",
|
"@types/jest": "^26.0.20",
|
||||||
"@types/jest": "^24.0.14",
|
"@types/jsdom": "^16.2.3",
|
||||||
"jest": "^24.8.0",
|
"jest": "^26.6.3",
|
||||||
"np": "^5.0.3",
|
"np": "^5.0.3",
|
||||||
"ts-jest": "^24.0.2",
|
"prettier": "^1.19.1",
|
||||||
|
"ts-jest": "^26.4.4",
|
||||||
"tslint": "^5.17.0",
|
"tslint": "^5.17.0",
|
||||||
"tslint-config-airbnb": "^5.11.1",
|
"tslint-config-airbnb": "^5.11.1",
|
||||||
"tslint-config-prettier": "^1.18.0",
|
"tslint-config-prettier": "^1.18.0",
|
||||||
|
51
src/@types/useragent-generator.d.ts
vendored
Normal file
51
src/@types/useragent-generator.d.ts
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
declare module 'useragent-generator' {
|
||||||
|
/********************
|
||||||
|
* Google Chrome *
|
||||||
|
/*******************/
|
||||||
|
export function chrome(opt: number | string | { version: string, os?: string }): string;
|
||||||
|
export namespace chrome {
|
||||||
|
function androidPhone(opt: number | string | { version: string, androidVersion?: string, device?: string }): string;
|
||||||
|
function androidTablet(opt: number | string | { version: string, androidVersion?: string, device?: string })
|
||||||
|
: string;
|
||||||
|
function androidWebview(opt: number | string | { androidVersion: string, chromeVersion?: string, device?: string })
|
||||||
|
: string;
|
||||||
|
function chromecast(opt: number | string | { version: string }): string;
|
||||||
|
function iOS(opt: number | string | { iOSVersion: string, chromeVersion?: string, device?: string }): string;
|
||||||
|
}
|
||||||
|
export function chromium(opt: number | string | { version: string, os?: string }): string;
|
||||||
|
/***************
|
||||||
|
* Firefox *
|
||||||
|
/*************/
|
||||||
|
export function firefox(opt: number | string | { version: string, os?: string }): string;
|
||||||
|
export namespace firefox {
|
||||||
|
function androidPhone(opt: number | string | { version: string, androidVersion?: string, device?: string }): string;
|
||||||
|
function androidTablet(opt: number | string | { version: string, androidVersion?: string, device?: string })
|
||||||
|
: string;
|
||||||
|
function iOS(opt: number | string | { iOSVersion: string, device?: string }): string;
|
||||||
|
}
|
||||||
|
/**************
|
||||||
|
* Safari *
|
||||||
|
/************/
|
||||||
|
export function safari(opt: number | string | { version: string, os?: string }): string;
|
||||||
|
export namespace safari {
|
||||||
|
function iOS(opt: number | string | { iOSVersion: string, safariVersion?: string, device?: string }): string;
|
||||||
|
function iOSWebview(opt: number | string | { iOSVersion: string, safariVersion?: string, device?: string }): string;
|
||||||
|
}
|
||||||
|
/***********************
|
||||||
|
* Internet Explorer *
|
||||||
|
/*********************/
|
||||||
|
export function ie(opt: number | string | { version: string, os?: string }): string;
|
||||||
|
export namespace ie {
|
||||||
|
function windowsPhone(opt: number | string | { version: string, device?: string }): string;
|
||||||
|
}
|
||||||
|
/**********************
|
||||||
|
* Microsoft Edge *
|
||||||
|
/********************/
|
||||||
|
export function edge(opt: number | string | { version: string, chromeVersion?: string, os?: string }): string;
|
||||||
|
/************************
|
||||||
|
* Search Engine Bots *
|
||||||
|
/**********************/
|
||||||
|
export function googleBot(opt?: number | string | { version?: string }): string;
|
||||||
|
export function bingBot(opt?: number | string | { version?: string }): string;
|
||||||
|
export function yahooBot(): string;
|
||||||
|
}
|
293
src/hiscores.ts
293
src/hiscores.ts
@@ -1,26 +1,23 @@
|
|||||||
import axios from 'axios';
|
|
||||||
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,
|
||||||
PlayerSkillRow,
|
PlayerSkillRow,
|
||||||
ActivityName,
|
ActivityName,
|
||||||
PlayerActivityRow,
|
PlayerActivityRow,
|
||||||
|
Bosses,
|
||||||
} from './types';
|
} from './types';
|
||||||
import {
|
import {
|
||||||
getStatsURL,
|
getStatsURL,
|
||||||
SKILLS,
|
SKILLS,
|
||||||
BH_MODES,
|
BH_MODES,
|
||||||
CLUES,
|
CLUES,
|
||||||
MODES,
|
|
||||||
getPlayerTableURL,
|
getPlayerTableURL,
|
||||||
getSkillPageURL,
|
getSkillPageURL,
|
||||||
GAMEMODES,
|
GAMEMODES,
|
||||||
@@ -28,94 +25,108 @@ import {
|
|||||||
numberFromElement,
|
numberFromElement,
|
||||||
rsnFromElement,
|
rsnFromElement,
|
||||||
getActivityPageURL,
|
getActivityPageURL,
|
||||||
|
httpGet,
|
||||||
|
BOSSES,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
import { JSDOM } from 'jsdom';
|
||||||
|
|
||||||
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 httpGet(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([
|
httpGet(getStatsURL('ironman', rsn)).catch(err => err),
|
||||||
axios(getStatsURL('iron', rsn)).catch(err => err),
|
httpGet(getStatsURL('hardcore', rsn)).catch(err => err),
|
||||||
axios(getStatsURL('hc', rsn)).catch(err => err),
|
httpGet(getStatsURL('ultimate', rsn)).catch(err => err),
|
||||||
axios(getStatsURL('ult', rsn)).catch(err => err),
|
getRSNFormat(rsn).catch(() => undefined),
|
||||||
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,
|
name: formattedName || rsn,
|
||||||
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.ironman = parseStats(ironRes.data);
|
||||||
|
if (hcRes.status === 200) {
|
||||||
|
player.mode = 'hardcore';
|
||||||
|
player.hardcore = parseStats(hcRes.data);
|
||||||
|
if (
|
||||||
|
player.ironman.skills.overall.xp !== player.hardcore.skills.overall.xp
|
||||||
|
) {
|
||||||
|
player.dead = true;
|
||||||
|
player.mode = 'ironman';
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
player.main.skills.overall.xp !== player.ironman.skills.overall.xp
|
||||||
|
) {
|
||||||
|
player.deironed = true;
|
||||||
|
player.mode = 'main';
|
||||||
|
}
|
||||||
|
} else if (ultRes.status === 200) {
|
||||||
|
player.mode = 'ultimate';
|
||||||
|
player.ultimate = parseStats(ultRes.data);
|
||||||
|
if (
|
||||||
|
player.ironman.skills.overall.xp !== player.ultimate.skills.overall.xp
|
||||||
|
) {
|
||||||
|
player.deulted = true;
|
||||||
|
player.mode = 'ironman';
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
player.main.skills.overall.xp !== player.ironman.skills.overall.xp
|
||||||
|
) {
|
||||||
|
player.deironed = true;
|
||||||
|
player.mode = 'main';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
player.mode = 'ironman';
|
||||||
|
if (
|
||||||
|
player.main.skills.overall.xp !== player.ironman.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 httpGet(getStatsURL(mode, rsn));
|
||||||
|
if (response.status !== 200) {
|
||||||
|
throw Error('Player not found');
|
||||||
|
}
|
||||||
|
const stats = parseStats(response.data);
|
||||||
|
|
||||||
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getSkillPage(
|
export async function getSkillPage(
|
||||||
@@ -132,22 +143,27 @@ export async function getSkillPage(
|
|||||||
}
|
}
|
||||||
const url = getSkillPageURL(mode, skill, page);
|
const url = getSkillPageURL(mode, skill, page);
|
||||||
|
|
||||||
const response = await axios(url);
|
const response = await httpGet(url);
|
||||||
const $ = cheerio.load(response.data);
|
const dom = new JSDOM(response.data);
|
||||||
const playersHTML = $('.personal-hiscores__row').toArray();
|
const playersHTML = dom.window.document.querySelectorAll(
|
||||||
|
'.personal-hiscores__row'
|
||||||
|
);
|
||||||
|
|
||||||
const players: PlayerSkillRow[] = playersHTML.map(row => {
|
const players: PlayerSkillRow[] = [];
|
||||||
const cells = row.children.filter(el => el.name === 'td');
|
playersHTML.forEach(row => {
|
||||||
const [rankEl, nameCell, levelEl, xpEl] = cells;
|
const rankEl = row.querySelector('td');
|
||||||
const [nameEl] = nameCell.children.filter(el => el.name === 'a');
|
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 {
|
players.push({
|
||||||
rsn: rsnFromElement(nameEl),
|
name: rsnFromElement(nameEl),
|
||||||
rank: numberFromElement(rankEl),
|
rank: numberFromElement(rankEl),
|
||||||
level: numberFromElement(levelEl),
|
level: numberFromElement(levelEl),
|
||||||
xp: numberFromElement(xpEl),
|
xp: numberFromElement(xpEl),
|
||||||
dead: nameCell.children.length === 4,
|
dead: isDead,
|
||||||
};
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return players;
|
return players;
|
||||||
@@ -167,21 +183,25 @@ export async function getActivityPage(
|
|||||||
}
|
}
|
||||||
const url = getActivityPageURL(mode, activity, page);
|
const url = getActivityPageURL(mode, activity, page);
|
||||||
|
|
||||||
const response = await axios(url);
|
const response = await httpGet(url);
|
||||||
const $ = cheerio.load(response.data);
|
const dom = new JSDOM(response.data);
|
||||||
const playersHTML = $('.personal-hiscores__row').toArray();
|
const playersHTML = dom.window.document.querySelectorAll(
|
||||||
|
'.personal-hiscores__row'
|
||||||
|
);
|
||||||
|
|
||||||
const players: PlayerActivityRow[] = playersHTML.map(row => {
|
const players: PlayerActivityRow[] = [];
|
||||||
const cells = row.children.filter(el => el.name === 'td');
|
playersHTML.forEach(row => {
|
||||||
const [rankEl, nameCell, scoreEl] = cells;
|
const rankEl = row.querySelector('td');
|
||||||
const [nameEl] = nameCell.children.filter(el => el.name === 'a');
|
const nameEl = row.querySelector('td a');
|
||||||
|
const scoreEl = row.querySelector('td.left + td');
|
||||||
|
const isDead = !!row.querySelector('td img');
|
||||||
|
|
||||||
return {
|
players.push({
|
||||||
rsn: rsnFromElement(nameEl),
|
name: rsnFromElement(nameEl),
|
||||||
rank: numberFromElement(rankEl),
|
rank: numberFromElement(rankEl),
|
||||||
score: numberFromElement(scoreEl),
|
score: numberFromElement(scoreEl),
|
||||||
dead: nameCell.children.length === 4,
|
dead: isDead,
|
||||||
};
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return players;
|
return players;
|
||||||
@@ -198,11 +218,14 @@ export async function getRSNFormat(rsn: string): Promise<string> {
|
|||||||
|
|
||||||
const url = getPlayerTableURL('main', rsn);
|
const url = getPlayerTableURL('main', rsn);
|
||||||
try {
|
try {
|
||||||
const response = await axios(url);
|
const response = await httpGet(url);
|
||||||
const $ = cheerio.load(response.data);
|
const dom = new JSDOM(response.data);
|
||||||
const rawName = $('[style="color:#AA0022;"]')[1].children[0].data;
|
const spans = dom.window.document.querySelectorAll(
|
||||||
if (rawName) {
|
'span[style="color:#AA0022;"]'
|
||||||
return rawName.replace(/\uFFFD/g, ' ');
|
);
|
||||||
|
if (spans.length >= 2) {
|
||||||
|
const nameSpan = spans[1];
|
||||||
|
return rsnFromElement(nameSpan);
|
||||||
}
|
}
|
||||||
throw Error('Player not found');
|
throw Error('Player not found');
|
||||||
} catch {
|
} catch {
|
||||||
@@ -219,10 +242,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,49 +254,52 @@ 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;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [leaguePoints] = activityObjects.splice(0, 1);
|
||||||
const bhObjects = activityObjects.splice(0, BH_MODES.length);
|
const bhObjects = activityObjects.splice(0, BH_MODES.length);
|
||||||
const [lms] = activityObjects.splice(0, 1);
|
|
||||||
const clueObjects = activityObjects.splice(0, CLUES.length);
|
const clueObjects = activityObjects.splice(0, CLUES.length);
|
||||||
|
const [lastManStanding, soulWarsZeal] = activityObjects.splice(0, 2);
|
||||||
|
const bossObjects = activityObjects.splice(0, BOSSES.length);
|
||||||
|
|
||||||
const skills: Skills = skillObjects.reduce<Skills>(
|
const skills: Skills = skillObjects.reduce<Skills>((prev, curr, index) => {
|
||||||
(prev, curr, index) => {
|
const newSkills = { ...prev };
|
||||||
const newSkills = { ...prev };
|
newSkills[SKILLS[index]] = curr;
|
||||||
newSkills[SKILLS[index]] = curr;
|
return newSkills;
|
||||||
return newSkills;
|
}, {} as Skills);
|
||||||
},
|
|
||||||
{} as Skills
|
|
||||||
);
|
|
||||||
|
|
||||||
const bh: BHStats = bhObjects.reduce<BHStats>(
|
const bountyHunter: 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 BH);
|
||||||
},
|
|
||||||
{} as BHStats
|
|
||||||
);
|
|
||||||
|
|
||||||
const clues: Clues = clueObjects.reduce<Clues>(
|
const clues: Clues = clueObjects.reduce<Clues>((prev, curr, index) => {
|
||||||
(prev, curr, index) => {
|
const newClues = { ...prev };
|
||||||
const newClues = { ...prev };
|
newClues[CLUES[index]] = curr;
|
||||||
newClues[CLUES[index]] = curr;
|
return newClues;
|
||||||
return newClues;
|
}, {} as Clues);
|
||||||
},
|
|
||||||
{} 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 = {
|
const stats: Stats = {
|
||||||
skills,
|
skills,
|
||||||
bh,
|
leaguePoints,
|
||||||
lms,
|
bountyHunter,
|
||||||
|
lastManStanding,
|
||||||
|
soulWarsZeal,
|
||||||
clues,
|
clues,
|
||||||
|
bosses,
|
||||||
};
|
};
|
||||||
|
|
||||||
return stats;
|
return stats;
|
||||||
|
@@ -2,5 +2,6 @@ import * as hiscores from './hiscores';
|
|||||||
|
|
||||||
export * from './hiscores';
|
export * from './hiscores';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
export * from './utils';
|
||||||
|
|
||||||
export default hiscores;
|
export default hiscores;
|
||||||
|
96
src/types.ts
96
src/types.ts
@@ -1,6 +1,11 @@
|
|||||||
export type Gamemode = 'main' | 'iron' | 'hc' | 'ult' | 'dmm' | 'sdmm' | 'dmmt';
|
export type Gamemode =
|
||||||
|
| 'main'
|
||||||
export type Mode = Gamemode | 'full';
|
| 'ironman'
|
||||||
|
| 'ultimate'
|
||||||
|
| 'hardcore'
|
||||||
|
| 'deadman'
|
||||||
|
| 'seasonal'
|
||||||
|
| 'tournament';
|
||||||
|
|
||||||
export interface Skill {
|
export interface Skill {
|
||||||
rank: number;
|
rank: number;
|
||||||
@@ -56,29 +61,82 @@ export type BHType = 'rogue' | 'hunter';
|
|||||||
|
|
||||||
export type BH = { [Type in BHType]: Activity };
|
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 =
|
export type ActivityName =
|
||||||
| 'hunterbh'
|
| 'leaguePoints'
|
||||||
| 'roguebh'
|
| 'hunterBH'
|
||||||
| 'lms'
|
| 'rogueBH'
|
||||||
| 'allclues'
|
| 'lastManStanding'
|
||||||
| 'beginnerclues'
|
| 'soulWarsZeal'
|
||||||
| 'easyclues'
|
| 'allClues'
|
||||||
| 'mediumclues'
|
| 'beginnerClues'
|
||||||
| 'hardclues'
|
| 'easyClues'
|
||||||
| 'eliteclues'
|
| 'mediumClues'
|
||||||
| 'masterclues';
|
| 'hardClues'
|
||||||
|
| 'eliteClues'
|
||||||
|
| 'masterClues'
|
||||||
|
| Boss;
|
||||||
|
|
||||||
export interface Stats {
|
export interface Stats {
|
||||||
skills: Skills;
|
skills: Skills;
|
||||||
clues: Clues;
|
clues: Clues;
|
||||||
bh: BH;
|
leaguePoints: Activity;
|
||||||
lms: Activity;
|
bountyHunter: BH;
|
||||||
|
lastManStanding: Activity;
|
||||||
|
soulWarsZeal: Activity;
|
||||||
|
bosses: Bosses;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Modes = { [M in Gamemode]?: Stats };
|
export type Modes = { [M in Gamemode]?: Stats };
|
||||||
|
|
||||||
export interface Player extends Modes {
|
export interface Player extends Modes {
|
||||||
rsn: string;
|
name: string;
|
||||||
mode: Gamemode;
|
mode: Gamemode;
|
||||||
dead: boolean;
|
dead: boolean;
|
||||||
deulted: boolean;
|
deulted: boolean;
|
||||||
@@ -86,11 +144,11 @@ export interface Player extends Modes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface PlayerSkillRow extends Skill {
|
export interface PlayerSkillRow extends Skill {
|
||||||
rsn: string;
|
name: string;
|
||||||
dead: boolean;
|
dead: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PlayerActivityRow extends Activity {
|
export interface PlayerActivityRow extends Activity {
|
||||||
rsn: string;
|
name: string;
|
||||||
dead: boolean;
|
dead: boolean;
|
||||||
}
|
}
|
||||||
|
@@ -1,16 +1,28 @@
|
|||||||
import { SkillName, ClueType, BHType, Gamemode, Mode } 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 STATS_URL = 'index_lite.ws?player=';
|
||||||
export const SCORES_URL = 'overall.ws?';
|
export const SCORES_URL = 'overall.ws?';
|
||||||
export const GAMEMODE_URL = {
|
|
||||||
dmm: '_deadman/',
|
export type GamemodeUrl = {
|
||||||
dmmt: '_tournament/',
|
[key in Gamemode]: string;
|
||||||
hc: '_hardcore_ironman/',
|
};
|
||||||
iron: '_ironman/',
|
|
||||||
main: '/',
|
export const GAMEMODE_URL: GamemodeUrl = {
|
||||||
sdmm: '_seasonal/',
|
main: `${BASE_URL}/`,
|
||||||
ult: '_ultimate/',
|
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[] = [
|
export const SKILLS: SkillName[] = [
|
||||||
'overall',
|
'overall',
|
||||||
@@ -47,26 +59,183 @@ export const CLUES: ClueType[] = [
|
|||||||
'elite',
|
'elite',
|
||||||
'master',
|
'master',
|
||||||
];
|
];
|
||||||
export const BH_MODES: BHType[] = ['rogue', 'hunter'];
|
export const BH_MODES: BHType[] = ['hunter', 'rogue'];
|
||||||
export const ACTIVITIES = [
|
|
||||||
'hunterbh',
|
|
||||||
'roguebh',
|
|
||||||
'lms',
|
|
||||||
'allclues',
|
|
||||||
'beginnerclues',
|
|
||||||
'easyclues',
|
|
||||||
'mediumclues',
|
|
||||||
'hardclues',
|
|
||||||
'eliteclues',
|
|
||||||
'masterclues',
|
|
||||||
];
|
|
||||||
export const GAMEMODES: Gamemode[] = [
|
export const GAMEMODES: Gamemode[] = [
|
||||||
'main',
|
'main',
|
||||||
'iron',
|
'ironman',
|
||||||
'hc',
|
'hardcore',
|
||||||
'ult',
|
'ultimate',
|
||||||
'dmm',
|
'deadman',
|
||||||
'sdmm',
|
'seasonal',
|
||||||
'dmmt',
|
'tournament',
|
||||||
];
|
];
|
||||||
export const MODES: Mode[] = [...GAMEMODES, 'full'];
|
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',
|
||||||
|
'soulWarsZeal',
|
||||||
|
...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_SOUL_WARS = 'Soul Wars Zeal';
|
||||||
|
export const FORMATTED_LEAGUE_POINTS = 'League Points';
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import * as ua from 'useragent-generator';
|
||||||
import { Gamemode, SkillName, ActivityName } from '../types';
|
import { Gamemode, SkillName, ActivityName } from '../types';
|
||||||
import {
|
import {
|
||||||
BASE_URL,
|
|
||||||
GAMEMODE_URL,
|
GAMEMODE_URL,
|
||||||
STATS_URL,
|
STATS_URL,
|
||||||
SCORES_URL,
|
SCORES_URL,
|
||||||
@@ -9,19 +10,19 @@ import {
|
|||||||
} from './constants';
|
} from './constants';
|
||||||
|
|
||||||
export const getStatsURL = (gamemode: Gamemode, rsn: string) =>
|
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) =>
|
export const getPlayerTableURL = (gamemode: Gamemode, rsn: string) =>
|
||||||
`${BASE_URL}${
|
`${GAMEMODE_URL[gamemode]}${SCORES_URL}table=0&user=${encodeURIComponent(
|
||||||
GAMEMODE_URL[gamemode]
|
rsn
|
||||||
}${SCORES_URL}table=0&user=${encodeURIComponent(rsn)}`;
|
)}`;
|
||||||
|
|
||||||
export const getSkillPageURL = (
|
export const getSkillPageURL = (
|
||||||
gamemode: Gamemode,
|
gamemode: Gamemode,
|
||||||
skill: SkillName,
|
skill: SkillName,
|
||||||
page: number
|
page: number
|
||||||
) =>
|
) =>
|
||||||
`${BASE_URL}${GAMEMODE_URL[gamemode]}${SCORES_URL}table=${SKILLS.indexOf(
|
`${GAMEMODE_URL[gamemode]}${SCORES_URL}table=${SKILLS.indexOf(
|
||||||
skill
|
skill
|
||||||
)}&page=${page}`;
|
)}&page=${page}`;
|
||||||
|
|
||||||
@@ -30,19 +31,28 @@ export const getActivityPageURL = (
|
|||||||
activity: ActivityName,
|
activity: ActivityName,
|
||||||
page: number
|
page: number
|
||||||
) =>
|
) =>
|
||||||
`${BASE_URL}${
|
`${
|
||||||
GAMEMODE_URL[gamemode]
|
GAMEMODE_URL[gamemode]
|
||||||
}${SCORES_URL}category_type=1&table=${ACTIVITIES.indexOf(
|
}${SCORES_URL}category_type=1&table=${ACTIVITIES.indexOf(
|
||||||
activity
|
activity
|
||||||
)}&page=${page}`;
|
)}&page=${page}`;
|
||||||
|
|
||||||
export const numberFromElement = (el: CheerioElement) => {
|
export const numberFromElement = (el: Element | null) => {
|
||||||
const innerText = el.firstChild.data;
|
const { innerHTML } = el || {};
|
||||||
const number = innerText ? innerText.replace(/[\n|,]/g, '') : '-1';
|
const number = innerHTML?.replace(/[\n|,]/g, '') ?? '-1';
|
||||||
return parseInt(number, 10);
|
return parseInt(number, 10);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const rsnFromElement = (el: CheerioElement) => {
|
export const rsnFromElement = (el: Element | null) => {
|
||||||
const innerText = el.firstChild.data;
|
const { innerHTML } = el || {};
|
||||||
return innerText ? innerText.replace(/\uFFFD/g, ' ') : '';
|
return innerHTML?.replace(/\uFFFD/g, ' ') || '';
|
||||||
|
};
|
||||||
|
|
||||||
|
export const httpGet = (url: string) => {
|
||||||
|
return axios.get(url, {
|
||||||
|
headers: {
|
||||||
|
// without User-Agent header requests may be rejected by DDoS protection mechanism
|
||||||
|
'User-Agent': ua.firefox(80)
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user