chore: replace osynic_osudb with own osudb parser
This commit is contained in:
+19
-22
@@ -1,5 +1,4 @@
|
||||
use hardware_id::get_id;
|
||||
use osynic_osudb::entity::osu::osudb::OsuDB;
|
||||
use reqwest::Client;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
@@ -13,6 +12,7 @@ use tokio::io::AsyncWriteExt;
|
||||
use tokio::process::Command;
|
||||
use tokio::time::{Duration, sleep};
|
||||
|
||||
use crate::osudb::parse_osudb;
|
||||
use crate::presence;
|
||||
use crate::utils::{
|
||||
check_folder_completeness, encrypt_password, get_osu_config, get_osu_user_config,
|
||||
@@ -161,10 +161,10 @@ pub async fn get_beatmapsets_count(folder: String) -> Option<u64> {
|
||||
if !osu_db_path.exists() {
|
||||
return Some(0);
|
||||
}
|
||||
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);
|
||||
let osu_db_bytes = fs::read(osu_db_path).await.ok()?;
|
||||
let osu_db = parse_osudb(osu_db_bytes).ok()?;
|
||||
let beatmap_sets = osu_db.beatmaps.iter().map(|b| b.beatmapset_id).collect::<HashSet<_>>().len();
|
||||
Some(beatmap_sets as u64)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
@@ -620,28 +620,25 @@ pub fn replace_ui_files(folder: String, revert: bool) -> Result<(), ReplaceUIErr
|
||||
})?;
|
||||
}
|
||||
|
||||
std::fs::copy(source, dest).map_err(|e| {
|
||||
ReplaceUIError::IoError(format!("Failed to copy {}: {}", name, e))
|
||||
})?;
|
||||
std::fs::copy(source, dest)
|
||||
.map_err(|e| ReplaceUIError::IoError(format!("Failed to copy {}: {}", name, e)))?;
|
||||
Ok(())
|
||||
};
|
||||
|
||||
let restore_backup = |bak: &PathBuf,
|
||||
dest: &PathBuf,
|
||||
name: &str|
|
||||
-> Result<(), ReplaceUIError> {
|
||||
if bak.exists() {
|
||||
if dest.exists() {
|
||||
std::fs::remove_file(dest).map_err(|e| {
|
||||
ReplaceUIError::IoError(format!("Failed to remove {}: {}", name, e))
|
||||
let restore_backup =
|
||||
|bak: &PathBuf, dest: &PathBuf, name: &str| -> Result<(), ReplaceUIError> {
|
||||
if bak.exists() {
|
||||
if dest.exists() {
|
||||
std::fs::remove_file(dest).map_err(|e| {
|
||||
ReplaceUIError::IoError(format!("Failed to remove {}: {}", name, e))
|
||||
})?;
|
||||
}
|
||||
std::fs::rename(bak, dest).map_err(|e| {
|
||||
ReplaceUIError::IoError(format!("Failed to rename {} from backup: {}", name, e))
|
||||
})?;
|
||||
}
|
||||
std::fs::rename(bak, dest).map_err(|e| {
|
||||
ReplaceUIError::IoError(format!("Failed to rename {} from backup: {}", name, e))
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
Ok(())
|
||||
};
|
||||
|
||||
if !revert {
|
||||
if osu_ui.exists() && !osu_ui_bak.exists() {
|
||||
|
||||
@@ -4,6 +4,7 @@ use tauri::Manager;
|
||||
pub mod commands;
|
||||
pub mod presence;
|
||||
pub mod utils;
|
||||
pub mod osudb;
|
||||
use crate::commands::{
|
||||
check_for_corruption, download_ezpp_launcher_update, download_ezpp_launcher_update_files,
|
||||
encrypt_string, exit, find_osu_installation, get_beatmapsets_count,
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
use std::io::{Cursor, Read};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use byteorder::{LittleEndian, ReadBytesExt};
|
||||
|
||||
pub struct OsuReader {
|
||||
cursor: Cursor<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl OsuReader {
|
||||
pub fn new(data: Vec<u8>) -> Self {
|
||||
Self {
|
||||
cursor: Cursor::new(data),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_i16(&mut self) -> Result<i16> {
|
||||
Ok(self.cursor.read_i16::<LittleEndian>()?)
|
||||
}
|
||||
|
||||
fn read_i32(&mut self) -> Result<i32> {
|
||||
Ok(self.cursor.read_i32::<LittleEndian>()?)
|
||||
}
|
||||
|
||||
fn read_i64(&mut self) -> Result<i64> {
|
||||
Ok(self.cursor.read_i64::<LittleEndian>()?)
|
||||
}
|
||||
|
||||
fn read_u8(&mut self) -> Result<u8> {
|
||||
Ok(self.cursor.read_u8()?)
|
||||
}
|
||||
|
||||
fn read_f32(&mut self) -> Result<f32> {
|
||||
Ok(self.cursor.read_f32::<LittleEndian>()?)
|
||||
}
|
||||
|
||||
fn read_f64(&mut self) -> Result<f64> {
|
||||
Ok(self.cursor.read_f64::<LittleEndian>()?)
|
||||
}
|
||||
|
||||
fn read_bool(&mut self) -> Result<bool> {
|
||||
Ok(self.read_u8()? != 0)
|
||||
}
|
||||
|
||||
fn read_string(&mut self) -> Result<Option<String>> {
|
||||
let indicator = self.read_u8()?;
|
||||
|
||||
if indicator == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
if indicator != 0x0B {
|
||||
return Err(anyhow!("Invalid osu string indicator"));
|
||||
}
|
||||
|
||||
let len = self.read_uleb128()? as usize;
|
||||
let mut buf = vec![0; len];
|
||||
self.cursor.read_exact(&mut buf)?;
|
||||
|
||||
Ok(Some(String::from_utf8(buf)?))
|
||||
}
|
||||
|
||||
fn read_uleb128(&mut self) -> Result<u64> {
|
||||
let mut result = 0;
|
||||
let mut shift = 0;
|
||||
|
||||
loop {
|
||||
let byte = self.read_u8()?;
|
||||
result |= ((byte & 0x7F) as u64) << shift;
|
||||
|
||||
if (byte & 0x80) == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
shift += 7;
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TimingPoint {
|
||||
pub bpm: f64,
|
||||
pub offset: f64,
|
||||
pub inherited: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Beatmap {
|
||||
pub artist_name: Option<String>,
|
||||
pub song_title: Option<String>,
|
||||
pub difficulty: Option<String>,
|
||||
pub md5: Option<String>,
|
||||
|
||||
pub beatmap_id: i32,
|
||||
pub beatmapset_id: i32,
|
||||
pub mode: u8,
|
||||
|
||||
pub timing_points: Vec<TimingPoint>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OsuDbData {
|
||||
pub osuver: i32,
|
||||
pub folder_count: i32,
|
||||
pub is_unlocked: bool,
|
||||
pub date_unlock_ticks: i64,
|
||||
pub username: Option<String>,
|
||||
pub beatmaps: Vec<Beatmap>,
|
||||
pub userperms: i32,
|
||||
}
|
||||
|
||||
//
|
||||
// =========================
|
||||
// PARSER
|
||||
// =========================
|
||||
//
|
||||
|
||||
pub fn parse_osudb(bytes: Vec<u8>) -> Result<OsuDbData> {
|
||||
let mut reader = OsuReader::new(bytes);
|
||||
|
||||
let osuver = reader.read_i32()?;
|
||||
let folder_count = reader.read_i32()?;
|
||||
let is_unlocked = reader.read_bool()?;
|
||||
let date_unlock_ticks = reader.read_i64()?;
|
||||
let username = reader.read_string()?;
|
||||
let beatmaps_count = reader.read_i32()?;
|
||||
|
||||
let mut beatmaps = Vec::new();
|
||||
|
||||
for _ in 0..beatmaps_count {
|
||||
if osuver < 20191107 {
|
||||
reader.read_i32()?; // entry size
|
||||
}
|
||||
|
||||
let artist_name = reader.read_string()?;
|
||||
reader.read_string()?; // artist unicode
|
||||
let song_title = reader.read_string()?;
|
||||
reader.read_string()?; // title unicode
|
||||
reader.read_string()?; // creator
|
||||
let difficulty = reader.read_string()?;
|
||||
reader.read_string()?; // audio
|
||||
let md5 = reader.read_string()?;
|
||||
reader.read_string()?; // osu file name
|
||||
|
||||
reader.read_u8()?; // ranked
|
||||
reader.read_i16()?;
|
||||
reader.read_i16()?;
|
||||
reader.read_i16()?;
|
||||
reader.read_i64()?; // last modification
|
||||
|
||||
if osuver < 20140609 {
|
||||
reader.read_u8()?;
|
||||
reader.read_u8()?;
|
||||
reader.read_u8()?;
|
||||
reader.read_u8()?;
|
||||
} else {
|
||||
reader.read_f32()?;
|
||||
reader.read_f32()?;
|
||||
reader.read_f32()?;
|
||||
reader.read_f32()?;
|
||||
}
|
||||
|
||||
reader.read_f64()?; // slider velocity
|
||||
|
||||
for _ in 0..4 {
|
||||
let len = reader.read_i32()?;
|
||||
for _ in 0..len {
|
||||
reader.read_u8()?;
|
||||
reader.read_i32()?;
|
||||
reader.read_u8()?;
|
||||
if osuver > 20250107 {
|
||||
reader.read_f32()?;
|
||||
} else {
|
||||
reader.read_f64()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reader.read_i32()?; // drain
|
||||
reader.read_i32()?; // total
|
||||
reader.read_i32()?; // preview
|
||||
|
||||
let timing_len = reader.read_i32()?;
|
||||
let mut timing_points = Vec::new();
|
||||
for _ in 0..timing_len {
|
||||
timing_points.push(TimingPoint {
|
||||
bpm: reader.read_f64()?,
|
||||
offset: reader.read_f64()?,
|
||||
inherited: reader.read_bool()?,
|
||||
});
|
||||
}
|
||||
|
||||
let beatmap_id = reader.read_i32()?;
|
||||
let beatmapset_id = reader.read_i32()?;
|
||||
reader.read_i32()?; // thread id
|
||||
|
||||
reader.read_u8()?;
|
||||
reader.read_u8()?;
|
||||
reader.read_u8()?;
|
||||
reader.read_u8()?;
|
||||
|
||||
reader.read_i16()?;
|
||||
reader.read_f32()?;
|
||||
|
||||
let mode = reader.read_u8()?;
|
||||
reader.read_string()?;
|
||||
reader.read_string()?;
|
||||
|
||||
reader.read_i16()?;
|
||||
reader.read_string()?;
|
||||
|
||||
reader.read_bool()?;
|
||||
reader.read_i64()?;
|
||||
reader.read_bool()?;
|
||||
reader.read_string()?;
|
||||
reader.read_i64()?;
|
||||
|
||||
reader.read_bool()?;
|
||||
reader.read_bool()?;
|
||||
reader.read_bool()?;
|
||||
reader.read_bool()?;
|
||||
reader.read_bool()?;
|
||||
|
||||
if osuver < 20140609 {
|
||||
reader.read_i16()?;
|
||||
}
|
||||
|
||||
reader.read_i32()?;
|
||||
reader.read_u8()?;
|
||||
|
||||
beatmaps.push(Beatmap {
|
||||
artist_name,
|
||||
song_title,
|
||||
difficulty,
|
||||
md5,
|
||||
beatmap_id,
|
||||
beatmapset_id,
|
||||
mode,
|
||||
timing_points,
|
||||
});
|
||||
}
|
||||
|
||||
let userperms = reader.read_i32()?;
|
||||
|
||||
Ok(OsuDbData {
|
||||
osuver,
|
||||
folder_count,
|
||||
is_unlocked,
|
||||
date_unlock_ticks,
|
||||
username,
|
||||
beatmaps,
|
||||
userperms,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user