chore: add file downloading for ezpplauncher files, add ui replacement
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { exists, mkdir, readTextFile, writeFile } from '@tauri-apps/plugin-fs';
|
||||
import * as path from '@tauri-apps/api/path';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { Crypto } from './crypto';
|
||||
import { getHWID } from './osuUtil';
|
||||
|
||||
export class Config {
|
||||
private fileName: string;
|
||||
@@ -16,7 +16,7 @@ export class Config {
|
||||
}
|
||||
|
||||
async init(): Promise<boolean> {
|
||||
const hwid: string = (await invoke('get_hwid')) ?? 'recorderinsandybridge';
|
||||
const hwid = (await getHWID()) ?? 'recorderinsandybridge';
|
||||
|
||||
this.crypto = new Crypto(hwid);
|
||||
|
||||
|
@@ -1,4 +1,23 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { UpdateFile, UpdateStatus } from './types';
|
||||
import { listen } from '@tauri-apps/api/event';
|
||||
|
||||
const updateUrl = 'https://ez-pp.farm/ezpplauncher';
|
||||
|
||||
export const getHWID = async () => {
|
||||
const hwid = await invoke('get_hwid');
|
||||
return typeof hwid === 'string' ? hwid : undefined;
|
||||
};
|
||||
|
||||
export const isValidOsuFolder = async (folder: string): Promise<boolean> => {
|
||||
const result = await invoke('valid_osu_folder', { folder });
|
||||
return typeof result === 'boolean' ? result : false;
|
||||
};
|
||||
|
||||
export const autoDetectOsuInstallFolder = async () => {
|
||||
const result = await invoke('find_osu_installation');
|
||||
return typeof result === 'string' ? result : undefined;
|
||||
};
|
||||
|
||||
export const setUserConfigValues = async (
|
||||
osuFolderPath: string,
|
||||
@@ -22,3 +41,71 @@ export const getReleaseStream = async (folder: string) => {
|
||||
const result = await invoke('get_osu_release_stream', { folder });
|
||||
return typeof result === 'string' ? result : undefined;
|
||||
};
|
||||
|
||||
export const getVersion = async (folder: string) => {
|
||||
const result = await invoke('get_osu_version', { folder });
|
||||
return typeof result === 'string' ? result : undefined;
|
||||
};
|
||||
|
||||
export const getBeatmapSetsCount = async (folder: string) => {
|
||||
const result = await invoke('get_beatmapsets_count', {
|
||||
folder,
|
||||
});
|
||||
return typeof result === 'number' ? result : 0;
|
||||
};
|
||||
|
||||
export const getSkinsCount = async (folder: string) => {
|
||||
const result = await invoke('get_skins_count', {
|
||||
folder,
|
||||
});
|
||||
return typeof result === 'number' ? result : 0;
|
||||
};
|
||||
|
||||
export const getSkin = async (folder: string) => {
|
||||
const result = await invoke('get_osu_skin', {
|
||||
folder,
|
||||
});
|
||||
|
||||
return typeof result === 'string' ? result : 'Default';
|
||||
};
|
||||
|
||||
export const runUpdater = async (folder: string) => await invoke('run_osu_updater', { folder });
|
||||
export const runOsu = async (folder: string) => await invoke('run_osu', { folder });
|
||||
|
||||
export const getEZPPLauncherUpdateFiles = async (folder: string) => {
|
||||
const result = await invoke('get_ezpp_launcher_update_files', { folder, updateUrl });
|
||||
if (typeof result === 'object') {
|
||||
const [filesToDownload, updateFiles] = result as [UpdateFile[], UpdateFile[]];
|
||||
return {
|
||||
filesToDownload,
|
||||
updateFiles,
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const downloadEZPPLauncherUpdateFiles = async (
|
||||
folder: string,
|
||||
updateFiles: UpdateFile[],
|
||||
allFiles: UpdateFile[],
|
||||
progressCallback: (file: UpdateStatus) => void
|
||||
) => {
|
||||
const downloadStatusListen = await listen('download-progress', (event) =>
|
||||
progressCallback(event.payload as UpdateStatus)
|
||||
);
|
||||
try {
|
||||
await invoke('download_ezpp_launcher_update_files', { folder, updateFiles, allFiles });
|
||||
} finally {
|
||||
downloadStatusListen();
|
||||
}
|
||||
};
|
||||
|
||||
export const replaceUIFiles = async (folder: string, revert: boolean) => {
|
||||
await invoke('replace_ui_files', { folder, revert });
|
||||
};
|
||||
|
||||
export const isOsuRunning = async () => {
|
||||
const result = await invoke('is_osu_running');
|
||||
return typeof result === 'boolean' ? result : false;
|
||||
};
|
||||
|
@@ -119,3 +119,18 @@ export type StreamsResult = {
|
||||
user_count: number;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type UpdateFile = {
|
||||
folder: string;
|
||||
md5: string;
|
||||
name: string;
|
||||
size: number;
|
||||
url: string;
|
||||
};
|
||||
|
||||
export type UpdateStatus = {
|
||||
fileName: string;
|
||||
downloaded: number;
|
||||
size: number;
|
||||
progress: number;
|
||||
};
|
||||
|
@@ -81,3 +81,15 @@ export const compareBuildNumbers = (current: string, target: string): number =>
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
export const formatBytes = (bytes: number, decimals = 2) => {
|
||||
if (!bytes) return '0 B';
|
||||
|
||||
const k = 1024;
|
||||
const dm = decimals < 0 ? 0 : decimals;
|
||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))}${sizes[i]}`;
|
||||
};
|
||||
|
@@ -37,6 +37,7 @@
|
||||
import Progress from '@/components/ui/progress/progress.svelte';
|
||||
import {
|
||||
compareBuildNumbers,
|
||||
formatBytes,
|
||||
formatTimeReadable,
|
||||
numberHumanReadable,
|
||||
releaseStreamToReadable,
|
||||
@@ -55,7 +56,6 @@
|
||||
} from '@/userSettings';
|
||||
import Input from '@/components/ui/input/input.svelte';
|
||||
import { open } from '@tauri-apps/plugin-dialog';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import Login from './Login.svelte';
|
||||
import { currentUser, userAuth } from '@/userAuthentication';
|
||||
@@ -69,10 +69,26 @@
|
||||
} from '@/gamemode';
|
||||
import { currentUserInfo } from '@/data';
|
||||
import { osuapi } from '@/api/osuapi';
|
||||
import { getReleaseStream, setConfigValues, setUserConfigValues } from '@/osuUtil';
|
||||
import {
|
||||
downloadEZPPLauncherUpdateFiles,
|
||||
getBeatmapSetsCount,
|
||||
getEZPPLauncherUpdateFiles,
|
||||
getReleaseStream,
|
||||
getSkin,
|
||||
getSkinsCount,
|
||||
getVersion,
|
||||
isOsuRunning,
|
||||
isValidOsuFolder,
|
||||
replaceUIFiles,
|
||||
runOsu,
|
||||
runUpdater,
|
||||
setConfigValues,
|
||||
setUserConfigValues,
|
||||
} from '@/osuUtil';
|
||||
import { getCurrentWindow } from '@tauri-apps/api/window';
|
||||
|
||||
let selectedTab = $state('home');
|
||||
let progress = $state(-1);
|
||||
let launchInfo = $state('');
|
||||
|
||||
let selectedGamemode = $derived(
|
||||
@@ -96,7 +112,7 @@
|
||||
if (selectedPath === $osuInstallationPath) {
|
||||
return;
|
||||
}
|
||||
const validFolder: boolean = await invoke('valid_osu_folder', { folder: selectedPath });
|
||||
const validFolder = await isValidOsuFolder(selectedPath);
|
||||
if (!validFolder) {
|
||||
toast.error('Oops...', {
|
||||
description:
|
||||
@@ -109,27 +125,29 @@
|
||||
$userSettings.save();
|
||||
toast.success('osu! installation path set successfully.');
|
||||
|
||||
const beatmapSetCount: number | null = await invoke('get_beatmapsets_count', {
|
||||
folder: selectedPath,
|
||||
});
|
||||
const beatmapSetCount: number | null = await getBeatmapSetsCount(selectedPath);
|
||||
if (beatmapSetCount) {
|
||||
beatmapSets.set(beatmapSetCount);
|
||||
}
|
||||
|
||||
const skinsCount: number | null = await invoke('get_skins_count', {
|
||||
folder: selectedPath,
|
||||
});
|
||||
const skinsCount: number | null = await getSkinsCount(selectedPath);
|
||||
if (skinsCount) {
|
||||
skins.set(skinsCount);
|
||||
}
|
||||
const skin: string = await invoke('get_osu_skin', {
|
||||
folder: $osuInstallationPath,
|
||||
});
|
||||
const skin: string = await getSkin(selectedPath);
|
||||
currentSkin.set(skin);
|
||||
}
|
||||
};
|
||||
|
||||
const launch = async (offline: boolean) => {
|
||||
const osuRunning = await isOsuRunning();
|
||||
if (osuRunning) {
|
||||
toast.error('Hold on a second!', {
|
||||
description:
|
||||
'osu! is currently running, please exit osu! before launching via EZPPLauncher!',
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!$osuBuild) {
|
||||
toast.error('Hmmm...', {
|
||||
description: 'There was an issue detecting your installed osu! version',
|
||||
@@ -137,10 +155,11 @@
|
||||
return;
|
||||
}
|
||||
const osuPath = $osuInstallationPath;
|
||||
|
||||
launchInfo = 'Validating osu! installation...';
|
||||
launching.set(true);
|
||||
|
||||
const validFolder: boolean = await invoke('valid_osu_folder', { folder: osuPath });
|
||||
const validFolder = await isValidOsuFolder(osuPath);
|
||||
if (!validFolder) {
|
||||
toast.error('Hmmm...', {
|
||||
description: 'Your selected osu! installation folder is not valid.',
|
||||
@@ -149,6 +168,34 @@
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
launchInfo = 'Looking for EZPPLauncher File updates...';
|
||||
const updateResult = await getEZPPLauncherUpdateFiles(osuPath);
|
||||
if (updateResult) {
|
||||
if (updateResult.filesToDownload.length > 0) {
|
||||
launchInfo = 'Found EZPPLauncher File updates!';
|
||||
await new Promise((res) => setTimeout(res, 1000));
|
||||
await downloadEZPPLauncherUpdateFiles(
|
||||
osuPath,
|
||||
updateResult.filesToDownload,
|
||||
updateResult.updateFiles,
|
||||
(file) => {
|
||||
progress = file.progress;
|
||||
launchInfo = `Downloading ${file.fileName}(${formatBytes(
|
||||
file.downloaded
|
||||
)}/${formatBytes(file.size)})...`;
|
||||
}
|
||||
);
|
||||
progress = -1;
|
||||
} else {
|
||||
launchInfo = 'EZPPLauncher Files are up to date!';
|
||||
await new Promise((res) => setTimeout(res, 1500));
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
try {
|
||||
const streamInfo = await osuapi.latestBuildVersion('stable40');
|
||||
if (!streamInfo) {
|
||||
@@ -181,7 +228,7 @@
|
||||
]);
|
||||
osuStream.set('Stable40');
|
||||
osuBuild.set(`b${streamInfo}`);
|
||||
await invoke('run_osu_updater', { folder: osuPath });
|
||||
await runUpdater(osuPath);
|
||||
launchInfo = 'osu! is now up to date!';
|
||||
if (forceUpdate)
|
||||
await setConfigValues(osuPath, [
|
||||
@@ -246,34 +293,27 @@
|
||||
}
|
||||
await new Promise((res) => setTimeout(res, 1500));
|
||||
launchInfo = 'Launching osu!...';
|
||||
await replaceUIFiles(osuPath, false);
|
||||
await new Promise((res) => setTimeout(res, 1000));
|
||||
await getCurrentWindow().hide();
|
||||
await invoke('run_osu', { folder: osuPath });
|
||||
await runOsu(osuPath);
|
||||
launchInfo = 'Cleaning up...';
|
||||
await getCurrentWindow().show();
|
||||
await new Promise((res) => setTimeout(res, 1000));
|
||||
await replaceUIFiles(osuPath, true);
|
||||
|
||||
const osuReleaseStream: string = await invoke('get_osu_release_stream', {
|
||||
folder: osuPath,
|
||||
});
|
||||
const osuReleaseStream = await getReleaseStream(osuPath);
|
||||
osuStream.set(osuReleaseStream);
|
||||
const osuVersion: string = await invoke('get_osu_version', {
|
||||
folder: osuPath,
|
||||
});
|
||||
const osuVersion = await getVersion(osuPath);
|
||||
osuBuild.set(osuVersion);
|
||||
|
||||
const beatmapSetCount: number | null = await invoke('get_beatmapsets_count', {
|
||||
folder: osuPath,
|
||||
});
|
||||
const beatmapSetCount = await getBeatmapSetsCount(osuPath);
|
||||
if (beatmapSetCount) beatmapSets.set(beatmapSetCount);
|
||||
|
||||
const skinCount: number | null = await invoke('get_skins_count', {
|
||||
folder: osuPath,
|
||||
});
|
||||
const skinCount = await getSkinsCount(osuPath);
|
||||
if (skinCount) skins.set(skinCount);
|
||||
|
||||
const skin: string = await invoke('get_osu_skin', {
|
||||
folder: $osuInstallationPath,
|
||||
});
|
||||
const skin = await getSkin(osuPath);
|
||||
currentSkin.set(skin);
|
||||
|
||||
launching.set(false);
|
||||
@@ -300,7 +340,7 @@
|
||||
<span class="font-semibold text-xl">Launching...</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center justify-center gap-2 p-3 rounded-lg">
|
||||
<Progress indeterminate />
|
||||
<Progress indeterminate={progress === -1} value={progress} />
|
||||
<span class="text-muted-foreground">{launchInfo}</span>
|
||||
</div>
|
||||
</AlertDialog.Content>
|
||||
|
@@ -26,7 +26,14 @@
|
||||
import { ezppfarm } from '@/api/ezpp';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { currentUserInfo } from '@/data';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import {
|
||||
getBeatmapSetsCount,
|
||||
getReleaseStream,
|
||||
getSkin,
|
||||
getSkinsCount,
|
||||
getVersion,
|
||||
isValidOsuFolder,
|
||||
} from '@/osuUtil';
|
||||
|
||||
let ezppLogo: HTMLImageElement;
|
||||
let spinnerCircle: SVGCircleElement;
|
||||
@@ -105,9 +112,7 @@
|
||||
|
||||
if (!$firstStartup) {
|
||||
currentLoadingInfo.set('Checking osu installation path...');
|
||||
const validFolder: boolean = await invoke('valid_osu_folder', {
|
||||
folder: $osuInstallationPath,
|
||||
});
|
||||
const validFolder = await isValidOsuFolder($osuInstallationPath);
|
||||
if (!validFolder) {
|
||||
osuInstallationPath.set('');
|
||||
$userSettings.value('osu_installation_path').del();
|
||||
@@ -117,29 +122,19 @@
|
||||
});
|
||||
} else {
|
||||
currentLoadingInfo.set('Getting osu version...');
|
||||
const osuReleaseStream: string = await invoke('get_osu_release_stream', {
|
||||
folder: $osuInstallationPath,
|
||||
});
|
||||
const osuReleaseStream = await getReleaseStream($osuInstallationPath);
|
||||
osuStream.set(osuReleaseStream);
|
||||
const osuVersion: string = await invoke('get_osu_version', {
|
||||
folder: $osuInstallationPath,
|
||||
});
|
||||
const osuVersion = await getVersion($osuInstallationPath);
|
||||
osuBuild.set(osuVersion);
|
||||
|
||||
currentLoadingInfo.set('Counting beatmapsets...');
|
||||
const beatmapSetCount: number | null = await invoke('get_beatmapsets_count', {
|
||||
folder: $osuInstallationPath,
|
||||
});
|
||||
const beatmapSetCount = await getBeatmapSetsCount($osuInstallationPath);
|
||||
if (beatmapSetCount) beatmapSets.set(beatmapSetCount);
|
||||
|
||||
currentLoadingInfo.set('Counting skins...');
|
||||
const skinCount: number | null = await invoke('get_skins_count', {
|
||||
folder: $osuInstallationPath,
|
||||
});
|
||||
const skinCount = await getSkinsCount($osuInstallationPath);
|
||||
if (skinCount) skins.set(skinCount);
|
||||
const skin: string = await invoke('get_osu_skin', {
|
||||
folder: $osuInstallationPath,
|
||||
});
|
||||
const skin: string = await getSkin($osuInstallationPath);
|
||||
currentSkin.set(skin);
|
||||
}
|
||||
}
|
||||
|
@@ -4,8 +4,7 @@
|
||||
import Input from '@/components/ui/input/input.svelte';
|
||||
import { animate } from 'animejs';
|
||||
import { onMount } from 'svelte';
|
||||
import { fade, scale } from 'svelte/transition';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { Check, CheckCircle, CircleOff, Settings2 } from 'lucide-svelte';
|
||||
import { open } from '@tauri-apps/plugin-dialog';
|
||||
import Checkbox from '@/components/ui/checkbox/checkbox.svelte';
|
||||
@@ -20,6 +19,15 @@
|
||||
import { beatmapSets, currentSkin, currentView, osuBuild, osuStream, skins } from '@/global';
|
||||
import Launch from './Launch.svelte';
|
||||
import Confetti from 'svelte-confetti';
|
||||
import {
|
||||
autoDetectOsuInstallFolder,
|
||||
getBeatmapSetsCount,
|
||||
getReleaseStream,
|
||||
getSkin,
|
||||
getSkinsCount,
|
||||
getVersion,
|
||||
isValidOsuFolder,
|
||||
} from '@/osuUtil';
|
||||
|
||||
let selectedStep = $state(1);
|
||||
const steps = ['Welcome', 'Locate your osu! Installation', 'Appearance Settings'];
|
||||
@@ -60,7 +68,7 @@
|
||||
});
|
||||
|
||||
if (typeof selectedPath === 'string') {
|
||||
const validFolder: boolean = await invoke('valid_osu_folder', { folder: selectedPath });
|
||||
const validFolder = await isValidOsuFolder(selectedPath);
|
||||
manualSelect = true;
|
||||
if (!validFolder) {
|
||||
manualSelectValid = false;
|
||||
@@ -78,39 +86,29 @@
|
||||
await $userSettings.save();
|
||||
osuInstallationPath.set(osuInstallPath);
|
||||
|
||||
const beatmapSetCount: number | null = await invoke('get_beatmapsets_count', {
|
||||
folder: osuInstallPath,
|
||||
});
|
||||
const beatmapSetCount = await getBeatmapSetsCount(osuInstallPath);
|
||||
if (beatmapSetCount) {
|
||||
beatmapSets.set(beatmapSetCount);
|
||||
}
|
||||
|
||||
const skinsCount: number | null = await invoke('get_skins_count', {
|
||||
folder: osuInstallPath,
|
||||
});
|
||||
const skinsCount: number | null = await getSkinsCount(osuInstallPath);
|
||||
if (skinsCount) {
|
||||
skins.set(skinsCount);
|
||||
}
|
||||
|
||||
const skin: string = await invoke('get_osu_skin', {
|
||||
folder: $osuInstallationPath,
|
||||
});
|
||||
const skin: string = await getSkin(osuInstallPath);
|
||||
currentSkin.set(skin);
|
||||
|
||||
const osuReleaseStream: string = await invoke('get_osu_release_stream', {
|
||||
folder: $osuInstallationPath,
|
||||
});
|
||||
const osuReleaseStream = await getReleaseStream(osuInstallPath);
|
||||
osuStream.set(osuReleaseStream);
|
||||
const osuVersion: string = await invoke('get_osu_version', {
|
||||
folder: $osuInstallationPath,
|
||||
});
|
||||
const osuVersion = await getVersion(osuInstallPath);
|
||||
osuBuild.set(osuVersion);
|
||||
|
||||
currentView.set(Launch);
|
||||
};
|
||||
|
||||
onMount(async () => {
|
||||
const osuPath: string | null = await invoke('find_osu_installation');
|
||||
const osuPath = await autoDetectOsuInstallFolder();
|
||||
if (osuPath) {
|
||||
osuInstallPath = osuPath;
|
||||
autoDetectedOsuPath = true;
|
||||
|
Reference in New Issue
Block a user