-
Notifications
You must be signed in to change notification settings - Fork 0
/
user.ts
332 lines (307 loc) · 10 KB
/
user.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
import { API, Beatmap, Beatmapset, Event, Rulesets, Score } from "./index.js"
import { getId } from "./misc.js"
export interface User {
avatar_url: string
country_code: string
default_group: string
id: number
is_active: boolean
is_bot: boolean
is_deleted: boolean
is_online: boolean
is_supporter: boolean
last_visit: Date | null
pm_friends_only: boolean
profile_colour: string | null
username: string
}
export namespace User {
/**
* An interface to tell the API how the returned Array should be like
* @group Parameter Object Interfaces
*/
export interface Config {
/**
* The maximum amount of elements returned in the array
* @remarks The server could send less than the limit because it deliberately limits itself; Putting this at 1000 doesn't mean you'll even get close to 200
*/
limit?: number
/** How many elements that would be at the top of the returned array get skipped (while still filling the array up to the limit) */
offset?: number
}
export interface WithKudosu extends User {
kudosu: {
available: number
total: number
}
}
export interface WithGroups extends User {
groups: {
colour: string | null
has_listing: boolean
has_playmodes: boolean
id: number
identifier: string
is_probationary: boolean
name: string
playmodes: (keyof typeof Rulesets)[] | null
short_name: string
}[]
}
/** @obtainableFrom {@link API.getMatch} */
export interface WithCountry extends User {
country: {
code: string
name: string
}
}
export interface WithCountryCover extends WithCountry {
cover: {
custom_url: string | null
url: string
id: number | null
}
}
/** @obtainableFrom {@link API.getUsers} */
export interface WithCountryCoverGroupsStatisticsrulesets extends WithCountryCover, WithGroups {
statistics_rulesets: {
osu?: Statistics
taiko?: Statistics
fruits?: Statistics
mania?: Statistics
}
}
/** @obtainableFrom {@link API.getFriends} */
export interface WithCountryCoverGroupsStatisticsSupport extends WithCountryCover, WithGroups {
statistics: Statistics
support_level: number
}
/** @obtainableFrom {@link API.getUser} */
export interface Extended extends WithCountryCoverGroupsStatisticsSupport, WithKudosu {
cover_url: string
discord: string | null
has_supported: boolean
interests: string | null
join_date: Date
location: string | null
max_blocks: number
max_friends: number
occupation: string | null
playmode: keyof typeof Rulesets
playstyle: string[]
post_count: number
profile_order: ("me" | "recent_activity" | "beatmaps" | "historical" | "kudosu" | "top_ranks" | "medals")[]
title: string | null
title_url: string | null
twitter: string | null
website: string | null
account_history: {
description: string | null
id: number
length: number
permanent: boolean
timestamp: Date
type: "note" | "restriction" | "silence"
}[]
active_tournament_banners: {
id: number
tournament_id: number
image: string
}[]
badges: {
awarded_at: Date
description: string
image_url: string
url: string
}[]
beatmap_playcounts_count: number
comments_count: number
favourite_beatmapset_count: number
follower_count: number
graveyard_beatmapset_count: number
guest_beatmapset_count: number
loved_beatmapset_count: number
mapping_follower_count: number
monthly_playcounts: {
start_date: Date
count: number
}[]
nominated_beatmapset_count: number
page: {
html: string
/** Basically the text with the BBCode */
raw: string
}
pending_beatmapset_count: number
previous_usernames: User["username"][]
rank_highest: {
rank: number
updated_at: Date
} | null
replays_watched_counts: {
start_date: Date
count: number
}[]
scores_best_count: number
scores_first_count: number
/** Specific to the Ruleset (`playmode`) */
scores_pinned_count: number
scores_recent_count: number
statistics: Statistics.WithCountryrank
support_level: number
user_achievements: {
achieved_at: Date
achievement_id: number
}[]
rank_history: {
mode: keyof typeof Rulesets
data: number[]
} | null
}
export namespace Extended {
/** @obtainableFrom {@link API.getResourceOwner} */
export interface WithStatisticsrulesets extends Extended, User.WithCountryCoverGroupsStatisticsrulesets {
is_restricted: boolean
}
}
export interface Statistics {
count_300: number
count_100: number
count_50: number
count_miss: number
global_rank: number | null
global_rank_exp: number | null
grade_counts: {
a: number
s: number
sh: number
ss: number
ssh: number
}
/** Accuracy in the normal format, where 96.56% would be `96.56` */
hit_accuracy: number
/** Hasn't become inactive in the rankings */
is_ranked: boolean
level: {
current: number
progress: number
}
maximum_combo: number
play_count: number
play_time: number | null
pp: number | null
pp_exp: number
ranked_score: number
replays_watched_by_others: number
total_hits: number
total_score: number
}
export namespace Statistics {
export interface WithCountryrank extends Statistics {
country_rank: number
}
export interface WithUser extends Statistics {
user: User.WithCountryCover
}
}
/** @obtainableFrom {@link API.getUserKudosu} */
export interface KudosuHistory {
id: number
action: "give" | "vote.give" | "reset" | "vote.reset" | "revoke" | "vote.revoke"
amount: number
model: string
created_at: Date
giver: {
url: string
username: string
} | null
post: {
url: string | null
title: string
}
}
// FUNCTIONS
/**
* Get extensive user data about the authorized user
* @scope {@link Scope"identify"}
* @param ruleset The data should be relevant to which ruleset? (defaults to **user's default Ruleset**)
*/
export async function getResourceOwner(this: API, ruleset?: Rulesets): Promise<User.Extended.WithStatisticsrulesets> {
return await this.request("get", "me", {mode: ruleset})
}
/**
* Get extensive user data about whoever you want!
* @param user A user id, a username or a `User` object!
* @param ruleset The data should be relevant to which ruleset? (defaults to **user's default Ruleset**)
*/
export async function getOne(this: API, user: User["id"] | User["username"] | User, ruleset?: Rulesets): Promise<User.Extended> {
const mode = ruleset !== undefined ? Rulesets[ruleset] : ""
if (typeof user === "string") return await this.request("get", `users/${user}/${mode}`, {key: "username"})
if (typeof user === "number") return await this.request("get", `users/${user}/${mode}`, {key: "id"})
return await this.request("get", `users/${user.id}/${mode}`, {key: "id"})
}
/**
* Get user data for up to 50 users at once!
* @param users An array containing user ids or/and `User` objects!
*/
export async function getMultiple(this: API, users: Array<User["id"] | User>): Promise<User.WithCountryCoverGroupsStatisticsrulesets[]> {
const ids = users.map((user) => getId(user))
const response = await this.request("get", "users", {ids})
return response.users
}
/**
* Get "notable" scores from a user
* @param user The user who set the scores
* @param type Do you want scores: in the user's top 100, that are top 1 on a beatmap, that have been recently set?
* @param ruleset The Ruleset the scores were made in (defaults to **user's default Ruleset**)
* @param include Do you also want lazer scores and failed scores? (defaults to **true for lazer** & **false for fails**)
* @param config Array limit & offset
*/
export async function getScores(this: API, user: User["id"] | User, type: "best" | "firsts" | "recent", ruleset?: Rulesets,
include: {lazer?: boolean, fails?: boolean} = {lazer: true, fails: false}, config?: Config): Promise<Score.WithUserBeatmapBeatmapset[]> {
const mode = ruleset !== undefined ? Rulesets[ruleset] : undefined
return await this.request("get", `users/${getId(user)}/scores/${type}`,
{mode, limit: config?.limit, offset: config?.offset, legacy_only: Number(!include.lazer), include_fails: String(Number(include.fails))})
}
/**
* Get beatmaps favourited or made by a user!
* @param user The user in question
* @param type The relation between the user and the beatmaps
* @param config Array limit & offset
*/
export async function getBeatmaps(this: API, user: User["id"] | User, type: "favourite" | "graveyard" | "guest" | "loved" | "nominated" | "pending" | "ranked",
config?: Config): Promise<Beatmapset.Extended.WithBeatmap[]> {
return await this.request("get", `users/${getId(user)}/beatmapsets/${type}`, {limit: config?.limit, offset: config?.offset})
}
/**
* Get the beatmaps most played by a user!
* @param user The user who played the beatmaps
* @param config Array limit & offset
*/
export async function getMostPlayed(this: API, user: User["id"] | User, config?: Config): Promise<Beatmap.Playcount[]> {
return await this.request("get", `users/${getId(user)}/beatmapsets/most_played`, {limit: config?.limit, offset: config?.offset})
}
/**
* Get an array of Events of different `type`s that relate to a user's activity during the last 31 days! (or 100 activities, whatever comes first)
* @param user The user in question
* @param config Array limit & offset
*/
export async function getRecentActivity(this: API, user: User["id"] | User, config?: Config): Promise<Event.AnyRecentActivity[]> {
return await this.request("get", `users/${getId(user)}/recent_activity`, {limit: config?.limit, offset: config?.offset})
}
/**
* Get data about the activity of a user kudosu-wise!
* @param user The user in question
* @param config Array limit & offset
*/
export async function getKudosu(this: API, user: User["id"] | User, config?: Config): Promise<User.KudosuHistory[]> {
return await this.request("get", `users/${getId(user)}/kudosu`, {limit: config?.limit, offset: config?.offset})
}
/**
* Get user data of each friend of the authorized user
* @scope {@link Scope"friends.read"}
*/
export async function getFriends(this: API): Promise<User.WithCountryCoverGroupsStatisticsSupport[]> {
return await this.request("get", "friends")
}
}