feat(overlay): add leaderboard toggle for BL and SS
All checks were successful
deploy / deploy (push) Successful in 58s
All checks were successful
deploy / deploy (push) Successful in 58s
This commit is contained in:
parent
fb2b72875f
commit
3e5f141938
@ -43,6 +43,12 @@ const nextConfig = {
|
|||||||
port: "",
|
port: "",
|
||||||
pathname: "/**",
|
pathname: "/**",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
protocol: "https",
|
||||||
|
hostname: "avatars.akamai.steamstatic.com",
|
||||||
|
port: "",
|
||||||
|
pathname: "/**",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
BIN
public/assets/logos/beatleader.png
Normal file
BIN
public/assets/logos/beatleader.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
BIN
public/assets/logos/scoresaber.png
Normal file
BIN
public/assets/logos/scoresaber.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
@ -79,10 +79,10 @@ export default function Analytics() {
|
|||||||
id: "scoresaber",
|
id: "scoresaber",
|
||||||
value: "ScoreSaber",
|
value: "ScoreSaber",
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// id: "beatleader",
|
id: "beatleader",
|
||||||
// value: "BeatLeader",
|
value: "BeatLeader",
|
||||||
// },
|
},
|
||||||
]}
|
]}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
settingsStore.setPlatform(value);
|
settingsStore.setPlatform(value);
|
||||||
|
@ -7,7 +7,8 @@ import ScoreStats from "@/components/overlay/ScoreStats";
|
|||||||
import SongInfo from "@/components/overlay/SongInfo";
|
import SongInfo from "@/components/overlay/SongInfo";
|
||||||
import { Card, CardDescription, CardTitle } from "@/components/ui/card";
|
import { Card, CardDescription, CardTitle } from "@/components/ui/card";
|
||||||
import { HttpSiraStatus } from "@/overlay/httpSiraStatus";
|
import { HttpSiraStatus } from "@/overlay/httpSiraStatus";
|
||||||
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
import { OverlayPlayer } from "@/overlay/type/overlayPlayer";
|
||||||
|
import { BeatLeaderAPI } from "@/utils/beatleader/api";
|
||||||
import { ScoreSaberAPI } from "@/utils/scoresaber/api";
|
import { ScoreSaberAPI } from "@/utils/scoresaber/api";
|
||||||
import { Component } from "react";
|
import { Component } from "react";
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ interface OverlayProps {}
|
|||||||
|
|
||||||
interface OverlayState {
|
interface OverlayState {
|
||||||
mounted: boolean;
|
mounted: boolean;
|
||||||
player: ScoresaberPlayer | undefined;
|
player: OverlayPlayer | undefined;
|
||||||
settings: any | undefined;
|
settings: any | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,13 +32,44 @@ export default class Overlay extends Component<OverlayProps, OverlayState> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePlayer = async (playerId: string) => {
|
updatePlayer = async (
|
||||||
|
playerId: string,
|
||||||
|
leaderboard: "scoresaber" | "beatleader" = "scoresaber",
|
||||||
|
) => {
|
||||||
console.log(`Updating player stats for ${playerId}`);
|
console.log(`Updating player stats for ${playerId}`);
|
||||||
const player = await ScoreSaberAPI.fetchPlayerData(playerId);
|
if (leaderboard == "scoresaber") {
|
||||||
if (!player) {
|
const player = await ScoreSaberAPI.fetchPlayerData(playerId);
|
||||||
return;
|
if (!player) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
player: {
|
||||||
|
id: player.id,
|
||||||
|
profilePicture: player.profilePicture,
|
||||||
|
country: player.country,
|
||||||
|
pp: player.pp,
|
||||||
|
rank: player.rank,
|
||||||
|
countryRank: player.countryRank,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leaderboard == "beatleader") {
|
||||||
|
const player = await BeatLeaderAPI.fetchPlayerData(playerId);
|
||||||
|
if (!player) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
player: {
|
||||||
|
id: player.id,
|
||||||
|
profilePicture: player.avatar,
|
||||||
|
country: player.country,
|
||||||
|
pp: player.pp,
|
||||||
|
rank: player.rank,
|
||||||
|
countryRank: player.countryRank,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
this.setState({ player });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@ -60,9 +92,9 @@ export default class Overlay extends Component<OverlayProps, OverlayState> {
|
|||||||
this.setState({ settings: settings });
|
this.setState({ settings: settings });
|
||||||
|
|
||||||
if (settings.settings.showPlayerStats) {
|
if (settings.settings.showPlayerStats) {
|
||||||
this.updatePlayer(settings.accountId);
|
this.updatePlayer(settings.accountId, settings.platform);
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
this.updatePlayer(settings.accountId);
|
this.updatePlayer(settings.accountId, settings.platform);
|
||||||
}, UPDATE_INTERVAL);
|
}, UPDATE_INTERVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,7 +145,7 @@ export default class Overlay extends Component<OverlayProps, OverlayState> {
|
|||||||
<main>
|
<main>
|
||||||
<div>
|
<div>
|
||||||
{this.state.settings.settings.showPlayerStats && player && (
|
{this.state.settings.settings.showPlayerStats && player && (
|
||||||
<PlayerStats player={player} />
|
<PlayerStats player={player} settings={this.state.settings} />
|
||||||
)}
|
)}
|
||||||
{this.state.settings.settings.showScoreStats && <ScoreStats />}
|
{this.state.settings.settings.showScoreStats && <ScoreStats />}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
import { OverlayPlayer } from "@/overlay/type/overlayPlayer";
|
||||||
import { formatNumber } from "@/utils/numberUtils";
|
import { formatNumber } from "@/utils/numberUtils";
|
||||||
import { GlobeAltIcon } from "@heroicons/react/20/solid";
|
import { GlobeAltIcon } from "@heroicons/react/20/solid";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import CountyFlag from "../CountryFlag";
|
import CountyFlag from "../CountryFlag";
|
||||||
|
|
||||||
type PlayerStatsProps = {
|
type PlayerStatsProps = {
|
||||||
player: ScoresaberPlayer;
|
player: OverlayPlayer;
|
||||||
|
settings: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function PlayerStats({ player }: PlayerStatsProps) {
|
const leaderboardImages: Record<string, string> = {
|
||||||
|
scoresaber: "/assets/logos/scoresaber.png",
|
||||||
|
beatleader: "/assets/logos/beatleader.png",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function PlayerStats({ player, settings }: PlayerStatsProps) {
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-2 p-2">
|
<div className="flex gap-2 p-2">
|
||||||
<Image
|
<Image
|
||||||
@ -19,7 +25,15 @@ export default function PlayerStats({ player }: PlayerStatsProps) {
|
|||||||
height={180}
|
height={180}
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-3xl font-bold">{formatNumber(player.pp, 2)}pp</p>
|
<div className="flex gap-2">
|
||||||
|
<Image
|
||||||
|
alt="Leaderboard logo"
|
||||||
|
src={leaderboardImages[settings.platform]}
|
||||||
|
width={36}
|
||||||
|
height={36}
|
||||||
|
/>
|
||||||
|
<p className="text-3xl font-bold">{formatNumber(player.pp, 2)}pp</p>
|
||||||
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<GlobeAltIcon width={25} height={25} />
|
<GlobeAltIcon width={25} height={25} />
|
||||||
<p className="text-3xl">#{formatNumber(player.rank)}</p>
|
<p className="text-3xl">#{formatNumber(player.rank)}</p>
|
||||||
|
8
src/overlay/type/overlayPlayer.ts
Normal file
8
src/overlay/type/overlayPlayer.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export type OverlayPlayer = {
|
||||||
|
id: string;
|
||||||
|
country: string;
|
||||||
|
profilePicture: string;
|
||||||
|
pp: number;
|
||||||
|
rank: number;
|
||||||
|
countryRank: number;
|
||||||
|
};
|
30
src/schemas/beatleader/difficulty.ts
Normal file
30
src/schemas/beatleader/difficulty.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
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;
|
||||||
|
};
|
16
src/schemas/beatleader/leaderboard.ts
Normal file
16
src/schemas/beatleader/leaderboard.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
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;
|
||||||
|
};
|
5
src/schemas/beatleader/metadata.ts
Normal file
5
src/schemas/beatleader/metadata.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export type BeatleaderMetadata = {
|
||||||
|
itemsPerPage: number;
|
||||||
|
page: number;
|
||||||
|
total: number;
|
||||||
|
};
|
18
src/schemas/beatleader/modifierRating.ts
Normal file
18
src/schemas/beatleader/modifierRating.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
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;
|
||||||
|
};
|
16
src/schemas/beatleader/modifiers.ts
Normal file
16
src/schemas/beatleader/modifiers.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
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;
|
||||||
|
};
|
9
src/schemas/beatleader/player.ts
Normal file
9
src/schemas/beatleader/player.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export type BeatLeaderPlayer = {
|
||||||
|
id: string;
|
||||||
|
country: string;
|
||||||
|
avatar: string;
|
||||||
|
pp: number;
|
||||||
|
rank: number;
|
||||||
|
countryRank: number;
|
||||||
|
// todo: finish this
|
||||||
|
};
|
51
src/schemas/beatleader/score.ts
Normal file
51
src/schemas/beatleader/score.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
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;
|
||||||
|
};
|
19
src/schemas/beatleader/scoreImprovement.ts
Normal file
19
src/schemas/beatleader/scoreImprovement.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
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;
|
||||||
|
};
|
8
src/schemas/beatleader/scoreOffsets.ts
Normal file
8
src/schemas/beatleader/scoreOffsets.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export type BeatleaderScoreOffsets = {
|
||||||
|
id: number;
|
||||||
|
frames: number;
|
||||||
|
notes: number;
|
||||||
|
walls: number;
|
||||||
|
heights: number;
|
||||||
|
pauses: number;
|
||||||
|
};
|
0
src/schemas/beatleader/scores.ts
Normal file
0
src/schemas/beatleader/scores.ts
Normal file
5
src/schemas/beatleader/smaller/smallerLeaderboard.ts
Normal file
5
src/schemas/beatleader/smaller/smallerLeaderboard.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { BeatleaderSmallerSong } from "./smallerSong";
|
||||||
|
|
||||||
|
export type BeatleaderSmallerLeaderboard = {
|
||||||
|
song: BeatleaderSmallerSong;
|
||||||
|
};
|
14
src/schemas/beatleader/smaller/smallerScore.ts
Normal file
14
src/schemas/beatleader/smaller/smallerScore.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
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;
|
||||||
|
};
|
@ -0,0 +1,9 @@
|
|||||||
|
export type BeatleaderSmallerScoreImprovement = {
|
||||||
|
score: number;
|
||||||
|
accuracy: number;
|
||||||
|
accRight: number;
|
||||||
|
accLeft: number;
|
||||||
|
badCuts: number;
|
||||||
|
missedNotes: number;
|
||||||
|
bombCuts: number;
|
||||||
|
};
|
4
src/schemas/beatleader/smaller/smallerSong.ts
Normal file
4
src/schemas/beatleader/smaller/smallerSong.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export type BeatleaderSmallerSong = {
|
||||||
|
hash: string;
|
||||||
|
bpm: number;
|
||||||
|
};
|
16
src/schemas/beatleader/song.ts
Normal file
16
src/schemas/beatleader/song.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
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; // ??
|
||||||
|
};
|
126
src/utils/beatleader/api.ts
Normal file
126
src/utils/beatleader/api.ts
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
import { BeatLeaderPlayer } from "@/schemas/beatleader/player";
|
||||||
|
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";
|
||||||
|
const PLAYER_URL = API_URL + "/player/{}?stats=false";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the player from the given player id
|
||||||
|
*
|
||||||
|
* @param playerId the id of the player
|
||||||
|
* @param searchType the type of search to perform
|
||||||
|
* @returns the player
|
||||||
|
*/
|
||||||
|
async function fetchPlayerData(
|
||||||
|
playerId: string,
|
||||||
|
): Promise<BeatLeaderPlayer | undefined> {
|
||||||
|
const response = await fetchQueue.fetch(
|
||||||
|
formatString(PLAYER_URL, true, playerId),
|
||||||
|
);
|
||||||
|
const json = await response.json();
|
||||||
|
|
||||||
|
// Check if there was an error fetching the user data
|
||||||
|
console.log(json);
|
||||||
|
|
||||||
|
return json as BeatLeaderPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<BeatleaderScore[] | undefined> {
|
||||||
|
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 = {
|
||||||
|
fetchPlayerData,
|
||||||
|
fetchScores,
|
||||||
|
fetchAllScores,
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user