feat: Refactor API interactions and enhance user settings management
- Updated ezpp API to include user info retrieval and improved error handling. - Introduced new writable stores for current user info and loading states. - Added gamemode enums and utility functions for better gamemode handling. - Refactored global state management to use consistent naming conventions. - Enhanced loading and login components to provide better user feedback. - Updated user settings to include preferred mode and type. - Improved layout and page components for better state management and user experience.
This commit is contained in:
@@ -1,14 +1,22 @@
|
||||
import type { EZPPUser } from '@/types';
|
||||
import type { EZPPUser, EZPPUserInfoResponse, EZPPUserResponse } from '@/types';
|
||||
import { betterFetch } from '@better-fetch/fetch';
|
||||
|
||||
const BANCHO_ENDPOINT = 'https://c.ez-pp.farm/';
|
||||
const API_ENDPOINT = 'https://api.ez-pp.farm/';
|
||||
const ENDPOINT = 'https://ez-pp.farm/';
|
||||
|
||||
const timeout = 5000; // 5 seconds;
|
||||
|
||||
export const ezppfarm = {
|
||||
ping: async (): Promise<number | undefined> => {
|
||||
try {
|
||||
const start = Date.now();
|
||||
const request = await betterFetch(BANCHO_ENDPOINT);
|
||||
const request = await betterFetch(BANCHO_ENDPOINT, {
|
||||
timeout,
|
||||
headers: {
|
||||
'User-Agent': 'EZPPLauncher',
|
||||
},
|
||||
});
|
||||
if (request.error) return undefined;
|
||||
const ping = Date.now() - start;
|
||||
return ping;
|
||||
@@ -23,32 +31,22 @@ export const ezppfarm = {
|
||||
| {
|
||||
code: number;
|
||||
message: string;
|
||||
user?: {
|
||||
id: number;
|
||||
donor: boolean;
|
||||
name: string;
|
||||
email: string;
|
||||
};
|
||||
user?: EZPPUser;
|
||||
}
|
||||
| undefined
|
||||
> => {
|
||||
const request = await betterFetch<{
|
||||
code: number;
|
||||
message: string;
|
||||
user?: EZPPUser;
|
||||
}>('https://ez-pp.farm/login/check', {
|
||||
const request = await betterFetch<EZPPUserResponse>(`${ENDPOINT}login/check`, {
|
||||
method: 'POST',
|
||||
timeout,
|
||||
body: JSON.stringify({
|
||||
username: username,
|
||||
password: password,
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0',
|
||||
'User-Agent': 'EZPPLauncher',
|
||||
},
|
||||
});
|
||||
console.log(request.error);
|
||||
if (request.error) {
|
||||
if (request.error.status >= 500 && request.error.status < 600)
|
||||
throw new Error('Server not reachable');
|
||||
@@ -56,4 +54,18 @@ export const ezppfarm = {
|
||||
}
|
||||
return request.data;
|
||||
},
|
||||
getUserInfo: async (userId: number) => {
|
||||
const request = await betterFetch<EZPPUserInfoResponse>(`${API_ENDPOINT}v1/get_player_info`, {
|
||||
timeout,
|
||||
query: {
|
||||
id: userId,
|
||||
scope: 'all',
|
||||
},
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': 'EZPPLauncher',
|
||||
},
|
||||
});
|
||||
return request.error ? undefined : request.data;
|
||||
},
|
||||
};
|
||||
|
4
src/lib/data.ts
Normal file
4
src/lib/data.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import type { EZPPUserInfo } from './types';
|
||||
|
||||
export const currentUserInfo = writable<EZPPUserInfo | undefined>(undefined);
|
186
src/lib/gamemode.ts
Normal file
186
src/lib/gamemode.ts
Normal file
@@ -0,0 +1,186 @@
|
||||
export enum Gamemodes {
|
||||
VANILLA_OSU = 0,
|
||||
VANILLA_TAIKO = 1,
|
||||
VANILLA_CATCH = 2,
|
||||
VANILLA_MANIA = 3,
|
||||
|
||||
RELAX_OSU = 4,
|
||||
RELAX_TAIKO = 5,
|
||||
RELAX_CATCH = 6,
|
||||
|
||||
AUTOPILOT_OSU = 8,
|
||||
}
|
||||
|
||||
export enum Mode {
|
||||
OSU = 0,
|
||||
TAIKO = 1,
|
||||
CATCH = 2,
|
||||
MANIA = 3,
|
||||
}
|
||||
|
||||
export enum Type {
|
||||
VANILLA = 0,
|
||||
RELAX = 4,
|
||||
AUTOPILOT = 8,
|
||||
}
|
||||
|
||||
export const validModes = [Mode.OSU, Mode.TAIKO, Mode.CATCH, Mode.MANIA];
|
||||
export const validTypes = [Type.VANILLA, Type.RELAX, Type.AUTOPILOT];
|
||||
export const validModeTypeCombinations = [0, 1, 2, 3, 4, 5, 6, 8];
|
||||
export const validModeTypeCombinationsSorted = [0, 4, 8, 1, 5, 2, 6, 3];
|
||||
|
||||
export const validMode = (modeStr: string) => modeStrToInt(modeStr) !== undefined;
|
||||
export const validType = (typeStr: string) => typeStrToInt(typeStr) !== undefined;
|
||||
|
||||
export const modeStrToInt = (modeStr: 'osu' | 'taiko' | 'catch' | 'mania' | string) => {
|
||||
switch (modeStr) {
|
||||
case 'taiko':
|
||||
return Mode.TAIKO;
|
||||
case 'catch':
|
||||
return Mode.CATCH;
|
||||
case 'mania':
|
||||
return Mode.MANIA;
|
||||
case 'osu':
|
||||
return Mode.OSU;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const modeIntToStr = (modeInt: number) => {
|
||||
switch (modeInt) {
|
||||
case Mode.TAIKO:
|
||||
return 'taiko';
|
||||
case Mode.CATCH:
|
||||
return 'catch';
|
||||
case Mode.MANIA:
|
||||
return 'mania';
|
||||
case Mode.OSU:
|
||||
return 'osu';
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const typeStrToInt = (typeStr: 'vanilla' | 'relax' | 'autopilot' | string) => {
|
||||
switch (typeStr) {
|
||||
case 'relax':
|
||||
return Type.RELAX;
|
||||
case 'autopilot':
|
||||
return Type.AUTOPILOT;
|
||||
case 'vanilla':
|
||||
return Type.VANILLA;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const typeIntToStr = (typeInt: number) => {
|
||||
switch (typeInt) {
|
||||
case Type.RELAX:
|
||||
return 'relax';
|
||||
case Type.AUTOPILOT:
|
||||
return 'autopilot';
|
||||
case Type.VANILLA:
|
||||
return 'vanilla';
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const getGamemodeInt = (
|
||||
mode: 'osu' | 'taiko' | 'catch' | 'mania' | string | undefined,
|
||||
type: 'vanilla' | 'relax' | 'autopilot' | string | undefined
|
||||
) => {
|
||||
let modee = 0;
|
||||
switch (mode) {
|
||||
case 'taiko':
|
||||
modee += Mode.TAIKO;
|
||||
break;
|
||||
case 'catch':
|
||||
modee += Mode.CATCH;
|
||||
break;
|
||||
case 'mania':
|
||||
modee += Mode.MANIA;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 'relax':
|
||||
modee += Type.RELAX;
|
||||
break;
|
||||
case 'autopilot':
|
||||
modee += Type.AUTOPILOT;
|
||||
break;
|
||||
}
|
||||
|
||||
return modee;
|
||||
};
|
||||
|
||||
export const getGamemodeName = (
|
||||
mode: 'osu' | 'taiko' | 'catch' | 'mania' | string | undefined,
|
||||
type: 'vanilla' | 'relax' | 'autopilot' | string | undefined
|
||||
) => {
|
||||
let modeStr = '';
|
||||
switch (mode) {
|
||||
case 'taiko':
|
||||
modeStr += 'taiko!';
|
||||
break;
|
||||
case 'catch':
|
||||
modeStr += 'catch!';
|
||||
break;
|
||||
case 'mania':
|
||||
modeStr += 'mania!';
|
||||
break;
|
||||
default:
|
||||
modeStr += 'osu!';
|
||||
break;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 'relax':
|
||||
modeStr += 'rx';
|
||||
break;
|
||||
case 'autopilot':
|
||||
modeStr += 'ap';
|
||||
break;
|
||||
default:
|
||||
modeStr += 'vn';
|
||||
break;
|
||||
}
|
||||
|
||||
return modeStr;
|
||||
};
|
||||
|
||||
export const getModeAndTypeFromGamemode = (gamemode: number) => {
|
||||
let mode = Mode.OSU;
|
||||
let type = Type.VANILLA;
|
||||
const vanillaMode = gamemode % 4;
|
||||
|
||||
switch (vanillaMode) {
|
||||
case Mode.TAIKO:
|
||||
mode = Mode.TAIKO;
|
||||
break;
|
||||
case Mode.CATCH:
|
||||
mode = Mode.CATCH;
|
||||
break;
|
||||
case Mode.MANIA:
|
||||
mode = Mode.MANIA;
|
||||
break;
|
||||
}
|
||||
|
||||
const typee = gamemode - vanillaMode;
|
||||
switch (typee) {
|
||||
case Type.RELAX:
|
||||
type = Type.RELAX;
|
||||
break;
|
||||
case Type.AUTOPILOT:
|
||||
type = Type.AUTOPILOT;
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
mode,
|
||||
type,
|
||||
};
|
||||
};
|
||||
|
||||
export const isValidGamemode = (gamemodeInt: number) => {
|
||||
return validModeTypeCombinations.includes(gamemodeInt);
|
||||
};
|
@@ -3,15 +3,18 @@ import { ezppfarm } from './api/ezpp';
|
||||
import type { Component } from 'svelte';
|
||||
import Loading from '../pages/Loading.svelte';
|
||||
|
||||
export const current_view = writable<Component>(Loading);
|
||||
export const first_startup = writable<boolean>(false);
|
||||
export const currentView = writable<Component>(Loading);
|
||||
|
||||
export const server_ping = writable<number | undefined>(undefined);
|
||||
export const server_connection_fails = writable(0);
|
||||
export const currentLoadingInfo = writable<string>('Initializing...');
|
||||
|
||||
export const online_friends = writable<number | undefined>(undefined);
|
||||
export const firstStartup = writable<boolean>(false);
|
||||
|
||||
export const beatmap_sets = writable<number | undefined>(undefined);
|
||||
export const serverPing = writable<number | undefined>(undefined);
|
||||
export const serverConnectionFails = writable(0);
|
||||
|
||||
export const onlineFriends = writable<number | undefined>(undefined);
|
||||
|
||||
export const beatmapSets = writable<number | undefined>(undefined);
|
||||
|
||||
export const setupValues = () => {
|
||||
updatePing();
|
||||
@@ -27,23 +30,19 @@ export const setupValues = () => {
|
||||
};
|
||||
|
||||
const updatePing = async () => {
|
||||
const serverPing = await ezppfarm.ping();
|
||||
if (!serverPing) {
|
||||
server_connection_fails.update((num) => num + 1);
|
||||
const currentServerPing = await ezppfarm.ping();
|
||||
if (!currentServerPing) {
|
||||
serverConnectionFails.update((num) => num + 1);
|
||||
} else {
|
||||
server_connection_fails.set(0);
|
||||
server_ping.set(serverPing);
|
||||
serverConnectionFails.set(0);
|
||||
serverPing.set(currentServerPing);
|
||||
}
|
||||
};
|
||||
|
||||
const updateFriends = async () => {
|
||||
await new Promise((res) => setTimeout(res, Math.random() * 300));
|
||||
const onlineFriends = Math.round(Math.random() * 10);
|
||||
online_friends.set(onlineFriends);
|
||||
const currentOnlineFriends = Math.round(Math.random() * 10);
|
||||
onlineFriends.set(currentOnlineFriends);
|
||||
};
|
||||
|
||||
const updateBeatmapSets = async () => {
|
||||
await new Promise((res) => setTimeout(res, Math.random() * 1500));
|
||||
const beatmapSets = Math.round(Math.random() * 5000);
|
||||
beatmap_sets.set(beatmapSets);
|
||||
};
|
||||
const updateBeatmapSets = async () => {};
|
||||
|
@@ -1,6 +1,97 @@
|
||||
export type EZPPUserResponse = {
|
||||
code: number;
|
||||
message: string;
|
||||
user?: EZPPUser;
|
||||
};
|
||||
|
||||
export type EZPPUser = {
|
||||
id: number;
|
||||
donor: boolean;
|
||||
name: string;
|
||||
email: string;
|
||||
};
|
||||
|
||||
export type EZPPUserInfoResponse = {
|
||||
status: string;
|
||||
player: EZPPUserInfo;
|
||||
};
|
||||
|
||||
export type EZPPUserInfo = {
|
||||
info: {
|
||||
id: number;
|
||||
name: string;
|
||||
safe_name: string;
|
||||
priv: number;
|
||||
country: string;
|
||||
silence_end: number;
|
||||
donor_end: number;
|
||||
creation_time: number;
|
||||
latest_activity: number;
|
||||
clan_id: number;
|
||||
clan_priv: number;
|
||||
preferred_mode: number;
|
||||
preferred_type: number;
|
||||
play_style: number;
|
||||
custom_badge_enabled: number;
|
||||
custom_badge_name: string;
|
||||
custom_badge_icon: string;
|
||||
custom_badge_color: string;
|
||||
userpage_content: string;
|
||||
recentFailed: number;
|
||||
social_discord: string;
|
||||
social_youtube: string;
|
||||
social_twitter: string;
|
||||
social_twitch: string;
|
||||
social_github: string;
|
||||
social_osu: string;
|
||||
clan: {
|
||||
id: number;
|
||||
name: string;
|
||||
tag: string;
|
||||
owner: number;
|
||||
created_at: Date;
|
||||
};
|
||||
username_history: string[];
|
||||
};
|
||||
stats: {
|
||||
[key: string]: {
|
||||
id: number;
|
||||
mode: number;
|
||||
tscore: number;
|
||||
rscore: number;
|
||||
pp: number;
|
||||
plays: number;
|
||||
playtime: number;
|
||||
acc: number;
|
||||
max_combo: number;
|
||||
total_hits: number;
|
||||
replay_views: number;
|
||||
xh_count: number;
|
||||
x_count: number;
|
||||
sh_count: number;
|
||||
s_count: number;
|
||||
a_count: number;
|
||||
level: number;
|
||||
level_progress: number;
|
||||
rank: number;
|
||||
country_rank: number;
|
||||
history: {
|
||||
pp: number[];
|
||||
};
|
||||
};
|
||||
};
|
||||
events: {
|
||||
userId: number;
|
||||
name: string;
|
||||
mapId: number;
|
||||
setId: number;
|
||||
artist: string;
|
||||
title: string;
|
||||
version: string;
|
||||
mode: number;
|
||||
rank: number;
|
||||
grade: string;
|
||||
event: 'GAINED' | 'LOST';
|
||||
time: Date;
|
||||
}[];
|
||||
};
|
||||
|
@@ -3,9 +3,12 @@ import { Config } from './config';
|
||||
|
||||
export const userSettings = writable<Config>(new Config('user_settings', false));
|
||||
|
||||
export const customCursor = writable<boolean>(true);
|
||||
export const cursorSmoothening = writable<boolean>(true);
|
||||
export const customCursor = writable<boolean>(false);
|
||||
export const cursorSmoothening = writable<boolean>(false);
|
||||
export const cursorSmoothness = writable<number>(180);
|
||||
export const reduceAnimations = writable<boolean>(false);
|
||||
|
||||
export const osuInstallationPath = writable<string>('');
|
||||
|
||||
export const preferredMode = writable<number>(0);
|
||||
export const preferredType = writable<number>(0);
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import { createAudioStore } from "@elron/svelte-audio-store";
|
||||
import { type ClassValue, clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { createAudioStore } from '@elron/svelte-audio-store';
|
||||
import { type ClassValue, clsx } from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
const sounds = {
|
||||
menuHeartbeat: "/audio/menuHeartbeat.mp3",
|
||||
menuBack: "/audio/menuBack.wav",
|
||||
menuHit: "/audio/menuHit.wav",
|
||||
menuHeartbeat: '/audio/menuHeartbeat.mp3',
|
||||
menuBack: '/audio/menuBack.wav',
|
||||
menuHit: '/audio/menuHit.wav',
|
||||
};
|
||||
|
||||
export const gameSounds = createAudioStore(sounds);
|
||||
@@ -23,3 +23,30 @@ export const playAudio = (path: string, volume: number) => {
|
||||
audio.volume = volume;
|
||||
audio.play();
|
||||
};
|
||||
|
||||
export const isNumber = (value: unknown) => {
|
||||
if (typeof value === 'number' || typeof value === 'string') {
|
||||
return value.toString().match(/^-?\d+(\.\d+)?$/) !== null;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export const formatTimeReadable = (initialSeconds: number) => {
|
||||
let seconds = initialSeconds;
|
||||
|
||||
const days = Math.floor(seconds / (24 * 3600));
|
||||
seconds -= days * 24 * 3600;
|
||||
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
seconds -= hours * 3600;
|
||||
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
|
||||
let result = '';
|
||||
|
||||
if (days > 0) result += `${days}d `;
|
||||
if (hours > 0) result += `${hours}h `;
|
||||
result += `${minutes}m`;
|
||||
|
||||
return result.trim();
|
||||
};
|
||||
|
Reference in New Issue
Block a user