Skip to content

Commit

Permalink
Fix Arrays not being understood in POST requests
Browse files Browse the repository at this point in the history
An unforeseen consequence of my previous commit
  • Loading branch information
TTTaevas committed Nov 8, 2023
1 parent f24cee5 commit 9dd2ae0
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 26 deletions.
4 changes: 2 additions & 2 deletions lib/beatmap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export interface BeatmapsetExtended extends Beatmapset {
has_favourited?: any
}

export interface BeatmapAttributes {
export interface BeatmapDifficultyAttributes {
star_rating: number
max_combo: number
/**
Expand Down Expand Up @@ -189,7 +189,7 @@ export interface BeatmapPack {
date: Date
name: string
/**
* Are difficulty reduction mods unable to be used to clear this pack?
* Are difficulty reduction mods unable to be used to clear this pack? (is `false` if you can use such mods)
*/
no_diff_reduction: boolean
ruleset_id: number,
Expand Down
46 changes: 32 additions & 14 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import fetch, { FetchError } from "node-fetch"
import querystring from "querystring"
import { BeatmapExtended, BeatmapAttributes, Beatmap, BeatmapPack, Beatmapset, BeatmapsetExtended } from "./beatmap.js"
import { BeatmapExtended, BeatmapDifficultyAttributes, Beatmap, BeatmapPack, Beatmapset, BeatmapsetExtended } from "./beatmap.js"
import { KudosuHistory, UserExtended, User } from "./user.js"
import { Leader, Match, MatchInfo, MultiplayerScore, PlaylistItem, Room } from "./multiplayer.js"
import { Rulesets, Mod } from "./misc.js"
Expand Down Expand Up @@ -209,7 +209,7 @@ export class API {
let err = "none"
let to_retry = false

if (parameters !== undefined) {
if (parameters !== undefined && method === "get") {
// If a parameter is an empty string or is undefined, remove it
for (let i = 0; i < Object.entries(parameters).length; i++) {
if (!String(Object.values(parameters)[i]).length || Object.values(parameters)[i] === undefined) {
Expand Down Expand Up @@ -343,27 +343,45 @@ export class API {

/**
* @remarks Will ignore the customization of your mods
* @param beatmap The Beatmap in question
* @param mods Defaults to No Mod, can be a bitset of mods, an array of mod acronyms ("DT" for DoubleTime), or an array of Mods
* @param ruleset Defaults to the Ruleset the Beatmap was made for, useful to specify if you want a convert
* @returns The (beatmap) difficulty attributes of the Beatmap
* @example ```ts
* await api.getBeatmapDifficultyAttributes({id: 811925}, ["HR", "HD"])
* ```
*/
async getBeatmapAttributes(beatmap: {id: number} | Beatmap,
ruleset: Rulesets, mods: Mod[] | string[] | number): Promise<BeatmapAttributes> {
async getBeatmapDifficultyAttributes(beatmap: {id: number} | Beatmap, mods?: Mod[] | string[] | number,
ruleset?: Rulesets): Promise<BeatmapDifficultyAttributes> {
const response = await this.request("post", `beatmaps/${beatmap.id}/attributes`, {ruleset_id: ruleset, mods})
return correctType(response) as BeatmapAttributes
}

async getBeatmapset(beatmapset: {id: number} | Beatmapset): Promise<BeatmapsetExtended> {
const response = await this.request("get", `beatmapsets/${beatmapset.id}`)
return correctType(response) as BeatmapsetExtended
return correctType(response.attributes) as BeatmapDifficultyAttributes
}

/**
* @remarks The specified ruleset will currently not affect the returned object
* @param beatmap The Beatmap the score was made on
* @param user The User who made the score
* @param mods The Mods used to make the score, defaults to any, you can use `["NM"]` to filter out scores with mods
* @param ruleset The Ruleset used to make the score, useful if it was made on a convert
* @returns An Object with the position of the score according to the specified Mods and Ruleset, and with the score itself
*/
async getBeatmapUserScore(beatmap: {id: number} | Beatmap, user: {id: number} | User,
ruleset?: Rulesets): Promise<BeatmapUserScore> {
const response = await this.request("get", `beatmaps/${beatmap.id}/scores/users/${user.id}`)
mods?: string[], ruleset?: Rulesets): Promise<BeatmapUserScore> {
const mode = ruleset ? Rulesets[ruleset] : undefined
const response = await this.request("get", `beatmaps/${beatmap.id}/scores/users/${user.id}`, {mods, mode})
return correctType(response) as BeatmapUserScore
}

async getBeatmapUserScores(beatmap: {id: number} | Beatmap, user: {id: number} | User, ruleset?: Rulesets): Promise<Score[]> {
const mode = ruleset ? Rulesets[ruleset] : undefined
const response = await this.request("get", `beatmaps/${beatmap.id}/scores/users/${user.id}/all`, {mode})
return response.scores.map((s: Score) => correctType(s)) as Score[]
}

async getBeatmapset(beatmapset: {id: number} | Beatmapset): Promise<BeatmapsetExtended> {
const response = await this.request("get", `beatmapsets/${beatmapset.id}`)
return correctType(response) as BeatmapsetExtended
}

async getBeatmapPack(pack: {tag: string} | BeatmapPack): Promise<BeatmapPack> {
const response = await this.request("get", `beatmaps/packs/${pack.tag}`)
return correctType(response) as BeatmapPack
Expand Down Expand Up @@ -484,7 +502,7 @@ function correctType(x: any): any {
} else if (!isNaN(x)) {
return x === null ? null : Number(x)
} else if (/^[+-[0-9][0-9]+-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$/.test(x) ||
/^[+-[0-9][0-9]+-[0-9]{2}-[0-9]{2}$/g.test(x)) {
/^[+-[0-9][0-9]+-[0-9]{2}-[0-9]{2}$/g.test(x) || /^[+-[0-9][0-9]+-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{0,}Z$/g.test(x)) {
return new Date(x)
} else if (/^[+-[0-9][0-9]+-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}$/.test(x)) {
x += "Z"
Expand Down
30 changes: 24 additions & 6 deletions lib/score.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ export interface Score {
best_id: number
user_id: number
accuracy: number
mods: any
/**
* 0 when NoMod
*/
mods: 0 | string[]
score: number
max_combo: number
perfect: any
perfect: boolean
statistics: {
count_50: number
count_100: number
Expand All @@ -19,22 +22,37 @@ export interface Score {
count_miss: number
}
passed: boolean
pp: any
rank: any
/**
* null when Beatmap is Loved (for example)
*/
pp: null | number
rank: string
created_at: Date
mode: any
mode: string
mode_int: Rulesets
replay: any
replay: boolean
beatmap?: Beatmap
beatmapset?: Beatmapset
rank_country?: any
rank_global?: any
weight?: any
user?: any
match?: any
/**
* @remarks Not in the API's documentation, expect it to either be unreliable or disappear
*/
current_user_attributes?: {
/**
* @remarks Seems to remain null even if the score is pinned on the user's profile
*/
pin: null
}
}

export interface BeatmapUserScore {
/**
* Value depends on the requested mode and mods!
*/
position: number
score: Score
}
Expand Down
39 changes: 35 additions & 4 deletions lib/tests/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const testUserStuff = async (): Promise<boolean> => {

let a1 = await <Promise<ReturnType<typeof api.getUser> | false>>attempt("\ngetUser: ", api.getUser({id: user_id}))
if (!isOk(a1, !a1 || (a1.id === user_id))) okay = false
let a2 = await <Promise<ReturnType<typeof api.getUsers> | false>>attempt("getUsers: ", api.getUsers([7276846, 2]))
let a2 = await <Promise<ReturnType<typeof api.getUsers> | false>>attempt("getUsers: ", api.getUsers([user_id, 2]))
if (!isOk(a2, !a2 || (a2.length === 2))) okay = false
let a3 = await <Promise<ReturnType<typeof api.getUserScores> | false>>attempt("getUserScores: ", api.getUserScores(5, {id: user_id}, "best"))
if (!isOk(a3, !a3 || (a3.length === 5))) okay = false
Expand All @@ -56,14 +56,45 @@ const testUserStuff = async (): Promise<boolean> => {
return okay
}

/**
* Check if getBeatmap() and similar work fine
*/
const testBeatmapStuff = async (): Promise<boolean> => {
const beatmap_id = 388463
let okay = true

let b1 = await <Promise<ReturnType<typeof api.getBeatmap> | false>>attempt("\ngetBeatmap: ", api.getBeatmap({id: beatmap_id}))
if (!isOk(b1, !b1 || (b1.id === beatmap_id))) okay = false
let b2 = await <Promise<ReturnType<typeof api.getBeatmaps> | false>>attempt("getBeatmaps: ", api.getBeatmaps([beatmap_id, 4089655]))
if (!isOk(b2, !b2 || (b2.length === 2))) okay = false
let b3 = await <Promise<ReturnType<typeof api.getBeatmapDifficultyAttributes> | false>>attempt(
"getBeatmapAttributes: ", api.getBeatmapDifficultyAttributes({id: beatmap_id}, ["DT"]))
if (!isOk(b3, !b3 || (b3.great_hit_window < 35))) okay = false
let b4 = await <Promise<ReturnType<typeof api.getBeatmapUserScore> | false>>attempt(
"getBeatmapUserScore: ", api.getBeatmapUserScore({id: 176960}, {id: 7276846}, ["NM"]))
if (!isOk(b4, !b4 || (b4.score.accuracy < 0.99))) okay = false
let b5 = await <Promise<ReturnType<typeof api.getBeatmapUserScores> | false>>attempt(
"getBeatmapUserScores: ", api.getBeatmapUserScores({id: 203993}, {id: 7276846}, osu.Rulesets.fruits))
if (!isOk(b5, !b5 || (b5.length === 1))) okay = false
let b6 = await <Promise<ReturnType<typeof api.getBeatmapset> | false>>attempt("getBeatmapset", api.getBeatmapset({id: 1971037}))
if (!isOk(b6, !b6 || (b6.submitted_date?.toISOString().substring(0, 10) === "2023-04-07"))) okay = false
let b7 = await <Promise<ReturnType<typeof api.getBeatmapPack> | false>>attempt("getBeatmapPack", api.getBeatmapPack({tag: "P217"}))
if (!isOk(b7, !b7 || (b7.tag === "P217"))) okay = false
let b8 = await <Promise<ReturnType<typeof api.getBeatmapPacks> | false>>attempt("getBeatmapPacks", api.getBeatmapPacks("tournament"))
if (!isOk(b8, !b8 || (b8.length > 3))) okay = false

return okay
}

const test = async (id: string, secret: string): Promise<void> => {
api = await osu.API.createAsync({id: Number(id), secret}, undefined, "all")

let u = await testUserStuff()
let a = await testUserStuff()
let b = await testBeatmapStuff()

let test_results = [u].map((bool: boolean, index: number) => bool ? `${index + 1}: ✔️\n` : `${index + 1}: ❌\n`)
let test_results = [a,b].map((bool: boolean, index: number) => bool ? `${index + 1}: ✔️\n` : `${index + 1}: ❌\n`)
console.log("\n", ...test_results)
if ([u].indexOf(false) === -1) {
if ([a,b].indexOf(false) === -1) {
console.log("✔️ Looks like the test went well!")
} else {
throw new Error("❌ Something in the test went wrong...")
Expand Down

0 comments on commit 9dd2ae0

Please sign in to comment.