feat: add osu status to rpc
This commit is contained in:
@@ -1,4 +1,9 @@
|
||||
import type { EZPPUser, EZPPUserInfoResponse, EZPPUserResponse } from '@/types';
|
||||
import type {
|
||||
EZPPUser,
|
||||
EZPPUserInfoResponse,
|
||||
EZPPUserResponse,
|
||||
EZPPUSerStatusResponse,
|
||||
} from '@/types';
|
||||
import { betterFetch } from '@better-fetch/fetch';
|
||||
|
||||
const BANCHO_ENDPOINT = 'https://c.ez-pp.farm/';
|
||||
@@ -68,4 +73,20 @@ export const ezppfarm = {
|
||||
});
|
||||
return request.error ? undefined : request.data;
|
||||
},
|
||||
getUserStatus: async (userId: number) => {
|
||||
const request = await betterFetch<EZPPUSerStatusResponse>(
|
||||
`${API_ENDPOINT}v1/get_player_status`,
|
||||
{
|
||||
timeout,
|
||||
query: {
|
||||
id: userId,
|
||||
},
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': 'EZPPLauncher',
|
||||
},
|
||||
}
|
||||
);
|
||||
return request.error ? undefined : request.data;
|
||||
},
|
||||
};
|
||||
|
@@ -3,15 +3,15 @@ import { invoke } from '@tauri-apps/api/core';
|
||||
export const connect = async () => await invoke('presence_connect');
|
||||
export const disconnect = async () => await invoke('presence_disconnect');
|
||||
export const updateStatus = async (status: {
|
||||
state?: string;
|
||||
details?: string;
|
||||
large_image_key?: string;
|
||||
state?: string | null;
|
||||
details?: string | null;
|
||||
largeImageKey?: string;
|
||||
}) =>
|
||||
await invoke('presence_update_status', {
|
||||
state: status.state,
|
||||
details: status.details,
|
||||
largeImageKey: status.large_image_key,
|
||||
largeImageKey: status.largeImageKey,
|
||||
});
|
||||
export const updateUser = async (user: { username: string; id: string }) =>
|
||||
export const updateUser = async (user: { username: string; id?: string | null }) =>
|
||||
await invoke('presence_update_user', { username: user.username, id: user.id });
|
||||
export const isConnected = async () => await invoke<boolean>('presence_is_connected');
|
||||
|
@@ -185,3 +185,65 @@ export type Release = {
|
||||
browser_download_url: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type EZPPUSerStatusResponse = EZPPUserOfflineStatus | EZPPUserOnlineStatus;
|
||||
|
||||
type EZPPUserOfflineStatus = {
|
||||
status: string;
|
||||
player_status: {
|
||||
online: false;
|
||||
last_seen: number;
|
||||
};
|
||||
};
|
||||
|
||||
type EZPPUserOnlineStatus = {
|
||||
status: string;
|
||||
player_status: {
|
||||
online: true;
|
||||
login_time: number;
|
||||
status: {
|
||||
action: EZPPActionStatus;
|
||||
info_text: string;
|
||||
mode: number;
|
||||
mods: number;
|
||||
beatmap: EZPPUserBeatmapStatus | null;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
type EZPPUserBeatmapStatus = {
|
||||
md5: string;
|
||||
id: number;
|
||||
set_id: number;
|
||||
artist: string;
|
||||
title: string;
|
||||
version: string;
|
||||
creator: string;
|
||||
last_update: string;
|
||||
total_length: number;
|
||||
max_combo: number;
|
||||
status: number;
|
||||
plays: number;
|
||||
passes: number;
|
||||
mode: number;
|
||||
bpm: number;
|
||||
cs: number;
|
||||
od: number;
|
||||
ar: number;
|
||||
hp: number;
|
||||
diff: number;
|
||||
};
|
||||
|
||||
export enum EZPPActionStatus {
|
||||
AFK = 1,
|
||||
PLAYING = 2,
|
||||
EDITING = 3,
|
||||
MODDING = 4,
|
||||
MULTIPLAYER_SELECT = 5,
|
||||
WATCHING = 6,
|
||||
TESTING = 8,
|
||||
SUBMITTING = 9,
|
||||
MULTIPLAYER_IDLE = 11,
|
||||
MULTIPLAYER_PLAYING = 12,
|
||||
DIRECT = 13,
|
||||
}
|
||||
|
@@ -89,3 +89,14 @@ export const formatBytes = (bytes: number, decimals = 2) => {
|
||||
export const openURL = async (url: string) => {
|
||||
await invoke('open_url_in_browser', { url });
|
||||
};
|
||||
|
||||
export const urlIsValidImage = async (url: string) => {
|
||||
try {
|
||||
const request = await fetch(url);
|
||||
if (!request.ok) return false;
|
||||
const contentType = request.headers.get('content-type');
|
||||
return contentType?.startsWith('image/');
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
@@ -48,6 +48,7 @@
|
||||
numberHumanReadable,
|
||||
openURL,
|
||||
releaseStreamToReadable,
|
||||
urlIsValidImage,
|
||||
} from '@/utils';
|
||||
import { fade, scale } from 'svelte/transition';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
@@ -98,6 +99,8 @@
|
||||
import { getCurrentWindow } from '@tauri-apps/api/window';
|
||||
import { ezppfarm } from '@/api/ezpp';
|
||||
import Hearts from '@/components/ui/effects/Hearts.svelte';
|
||||
import { EZPPActionStatus } from '@/types';
|
||||
import * as presence from '@/presence';
|
||||
|
||||
let selectedTab = $state('home');
|
||||
let progress = $state(-1);
|
||||
@@ -315,7 +318,116 @@
|
||||
await replaceUIFiles(osuPath, false);
|
||||
await new Promise((res) => setTimeout(res, 1000));
|
||||
await getCurrentWindow().hide();
|
||||
|
||||
let presenceUpdater: number | undefined = undefined;
|
||||
|
||||
const isPresenceConnected = await presence.isConnected();
|
||||
|
||||
if ($discordPresence && isPresenceConnected) {
|
||||
let osuDetected = false;
|
||||
presenceUpdater = window.setInterval(async () => {
|
||||
if (!osuDetected) {
|
||||
const osuRunning = await isOsuRunning();
|
||||
if (osuRunning) osuDetected = true;
|
||||
return;
|
||||
}
|
||||
if ($currentUser) {
|
||||
const userStatus = await ezppfarm.getUserStatus($currentUser.id);
|
||||
if (userStatus?.player_status.online) {
|
||||
let largeImageKey = 'ezppfarm';
|
||||
let details = 'Idle...';
|
||||
let state =
|
||||
userStatus.player_status.status.info_text.length > 0
|
||||
? userStatus.player_status.status.info_text
|
||||
: ' ';
|
||||
let beatmapCover = false;
|
||||
const gamemode = getModeAndTypeFromGamemode(userStatus.player_status.status.mode);
|
||||
const gamemodeName = getGamemodeName(
|
||||
modeIntToStr(gamemode.mode),
|
||||
typeIntToStr(gamemode.type)
|
||||
);
|
||||
|
||||
switch (userStatus.player_status.status.action) {
|
||||
case EZPPActionStatus.AFK:
|
||||
details = 'AFK...';
|
||||
state = ' ';
|
||||
break;
|
||||
case EZPPActionStatus.PLAYING:
|
||||
details = 'Playing...';
|
||||
break;
|
||||
case EZPPActionStatus.EDITING:
|
||||
details = 'Editing...';
|
||||
break;
|
||||
case EZPPActionStatus.MODDING:
|
||||
details = 'Modding...';
|
||||
break;
|
||||
case EZPPActionStatus.MULTIPLAYER_SELECT:
|
||||
details = 'Multiplayer: Selecting a Beatmap...';
|
||||
state = ' ';
|
||||
break;
|
||||
case EZPPActionStatus.WATCHING:
|
||||
details = 'Watching...';
|
||||
break;
|
||||
case EZPPActionStatus.TESTING:
|
||||
details = 'Testing...';
|
||||
break;
|
||||
case EZPPActionStatus.SUBMITTING:
|
||||
details = 'Submitting...';
|
||||
break;
|
||||
case EZPPActionStatus.MULTIPLAYER_IDLE:
|
||||
details = 'Multiplayer: Idle...';
|
||||
state = ' ';
|
||||
break;
|
||||
case EZPPActionStatus.MULTIPLAYER_PLAYING:
|
||||
details = 'Multiplayer: Playing...';
|
||||
break;
|
||||
case EZPPActionStatus.DIRECT:
|
||||
details = 'Browsing osu!direct...';
|
||||
state = ' ';
|
||||
break;
|
||||
}
|
||||
|
||||
if (userStatus.player_status.status.beatmap !== null && beatmapCover) {
|
||||
const beatmapCoverImage = `https://assets.ppy.sh/beatmaps/${userStatus.player_status.status.beatmap.set_id}/covers/list@2x.jpg`;
|
||||
const isValidImage = await urlIsValidImage(beatmapCoverImage);
|
||||
if (isValidImage) largeImageKey = beatmapCoverImage;
|
||||
}
|
||||
|
||||
details = `[${gamemodeName}] ${details}`;
|
||||
|
||||
await Promise.all([
|
||||
presence.updateUser({
|
||||
username: $currentUser.name,
|
||||
id: $currentUser.id.toFixed(),
|
||||
}),
|
||||
presence.updateStatus({
|
||||
details,
|
||||
state,
|
||||
largeImageKey,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}, 1000 * 5);
|
||||
}
|
||||
|
||||
await runOsu(osuPath, true);
|
||||
|
||||
if (presenceUpdater) {
|
||||
window.clearInterval(presenceUpdater);
|
||||
await Promise.all([
|
||||
presence.updateUser({
|
||||
username: ' ',
|
||||
id: null,
|
||||
}),
|
||||
presence.updateStatus({
|
||||
details: null,
|
||||
state: 'Idle in Launcher...',
|
||||
largeImageKey: 'ezppfarm',
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
launchInfo = 'Cleaning up...';
|
||||
await getCurrentWindow().show();
|
||||
await new Promise((res) => setTimeout(res, 1000));
|
||||
|
@@ -109,14 +109,6 @@
|
||||
osuInstallationPath.set(config_osu_installation_path.get(''));
|
||||
discordPresence.set(config_discord_presence.get(true));
|
||||
|
||||
try {
|
||||
if ($discordPresence) {
|
||||
presenceLoading.set(true);
|
||||
await presence.connect();
|
||||
presenceLoading.set(false);
|
||||
}
|
||||
} catch {}
|
||||
|
||||
patch.subscribe((val) => config_patching.set(val));
|
||||
customCursor.subscribe((val) => config_custom_cursor.set(val));
|
||||
cursorSmoothening.subscribe((val) => config_cursor_smoothening.set(val));
|
||||
@@ -134,6 +126,15 @@
|
||||
} catch {}
|
||||
});
|
||||
|
||||
try {
|
||||
if ($discordPresence) {
|
||||
currentLoadingInfo.set('Connecting to Discord RPC...');
|
||||
presenceLoading.set(true);
|
||||
await presence.connect();
|
||||
presenceLoading.set(false);
|
||||
}
|
||||
} catch {}
|
||||
|
||||
firstStartup.set(isFirstStartup);
|
||||
});
|
||||
</script>
|
||||
|
Reference in New Issue
Block a user