feat: display music details
This commit is contained in:
@@ -11,4 +11,4 @@ pub fn level_name(level: u32) -> &'static str {
|
||||
}
|
||||
|
||||
mod music_db;
|
||||
pub use music_db::{Level, MUSIC_DB, MusicInfo};
|
||||
pub use music_db::{Level, MusicInfo, query_music, query_music_level, preload_db};
|
||||
|
||||
@@ -25,6 +25,22 @@ pub struct Level {
|
||||
|
||||
type MusicDB = FxHashMap<u32, MusicInfo>;
|
||||
|
||||
pub fn preload_db() {
|
||||
_ = &*MUSIC_DB;
|
||||
}
|
||||
|
||||
pub fn query_music(music_id: &u32) -> Option<&'static MusicInfo> {
|
||||
MUSIC_DB.as_ref()?.get(music_id)
|
||||
}
|
||||
pub fn query_music_level(music_id: u32, level: u32) -> Option<&'static Level> {
|
||||
MUSIC_DB
|
||||
.as_ref()?
|
||||
.get(&music_id)?
|
||||
.levels
|
||||
.iter()
|
||||
.find(|d| d.level == level)
|
||||
}
|
||||
|
||||
pub static MUSIC_DB: LazyLock<Option<MusicDB>> = LazyLock::new(|| {
|
||||
let time = SystemTime::now();
|
||||
info!("loading musicDB...");
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::helper::level_name;
|
||||
use crate::helper::query_music;
|
||||
use crate::helper::query_music_level;
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GetUserMusicApi {
|
||||
@@ -31,11 +37,78 @@ pub struct UserMusicDetail {
|
||||
pub music_id: u32,
|
||||
pub level: u32,
|
||||
pub play_count: i64,
|
||||
/// 达成率
|
||||
pub achievement: i64,
|
||||
|
||||
/// Full Combo
|
||||
///
|
||||
/// - 0: None
|
||||
/// - 1: Full Combo
|
||||
/// - 2: Full Combo+
|
||||
/// - 3: All Perfect
|
||||
/// - 4: All Perfect+
|
||||
pub combo_status: i64,
|
||||
|
||||
/// Full Sync
|
||||
///
|
||||
/// - 0: None
|
||||
/// - 1: FullSync
|
||||
/// - 2: FullSync+
|
||||
/// - 3: FullSync DX
|
||||
/// - 4: Full Sync DX+
|
||||
/// - 5: SYNC
|
||||
pub sync_status: i64,
|
||||
|
||||
pub deluxscore_max: i64,
|
||||
pub score_rank: i64,
|
||||
|
||||
pub ext_num1: i64,
|
||||
pub ext_num2: i64,
|
||||
}
|
||||
|
||||
impl Display for UserMusicDetail {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if let Some(music_title) = query_music(&self.music_id).map(|i| &i.name) {
|
||||
f.write_fmt(format_args!("曲目: \t{music_title}\n"))?;
|
||||
}
|
||||
f.write_fmt(format_args!("难度: \t{}\n", level_name(self.level)))?;
|
||||
f.write_fmt(format_args!(
|
||||
"达成率: \t{}.{:04}%\n",
|
||||
self.achievement / 10000,
|
||||
self.achievement % 10000
|
||||
))?;
|
||||
|
||||
f.write_fmt(format_args!(
|
||||
"达成状态: \t{}\n",
|
||||
match self.combo_status {
|
||||
0 => "无",
|
||||
1 => "Full Combo",
|
||||
2 => "Full Combo+",
|
||||
3 => "All Perfect",
|
||||
4 => "All Perfect+",
|
||||
_ => "未知",
|
||||
}
|
||||
))?;
|
||||
|
||||
f.write_fmt(format_args!(
|
||||
"同步状态: \t{}\n",
|
||||
match self.sync_status {
|
||||
0 => "无",
|
||||
1 => "Full Sync",
|
||||
2 => "Full Sync+",
|
||||
3 => "Full Sync DX",
|
||||
4 => "Full Sync DX+",
|
||||
_ => "未知",
|
||||
}
|
||||
))?;
|
||||
|
||||
f.write_fmt(format_args!("DX 分数: \t{}\n", self.deluxscore_max))?;
|
||||
|
||||
if let Some(level) = query_music_level(self.music_id, self.level) {
|
||||
let rating = level.dx_rating(self.achievement as _);
|
||||
f.write_fmt(format_args!("DX RATING: \t{rating}"))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
helper::MUSIC_DB,
|
||||
helper::query_music,
|
||||
title::model::get_user_rating_api::{
|
||||
MusicRating, UserRating,
|
||||
dxrating::{DxCalculatedEntries, DxLevelName, DxMusicRecord, DxSheetId},
|
||||
@@ -37,9 +37,7 @@ impl TryFrom<&MusicRating> for DxMusicRecord {
|
||||
type Error = ConversionError;
|
||||
|
||||
fn try_from(value: &MusicRating) -> Result<Self, Self::Error> {
|
||||
let music_title = MUSIC_DB
|
||||
.as_ref()
|
||||
.and_then(|db| db.get(&value.music_id))
|
||||
let music_title = query_music(&value.music_id)
|
||||
.map(|info| info.name.clone())
|
||||
.ok_or(ConversionError::MusicNotInDB)?;
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@ use std::fmt::Display;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::helper::MUSIC_DB;
|
||||
use crate::helper::level_name;
|
||||
use crate::helper::query_music;
|
||||
use crate::helper::query_music_level;
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -150,22 +151,11 @@ impl Display for MusicRating {
|
||||
|
||||
impl MusicRating {
|
||||
pub fn music_title(&self) -> Option<String> {
|
||||
MUSIC_DB
|
||||
.as_ref()?
|
||||
.get(&self.music_id)
|
||||
.map(|music_info| music_info.name.clone())
|
||||
Some(query_music(&self.music_id).as_ref()?.name.clone())
|
||||
}
|
||||
|
||||
pub fn dx_rating(&self) -> Option<u32> {
|
||||
Some(
|
||||
MUSIC_DB
|
||||
.as_ref()?
|
||||
.get(&self.music_id)?
|
||||
.levels
|
||||
.iter()
|
||||
.find(|d| d.level == self.level)?
|
||||
.dx_rating(self.achievement),
|
||||
)
|
||||
Some(query_music_level(self.music_id, self.level)?.dx_rating(self.achievement))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ use spdlog::{Level, LevelFilter::MoreSevereEqual, sink::StdStreamSink, terminal_
|
||||
use sdgb_api::{
|
||||
all_net::QRCode,
|
||||
auth_lite::{SDGB, SDHJ, delivery_raw},
|
||||
helper::MUSIC_DB,
|
||||
helper::preload_db,
|
||||
title::{
|
||||
MaiVersionExt, Sdgb1_50,
|
||||
methods::APIMethod,
|
||||
@@ -69,8 +69,6 @@ async fn main() -> Result<(), Box<dyn snafu::Error>> {
|
||||
}
|
||||
})?;
|
||||
|
||||
let _ = &*MUSIC_DB;
|
||||
|
||||
let Cli {
|
||||
command,
|
||||
machine_readable,
|
||||
@@ -78,6 +76,7 @@ async fn main() -> Result<(), Box<dyn snafu::Error>> {
|
||||
let human_readable = !machine_readable;
|
||||
|
||||
let client = ClientBuilder::default().build_async().await?;
|
||||
preload_db();
|
||||
|
||||
// TODO: refactor via enum_dispatch
|
||||
match command {
|
||||
@@ -112,9 +111,15 @@ async fn main() -> Result<(), Box<dyn snafu::Error>> {
|
||||
index = Some(next_index);
|
||||
}
|
||||
|
||||
// TODO: `Display` support for MusicDetail
|
||||
if human_readable {
|
||||
for detail in music_detail {
|
||||
println!("{detail}");
|
||||
println!("----------");
|
||||
}
|
||||
} else {
|
||||
json_display(music_detail)?;
|
||||
}
|
||||
}
|
||||
commands::Commands::Rating { user_id, format } => {
|
||||
let rating: GetUserRatingApiResp = Sdgb1_50::request(
|
||||
&client,
|
||||
|
||||
Reference in New Issue
Block a user