add osu API
This commit is contained in:
119
src/lib/server/osu/api.ts
Normal file
119
src/lib/server/osu/api.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import { env } from '$env/dynamic/private';
|
||||
import { db } from '$lib/server/db';
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import { account } from '$lib/server/db/auth.schema';
|
||||
|
||||
let clientToken: string | null = null;
|
||||
let clientTokenExpiresAt = 0;
|
||||
|
||||
// Client credentials token (no user needed, for public endpoints)
|
||||
async function getClientToken(): Promise<string> {
|
||||
if (clientToken && Date.now() < clientTokenExpiresAt - 60_000) {
|
||||
return clientToken;
|
||||
}
|
||||
|
||||
const res = await fetch('https://osu.ppy.sh/oauth/token', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
client_id: env.OSU_CLIENT_ID!,
|
||||
client_secret: env.OSU_CLIENT_SECRET!,
|
||||
grant_type: 'client_credentials',
|
||||
scope: 'identify public'
|
||||
})
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to get osu! client token: ${res.status} ${res.statusText}`);
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
clientToken = data.access_token;
|
||||
clientTokenExpiresAt = Date.now() + data.expires_in * 1000;
|
||||
return clientToken!;
|
||||
}
|
||||
|
||||
// Get a user's access token (for user-scoped endpoints)
|
||||
async function getUserToken(userId: string): Promise<string | null> {
|
||||
const acc = await db.query.account.findFirst({
|
||||
where: and(eq(account.userId, userId), eq(account.providerId, 'osu'))
|
||||
});
|
||||
|
||||
if (!acc?.accessToken) return null;
|
||||
|
||||
// Check if expired and refresh if needed
|
||||
if (acc.accessTokenExpiresAt && acc.accessTokenExpiresAt < new Date()) {
|
||||
if (!acc.refreshToken) return null;
|
||||
|
||||
const res = await fetch('https://osu.ppy.sh/oauth/token', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
client_id: env.OSU_CLIENT_ID!,
|
||||
client_secret: env.OSU_CLIENT_SECRET!,
|
||||
grant_type: 'refresh_token',
|
||||
refresh_token: acc.refreshToken,
|
||||
scope: 'identify public'
|
||||
})
|
||||
});
|
||||
|
||||
if (!res.ok) return null;
|
||||
|
||||
const data = await res.json();
|
||||
await db
|
||||
.update(account)
|
||||
.set({
|
||||
accessToken: data.access_token,
|
||||
refreshToken: data.refresh_token,
|
||||
accessTokenExpiresAt: new Date(Date.now() + data.expires_in * 1000)
|
||||
})
|
||||
.where(eq(account.id, acc.id));
|
||||
|
||||
return data.access_token;
|
||||
}
|
||||
|
||||
return acc.accessToken;
|
||||
}
|
||||
|
||||
async function osuFetch(path: string, token?: string) {
|
||||
const t = token ?? (await getClientToken());
|
||||
const res = await fetch(`https://osu.ppy.sh/api/v2${path}`, {
|
||||
headers: { Authorization: `Bearer ${t}` }
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`osu! API ${path}: ${res.status} ${res.statusText}`);
|
||||
}
|
||||
|
||||
return res.json();
|
||||
}
|
||||
|
||||
// ── Public API ──────────────────────────────────────────────────────────
|
||||
|
||||
export async function getBeatmap(beatmapId: string | number) {
|
||||
return osuFetch(`/beatmaps/${beatmapId}`);
|
||||
}
|
||||
|
||||
export async function getBeatmapset(beatmapsetId: string | number) {
|
||||
return osuFetch(`/beatmapsets/${beatmapsetId}`);
|
||||
}
|
||||
|
||||
export async function getUser(userId: string | number) {
|
||||
return osuFetch(`/users/${userId}`);
|
||||
}
|
||||
|
||||
export async function getUserScores(
|
||||
userId: string | number,
|
||||
type: 'best' | 'recent' | 'firsts' = 'best',
|
||||
limit = 10
|
||||
) {
|
||||
return osuFetch(`/users/${userId}/scores/${type}?limit=${limit}`);
|
||||
}
|
||||
|
||||
export { getUserToken, getClientToken };
|
||||
Reference in New Issue
Block a user