BeatLeader_Leaderboard.js

const {beatleader} = require('../api_urls.json').urls
const {parseSearchOptions} = require('./utility/parseSearchOptions')

/**
 * Interact with the BeatLeader Leaderboard API endpoints
 * @namespace BeatLeader.Leaderboards
 * @memberof BeatLeader
 */

/**
 * Retrieves a list of leaderboards
 * @function get
 * @memberof BeatLeader.Leaderboards
 * @param {Object} leaderboardSearchOptions Filters to narrow search. See options in table below
 * | Parameter           | Type                    | Description                          | Valid Values                                                                                       |
 * |---------------------|-------------------------|--------------------------------------|-----------------------------------------------------------------------------------------------------|
 * | page                | number                  | (Optional) Page number               | N/A                                                                                                 |
 * | count               | number                  | (Optional) Number of items per page  | N/A                                                                                                 |
 * | sortBy              | LeaderboardSortBy       | (Optional) Sorting criteria          | `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `"date"`, `"pp"`, `"acc"`, `"pauses"`, `"rank"`, `"maxStreak"`, `"mistakes"`, `"weight"`, `"weightedPp"` |
 * | order               | Order                   | (Optional)Sorting order                        | `"asc"`, `"desc"`                                                                                       |
 * | search              | string                  | (Optional) Search query              | N/A                                                                                                 |
 * | type                | Type                    | (Optional) Type of item              | N/A                                                                                                 |
 * | mode                | string                  | (Optional) Mode of item              | N/A                                                                                                 |
 * | difficulty          | Difficulties            | (Optional) Difficulty level          |`"Standard"`, `"OneSaber"`, `"90Degree"`, `"360Degree"`                                              |
 * | mapType             | MapsType                | (Optional) Map type                  | `0`, `1`, `2`, `"ranked"`, `"unranked"`, `"all"`                                                                |
 * | allTypes            | Operation               | (Optional) Operation for all types   | `0`, `1`, `2`, `"any"`, `"all"`, `"not"`                                                                        |
 * | mapRequirements     | RequirementsString      | (Optional) Map requirements          | `"none"`, `"chroma"`, `"noodles"`, `"mappingExtensions"`, `"cinema"`, `"v3"`, `"optionalProperties"`, `"ignore"`    |
 * | allRequirements     | Operation               | (Optional) Operation for all requirements | `0`, `1`, `2`, `"any"`, `"all"`, `"not"`                                                                    |
 * | songStatus          | SongStatus              | (Optional) Status of the song        | `0`, `2`, `4`, `8`, `16`, `32`, `"none"`, `"curated"`, `"mapOfTheWeek"`, `"noodleMonday"`, `"featuredOnCC"`, `"beastSaberAwarded"` |
 * | leaderboardContext  | LeaderboardContexts     | (Optional) Context of the leaderboard | `0`, `2`, `4`, `8`, `16`, `32`, `64`, `128`, `"none"`, `"general"`, `"noMods"`, `"noPause"`, `"golf"`, `"sCPM"`, `"speedrun"`, `"speedrunBackup"` |
 * | mytype              | MyType                  | (Optional) Custom type               | `0`, `1`, `2`, `3`, `4`, `5`, `6`, `"none"`, `"played"`, `"unplayed"`, `"myNominated"`, `"othersNominated"`, `"myMaps"`      |
 * | stars_from          | number                  | (Optional) Minimum stars             | N/A                                                                                                 |
 * | stars_to            | number                  | (Optional) Maximum stars             | N/A                                                                                                 |
 * | accrating_from      | number                  | (Optional) Minimum accuracy rating   | N/A                                                                                                 |
 * | accrating_to        | number                  | (Optional) Maximum accuracy rating   | N/A                                                                                                 |
 * | passrating_from     | number                  | (Optional) Minimum pass rating       | N/A                                                                                                 |
 * | passrating_to       | number                  | (Optional) Maximum pass rating       | N/A                                                                                                 |
 * | techrating_from     | number                  | (Optional) Minimum tech rating       | N/A                                                                                                 |
 * | techrating_to       | number                  | (Optional) Maximum tech rating       | N/A                                                                                                 |
 * | date_from           | number                  | (Optional) Start date                | N/A                                                                                                 |
 * | mapper              | number                  | (Optional) Mapper ID                 | N/A                                                                                                 |
 * | overrideCurrentId   | string                  | (Optional) Override current ID       | N/A                                                                                                 |
 * @returns {Promise} A promise with a list of leaderboards
 */
