Compare commits

...

9 Commits

11 changed files with 258 additions and 107 deletions
+29 -2
View File
@@ -19,7 +19,11 @@
"buffer": "^6.0.3",
"crypto-js": "^4.2.0",
"lucide-svelte": "^0.562.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-to-webcomponent": "^2.0.1",
"semver": "^7.7.2",
"sileo": "^0.1.3",
"svelte-confetti": "^2.3.2",
"tw-animate-css": "^1.3.8",
},
@@ -27,13 +31,14 @@
"@eslint/compat": "^2.0.0",
"@eslint/js": "^9.35.0",
"@iarna/toml": "2.2.5",
"@lucide/svelte": "^0.482.0",
"@lucide/svelte": "^0.562.0",
"@sveltejs/adapter-static": "^3.0.9",
"@sveltejs/kit": "^2.37.1",
"@sveltejs/vite-plugin-svelte": "^6.1.4",
"@tauri-apps/cli": "^2.9.6",
"@types/bun": "^1.2.21",
"@types/crypto-js": "^4.2.2",
"@types/react-dom": "^19.2.3",
"@types/semver": "^7.7.1",
"autoprefixer": "10.4.21",
"bits-ui": "^1.4.7",
@@ -174,7 +179,7 @@
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
"@lucide/svelte": ["@lucide/svelte@0.482.0", "", { "peerDependencies": { "svelte": "^5" } }, "sha512-n2ycHU9cNcleRDwwpEHBJ6pYzVhHIaL3a+9dQa8kns9hB2g05bY+v2p2KP8v0pZwtNhYTHk/F2o2uZ1bVtQGhw=="],
"@lucide/svelte": ["@lucide/svelte@0.562.0", "", { "peerDependencies": { "svelte": "^5" } }, "sha512-wDMULwtTFN2Sc/TFBm6gfuVCNb4Y5P9LDrwxNnUbV52+IEU7NXZmvxwXoz+vrrpad6Xupq+Hw5eUlqIHEGhouw=="],
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
@@ -214,6 +219,8 @@
"@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="],
"@r2wc/core": ["@r2wc/core@1.3.0", "", {}, "sha512-aPBnND92Itl+SWWbWyyxdFFF0+RqKB6dptGHEdiPB8ZvnHWHlVzOfEvbEcyUYGtB6HBdsfkVuBiaGYyBFVTzVQ=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.44.1", "", { "os": "android", "cpu": "arm" }, "sha512-JAcBr1+fgqx20m7Fwe1DxPUl/hPkee6jA6Pl7n1v2EFiktAHenTaXl5aIFjUIEsfn9w3HE4gK1lEgNGMzBDs1w=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.44.1", "", { "os": "android", "cpu": "arm64" }, "sha512-RurZetXqTu4p+G0ChbnkwBuAtwAbIwJkycw1n6GvlGlBuS4u5qlr5opix8cBAYFJgaY05TWtM+LaoFggUmbZEQ=="],
@@ -346,6 +353,8 @@
"@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="],
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
"@types/semver": ["@types/semver@7.7.1", "", {}, "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA=="],
"@types/umami": ["@types/umami@2.10.1", "", {}, "sha512-CvOEMq+BFOUXj8yciq4hPsdOt0o9KBg5jQXnF1FrdOMKZMxJiwryyZNLa9Ud2NVO6nXSwU22YMKR3E+Xhbo+DA=="],
@@ -506,6 +515,8 @@
"fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="],
"framer-motion": ["framer-motion@12.34.1", "", { "dependencies": { "motion-dom": "^12.34.1", "motion-utils": "^12.29.2", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-kcZyNaYQfvE2LlH6+AyOaJAQV4rGp5XbzfhsZpiSZcwDMfZUHhuxLWeyRzf5I7jip3qKRpuimPA9pXXfr111kQ=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
@@ -610,6 +621,12 @@
"mode-watcher": ["mode-watcher@1.1.0", "", { "dependencies": { "runed": "^0.25.0", "svelte-toolbelt": "^0.7.1" }, "peerDependencies": { "svelte": "^5.27.0" } }, "sha512-mUT9RRGPDYenk59qJauN1rhsIMKBmWA3xMF+uRwE8MW/tjhaDSCCARqkSuDTq8vr4/2KcAxIGVjACxTjdk5C3g=="],
"motion": ["motion@12.34.1", "", { "dependencies": { "framer-motion": "^12.34.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-N9RVNGn/NSo85OgHX1wGaUWHvReuQ7dZUwuQRhHyzY2wfVOvY3cEgn0Mw4NXOsXMHL/y7EYuzA+b59PYI6EejA=="],
"motion-dom": ["motion-dom@12.34.1", "", { "dependencies": { "motion-utils": "^12.29.2" } }, "sha512-SC7ZC5dRcGwku2g7EsPvI4q/EzHumUbqsDNumBmZTLFg+goBO5LTJvDu9MAxx+0mtX4IA78B2be/A3aRjY0jnw=="],
"motion-utils": ["motion-utils@12.29.2", "", {}, "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A=="],
"mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="],
"mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
@@ -666,6 +683,12 @@
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
"react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="],
"react-to-webcomponent": ["react-to-webcomponent@2.0.1", "", { "dependencies": { "@r2wc/core": "^1.0.0" }, "peerDependencies": { "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-jpVztcA0SbV6TnBRV6EFuU+hmuuSIxgEww3wRcbneT0ytqn57y9ygeRfUmhzz8+bYg53u1h4COKk8iAextHE+Q=="],
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
@@ -722,6 +745,8 @@
"sass-embedded-win32-x64": ["sass-embedded-win32-x64@1.92.1", "", { "os": "win32", "cpu": "x64" }, "sha512-B6Nz/GbH7Vkpb2TkQHsGcczWM5t+70VWopWF1x5V5yxLpA8ZzVQ7NTKKi+jDoVY2Efu6ZyzgT9n5KgG2kWliXA=="],
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
"semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
"set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="],
@@ -730,6 +755,8 @@
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
"sileo": ["sileo@0.1.3", "", { "dependencies": { "motion": "^12.34.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-kmGjM2ts2TpuPzOaD7llxcMpU37Pyj5dO8s4wGXvDlR143zV2sB6sJ76PCVP4kY2+hfkrLJhiSm/wXGdUHDFjQ=="],
"sirv": ["sirv@3.0.1", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
+5
View File
@@ -33,7 +33,11 @@
"buffer": "^6.0.3",
"crypto-js": "^4.2.0",
"lucide-svelte": "^0.562.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-to-webcomponent": "^2.0.1",
"semver": "^7.7.2",
"sileo": "^0.1.3",
"svelte-confetti": "^2.3.2",
"tw-animate-css": "^1.3.8"
},
@@ -48,6 +52,7 @@
"@tauri-apps/cli": "^2.9.6",
"@types/bun": "^1.2.21",
"@types/crypto-js": "^4.2.2",
"@types/react-dom": "^19.2.3",
"@types/semver": "^7.7.1",
"autoprefixer": "10.4.21",
"bits-ui": "^1.4.7",
+34 -57
View File
@@ -56,17 +56,11 @@ pub fn valid_osu_folder(folder: String) -> bool {
"scores.db",
];
let folder_files: Vec<&str> = osu_folder_files.iter().map(|&s| s).collect();
if folder_files.iter().any(|&file| file == "osu!.exe") == false {
let path = PathBuf::from(folder);
if !path.join("osu!.exe").exists() {
return false;
}
let path = PathBuf::from(folder);
let match_percentage = check_folder_completeness(path, &osu_folder_files) >= 70.0;
if match_percentage {
return true;
}
return false;
check_folder_completeness(path, &osu_folder_files) >= 70.0
}
#[cfg(not(windows))]
@@ -160,7 +154,7 @@ pub fn find_osu_installation() -> Option<String> {
}
#[tauri::command]
pub fn get_beatmapsets_count(folder: String) -> Option<u64> {
pub async fn get_beatmapsets_count(folder: String) -> Option<u64> {
let path = PathBuf::from(folder);
let osu_user_config = get_osu_user_config(path.clone());
let songs_path = osu_user_config
@@ -173,12 +167,12 @@ pub fn get_beatmapsets_count(folder: String) -> Option<u64> {
}
let mut count = 0;
if let Ok(entries) = std::fs::read_dir(songs_folder) {
for entry in entries.flatten() {
if entry.file_type().map_or(false, |ft| ft.is_dir()) {
if let Ok(mut entries) = fs::read_dir(songs_folder).await {
while let Ok(Some(entry)) = entries.next_entry().await {
if entry.file_type().await.map_or(false, |ft| ft.is_dir()) {
let dir_path = entry.path();
if let Ok(files) = std::fs::read_dir(&dir_path) {
for file in files.flatten() {
if let Ok(mut files) = fs::read_dir(&dir_path).await {
while let Ok(Some(file)) = files.next_entry().await {
if file.path().extension().map_or(false, |ext| ext == "osu") {
count += 1;
break;
@@ -192,7 +186,7 @@ pub fn get_beatmapsets_count(folder: String) -> Option<u64> {
}
#[tauri::command]
pub fn get_skins_count(folder: String) -> Option<u64> {
pub async fn get_skins_count(folder: String) -> Option<u64> {
let path = PathBuf::from(folder);
let skins_folder = path.join("Skins");
@@ -201,12 +195,12 @@ pub fn get_skins_count(folder: String) -> Option<u64> {
}
let mut count = 0;
if let Ok(entries) = std::fs::read_dir(skins_folder) {
for entry in entries.flatten() {
if entry.file_type().map_or(false, |ft| ft.is_dir()) {
if let Ok(mut entries) = fs::read_dir(skins_folder).await {
while let Ok(Some(entry)) = entries.next_entry().await {
if entry.file_type().await.map_or(false, |ft| ft.is_dir()) {
let dir_path = entry.path();
if let Ok(files) = std::fs::read_dir(&dir_path) {
for file in files.flatten() {
if let Ok(mut files) = fs::read_dir(&dir_path).await {
while let Ok(Some(file)) = files.next_entry().await {
if file.path().extension().map_or(false, |ext| ext == "ini") {
count += 1;
break;
@@ -222,28 +216,28 @@ pub fn get_skins_count(folder: String) -> Option<u64> {
#[tauri::command]
pub fn get_osu_skin(folder: String) -> String {
let path = PathBuf::from(folder);
let osu_user_config = get_osu_user_config(path.clone());
return osu_user_config
let osu_user_config = get_osu_user_config(path);
osu_user_config
.and_then(|config| config.get("Skin").cloned())
.unwrap_or_else(|| "Default".to_string());
.unwrap_or_else(|| "Default".to_string())
}
#[tauri::command]
pub fn get_osu_version(folder: String) -> String {
let path = PathBuf::from(folder);
let osu_user_config = get_osu_user_config(path.clone());
return osu_user_config
let osu_user_config = get_osu_user_config(path);
osu_user_config
.and_then(|config| config.get("LastVersion").cloned())
.unwrap_or_else(|| "failed".to_string());
.unwrap_or_else(|| "failed".to_string())
}
#[tauri::command]
pub fn get_osu_release_stream(folder: String) -> String {
let path = PathBuf::from(folder);
let osu_config = get_osu_config(path.clone());
return osu_config
let osu_config = get_osu_config(path);
osu_config
.and_then(|config| config.get("_ReleaseStream").cloned())
.unwrap_or_else(|| "Stable40".to_string());
.unwrap_or_else(|| "Stable40".to_string())
}
#[derive(serde::Deserialize)]
@@ -261,10 +255,7 @@ pub fn set_osu_user_config_values(
.iter()
.map(|entry| (entry.key.as_str(), Some(entry.value.as_str())))
.collect();
match set_osu_user_config_vals(&osu_folder_path, &converted) {
Ok(_) => Ok(true),
Err(_) => Ok(false),
}
Ok(set_osu_user_config_vals(&osu_folder_path, &converted).is_ok())
}
#[tauri::command]
@@ -276,22 +267,16 @@ pub fn set_osu_config_values(
.iter()
.map(|entry| (entry.key.as_str(), Some(entry.value.as_str())))
.collect();
match set_osu_config_vals(&osu_folder_path, &converted) {
Ok(_) => Ok(true),
Err(_) => Ok(false),
}
Ok(set_osu_config_vals(&osu_folder_path, &converted).is_ok())
}
#[tauri::command]
pub async fn run_osu_updater(folder: String) -> Result<(), String> {
#[cfg(windows)]
const DETACHED_PROCESS: u32 = 0x00000008;
#[cfg(windows)]
const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
let mut updater_process = {
#[cfg(windows)]
{
const DETACHED_PROCESS: u32 = 0x00000008;
const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
let osu_exe_path = PathBuf::from(&folder).join("osu!.exe");
Command::new(&osu_exe_path)
.arg("-repair")
@@ -368,9 +353,6 @@ pub async fn run_osu_updater(folder: String) -> Result<(), String> {
#[tauri::command]
pub async fn run_osu(folder: String, patch: bool) -> Result<(), String> {
/* #[cfg(windows)]
use std::os::windows::process::CommandExt; */
#[cfg(windows)]
const DETACHED_PROCESS: u32 = 0x00000008;
#[cfg(windows)]
@@ -385,7 +367,7 @@ pub async fn run_osu(folder: String, patch: bool) -> Result<(), String> {
.arg("ez-pp.farm")
.creation_flags(DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP)
.spawn()
.map_err(|e| format!("Failed to spawn updater: {}", e))?
.map_err(|e| format!("Failed to spawn osu: {}", e))?
}
#[cfg(not(windows))]
@@ -394,7 +376,7 @@ pub async fn run_osu(folder: String, patch: bool) -> Result<(), String> {
.arg("--devserver")
.arg("ez-pp.farm")
.spawn()
.map_err(|e| format!("Failed to spawn updater: {}", e))?
.map_err(|e| format!("Failed to spawn osu: {}", e))?
}
};
@@ -593,7 +575,7 @@ pub fn replace_ui_files(folder: String, revert: bool) -> Result<(), ReplaceUIErr
if !revert {
try_rename(&osu_ui, &osu_ui_bak)?;
try_rename(&ezpp_ui, &osu_ui)?;
try_rename(&osu_seasonal, &osu_seasonal_bak)?;
try_rename(&ezpp_seasonal, &osu_seasonal)?;
@@ -602,7 +584,7 @@ pub fn replace_ui_files(folder: String, revert: bool) -> Result<(), ReplaceUIErr
} else {
try_rename(&osu_ui, &ezpp_ui)?;
try_rename(&osu_ui_bak, &osu_ui)?;
try_rename(&osu_seasonal, &ezpp_seasonal)?;
try_rename(&osu_seasonal_bak, &osu_seasonal)?;
@@ -732,12 +714,7 @@ pub async fn has_net8() -> bool {
#[tauri::command]
pub fn encrypt_string(string: String, entropy: String) -> String {
let encrypted = encrypt_password(&string, &entropy);
match encrypted {
Ok(encrypted_vec) => encrypted_vec,
Err(_) => string,
}
encrypt_password(&string, &entropy).unwrap_or(string)
}
#[tauri::command]
@@ -773,7 +750,7 @@ pub async fn download_ezpp_launcher_update(app: AppHandle, url: String) -> Resul
UpdateStatus {
file_name: "Update".to_string(),
downloaded,
size: size,
size,
progress: ((downloaded as f64 / size as f64 * 100.0) * 100.0).trunc() / 100.0,
},
)
@@ -0,0 +1,21 @@
<script lang="ts">
import { createElement } from 'react'
import { createRoot } from 'react-dom/client'
import type { SileoOptions } from 'sileo'
let props: SileoOptions = $props()
let rootEl: HTMLElement
$effect(() => {
const root = createRoot(rootEl)
import('sileo').then(({ Toaster }) => {
const sileo = createElement(Toaster, { ...props })
root.render(sileo)
})
return () => root.unmount()
})
</script>
<div bind:this={rootEl}></div>
+1 -4
View File
@@ -44,8 +44,7 @@ export class Config {
this.encrypt && this.crypto ? this.crypto.decrypt(fileStream) : fileStream
) as Record<string, unknown>;
this.config = decryptedJSON;
} catch (err) {
console.log(err);
} catch {
this.config = {};
await this.save();
}
@@ -65,13 +64,11 @@ export class Config {
}
value(key: string) {
console.log('Accessing config key:', key, this.config[key]);
return {
set: <T>(val: T) => {
this.config[key] = val;
},
exists: () => {
console.log('Checking existence of key:', key, this.config[key] !== undefined);
return this.config[key] !== undefined;
},
get: <T>(fallback: T): T => {
-1
View File
@@ -8,7 +8,6 @@ export function estimateRefreshRate(): Promise<number> {
frames++;
if (now - last >= 1000) {
console.log(`Estimated Refresh Rate: ${frames - 2} FPS`);
resolve(frames - 2);
} else {
requestAnimationFrame(loop);
+1 -2
View File
@@ -3,7 +3,7 @@ import type { UpdateFile, UpdateStatus } from './types';
import { listen } from '@tauri-apps/api/event';
import { betterFetch } from '@better-fetch/fetch';
const updateUrl = 'https://next.ez-pp.farm/api/ezpplauncher';
const updateUrl = 'https://ez-pp.farm/api/ezpplauncher';
export const getHWID = async () => {
const hwid = await invoke('get_hwid');
@@ -82,7 +82,6 @@ export const getEZPPLauncherStreams = async () => {
if (!resp.error) {
return resp.data.streams;
}
return undefined;
};
-1
View File
@@ -44,7 +44,6 @@ export const formatTimeReadable = (initialSeconds: number) => {
};
export const releaseStreamToReadable = (releaseStream: string) => {
console.log(releaseStream.replaceAll(' ', '').toLowerCase());
if (releaseStream.replaceAll(' ', '').toLowerCase() === 'cuttingedge') return 'Cutting Edge';
return 'Stable';
};
+2 -2
View File
@@ -25,7 +25,7 @@
userSettings,
} from '@/userSettings';
import { Buffer } from 'buffer';
import { Toaster } from '@/components/ui/sonner';
import SileoToast from '@/components/ui/sileo/sileo-toast.svelte';
import { userAuth } from '@/userAuthentication';
import { encryptString, exit, getLauncherVersion, getPlatform } from '@/osuUtil';
import Button from '@/components/ui/button/button.svelte';
@@ -150,7 +150,7 @@
<OsuCursor smoothCursor={$cursorSmoothening} />
{/if}
<Toaster richColors closeButton theme="dark" position="top-right" />
<SileoToast position="top-center" fill="black" />
<Titlebar />
+115 -25
View File
@@ -64,7 +64,6 @@
} from '@/userSettings';
import Input from '@/components/ui/input/input.svelte';
import { open } from '@tauri-apps/plugin-dialog';
import { toast } from 'svelte-sonner';
import { currentUser, userAuth } from '@/userAuthentication';
import {
getGamemodeInt,
@@ -109,6 +108,7 @@
import DownloadButton from '@/components/ui/download-button/DownloadButton.svelte';
import { animate } from 'animejs';
import AnimatedBg from '@/components/ui/animated-bg/AnimatedBg.svelte';
import { sileo } from 'sileo';
let selectedView = $state('home');
let progress = $state(-1);
@@ -146,16 +146,28 @@
}
const validFolder = await isValidOsuFolder(selectedPath);
if (!validFolder) {
toast.error('Oops...', {
sileo.error({
title: 'Hmm...',
description:
'The selected folder is not a valid osu! installation folder. Please select the correct folder.',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
return;
}
osuInstallationPath.set(selectedPath);
$userSettings.value('osu_installation_path').set(selectedPath);
$userSettings.save();
toast.success('osu! installation path set successfully.');
sileo.success({
title: 'Yay!',
description: 'osu! installation path set successfully.',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
const beatmapSetCount: number | null = await getBeatmapSetsCount(selectedPath);
if (beatmapSetCount) beatmapSets.set(beatmapSetCount);
@@ -178,15 +190,25 @@
if ($trackingEnabled) umami.track('app_launch_osu');
const osuRunning = await isOsuRunning();
if (osuRunning) {
toast.error('Hold on a second!', {
sileo.error({
title: 'Hold on a second!',
description:
'osu! is currently running, please exit osu! before launching via EZPPLauncher!',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
return;
}
if (!$osuBuild) {
toast.error('Hmmm...', {
sileo.error({
title: 'Hmmm...',
description: 'There was an issue detecting your installed osu! version',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
return;
}
@@ -197,8 +219,13 @@
const validFolder = await isValidOsuFolder(osuPath);
if (!validFolder) {
toast.error('Hmmm...', {
sileo.error({
title: 'Hmmm...',
description: 'Your selected osu! installation folder is not valid.',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
launching.set(false);
return;
@@ -206,15 +233,25 @@
if ($platform === 'linux') {
if (!(await hasWMCTRL())) {
toast.error('Hmmm...', {
sileo.error({
title: 'Hmmm...',
description: 'wmctrl seems to be missing, please install via AUR.',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
launching.set(false);
return;
}
if (!(await hasOsuWinello())) {
toast.error('Hmmm...', {
sileo.error({
title: 'Hmmm...',
description: 'osu-winello seems to be missing, please install it.',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
launching.set(false);
return;
@@ -249,7 +286,6 @@
}
}
} catch (err) {
console.log(err);
launchError = err as Error;
launching.set(false);
return;
@@ -258,8 +294,13 @@
try {
const streamInfo = await osuapi.latestBuildVersion('stable40');
if (!streamInfo) {
toast.error('Hmmm...', {
sileo.error({
title: 'Hmmm...',
description: 'Failed to check for updates, maybe osu! is down?',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
launching.set(false);
return;
@@ -268,8 +309,13 @@
const releaseStream = await getReleaseStream(osuPath);
if (releaseStream === undefined) {
toast.error('Hmmm...', {
sileo.error({
title: 'Hmmm...',
description: 'Failed to get osu! release stream.',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
launching.set(false);
return;
@@ -277,8 +323,13 @@
// only stable osu! release streams are supported for now
if (!releaseStream.toLowerCase().includes('stable')) {
toast.error('Hmmm...', {
sileo.error({
title: 'Hmmm...',
description: 'You are not on the stable release stream, please switch to it.',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
launching.set(false);
return;
@@ -487,7 +538,6 @@
await getCurrentWindow().show();
if (presenceUpdater) {
window.clearInterval(presenceUpdater);
console.log('clearing discord presence...');
try {
await Promise.all([
presence.updateUser({
@@ -501,7 +551,6 @@
}),
]);
} catch {}
console.log('discord presence cleared...');
}
await new Promise((res) => setTimeout(res, 1000));
await replaceUIFiles(osuPath, true);
@@ -531,8 +580,13 @@
cleanup = false;
const error = err as Error;
if (error.name === 'AbortError') {
toast.error('Hmmm...', {
sileo.error({
title: 'Hmmm...',
description: 'Failed to launch.',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
launching.set(false);
launchError = {
@@ -541,8 +595,13 @@
};
} else {
launchError = error;
toast.error('Hmmm...', {
sileo.error({
title: 'Hmmm...',
description: 'Failed to launch.',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
launching.set(false);
if ($trackingEnabled) umami.track('app_launch_fail', { error: err });
@@ -560,8 +619,13 @@
try {
const loginResult = await ezppfarm.login(username, password);
if (loginResult && loginResult.user) {
toast.success('Login successful!', {
sileo.success({
title: 'Login successful!',
description: `Welcome back, ${loginResult.user.name}!`,
fill: '#181825',
styles: {
description: 'text-center!',
},
});
$userAuth.value('username').set(username);
@@ -571,14 +635,24 @@
currentUser.set(loginResult.user);
selectedView = 'home';
} else {
toast.error('Login failed!', {
sileo.error({
title: 'Login failed!',
description: 'Please check your username and password.',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
loginIsLoading = false;
}
} catch {
toast.error('Server error occurred during login.', {
sileo.error({
title: 'Login failed!',
description: 'There was an issue connecting to the server. Please try again later.',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
loginIsLoading = false;
}
@@ -706,8 +780,13 @@
onclick={async () => {
const updateFile = $newVersion?.assets.find((asset) => asset.name.endsWith('.exe'));
if (!updateFile) {
toast.error('Hmmm...', {
sileo.error({
title: 'Hmmm...',
description: 'No update file found.',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
$newVersion = undefined;
return;
@@ -836,8 +915,13 @@
$userAuth.value('username').del();
$userAuth.value('password').del();
await $userAuth.save();
toast.success('Logout successful!', {
sileo.success({
title: 'Logout successful!',
description: 'See you soon!',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
currentUser.set(undefined);
currentUserInfo.set(undefined);
@@ -1289,11 +1373,17 @@
bind:value={$launcherStream}
onValueChange={async (newStream) => {
const isNet8Installed = await hasNet8();
if (newStream === 'experimental' && !isNet8Installed) {
if (!isNet8Installed) {
launcherStream.set('stable');
toast.error('.NET 8.0 Desktop Runtime not found!', {
action: {
label: 'Download .NET 8.0',
sileo.error({
title: 'Hmm...',
description: '.NET 8.0 Desktop Runtime not found!',
fill: '#181825',
styles: {
description: 'text-center!',
},
button: {
title: 'Download .NET 8.0',
onClick: async () =>
await openURL(
'https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-8.0.22-windows-x64-installer'
+50 -13
View File
@@ -28,7 +28,6 @@
import Launch from './Launch.svelte';
import { currentUser, userAuth } from '@/userAuthentication';
import { ezppfarm } from '@/api/ezpp';
import { toast } from 'svelte-sonner';
import { currentUserInfo } from '@/data';
import {
getBeatmapSetsCount,
@@ -40,6 +39,8 @@
isValidOsuFolder,
} from '@/osuUtil';
import { git } from '@/api/git';
import { sileo } from 'sileo';
import type { EZPPUser } from '@/types';
let ezppLogo: HTMLImageElement;
let spinnerCircle: SVGCircleElement;
@@ -84,25 +85,32 @@
const username = $userAuth.value('username').get('');
const password = $userAuth.value('password').get('');
if (username.length > 0 && password.length > 0) {
const shouldLogin = username.length > 0 && password.length > 0;
let userLoginResult: { message: string; user?: EZPPUser } = {
message: 'An unknown error occured!',
};
if (shouldLogin) {
currentLoadingInfo.set('Logging in...');
try {
const loginResult = await ezppfarm.login(username, password);
if (loginResult && loginResult.user) {
toast.success('Login successful!', {
description: `Welcome back, ${loginResult.user.name}!`,
});
userLoginResult = {
message: `Welcome back, ${loginResult.user.name}!`,
user: loginResult.user,
};
currentUser.set(loginResult.user);
} else {
toast.error('Login failed!', {
description: 'Please check your username and password.',
});
userLoginResult = {
message: 'Please check your username and password.',
};
}
} catch {
toast.error('Server error occurred during login.', {
description: 'There was an issue connecting to the server. Please try again later.',
});
userLoginResult = {
message: 'There was an issue connecting to the server. Please try again later.',
};
}
}
if ($currentUser) {
@@ -123,8 +131,13 @@
osuInstallationPath.set('');
$userSettings.value('osu_installation_path').del();
await $userSettings.save();
toast.error('Oops...', {
sileo.error({
title: 'Hmm...',
description: 'Your previously set osu! installation path seems to be invalid.',
fill: '#181825',
styles: {
description: 'text-center!',
},
});
} else {
currentLoadingInfo.set('Getting osu version...');
@@ -174,7 +187,31 @@
});
setTimeout(() => {
if ($firstStartup) currentView.set(SetupWizard);
else currentView.set(Launch);
else {
currentView.set(Launch);
if (shouldLogin) {
if (userLoginResult.user) {
sileo.success({
title: 'Login successful!',
description: userLoginResult.message,
fill: '#181825',
styles: {
description: 'text-center!',
},
duration: 2500,
});
} else {
sileo.error({
title: 'Login failed!',
description: userLoginResult.message,
fill: '#181825',
styles: {
description: 'text-center!',
},
});
}
}
}
}, 250);
};