diff --git a/src/hiscores.js b/src/hiscores.js deleted file mode 100644 index 4ea120d..0000000 --- a/src/hiscores.js +++ /dev/null @@ -1,353 +0,0 @@ -const axios = require('axios'); -const cheerio = require('cheerio'); - -const URLs = { - main: 'http://services.runescape.com/m=hiscore_oldschool/', - iron: 'http://services.runescape.com/m=hiscore_oldschool_ironman/', - ult: 'http://services.runescape.com/m=hiscore_oldschool_ultimate/', - hc: 'http://services.runescape.com/m=hiscore_oldschool_hardcore_ironman/', - dmm: 'http://services.runescape.com/m=hiscore_oldschool_deadman/', - sdmm: 'http://services.runescape.com/m=hiscore_oldschool_seasonal/', - dmmt: 'http://services.runescape.com/m=hiscore_oldschool_tournament/', - stats: 'index_lite.ws?player=', - scores: 'overall.ws?', - }, - hiscores = { - skills: [ - 'overall', - 'attack', - 'defence', - 'strength', - 'hitpoints', - 'ranged', - 'prayer', - 'magic', - 'cooking', - 'woodcutting', - 'fletching', - 'fishing', - 'firemaking', - 'crafting', - 'smithing', - 'mining', - 'herblore', - 'agility', - 'thieving', - 'slayer', - 'farming', - 'runecraft', - 'hunter', - 'construction', - ], - clues: ['all', 'beginner', 'easy', 'medium', 'hard', 'elite', 'master'], - bh: ['rouge', 'hunter'], - other: [ - 'hunterbh', - 'roguebh', - 'lms', - 'allclues', - 'beginnerclues', - 'easyclues', - 'mediumclues', - 'hardclues', - 'eliteclues', - 'masterclues', - ], - }, - validModes = ['full', 'main', 'iron', 'hc', 'ult', 'dmm', 'sdmm', 'dmmt']; - -/** - * Gets a player's stats. - * - * Gets CSV from OSRS API and converts to JS object. - * - * @access public - * - * @param {string} rsn The player's username. - * @param {string} [mode] The game mode. - * - * @returns {Object} A player object. - */ -async function getStats(rsn, mode = 'full') { - 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 (!validModes.includes(mode.toLowerCase())) { - throw Error('Invalid game mode'); - } else { - return await getPlayerStats(rsn, mode.toLowerCase()); - } -} - -/** - * Gets a player's stats. - * - * Gets CSV from OSRS API and converts to JS object. - * - * @access private - * - * @param {string} rsn The player's username. - * @param {string} mode The game mode. - * - * @returns {Object} A player object. - */ -async function getPlayerStats(rsn, mode) { - let player = { - rsn: rsn, - mode: mode, - dead: false, - deironed: false, - }; - - if (mode === 'full') { - const responses = []; - - responses[0] = await axios( - URLs.main + URLs.stats + encodeURIComponent(rsn) - ); - - if (responses[0].status === 200) { - const otherResponses = await Promise.all([ - axios(URLs.iron + URLs.stats + encodeURIComponent(rsn)).catch( - res => res - ), - axios(URLs.hc + URLs.stats + encodeURIComponent(rsn)).catch(res => res), - axios(URLs.ult + URLs.stats + encodeURIComponent(rsn)).catch( - res => res - ), - getRSNFormat(rsn), - ]); - - player.rsn = otherResponses.pop(); - - for (let res of otherResponses) { - responses.push(res); - } - - if (responses[1].status === 200) { - if (responses[2].status === 200) { - player.mode = 'hc'; - } else if (responses[3].status === 200) { - player.mode = 'ult'; - } else { - player.mode = 'iron'; - } - } else { - player.mode = 'main'; - } - } else { - throw Error('Player not found'); - } - - switch (player.mode) { - case 'main': - player.main = parseStats(responses[0].data); - break; - case 'iron': - player.main = parseStats(responses[0].data); - player.iron = parseStats(responses[1].data); - if (player.main.stats.overall.xp !== player.iron.stats.overall.xp) { - player.deironed = true; - player.mode = 'main'; - } - break; - case 'hc': - player.main = parseStats(responses[0].data); - player.iron = parseStats(responses[1].data); - player.hc = parseStats(responses[2].data); - if (player.iron.stats.overall.xp !== player.hc.stats.overall.xp) { - player.dead = true; - player.mode = 'iron'; - } - if (player.main.stats.overall.xp !== player.iron.stats.overall.xp) { - player.deironed = true; - player.mode = 'main'; - } - break; - case 'ult': - player.main = parseStats(responses[0].data); - player.iron = parseStats(responses[1].data); - player.ult = parseStats(responses[3].data); - if (player.main.stats.overall.xp !== player.iron.stats.overall.xp) { - player.deironed = true; - player.mode = 'main'; - } - break; - } - - return player; - } else { - const response = await axios( - URLs[mode] + URLs.stats + encodeURIComponent(rsn) - ); - if (response.status !== 200) { - throw Error('Player not found'); - } - player[mode] = parseStats(response.data); - return player; - } -} - -/** - * Gets a hiscore page. - * - * Scrapes OSRS hiscores and converts to objects. - * - * @access public - * - * @param {string} mode The game mode. - * @param {string} [category] The category of hiscores. - * @param {number} [page] The page of players. - * - * @returns {Object[]} Array of player objects. - */ -async function getHiscores(mode, category = 'overall', page = 1) { - if ( - !validModes.includes(mode.toLowerCase()) || - mode.toLowerCase() === 'full' - ) { - throw Error('Invalid game mode'); - } else if (!Number.isInteger(page) || page < 1) { - throw Error('Page must be an integer greater than 0'); - } else if ( - !hiscores.skills.includes(category.toLowerCase()) && - !hiscores.other.includes(category.toLowerCase()) - ) { - throw Error('Invalid category'); - } else { - return await getHiscoresPage( - mode.toLowerCase(), - category.toLowerCase(), - page - ); - } -} - -/** - * Gets a hiscore page. - * - * Scrapes OSRS hiscores and converts to objects. - * - * @access private - * - * @param {string} mode The game mode. - * @param {string} category The category of hiscores. - * @param {number} page The page of players. - * - * @returns {Object[]} Array of player objects. - */ -async function getHiscoresPage(mode, category, page) { - const url = - URLs[mode] + - URLs.scores + - (hiscores.skills.includes(category) - ? 'table=' + hiscores.skills.indexOf(category) - : 'category_type=1' + '&table=' + hiscores.other.indexOf(category)) + - '&page=' + - page; - - const players = []; - const response = await axios(url); - const $ = cheerio.load(response.data); - const playersHTML = $('.personal-hiscores__row').toArray(); - - for (let player of playersHTML) { - const attributes = player.children.filter(node => node.name === 'td'); - console.log(); - let playerInfo = { - mode: mode, - category: category, - rank: attributes[0].children[0].data.slice(1, -1), - rsn: attributes[1].children[1].children[0].data.replace(/\uFFFD/g, ' '), - }; - - hiscores.skills.includes(category.toLowerCase()) - ? (playerInfo = Object.assign( - { - level: attributes[2].children[0].data.slice(1, -1), - xp: attributes[3].children[0].data.slice(1, -1), - }, - playerInfo - )) - : (playerInfo.score = attributes[2].children[0].data.slice(1, -1)); - - if (mode === 'hc') { - playerInfo.dead = attributes[1].children.length > 1; - } - - players.push(playerInfo); - } - - return players; -} - -/** - * Returns proper capitalization and punctuation in a username. - * - * Searches hiscores table with rsn and returns the text from the username cell. - * - * @access public - * - * @param {string} rsn The player's username. - * - * @returns {string} The player's formatted username. - */ -async function getRSNFormat(rsn) { - const url = - URLs.main + URLs.scores + 'table=0&user=' + encodeURIComponent(rsn); - - try { - const response = await axios(url); - const $ = cheerio.load(response.data); - return $('[style="color:#AA0022;"]')[1].children[0].data.replace( - /\uFFFD/g, - ' ' - ); - } catch { - throw Error('Player not found'); - } -} - -let parseStats = csv => { - const stats = { - stats: {}, - clues: {}, - bh: {}, - lms: {}, - }; - const splitCSV = csv.split('\n'); - - const statObjects = splitCSV - .filter(stat => !!stat) - .map(stat => { - const splitStat = stat.split(','); - const obj = {}; - if (splitStat.length === 3) { - [obj.rank, obj.level, obj.xp] = splitStat; - } else { - [obj.rank, obj.score] = splitStat; - } - return obj; - }); - - statObjects.forEach((obj, index) => { - if (index < hiscores.skills.length) { - stats.stats[hiscores.skills[index]] = obj; - } else if (index < hiscores.skills.length + hiscores.bh.length) { - stats.bh[hiscores.bh[index - hiscores.skills.length]] = obj; - } else if (index < hiscores.skills.length + hiscores.bh.length + 1) { - stats.lms = obj; - } else { - stats.clues[ - hiscores.clues[index - hiscores.skills.length - hiscores.bh.length - 1] - ] = obj; - } - }); - - return stats; -}; - -module.exports = { getStats, getHiscores, getRSNFormat };