async function get(leaderboardSearchOptions = {}) {
    try {
        let route = new URL(beatleader + 'leaderboards').href
        let parsedSearchOptions = parseSearchOptions(leaderboardSearchOptions)
        route += parsedSearchOptions

        let res = await fetch(encodeURI(route))
        if(res.status == 404)
            return Promise.reject(new Error("Leaderboards not found"))
        if(res.status != 200)
            return Promise.reject(new Error("Undocumented error: " + res.status))
        return res.json()
    } catch (error) {
        throw new Error(error)
    }
}

/**
 * Retrieves a list of leaderboards
 * @function getById
 * @memberof BeatLeader.Leaderboards
 * @param {string} id ID of the leaderboard to retrieve details for
 * @param {Object} leaderboardSearchOptions Filters to narrow search. See options in table below
 * | Parameter           | Type                    | Description                          | Valid Values                                                                                       |
 * |---------------------|-------------------------|--------------------------------------|-----------------------------------------------------------------------------------------------------|
 * | page                | number                  | (Optional) Page number               | N/A                                                                                                 |
 * | count               | number                  | (Optional) Number of items per page  | N/A                                                                                                 |
 * | sortBy              | LeaderboardSortBy       | (Optional) Sorting criteria          | `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `"date"`, `"pp"`, `"acc"`, `"pauses"`, `"rank"`, `"maxStreak"`, `"mistakes"`, `"weight"`, `"weightedPp"` |
 * | order               | Order                   | (Optional) Sorting order                        | `"asc"`, `"desc"`                                                                                       |
 * | scoreStatus         | ScoreFilterStatus       | (Optional) Score status filter       | `0`, `1`, `"none"`, `"suspicious"`                                                                                                 |
 * | leaderboardContext  | LeaderboardContexts     | (Optional) Context of the leaderboard | `0`, `2`, `4`, `8`, `16`, `32`, `64`, `128`, `"none"`, `"general"`, `"noMods"`, `"noPause"`, `"golf"`, `"sCPM"`, `"speedrun"`, `"speedrunBackup"` |
 * | countries           | Array<string>           | (Optional) List of country codes     | N/A                                                                                                 |
 * | search              | string                  | (Optional) Search query              | N/A                                                                                                 |
 * | modifiers           | string                  | (Optional) Modifiers                 | N/A                                                                                                 |
 * | friends             | boolean                 | (Optional) Filter by friends         | N/A                                                                                                 |
 * | voters              | boolean                 | (Optional) Filter by voters          | N/A                                                                                                 |
 * | prediction          | boolean                 | (Optional) Prediction filter         | N/A                                                                                                 |
 * @returns {Promise} A promise with leaderboard details
 */
async function getById(id, leaderboardSearchOptions = {}) {
    try {
        let route = new URL(beatleader + 'leaderboard').href
        route += `/${id}`
        let parsedSearchOptions = parseSearchOptions(leaderboardSearchOptions)
        route += parsedSearchOptions

        let res = await fetch(encodeURI(route))
        if(res.status == 404)
            return Promise.reject(new Error("Leaderboard not found"))
        if(res.status != 200)
            return Promise.reject(new Error("Undocumented error: " + res.status))
        return res.json()
    } catch (error) {
        throw new Error(error)
    }
}

/**
 * Retrieves clan rankings for a leaderboard
 * @function getClanRankingsById
 * @memberof BeatLeader.Leaderboards
 * @param {string} id ID of the leaderboard to retrieve clan rankings for
 * @param {number} page Page number for pagination, default is 1
 * @param {number} count Number of rankings per page, default is 10
 * @returns {Promise} A promise with clan rankings
 */
async function getClanRankingsById(id, page = 1, count = 10) {
    try {
        let route = new URL(beatleader + 'leaderboard/clanRankings').href
        route += `/${id}?page=${page}&count=${count}`

        let res = await fetch(encodeURI(route))
        if(res.status == 404)
            return Promise.reject(new Error("Clan rankings not found"))

        if(res.status != 200)
            return Promise.reject(new Error("Undocumented error: " + res.status))

        return res.json()
    } catch (error) {
        throw new Error(error)
    }
}

/**
 * Retrieves the score graph for a leaderboard
 * @function getScoregraphById
 * @memberof BeatLeader.Leaderboards
 * @param {string} id ID of the leaderboard to retrieve the score graph for
 * @returns {Promise} A promise with score graph data
 */
async function getScoregraphById(id) {
    try {
        let route = new URL(beatleader + 'leaderboard').href
        route += `/${id}/scoregraph`

        let res = await fetch(encodeURI(route))
        if(res.status == 404)
            return Promise.reject(new Error("Score graph not found"))

        if(res.status != 200)
            return Promise.reject(new Error("Undocumented error: " + res.status))

        return res.json()
    } catch (error) {
        throw new Error(error)
    }
}

exports.BeatLeaderLeaderboards = {
    get: get,
    getById: getById,
    getClanRankingsById: getClanRankingsById,
    getScoregraphById: getScoregraphById
}