Compare commits

..

19 Commits

Author SHA1 Message Date
maxswa
0f68c1995c v2.3.0 2021-01-10 16:20:54 -05:00
Max Swartwout
7a3f3a0800 Merge pull request #17 from maxswa/dependabot/npm_and_yarn/ini-1.3.7
Bump ini from 1.3.5 to 1.3.7
2021-01-10 16:00:05 -05:00
Max Swartwout
b16e8ace6e Merge pull request #18 from maxswa/dependabot/npm_and_yarn/axios-0.21.1
Bump axios from 0.19.2 to 0.21.1
2021-01-10 15:59:55 -05:00
Max Swartwout
09f7805fd4 Merge pull request #20 from molo-pl/master
Fixes #19 adding support for Soul Wars Zeal
2021-01-10 15:59:43 -05:00
molo-pl
939f4d2721 Fixes #19 adding support for Soul Wars Zeal 2021-01-06 17:21:46 +01:00
dependabot[bot]
a4577ffb2c Bump axios from 0.19.2 to 0.21.1
Bumps [axios](https://github.com/axios/axios) from 0.19.2 to 0.21.1.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v0.21.1/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v0.19.2...v0.21.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-01-05 09:06:49 +00:00
dependabot[bot]
19ba7e2916 Bump ini from 1.3.5 to 1.3.7
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.7.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.7)

Signed-off-by: dependabot[bot] <support@github.com>
2020-12-11 09:18:50 +00:00
maxswa
7de2d9a95a v2.2.0 2020-07-23 18:22:38 -04:00
Max Swartwout
a143306519 Merge pull request #15 from maxswa/release/2.2.0
Release/2.2.0
2020-07-23 18:20:49 -04:00
maxswa
86b81abfd8 Upgrade dependencies. 2020-07-23 18:18:58 -04:00
maxswa
8d065742d0 Replace cheerio with jsdom. 2020-07-23 18:13:51 -04:00
Max
eaa3d4a299 v2.1.0 2020-04-01 00:30:08 -04:00
Max Swartwout
a92fa7fffe Merge pull request #10 from maxswa/release/1.2.2
Release/1.2.2
2020-04-01 00:27:54 -04:00
Max
90f2939761 Upgrade dependencies, fix tests. 2020-04-01 00:23:56 -04:00
Max
12046246ef Add nightmare to boss list. 2020-04-01 00:23:37 -04:00
Max Swartwout
adf73e59c4 Merge pull request #9 from maxswa/dependabot/npm_and_yarn/acorn-5.7.4
Bump acorn from 5.7.3 to 5.7.4
2020-03-31 23:53:56 -04:00
dependabot[bot]
f2fcbad1c4 Bump acorn from 5.7.3 to 5.7.4
Bumps [acorn](https://github.com/acornjs/acorn) from 5.7.3 to 5.7.4.
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/5.7.3...5.7.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-04-01 03:53:20 +00:00
Max Swartwout
0f47310814 Merge pull request #8 from maxswa/bug/rsn-format-error
Add catch for getRSNFormat error.
2020-03-31 23:52:30 -04:00
maxswa
30530fde01 Add catch for getRSNFormat error. 2020-01-29 12:24:59 -05:00
9 changed files with 762 additions and 692 deletions

View File

@@ -108,6 +108,7 @@ Activities consist of all levels of clue scrolls as well as minigames and bosses
| Bounty Hunter (Rogue) | `rogueBH` | | Bounty Hunter (Rogue) | `rogueBH` |
| Bounty Hunter (Hunter) | `hunterBH` | | Bounty Hunter (Hunter) | `hunterBH` |
| Last Man Standing | `lastManStanding` | | Last Man Standing | `lastManStanding` |
| Soul Wars Zeal | `soulWarsZeal` |
### Leagues ### Leagues
@@ -146,6 +147,7 @@ Activities consist of all levels of clue scrolls as well as minigames and bosses
| Kreearra | `kreeArra` | | Kreearra | `kreeArra` |
| K'ril Tsutsaroth | `krilTsutsaroth` | | K'ril Tsutsaroth | `krilTsutsaroth` |
| Mimic | `mimic` | | Mimic | `mimic` |
| The Nightmare of Ashihama | `nightmare` |
| Obor | `obor` | | Obor | `obor` |
| Sarachnis | `sarachnis` | | Sarachnis | `sarachnis` |
| Scorpia | `scorpia` | | Scorpia | `scorpia` |
@@ -185,6 +187,7 @@ Activities consist of all levels of clue scrolls as well as minigames and bosses
leaguePoints: {}, leaguePoints: {},
bountyHunter: {}, bountyHunter: {},
lastManStanding: {}, lastManStanding: {},
soulWarsZeal: {},
bosses: {} bosses: {}
} }
} }

View File

