remove BL data (for now until I can come up with a better soloution)
All checks were successful
deploy / deploy (push) Successful in 59s
All checks were successful
deploy / deploy (push) Successful in 59s
This commit is contained in:
parent
80e6c0da43
commit
2b91388b95
@ -1,6 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useBeatLeaderScoresStore } from "@/store/beatLeaderScoresStore";
|
|
||||||
import { useScoresaberScoresStore } from "@/store/scoresaberScoresStore";
|
import { useScoresaberScoresStore } from "@/store/scoresaberScoresStore";
|
||||||
|
|
||||||
type AppProviderProps = {
|
type AppProviderProps = {
|
||||||
@ -13,11 +12,6 @@ export function AppProvider({ children }: AppProviderProps) {
|
|||||||
|
|
||||||
const UPDATE_INTERVAL = 1000 * 60 * 15; // 15 minutes
|
const UPDATE_INTERVAL = 1000 * 60 * 15; // 15 minutes
|
||||||
|
|
||||||
useBeatLeaderScoresStore.getState().updatePlayerScores();
|
|
||||||
setInterval(() => {
|
|
||||||
useBeatLeaderScoresStore.getState().updatePlayerScores();
|
|
||||||
}, UPDATE_INTERVAL);
|
|
||||||
|
|
||||||
useScoresaberScoresStore.getState().updatePlayerScores();
|
useScoresaberScoresStore.getState().updatePlayerScores();
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
useScoresaberScoresStore.getState().updatePlayerScores();
|
useScoresaberScoresStore.getState().updatePlayerScores();
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
||||||
import { useBeatLeaderScoresStore } from "@/store/beatLeaderScoresStore";
|
|
||||||
import { useScoresaberScoresStore } from "@/store/scoresaberScoresStore";
|
import { useScoresaberScoresStore } from "@/store/scoresaberScoresStore";
|
||||||
import { useSettingsStore } from "@/store/settingsStore";
|
import { useSettingsStore } from "@/store/settingsStore";
|
||||||
import { formatNumber } from "@/utils/number";
|
import { formatNumber } from "@/utils/number";
|
||||||
@ -51,80 +50,39 @@ export default function PlayerInfo({ playerData }: PlayerInfoProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function addProfile(isFriend: boolean) {
|
async function addProfile(isFriend: boolean) {
|
||||||
const setupScoresaber = async () => {
|
if (!useScoresaberScoresStore.getState().exists(playerId)) {
|
||||||
if (!useScoresaberScoresStore.getState().exists(playerId)) {
|
const reponse = await playerScoreStore?.addPlayer(
|
||||||
const reponse = await playerScoreStore?.addPlayer(
|
playerId,
|
||||||
playerId,
|
(page, totalPages) => {
|
||||||
(page, totalPages) => {
|
const autoClose = page == totalPages ? 5000 : false;
|
||||||
const autoClose = page == totalPages ? 5000 : false;
|
|
||||||
|
|
||||||
if (page == 1) {
|
if (page == 1) {
|
||||||
toastId.current = toast.info(
|
toastId.current = toast.info(
|
||||||
`Fetching ScoreSaber scores ${page}/${totalPages}`,
|
`Fetching scores ${page}/${totalPages}`,
|
||||||
{
|
{
|
||||||
autoClose: autoClose,
|
|
||||||
progress: page / totalPages,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
toast.update(toastId.current, {
|
|
||||||
progress: page / totalPages,
|
|
||||||
render: `Fetching ScoreSaber scores ${page}/${totalPages}`,
|
|
||||||
autoClose: autoClose,
|
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,
|
progress: page / totalPages,
|
||||||
render: `Fetching BeatLeader scores ${page}/${totalPages}`,
|
},
|
||||||
autoClose: autoClose,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
`Fetching BeatLeader scores for ${playerId} (${page}/${totalPages})`,
|
|
||||||
);
|
);
|
||||||
},
|
} else {
|
||||||
);
|
toast.update(toastId.current, {
|
||||||
if (reponse?.error) {
|
progress: page / totalPages,
|
||||||
toast.error("Failed to fetch scores");
|
render: `Fetching scores ${page}/${totalPages}`,
|
||||||
console.log(reponse.message);
|
autoClose: autoClose,
|
||||||
return;
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
await setupScoresaber();
|
console.log(
|
||||||
await setupBeatleader();
|
`Fetching scores for ${playerId} (${page}/${totalPages})`,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (reponse?.error) {
|
||||||
|
toast.error("Failed to fetch scores");
|
||||||
|
console.log(reponse.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!isFriend) {
|
if (!isFriend) {
|
||||||
toast.success(`Successfully set ${playerData.name} as your profile`);
|
toast.success(`Successfully set ${playerData.name} as your profile`);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { ScoresaberLeaderboardInfo } from "@/schemas/scoresaber/leaderboard";
|
import { ScoresaberLeaderboardInfo } from "@/schemas/scoresaber/leaderboard";
|
||||||
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
||||||
import { ScoresaberScore } from "@/schemas/scoresaber/score";
|
import { ScoresaberScore } from "@/schemas/scoresaber/score";
|
||||||
import { useBeatLeaderScoresStore } from "@/store/beatLeaderScoresStore";
|
|
||||||
import { formatNumber } from "@/utils/number";
|
import { formatNumber } from "@/utils/number";
|
||||||
import {
|
import {
|
||||||
CheckIcon,
|
CheckIcon,
|
||||||
@ -21,11 +20,6 @@ type ScoreProps = {
|
|||||||
|
|
||||||
export default function Score({ score, player, leaderboard }: ScoreProps) {
|
export default function Score({ score, player, leaderboard }: ScoreProps) {
|
||||||
const isFullCombo = score.missedNotes + score.badCuts === 0;
|
const isFullCombo = score.missedNotes + score.badCuts === 0;
|
||||||
const beatleaderScoreData = useBeatLeaderScoresStore
|
|
||||||
.getState()
|
|
||||||
.getScore(player.id, leaderboard.songHash);
|
|
||||||
|
|
||||||
console.log(beatleaderScoreData);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-1 pb-2 pt-2 first:pt-0 last:pb-0 md:grid-cols-[1.1fr_6fr_3fr] xl:md:grid-cols-[.95fr_6fr_3fr]">
|
<div className="grid grid-cols-1 pb-2 pt-2 first:pt-0 last:pb-0 md:grid-cols-[1.1fr_6fr_3fr] xl:md:grid-cols-[.95fr_6fr_3fr]">
|
||||||
|
@ -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;
|
|
||||||
};
|
|
@ -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;
|
|
||||||
};
|
|
@ -1,5 +0,0 @@
|
|||||||
export type BeatleaderMetadata = {
|
|
||||||
itemsPerPage: number;
|
|
||||||
page: number;
|
|
||||||
total: number;
|
|
||||||
};
|
|
@ -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;
|
|
||||||
};
|
|
@ -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;
|
|
||||||
};
|
|
@ -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;
|
|
||||||
};
|
|
@ -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;
|
|
||||||
};
|
|
@ -1,8 +0,0 @@
|
|||||||
export type BeatleaderScoreOffsets = {
|
|
||||||
id: number;
|
|
||||||
frames: number;
|
|
||||||
notes: number;
|
|
||||||
walls: number;
|
|
||||||
heights: number;
|
|
||||||
pauses: number;
|
|
||||||
};
|
|
@ -1,5 +0,0 @@
|
|||||||
import { BeatleaderSmallerSong } from "./smallerSong";
|
|
||||||
|
|
||||||
export type BeatleaderSmallerLeaderboard = {
|
|
||||||
song: BeatleaderSmallerSong;
|
|
||||||
};
|
|
@ -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;
|
|
||||||
};
|
|
@ -1,9 +0,0 @@
|
|||||||
export type BeatleaderSmallerScoreImprovement = {
|
|
||||||
score: number;
|
|
||||||
accuracy: number;
|
|
||||||
accRight: number;
|
|
||||||
accLeft: number;
|
|
||||||
badCuts: number;
|
|
||||||
missedNotes: number;
|
|
||||||
bombCuts: number;
|
|
||||||
};
|
|
@ -1,4 +0,0 @@
|
|||||||
export type BeatleaderSmallerSong = {
|
|
||||||
hash: string;
|
|
||||||
bpm: number;
|
|
||||||
};
|
|
@ -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; // ??
|
|
||||||
};
|
|
@ -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<BeatLeaderScoresStore>()(
|
|
||||||
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<BeatleaderSmallerScore>();
|
|
||||||
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<ScoresaberPlayer>();
|
|
||||||
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;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
@ -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<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 = {
|
|
||||||
fetchScores,
|
|
||||||
fetchAllScores,
|
|
||||||
};
|
|
Loading…
Reference in New Issue
Block a user