Compare commits

..

3 Commits

6 changed files with 63 additions and 143 deletions
+44
View File
@@ -475,8 +475,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
"serde",
"wasm-bindgen",
"windows-link 0.2.1",
]
@@ -995,6 +997,7 @@ dependencies = [
"md5",
"once_cell",
"open",
"osynic_osudb",
"reqwest",
"serde",
"serde_json",
@@ -2052,6 +2055,26 @@ dependencies = [
"winapi",
]
[[package]]
name = "liblzma"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6033b77c21d1f56deeae8014eb9fbe7bdf1765185a6c508b5ca82eeaed7f899"
dependencies = [
"liblzma-sys",
]
[[package]]
name = "liblzma-sys"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f2db66f3268487b5033077f266da6777d057949b8f93c8ad82e441df25e6186"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]]
name = "libredox"
version = "0.1.12"
@@ -2262,6 +2285,15 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "nom"
version = "8.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
dependencies = [
"memchr",
]
[[package]]
name = "ntapi"
version = "0.4.2"
@@ -2605,6 +2637,18 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "osynic_osudb"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d7f03567d97cdc0bf54380f0c525a00de1ce58ed9497f2409dfaf6112346b8a"
dependencies = [
"chrono",
"liblzma",
"nom",
"serde",
]
[[package]]
name = "pango"
version = "0.18.3"
+1
View File
@@ -35,6 +35,7 @@ open = "5.3.3"
discord-rich-presence = "1.1.0"
once_cell = "1.21.3"
futures-util = "0.3.32"
osynic_osudb = "0.1.4"
[target.'cfg(windows)'.dependencies]
winreg = "0.55.0"
+8 -26
View File
@@ -1,4 +1,5 @@
use hardware_id::get_id;
use osynic_osudb::entity::osu::osudb::OsuDB;
use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
@@ -156,33 +157,14 @@ pub fn find_osu_installation() -> Option<String> {
#[tauri::command]
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
.and_then(|config| config.get("Songs").cloned())
.unwrap_or_else(|| path.join("Songs").to_string_lossy().into_owned());
let songs_folder = PathBuf::from(songs_path);
if !songs_folder.exists() {
return None;
let osu_db_path = path.join("osu!.db");
if !osu_db_path.exists() {
return Some(0);
}
let mut count = 0;
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(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;
}
}
}
}
}
}
return Some(count);
let mut osudb = OsuDB::from_file(&osu_db_path).unwrap();
let beatmaps = osudb.beatmaps.iter_mut();
let beatmap_sets = beatmaps.map(|b| b.beatmapset_id).collect::<HashSet<_>>();
return Some(beatmap_sets.len() as u64);
}
#[derive(Serialize, Deserialize, Debug, Clone)]
@@ -24,7 +24,7 @@
<div class="relative flex items-center justify-center p-1 group" id="titlebar-minimize">
<div
class="absolute inset-0 bg-background rounded
scale-50 opacity-0
scale-80 opacity-0
group-hover:opacity-100
group-hover:scale-100
{$reduceAnimations ? '' : 'transition-all duration-200 ease-out'}
@@ -36,7 +36,7 @@
<div class="relative flex items-center justify-center p-1 group" id="titlebar-close">
<div
class="absolute inset-0 bg-red-500 rounded
scale-50 opacity-0
scale-80 opacity-0
group-hover:opacity-100
group-hover:scale-100
{$reduceAnimations ? '' : 'transition-all duration-200 ease-out'}
+4 -3
View File
@@ -174,14 +174,15 @@
audio.loop = true;
audio.volume = 0;
audio.play();
const fadeInVolume = 0.15;
const fadeInDuration = 2000; // 2 seconds
const fadeInSteps = 20;
const fadeInStepTime = fadeInDuration / fadeInSteps;
const volumeStep = (1 - audio.volume) / fadeInSteps;
const volumeStep = (fadeInVolume - audio.volume) / fadeInSteps;
const fadeInInterval = setInterval(() => {
if (audio.volume < 0.3) {
audio.volume = Math.min(0.3, audio.volume + volumeStep);
if (audio.volume < fadeInVolume) {
audio.volume = Math.min(fadeInVolume, audio.volume + volumeStep);
} else {
clearInterval(fadeInInterval);
}
+4 -112
View File
@@ -112,9 +112,6 @@
import DownloadButton from '@/components/ui/download-button/DownloadButton.svelte';
import { animate } from 'animejs';
import { sileo } from 'sileo';
import Check from '@lucide/svelte/icons/check';
import ScrollContainer from '@/components/ui/scroll-container/ScrollContainer.svelte';
import { sortSkins } from '@/sort';
let selectedView = $state('home');
let progress = $state(-1);
@@ -573,14 +570,15 @@
audio.play();
audio.volume = 0;
const fadeInVolume = 0.15;
const fadeInDuration = 2000; // 2 seconds
const fadeInSteps = 20;
const fadeInStepTime = fadeInDuration / fadeInSteps;
const volumeStep = (1 - audio.volume) / fadeInSteps;
const volumeStep = (fadeInVolume - audio.volume) / fadeInSteps;
const fadeInInterval = setInterval(() => {
if (audio.volume < 0.3) {
audio.volume = Math.min(0.3, audio.volume + volumeStep);
if (audio.volume < fadeInVolume) {
audio.volume = Math.min(fadeInVolume, audio.volume + volumeStep);
} else {
clearInterval(fadeInInterval);
}
@@ -945,18 +943,6 @@
>
<House class="text-theme-200 !size-5" />
</Button>
<Button
class="flex size-12 items-center gap-2 ring-1 ring-inset ring-white/15 {selectedView ===
'skins'
? 'bg-primary-300/50'
: 'bg-black/20 border-black/20'} hover:bg-primary-300/50 rounded-[0.85rem] p-3 mt-3"
disabled={$launching}
onclick={() => {
if (!$launching) selectedView = 'skins';
}}
>
<Paintbrush class="text-theme-200 !size-5" />
</Button>
<Button
class="flex size-12 items-center gap-2 ring-1 ring-inset ring-white/15 {selectedView ===
'settings'
@@ -1545,100 +1531,6 @@
</Button>
</form>
</div>
{:else if selectedView === 'skins'}
<div
class="h-[100vh] w-full flex flex-col items-center justify-center bg-black/20 backdrop-blur-sm"
in:fly={{
duration: $reduceAnimations ? 0 : 400,
delay: $reduceAnimations ? 0 : 400,
y: 5,
opacity: 0,
}}
out:fly={{ duration: $reduceAnimations ? 0 : 400, y: -5, opacity: 0 }}
>
{#if $skins.length > 0}
{@const skinsSorted = sortSkins($skins)}
<ScrollContainer
class="flex flex-col max-h-[100vh] overflow-y-auto items-center gap-4 p-16 w-full"
topOffset={35}
>
{#each skinsSorted as skin (skin.name)}
<div
class={`group w-full flex items-center border rounded-lg transition-all duration-150 ${
skin.name === $currentSkin
? 'bg-primary/20 border-primary/40'
: 'bg-black/40 border-black/60 hover:bg-black/70 hover:border-border'
}`}
>
<div class="flex-1 min-w-0 px-5 py-3.5">
<p class="text-sm text-foreground/90 truncate font-medium line-clamp-1">
{skin.name}
</p>
<div class="flex items-center gap-4 mt-1">
<span class="text-[11px] text-muted-foreground">
{skin.author || 'Unknown'}
</span>
<span class="text-[11px] text-muted-foreground/50">
{new Date(skin.modified * 1000).toLocaleDateString(undefined, {
year: '2-digit',
month: 'short',
day: 'numeric',
})}
</span>
</div>
</div>
<div
class="flex items-center gap-1.5 pr-3 opacity-0 group-hover:opacity-100 transition-opacity duration-150"
>
{#if $currentSkin !== skin.name}
<button
transition:fade={{
duration: 150,
}}
class="p-2 rounded-md text-muted-foreground hover:text-primary hover:bg-primary/10 transition-colors"
onclick={async () => {
if (skin.name === $currentSkin) return;
await setUserConfigValues($osuInstallationPath, [
{ key: 'Skin', value: skin.name },
]);
currentSkin.set(skin.name);
sileo.success({
title: 'Skin applied!',
description: `${skin.name} is now your active skin!`,
fill: '#181825',
styles: {
description: 'text-center!',
},
});
}}
>
<Check class="w-4 h-4" />
</button>
{/if}
<!-- <button
class="p-2 rounded-md transition-colors text-muted-foreground hover:text-destructive hover:bg-destructive/10"
>
<Trash2 class="w-4 h-4" />
</button> -->
</div>
</div>
{/each}
</ScrollContainer>
{:else}
<div class="flex flex-col items-center justify-center gap-4">
<FileQuestionMark class="size-12 text-muted-foreground" strokeWidth={1.5} />
<span class="text-sm text-muted-foreground">No skins found!</span>
</div>
{/if}
</div>
{/if}
</div>
</div>
<style lang="scss">
.custom-scrollbox {
scrollbar-color: #999 transparent;
scrollbar-width: 0px !important;
}
</style>