@@ -43,6 +43,7 @@ test('Parse CSV to json', () => {
392,250 392,250
1,6143 1,6143
4814,898 4814,898
37,225
382,2780 382,2780
944,3000 944,3000
1981,1452 1981,1452
@@ -70,6 +71,7 @@ test('Parse CSV to json', () => {
625,2391 625,2391
120,2981 120,2981
1,109 1,109
3,22666
26,323 26,323
201,1101 201,1101
82,3404 82,3404
@@ -120,6 +122,7 @@ test('Parse CSV to json', () => {
hunter: { rank: -1, score: -1 }, hunter: { rank: -1, score: -1 },
}, },
lastManStanding: { rank: 4814, score: 898 }, lastManStanding: { rank: 4814, score: 898 },
soulWarsZeal: { rank: 37, score: 225 },
clues: { clues: {
all: { rank: 32, score: 12148 }, all: { rank: 32, score: 12148 },
beginner: { rank: 3105, score: 76 }, beginner: { rank: 3105, score: 76 },
@@ -157,6 +160,7 @@ test('Parse CSV to json', () => {
kreeArra: { rank: 625, score: 2391 }, kreeArra: { rank: 625, score: 2391 },
krilTsutsaroth: { rank: 120, score: 2981 }, krilTsutsaroth: { rank: 120, score: 2981 },
mimic: { rank: 1, score: 109 }, mimic: { rank: 1, score: 109 },
nightmare: { rank: 3, score: 22666 },
obor: { rank: 26, score: 323 }, obor: { rank: 26, score: 323 },
sarachnis: { rank: 201, score: 1101 }, sarachnis: { rank: 201, score: 1101 },
scorpia: { rank: 82, score: 3404 }, scorpia: { rank: 82, score: 3404 },

View File

@@ -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"
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "osrs-json-hiscores", "name": "osrs-json-hiscores",
"version": "2.0.2", "version": "2.3.0",
"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",
@@ -36,12 +36,12 @@
}, },
"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"
}, },
"devDependencies": { "devDependencies": {
"@types/cheerio": "^0.22.11",
"@types/jest": "^24.0.14", "@types/jest": "^24.0.14",
"@types/jsdom": "^16.2.3",
"jest": "^24.8.0", "jest": "^24.8.0",
"np": "^5.0.3", "np": "^5.0.3",
"prettier": "^1.19.1", "prettier": "^1.19.1",

View File

@@ -1,5 +1,4 @@
import axios from 'axios'; import axios from 'axios';
import * as cheerio from 'cheerio';
import { import {
Player, Player,
Activity, Activity,
@@ -14,7 +13,6 @@ import {
ActivityName, ActivityName,
PlayerActivityRow, PlayerActivityRow,
Bosses, Bosses,
Boss,
} from './types'; } from './types';
import { import {
getStatsURL, getStatsURL,
@@ -30,6 +28,7 @@ import {
getActivityPageURL, getActivityPageURL,
BOSSES, BOSSES,
} from './utils'; } from './utils';
import { JSDOM } from 'jsdom';
export async function getStats(rsn: string): Promise<Player> { export async function getStats(rsn: string): Promise<Player> {
if (typeof rsn !== 'string') { if (typeof rsn !== 'string') {
@@ -46,13 +45,13 @@ export async function getStats(rsn: string): Promise<Player> {
axios(getStatsURL('ironman', rsn)).catch(err => err), axios(getStatsURL('ironman', rsn)).catch(err => err),
axios(getStatsURL('hardcore', rsn)).catch(err => err), axios(getStatsURL('hardcore', rsn)).catch(err => err),
axios(getStatsURL('ultimate', rsn)).catch(err => err), axios(getStatsURL('ultimate', rsn)).catch(err => err),
getRSNFormat(rsn), getRSNFormat(rsn).catch(() => undefined),
]); ]);
const [ironRes, hcRes, ultRes, formattedName] = otherResponses; const [ironRes, hcRes, ultRes, formattedName] = otherResponses;
const player: Player = { const player: Player = {
name: formattedName, name: formattedName || rsn,
mode: 'main', mode: 'main',
dead: false, dead: false,
deulted: false, deulted: false,
@@ -145,22 +144,26 @@ export async function getSkillPage(
const url = getSkillPageURL(mode, skill, page); const url = getSkillPageURL(mode, skill, page);
const response = await axios(url); const response = await axios(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.find(el => el.name === 'a'); const nameEl = row.querySelector('td a');
const isDead = !!nameCell.children.find(el => el.name === 'img'); const levelEl = row.querySelector('td.left + td');
const xpEl = row.querySelector('td.left + td + td');
const isDead = !!row.querySelector('td img');
return { players.push({
name: rsnFromElement(nameEl), name: rsnFromElement(nameEl),
rank: numberFromElement(rankEl), rank: numberFromElement(rankEl),
level: numberFromElement(levelEl), level: numberFromElement(levelEl),
xp: numberFromElement(xpEl), xp: numberFromElement(xpEl),
dead: isDead, dead: isDead,
}; });
}); });
return players; return players;
@@ -181,21 +184,24 @@ export async function getActivityPage(
const url = getActivityPageURL(mode, activity, page); const url = getActivityPageURL(mode, activity, page);
const response = await axios(url); const response = await axios(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.find(el => el.name === 'a'); const nameEl = row.querySelector('td a');
const isDead = !!nameCell.children.find(el => el.name === 'img'); const scoreEl = row.querySelector('td.left + td');
const isDead = !!row.querySelector('td img');
return { players.push({
name: rsnFromElement(nameEl), name: rsnFromElement(nameEl),
rank: numberFromElement(rankEl), rank: numberFromElement(rankEl),
score: numberFromElement(scoreEl), score: numberFromElement(scoreEl),
dead: isDead, dead: isDead,
}; });
}); });
return players; return players;
@@ -213,10 +219,13 @@ 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 axios(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 {
@@ -256,7 +265,7 @@ export function parseStats(csv: string): Stats {
const [leaguePoints] = activityObjects.splice(0, 1); const [leaguePoints] = activityObjects.splice(0, 1);
const bhObjects = activityObjects.splice(0, BH_MODES.length); const bhObjects = activityObjects.splice(0, BH_MODES.length);
const clueObjects = activityObjects.splice(0, CLUES.length); const clueObjects = activityObjects.splice(0, CLUES.length);
const [lastManStanding] = activityObjects.splice(0, 1); const [lastManStanding, soulWarsZeal] = activityObjects.splice(0, 2);
const bossObjects = activityObjects.splice(0, BOSSES.length); const bossObjects = activityObjects.splice(0, BOSSES.length);
const skills: Skills = skillObjects.reduce<Skills>((prev, curr, index) => { const skills: Skills = skillObjects.reduce<Skills>((prev, curr, index) => {
@@ -288,6 +297,7 @@ export function parseStats(csv: string): Stats {
leaguePoints, leaguePoints,
bountyHunter, bountyHunter,
lastManStanding, lastManStanding,
soulWarsZeal,
clues, clues,
bosses, bosses,
}; };

View File

@@ -89,6 +89,7 @@ export type Boss =
| 'kreeArra' | 'kreeArra'
| 'krilTsutsaroth' | 'krilTsutsaroth'
| 'mimic' | 'mimic'
| 'nightmare'
| 'obor' | 'obor'
| 'sarachnis' | 'sarachnis'
| 'scorpia' | 'scorpia'
@@ -113,6 +114,7 @@ export type ActivityName =
| 'hunterBH' | 'hunterBH'
| 'rogueBH' | 'rogueBH'
| 'lastManStanding' | 'lastManStanding'
| 'soulWarsZeal'
| 'allClues' | 'allClues'
| 'beginnerClues' | 'beginnerClues'
| 'easyClues' | 'easyClues'
@@ -128,6 +130,7 @@ export interface Stats {
leaguePoints: Activity; leaguePoints: Activity;
bountyHunter: BH; bountyHunter: BH;
lastManStanding: Activity; lastManStanding: Activity;
soulWarsZeal: Activity;
bosses: Bosses; bosses: Bosses;
} }
export type Modes = { [M in Gamemode]?: Stats }; export type Modes = { [M in Gamemode]?: Stats };

View File

@@ -7,7 +7,7 @@ import {
ActivityName, ActivityName,
} from '../types'; } 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?';
@@ -97,6 +97,7 @@ export const BOSSES: Boss[] = [
'kreeArra', 'kreeArra',
'krilTsutsaroth', 'krilTsutsaroth',
'mimic', 'mimic',
'nightmare',
'obor', 'obor',
'sarachnis', 'sarachnis',
'scorpia', 'scorpia',
@@ -126,6 +127,7 @@ export const ACTIVITIES: ActivityName[] = [
'eliteClues', 'eliteClues',
'masterClues', 'masterClues',
'lastManStanding', 'lastManStanding',
'soulWarsZeal',
...BOSSES, ...BOSSES,
]; ];
@@ -161,6 +163,7 @@ export const FORMATTED_BOSS_NAMES: FormattedBossNames = {
kreeArra: "Kree'Arra", kreeArra: "Kree'Arra",
krilTsutsaroth: "K'ril Tsutsaroth", krilTsutsaroth: "K'ril Tsutsaroth",
mimic: 'Mimic', mimic: 'Mimic',
nightmare: 'The Nightmare of Ashihama',
obor: 'Obor', obor: 'Obor',
sarachnis: 'Sarachnis', sarachnis: 'Sarachnis',
scorpia: 'Scorpia', scorpia: 'Scorpia',
@@ -234,4 +237,5 @@ export const FORMATTED_BH_NAMES: FormattedBHNames = {
}; };
export const FORMATTED_LMS = 'Last Man Standing'; export const FORMATTED_LMS = 'Last Man Standing';
export const FORMATTED_SOUL_WARS = 'Soul Wars Zeal';
export const FORMATTED_LEAGUE_POINTS = 'League Points'; export const FORMATTED_LEAGUE_POINTS = 'League Points';

View File

@@ -35,13 +35,13 @@ export const getActivityPageURL = (
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 | undefined) => { 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, ' ') || '';
}; };

1351
yarn.lock

File diff suppressed because it is too large Load Diff