diff --git a/src/components/AppProvider.tsx b/src/components/AppProvider.tsx index 4bc5fd2..f742acf 100644 --- a/src/components/AppProvider.tsx +++ b/src/components/AppProvider.tsx @@ -1,6 +1,5 @@ "use client"; -import { useBeatLeaderScoresStore } from "@/store/beatLeaderScoresStore"; import { useScoresaberScoresStore } from "@/store/scoresaberScoresStore"; type AppProviderProps = { @@ -13,11 +12,6 @@ export function AppProvider({ children }: AppProviderProps) { const UPDATE_INTERVAL = 1000 * 60 * 15; // 15 minutes -useBeatLeaderScoresStore.getState().updatePlayerScores(); -setInterval(() => { - useBeatLeaderScoresStore.getState().updatePlayerScores(); -}, UPDATE_INTERVAL); - useScoresaberScoresStore.getState().updatePlayerScores(); setInterval(() => { useScoresaberScoresStore.getState().updatePlayerScores(); diff --git a/src/components/player/PlayerInfo.tsx b/src/components/player/PlayerInfo.tsx index cecd369..6ca7059 100644 --- a/src/components/player/PlayerInfo.tsx +++ b/src/components/player/PlayerInfo.tsx @@ -1,5 +1,4 @@ import { ScoresaberPlayer } from "@/schemas/scoresaber/player"; -import { useBeatLeaderScoresStore } from "@/store/beatLeaderScoresStore"; import { useScoresaberScoresStore } from "@/store/scoresaberScoresStore"; import { useSettingsStore } from "@/store/settingsStore"; import { formatNumber } from "@/utils/number"; @@ -51,80 +50,39 @@ export default function PlayerInfo({ playerData }: PlayerInfoProps) { } async function addProfile(isFriend: boolean) { - const setupScoresaber = async () => { - if (!useScoresaberScoresStore.getState().exists(playerId)) { - const reponse = await playerScoreStore?.addPlayer( - playerId, - (page, totalPages) => { - const autoClose = page == totalPages ? 5000 : false; + if (!useScoresaberScoresStore.getState().exists(playerId)) { + const reponse = await playerScoreStore?.addPlayer( + playerId, + (page, totalPages) => { + const autoClose = page == totalPages ? 5000 : false; - if (page == 1) { - toastId.current = toast.info( - `Fetching ScoreSaber scores ${page}/${totalPages}`, - { - autoClose: autoClose, - progress: page / totalPages, - }, - ); - } else { - toast.update(toastId.current, { - progress: page / totalPages, - render: `Fetching ScoreSaber scores ${page}/${totalPages}`, + if (page == 1) { + toastId.current = toast.info( + `Fetching scores ${page}/${totalPages}`, + { autoClose: autoClose, - }); - } - - console.log( - `Fetching ScoreSaber scores for ${playerId} (${page}/${totalPages})`, - ); - }, - ); - if (reponse?.error) { - toast.error("Failed to fetch scores"); - console.log(reponse.message); - return; - } - } - }; - - const setupBeatleader = async () => { - if (!useBeatLeaderScoresStore.getState().exists(playerId)) { - const reponse = await playerScoreStore?.addPlayer( - playerId, - (page, totalPages) => { - const autoClose = page == totalPages ? 5000 : false; - - if (page == 1) { - toastId.current = toast.info( - `Fetching BeatLeader scores ${page}/${totalPages}`, - { - autoClose: autoClose, - progress: page / totalPages, - }, - ); - } else { - toast.update(toastId.current, { progress: page / totalPages, - render: `Fetching BeatLeader scores ${page}/${totalPages}`, - autoClose: autoClose, - }); - } - - console.log( - `Fetching BeatLeader scores for ${playerId} (${page}/${totalPages})`, + }, ); - }, - ); - if (reponse?.error) { - toast.error("Failed to fetch scores"); - console.log(reponse.message); - return; - } - } - }; + } else { + toast.update(toastId.current, { + progress: page / totalPages, + render: `Fetching scores ${page}/${totalPages}`, + autoClose: autoClose, + }); + } - await setupScoresaber(); - await setupBeatleader(); + console.log( + `Fetching scores for ${playerId} (${page}/${totalPages})`, + ); + }, + ); + if (reponse?.error) { + toast.error("Failed to fetch scores"); + console.log(reponse.message); + return; + } + } if (!isFriend) { toast.success(`Successfully set ${playerData.name} as your profile`); diff --git a/src/components/player/Score.tsx b/src/components/player/Score.tsx index 0b30c4f..532e825 100644 --- a/src/components/player/Score.tsx +++ b/src/components/player/Score.tsx @@ -1,7 +1,6 @@ import { ScoresaberLeaderboardInfo } from "@/schemas/scoresaber/leaderboard"; import { ScoresaberPlayer } from "@/schemas/scoresaber/player"; import { ScoresaberScore } from "@/schemas/scoresaber/score"; -import { useBeatLeaderScoresStore } from "@/store/beatLeaderScoresStore"; import { formatNumber } from "@/utils/number"; import { CheckIcon, @@ -21,11 +20,6 @@ type ScoreProps = { export default function Score({ score, player, leaderboard }: ScoreProps) { const isFullCombo = score.missedNotes + score.badCuts === 0; - const beatleaderScoreData = useBeatLeaderScoresStore - .getState() - .getScore(player.id, leaderboard.songHash); - - console.log(beatleaderScoreData); return (
diff --git a/src/schemas/beatleader/difficulty.ts b/src/schemas/beatleader/difficulty.ts deleted file mode 100644 index f3d69b3..0000000 --- a/src/schemas/beatleader/difficulty.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { BeatleaderModifierRating } from "./modifierRating"; -import { BeatleaderModifier } from "./modifiers"; - -export type BeatleaderDifficulty = { - id: number; - value: number; - mode: number; - difficultyName: string; - modeName: string; - status: number; - modifierValues: BeatleaderModifier; - modifiersRating: BeatleaderModifierRating; - nominatedTime: number; - qualifiedTime: number; - rankedTime: number; - stars: number; - predictedAcc: number; - passRating: number; - accRating: number; - techRating: number; - type: number; - njs: number; - nps: number; - notes: number; - bombs: number; - walls: number; - maxScore: number; - duration: number; - requirements: number; -}; diff --git a/src/schemas/beatleader/leaderboard.ts b/src/schemas/beatleader/leaderboard.ts deleted file mode 100644 index 42c8771..0000000 --- a/src/schemas/beatleader/leaderboard.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { BeatleaderDifficulty } from "./difficulty"; -import { BeatleaderSong } from "./song"; - -export type BeatleaderLeaderboard = { - id: string; - song: BeatleaderSong; - difficulty: BeatleaderDifficulty; - scores: null; // ?? - changes: null; // ?? - qualification: null; // ?? - reweight: null; // ?? - leaderboardGroup: null; // ?? - plays: number; - clan: null; // ?? - clanRankingContested: boolean; -}; diff --git a/src/schemas/beatleader/metadata.ts b/src/schemas/beatleader/metadata.ts deleted file mode 100644 index 15e27de..0000000 --- a/src/schemas/beatleader/metadata.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type BeatleaderMetadata = { - itemsPerPage: number; - page: number; - total: number; -}; diff --git a/src/schemas/beatleader/modifierRating.ts b/src/schemas/beatleader/modifierRating.ts deleted file mode 100644 index f1a21e8..0000000 --- a/src/schemas/beatleader/modifierRating.ts +++ /dev/null @@ -1,18 +0,0 @@ -export type BeatleaderModifierRating = { - id: number; - fsPredictedAcc: number; - fsPassRating: number; - fsAccRating: number; - fsTechRating: number; - fsStars: number; - ssPredictedAcc: number; - ssPassRating: number; - ssAccRating: number; - ssTechRating: number; - ssStars: number; - sfPredictedAcc: number; - sfPassRating: number; - sfAccRating: number; - sfTechRating: number; - sfStars: number; -}; diff --git a/src/schemas/beatleader/modifiers.ts b/src/schemas/beatleader/modifiers.ts deleted file mode 100644 index 38d45ab..0000000 --- a/src/schemas/beatleader/modifiers.ts +++ /dev/null @@ -1,16 +0,0 @@ -export type BeatleaderModifier = { - modifierId: number; - da: number; - fs: number; - sf: number; - ss: number; - gn: number; - na: number; - nb: number; - nf: number; - no: number; - pm: number; - sc: number; - sa: number; - op: number; -}; diff --git a/src/schemas/beatleader/score.ts b/src/schemas/beatleader/score.ts deleted file mode 100644 index 52321db..0000000 --- a/src/schemas/beatleader/score.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { BeatleaderLeaderboard } from "./leaderboard"; -import { BeatleaderScoreImprovement } from "./scoreImprovement"; -import { BeatleaderScoreOffsets } from "./scoreOffsets"; - -export type BeatleaderScore = { - myScore: null; // ?? - validContexts: number; - leaderboard: BeatleaderLeaderboard; - contextExtensions: null; // ?? - accLeft: number; - accRight: number; - id: number; - baseScore: number; - modifiedScore: number; - accuracy: number; - playerId: string; - pp: number; - bonusPp: number; - passPP: number; - accPP: number; - techPP: number; - rank: number; - country: string; - fcAccuracy: number; - fcPp: number; - weight: number; - replay: string; - modifiers: string; - badCuts: number; - missedNotes: number; - bombCuts: number; - wallsHit: number; - pauses: number; - fullCombo: boolean; - platform: string; - maxCombo: number; - maxStreak: number; - hmd: number; - controller: number; - leaderboardId: string; - timeset: string; - timepost: number; - replaysWatched: number; - playCount: number; - priority: number; - player: null; // ?? - scoreImprovement: BeatleaderScoreImprovement; - rankVoting: null; // ?? - metadata: null; // ?? - offsets: BeatleaderScoreOffsets; -}; diff --git a/src/schemas/beatleader/scoreImprovement.ts b/src/schemas/beatleader/scoreImprovement.ts deleted file mode 100644 index a20b54a..0000000 --- a/src/schemas/beatleader/scoreImprovement.ts +++ /dev/null @@ -1,19 +0,0 @@ -export type BeatleaderScoreImprovement = { - id: number; - timeset: number; - score: number; - accuracy: number; - pp: number; - bonusPp: number; - rank: number; - accRight: number; - accLeft: number; - averageRankedAccuracy: number; - totalPp: number; - totalRank: number; - badCuts: number; - missedNotes: number; - bombCuts: number; - wallsHit: number; - pauses: number; -}; diff --git a/src/schemas/beatleader/scoreOffsets.ts b/src/schemas/beatleader/scoreOffsets.ts deleted file mode 100644 index d443d40..0000000 --- a/src/schemas/beatleader/scoreOffsets.ts +++ /dev/null @@ -1,8 +0,0 @@ -export type BeatleaderScoreOffsets = { - id: number; - frames: number; - notes: number; - walls: number; - heights: number; - pauses: number; -}; diff --git a/src/schemas/beatleader/scores.ts b/src/schemas/beatleader/scores.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/schemas/beatleader/smaller/smallerLeaderboard.ts b/src/schemas/beatleader/smaller/smallerLeaderboard.ts deleted file mode 100644 index 584827f..0000000 --- a/src/schemas/beatleader/smaller/smallerLeaderboard.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { BeatleaderSmallerSong } from "./smallerSong"; - -export type BeatleaderSmallerLeaderboard = { - song: BeatleaderSmallerSong; -}; diff --git a/src/schemas/beatleader/smaller/smallerScore.ts b/src/schemas/beatleader/smaller/smallerScore.ts deleted file mode 100644 index 9e21033..0000000 --- a/src/schemas/beatleader/smaller/smallerScore.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { BeatleaderSmallerLeaderboard } from "./smallerLeaderboard"; -import { BeatleaderSmallerScoreImprovement } from "./smallerScoreImprovement"; - -export type BeatleaderSmallerScore = { - id: number; - timepost: number; - accLeft: number; - accRight: number; - fcAccuracy: number; - wallsHit: number; - replay: string; - leaderboard: BeatleaderSmallerLeaderboard; - scoreImprovement: BeatleaderSmallerScoreImprovement | null; -}; diff --git a/src/schemas/beatleader/smaller/smallerScoreImprovement.ts b/src/schemas/beatleader/smaller/smallerScoreImprovement.ts deleted file mode 100644 index 2c32ce3..0000000 --- a/src/schemas/beatleader/smaller/smallerScoreImprovement.ts +++ /dev/null @@ -1,9 +0,0 @@ -export type BeatleaderSmallerScoreImprovement = { - score: number; - accuracy: number; - accRight: number; - accLeft: number; - badCuts: number; - missedNotes: number; - bombCuts: number; -}; diff --git a/src/schemas/beatleader/smaller/smallerSong.ts b/src/schemas/beatleader/smaller/smallerSong.ts deleted file mode 100644 index 3b8811c..0000000 --- a/src/schemas/beatleader/smaller/smallerSong.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type BeatleaderSmallerSong = { - hash: string; - bpm: number; -}; diff --git a/src/schemas/beatleader/song.ts b/src/schemas/beatleader/song.ts deleted file mode 100644 index 51c8898..0000000 --- a/src/schemas/beatleader/song.ts +++ /dev/null @@ -1,16 +0,0 @@ -export type BeatleaderSong = { - id: string; - hash: string; - name: string; - subName: string; - author: string; - mapperId: string; - coverImage: string; - fullCoverImage: string; - downloadUrl: string; - bpm: number; - duration: number; - tags: string; - uploadTime: number; - difficulties: null; // ?? -}; diff --git a/src/store/beatLeaderScoresStore.ts b/src/store/beatLeaderScoresStore.ts deleted file mode 100644 index 3119100..0000000 --- a/src/store/beatLeaderScoresStore.ts +++ /dev/null @@ -1,347 +0,0 @@ -"use client"; - -import { BeatleaderSmallerScore } from "@/schemas/beatleader/smaller/smallerScore"; -import { ScoresaberPlayer } from "@/schemas/scoresaber/player"; -import { BeatLeaderAPI } from "@/utils/beatleader/api"; -import moment from "moment"; -import { toast } from "react-toastify"; -import { create } from "zustand"; -import { createJSONStorage, persist } from "zustand/middleware"; -import { useSettingsStore } from "./settingsStore"; - -type Player = { - id: string; - scores: BeatleaderSmallerScore[]; -}; - -interface BeatLeaderScoresStore { - lastUpdated: number; - players: Player[]; - - /** - * Sets when the player scores were last updated - * - * @param lastUpdated when the player scores were last updated - */ - setLastUpdated: (lastUpdated: number) => void; - - /** - * Checks if the player exists - * - * @param playerId the player id - * @returns if the player exists - */ - exists: (playerId: string) => boolean; - - /** - * Gets the given player - * - * @param playerId the player id - * @returns the player - */ - get(playerId: string): Player | undefined; - - /** - * Gets the score for the given player and song hash - * - * @param playerId the player id - * @param songHash the song hash - */ - getScore( - playerId: string, - songHash: string, - ): BeatleaderSmallerScore | undefined; - - /** - * Adds the player to the local database - * - * @param playerId the player id - * @param callback a callback to call when a score page is fetched - * @returns if the player was added successfully - */ - addPlayer: ( - playerId: string, - callback?: (page: number, totalPages: number) => void, - ) => Promise<{ - error: boolean; - message: string; - }>; - - /** - * Refreshes the player scores and adds any new scores to the local database - */ - updatePlayerScores: () => void; -} - -const UPDATE_INTERVAL = 1000 * 60 * 30; // 30 minutes - -export const useBeatLeaderScoresStore = create()( - persist( - (set) => ({ - lastUpdated: 0, - players: [], - - setLastUpdated: (lastUpdated: number) => { - set({ lastUpdated }); - }, - - exists: (playerId: string) => { - const players: Player[] = useBeatLeaderScoresStore.getState().players; - return players.some((player) => player.id == playerId); - }, - - get: (playerId: string) => { - const players: Player[] = useBeatLeaderScoresStore.getState().players; - return players.find((player) => player.id == playerId); - }, - - getScore: (playerId: string, songHash: string) => { - const player = useBeatLeaderScoresStore.getState().get(playerId); - if (player == undefined) return undefined; - - return player.scores.find( - (score) => score.leaderboard.song.hash == songHash, - ); - }, - - addPlayer: async ( - playerId: string, - callback?: ( - page: number, - totalPages: number, - leaderboardName: string, - ) => void, - ) => { - const players = useBeatLeaderScoresStore.getState().players; - - // Check if the player already exists - if (useBeatLeaderScoresStore.getState().exists(playerId)) { - return { - error: true, - message: "Player already exists", - }; - } - - // Get all of the players scores - const scores = await BeatLeaderAPI.fetchAllScores( - playerId, - (page, totalPages) => { - if (callback) callback(page, totalPages, "BeatLeader"); - }, - ); - if (scores == undefined) { - return { - error: true, - message: "Could not fetch beatleader scores for player", - }; - } - let smallerScores = new Array(); - for (const score of scores) { - // We have to do this to limit the amount of data we store - // so we don't exceed the local storage limit - smallerScores.push({ - id: score.id, - accLeft: score.accLeft, - accRight: score.accRight, - fcAccuracy: score.fcAccuracy, - wallsHit: score.wallsHit, - replay: score.replay, - leaderboard: { - song: { - bpm: score.leaderboard.song.bpm, - hash: score.leaderboard.song.hash, - }, - }, - scoreImprovement: - score.scoreImprovement != null - ? { - score: score.scoreImprovement.score, - accuracy: score.scoreImprovement.accuracy, - accRight: score.scoreImprovement.accRight, - accLeft: score.scoreImprovement.accLeft, - badCuts: score.scoreImprovement.badCuts, - missedNotes: score.scoreImprovement.missedNotes, - bombCuts: score.scoreImprovement.bombCuts, - } - : null, - timepost: score.timepost, - }); - } - - // Remove scores that are already in the database - const player = useBeatLeaderScoresStore.getState().get(playerId); - if (player) { - smallerScores = smallerScores.filter( - (score) => player.scores.findIndex((s) => s.id == score.id) == -1, - ); - } - - set({ - lastUpdated: Date.now(), - players: [ - ...players, - { - id: playerId, - scores: smallerScores, - }, - ], - }); - return { - error: false, - message: "Player added successfully", - }; - }, - - updatePlayerScores: async () => { - const players = useBeatLeaderScoresStore.getState().players; - const friends = useSettingsStore.getState().friends; - - let allPlayers = new Array(); - for (const friend of friends) { - allPlayers.push(friend); - } - const localPlayer = useSettingsStore.getState().player; - if (localPlayer) { - allPlayers.push(localPlayer); - } - - // add local player and friends if they don't exist - for (const player of allPlayers) { - if (useBeatLeaderScoresStore.getState().get(player.id) == undefined) { - toast.info( - `${ - player.id == localPlayer?.id - ? `You were` - : `Friend ${player.name} was` - } missing from the BeatLeader scores database, adding...`, - ); - await useBeatLeaderScoresStore.getState().addPlayer(player.id); - toast.success( - `${ - player.id == useSettingsStore.getState().player?.id - ? `You were` - : `Friend ${player.name} was` - } added to the BeatLeader scores database`, - ); - } - } - - // Skip if we refreshed the scores recently - const timeUntilRefreshMs = - UPDATE_INTERVAL - - (Date.now() - useBeatLeaderScoresStore.getState().lastUpdated); - if (timeUntilRefreshMs > 0) { - console.log( - "Waiting", - moment.duration(timeUntilRefreshMs).humanize(), - "to refresh scores for players", - ); - setTimeout( - () => useBeatLeaderScoresStore.getState().updatePlayerScores(), - timeUntilRefreshMs, - ); - return; - } - - // loop through all of the players and update their scores - for (const player of players) { - if (player == undefined) continue; - console.log(`Updating scores for ${player.id}...`); - - let newPlayers = players; - let oldScores = player.scores; - - // Sort the scores by date (newset to oldest), so we know when to stop searching for new scores - oldScores = oldScores.sort((a, b) => { - return a.timepost - b.timepost; - }); - if (!oldScores.length) return; - - const mostRecentScore = oldScores[0]; - let search = true; - - let page = 0; - let newScoresCount = 0; - while (search) { - page++; - const newScores = await BeatLeaderAPI.fetchScores(player.id, page); - if (newScores == undefined) continue; - - for (const score of newScores.scores) { - if (mostRecentScore && score.id == mostRecentScore.id) { - search = false; - break; - } - - // remove the old score - const oldScoreIndex = oldScores.findIndex( - (score) => score.id == score.id, - ); - if (oldScoreIndex != -1) { - oldScores = oldScores.splice(oldScoreIndex, 1); - } - oldScores.push({ - id: score.id, - accLeft: score.accLeft, - accRight: score.accRight, - fcAccuracy: score.fcAccuracy, - wallsHit: score.wallsHit, - replay: score.replay, - leaderboard: { - song: { - bpm: score.leaderboard.song.bpm, - hash: score.leaderboard.song.hash, - }, - }, - scoreImprovement: - score.scoreImprovement != null - ? { - score: score.scoreImprovement.score, - accuracy: score.scoreImprovement.accuracy, - accRight: score.scoreImprovement.accRight, - accLeft: score.scoreImprovement.accLeft, - badCuts: score.scoreImprovement.badCuts, - missedNotes: score.scoreImprovement.missedNotes, - bombCuts: score.scoreImprovement.bombCuts, - } - : null, - timepost: score.timepost, - }); - newScoresCount++; - } - } - - // Remove the player if it already exists - newPlayers = newPlayers.filter((playerr) => playerr.id != player.id); - // Add the player - newPlayers.push({ - id: player.id, - scores: oldScores, - }); - - if (newScoresCount > 0) { - console.log( - `Found ${newScoresCount} new beatleader scores for ${player.id}`, - ); - } - - set({ - players: newPlayers, - lastUpdated: Date.now(), - }); - console.log(friends); - } - }, - }), - { - name: "beatleaderScores", - storage: createJSONStorage(() => localStorage), - version: 2, - - migrate: (state: any, version: number) => { - state.scores = []; - return state; - }, - }, - ), -); diff --git a/src/utils/beatleader/api.ts b/src/utils/beatleader/api.ts deleted file mode 100644 index 666f38d..0000000 --- a/src/utils/beatleader/api.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { BeatleaderScore } from "@/schemas/beatleader/score"; -import { ssrSettings } from "@/ssrSettings"; -import { FetchQueue } from "../fetchWithQueue"; -import { formatString } from "../string"; - -// Create a fetch instance with a cache -const fetchQueue = new FetchQueue(); - -// Api endpoints -const API_URL = ssrSettings.proxy + "/https://api.beatleader.xyz"; -const PLAYER_SCORES_URL = - API_URL + "/player/{}/scores?sortBy=date&order=0&page={}&count=100"; - -/** - * Get the players scores from the given page - * - * @param playerId the id of the player - * @param page the page to get the scores from - * @param searchType the type of search to perform - * @param limit the limit of scores to get - * @returns a list of scores - */ -async function fetchScores( - playerId: string, - page: number = 1, - limit: number = 100, -): Promise< - | { - scores: BeatleaderScore[]; - pageInfo: { - totalScores: number; - page: number; - totalPages: number; - }; - } - | undefined -> { - if (limit > 100) { - throw new Error("Limit cannot be greater than 100"); - } - - const response = await fetchQueue.fetch( - formatString(PLAYER_SCORES_URL, true, playerId, page), - ); - const json = await response.json(); - - // Check if there was an error fetching the user data - console.log(json); - - const metadata = json.metadata; - return { - scores: json.data as BeatleaderScore[], - pageInfo: { - totalScores: json.totalScores, - page: json.page, - totalPages: Math.ceil(json.totalScores / metadata.itemsPerPage), - }, - }; -} - -/** - * Gets all of the players for the given player id - * - * @param playerId the id of the player - * @param searchType the type of search to perform - * @param callback a callback to call when a page is fetched - * @returns a list of scores - */ -async function fetchAllScores( - playerId: string, - callback?: (currentPage: number, totalPages: number) => void, -): Promise { - const scores = new Array(); - - let done = false, - page = 1; - do { - const response = await fetchScores(playerId, page); - if (response == undefined) { - done = true; - break; - } - const { scores: scoresFetched } = response; - if (scoresFetched.length === 0) { - done = true; - break; - } - scores.push(...scoresFetched); - - if (callback) { - callback(page, response.pageInfo.totalPages); - } - page++; - } while (!done); - - return scores as BeatleaderScore[]; -} - -export const BeatLeaderAPI = { - fetchScores, - fetchAllScores, -};