Skip to content

Commit

Permalink
Make Ranking stuff better overall
Browse files Browse the repository at this point in the history
  • Loading branch information
TTTaevas committed Nov 11, 2023
1 parent 8b7458b commit 998f8a8
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 17 deletions.
42 changes: 31 additions & 11 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export {ChangelogBuild, UpdateStream}

/**
* Scopes determine what the API instance can do as a user!
* @remarks "identify" is always implicity provided
* @remarks "identify" is always implicity provided, "public" is implicitly needed for almost everything
*/
type Scope = "chat.read" | "chat.write" | "chat.write_manage" | "delegate" | "forum.write" | "friends.read" | "identify" | "public"

Expand Down Expand Up @@ -478,7 +478,7 @@ export class API {
* ```
*/
async getChangelogStreams(): Promise<UpdateStream[]> {
const response = await this.request("get", `changelog`, {max_id: 0})
const response = await this.request("get", "changelog", {max_id: 0})
return response.streams.map((s: UpdateStream) => correctType(s)) as UpdateStream[]
}

Expand Down Expand Up @@ -511,7 +511,8 @@ export class API {
/**
* Get the scores on a specific item of a room
* @scope public
* @remarks (2023-11-05) Is currently broken on osu!'s side, gotta love the API not being stable!
* @remarks (2023-11-10) Items are broken for multiplayer (real-time) rooms, not for playlists (like spotlights), that's an osu! bug
* https://github.com/ppy/osu-web/issues/10725
*/
async getPlaylistItemScores(item: {id: number, room_id: number} | PlaylistItem): Promise<MultiplayerScore[]> {
const response = await this.request("get", `rooms/${item.room_id}/playlist/${item.id}/scores`)
Expand Down Expand Up @@ -539,17 +540,36 @@ export class API {

// RANKING STUFF

async getRanking(ruleset: Rulesets, type: "charts" | "country" | "performance" | "score", filter: "all" | "friends",
options?: {country?: number, spotlight?: {id: number} | Spotlight, variant?: "4k" | "7k"}): Promise<Rankings> {
const response = await this.request("get", `rankings/${Rulesets[ruleset]}/${type}`, {
filter,
country: options?.country,
spotlight: options?.spotlight,
variant: options?.variant
})
/**
* Get the top 50 players who have the most total kudosu!
*/
async getKudosuRanking(): Promise<User[]> {
const response = await this.request("get", "rankings/kudosu")
return response.ranking.map((u: User) => correctType(u)) as User[]
}

/**
* Get the top players of the game, with some filters!
* @param ruleset Self-explanatory, is also known as "Gamemode"
* @param type `charts` is essentially for older spotlights, the rest should be obvious enough
* @param page (defaults to 1) Imagine `Rankings` as a page, it can only have a maximum of 50 players, while 50 others may be on the next one
* @param filter What kind of players do you want to see? Defaults to `all`, `friends` has no effect if no authorized user
* @param country Only get players from a specific country, using its ISO 3166-1 alpha-2 country code! (France would be `FR`, United States `US`)
* @param spotlight If `type` is `charts`, you can specify the id of a spotlight! Defaults to the latest spotlight
* @param variant If `type` is `performance` and `ruleset` is mania, choose between 4k and 7k!
* @scope public (only if there's an authorized user) (the `friends.read` scope isn't needed to use the `friends` filter)
*/
async getRanking(ruleset: Rulesets, type: "charts" | "country" | "performance" | "score", page: number = 1, filter: "all" | "friends" = "all",
country?: string, spotlight?: {id: number} | Spotlight, variant?: "4k" | "7k"): Promise<Rankings> {
const response = await this.request("get", `rankings/${Rulesets[ruleset]}/${type}`, {page, filter, country, spotlight, variant})
return correctType(response) as Rankings
}

/**
* Get ALL legacy spotlights! (2009-2020, somewhat known as charts/ranking charts, available @ https://osu.ppy.sh/rankings/osu/charts)
* @remarks The data for newer spotlights (2020-, somewhat known as seasons) can be obtained through `getRoom()`
* but you can't really get their id without going through the website's URLs (https://osu.ppy.sh/seasons/latest) as far as I know :(
*/
async getSpotlights(): Promise<Spotlight[]> {
const response = await this.request("get", "spotlights")
return response.spotlights.map((s: Spotlight) => correctType(s)) as Spotlight[]
Expand Down
13 changes: 11 additions & 2 deletions lib/ranking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,17 @@ export interface Spotlight {
}

export interface Rankings {
beatmapsets?: BeatmapsetExtended[]
ranking: UserStatistics[]
spotlight?: Spotlight
/**
* Total amount of users available across all pages, not on this specific page! Maximum of 10000
*/
total: number
cursor: {
/**
* The number of the next page, is null if no more results are available
*/
page: number | null
}
beatmapsets?: BeatmapsetExtended[]
spotlight?: Spotlight
}
35 changes: 33 additions & 2 deletions lib/tests/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ const testBeatmapStuff = async (): Promise<boolean> => {
return okay
}

/**
* Check if getChangelogBuild() and similar work fine
*/
const testChangelogStuff = async (): Promise<boolean> => {
let okay = true

Expand All @@ -100,16 +103,44 @@ const testChangelogStuff = async (): Promise<boolean> => {
return okay
}

/**
* Check if getRoom(), getMatch() and similar work fine
*/
const testMultiplayerStuff = async (): Promise<boolean> => {
let okay = true

return okay
}

/**
* Check if getRanking() and similar work fine
*/
const testRankingStuff = async (): Promise<boolean> => {
let okay = true

let e1 = await <Promise<ReturnType<typeof api.getKudosuRanking> | false>>attempt("\ngetKudosuRanking: ", api.getKudosuRanking())
if (!isOk(e1, !e1 || (e1[0].kudosu!.total > 10000))) okay = false
let e2 = await <Promise<ReturnType<typeof api.getRanking> | false>>attempt(
"getRanking: ", api.getRanking(osu.Rulesets.osu, "score", 1, "all", "FR"))
if (!isOk(e2, !e2 || (e2.ranking[0].level.current > 106))) okay = false
let e3 = await <Promise<ReturnType<typeof api.getSpotlights> | false>>attempt("getSpotlights: ", api.getSpotlights())
if (!isOk(e3, !e3 || (e3.length >= 132))) 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 a = await testUserStuff()
let b = await testBeatmapStuff()
let c = await testChangelogStuff()
let d = await testMultiplayerStuff()
let e = await testRankingStuff()

let test_results = [a,b,c].map((bool: boolean, index: number) => bool ? `${index + 1}: ✔️\n` : `${index + 1}: ❌\n`)
let test_results = [a,b,c,d,e].map((bool: boolean, index: number) => bool ? `${index + 1}: ✔️\n` : `${index + 1}: ❌\n`)
console.log("\n", ...test_results)
if ([a,b,c].indexOf(false) === -1) {
if ([a,b,c,d,e].indexOf(false) === -1) {
console.log("✔️ Looks like the test went well!")
} else {
throw new Error("❌ Something in the test went wrong...")
Expand Down
8 changes: 6 additions & 2 deletions lib/tests/test_authorized.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@ async function test(id: string | undefined, secret: string | undefined, redirect
if (secret === undefined) {throw new Error("no SECRET env var")}
if (redirect_uri === undefined) {throw new Error("no REDIRECT_URI env var")}

let url = osu.generateAuthorizationURL(Number(id), redirect_uri, ["identify"])
let url = osu.generateAuthorizationURL(Number(id), redirect_uri, ["public"])
exec(`xdg-open "${url}"`)
let code = prompt(`What code do you get from: ${url}\n\n`)

let api = await osu.API.createAsync({id: Number(id), secret}, {code, redirect_uri}, "all")
if (api) {
let me = await api.getResourceOwner()
let d1 = await api.getRanking(osu.Rulesets.osu, "performance", 1, "friends")
if (d1) {
d1.ranking = [d1.ranking[0]]
console.log(d1)
}
}
}

Expand Down
13 changes: 13 additions & 0 deletions lib/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ export interface User {
short_name: string
}[] | 0
is_restricted?: boolean | null
kudosu?: {
available: number
total: number
}
loved_beatmapset_count?: number
monthly_playcounts?: {
start_date: Date
Expand Down Expand Up @@ -112,6 +116,15 @@ export interface User {
}

export interface UserExtended extends User {
country: {
code: string
name: string
}
cover: {
custom_url: string | null
url: string
id: string | null
}
cover_url: string
discord: string | null
has_supported: boolean
Expand Down

0 comments on commit 998f8a8

Please sign in to comment.