feat: convert music detail to dxrating
This commit is contained in:
@@ -58,7 +58,7 @@ impl QRCode<'_> {
|
|||||||
2 => Err(QRLoginError::QRCodeExpired10),
|
2 => Err(QRLoginError::QRCodeExpired10),
|
||||||
1 => Err(QRLoginError::QRCodeExpired30),
|
1 => Err(QRLoginError::QRCodeExpired30),
|
||||||
50 => Err(QRLoginError::BadSingature),
|
50 => Err(QRLoginError::BadSingature),
|
||||||
error_kind @ _ => Err(QRLoginError::Unknown { error_kind }),
|
error_kind => Err(QRLoginError::Unknown { error_kind }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ pub fn preload_db() {
|
|||||||
_ = &*MUSIC_DB;
|
_ = &*MUSIC_DB;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn query_music(music_id: &u32) -> Option<&'static MusicInfo> {
|
pub fn query_music(music_id: u32) -> Option<&'static MusicInfo> {
|
||||||
MUSIC_DB.as_ref()?.get(music_id)
|
MUSIC_DB.as_ref()?.get(&music_id)
|
||||||
}
|
}
|
||||||
pub fn query_music_level(music_id: u32, level: u32) -> Option<&'static Level> {
|
pub fn query_music_level(music_id: u32, level: u32) -> Option<&'static Level> {
|
||||||
MUSIC_DB
|
MUSIC_DB
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
helper::query_music,
|
helper::query_music,
|
||||||
title::model::get_user_rating_api::{
|
title::model::{
|
||||||
MusicRating, UserRating,
|
|
||||||
dxrating::{DxCalculatedEntries, DxLevelName, DxMusicRecord, DxSheetId},
|
dxrating::{DxCalculatedEntries, DxLevelName, DxMusicRecord, DxSheetId},
|
||||||
|
get_user_music_api::UserMusicDetail,
|
||||||
|
get_user_rating_api::{MusicRating, UserRating},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -33,21 +34,54 @@ impl TryFrom<u32> for DxLevelName {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&MusicRating> for DxMusicRecord {
|
impl TryFrom<&UserMusicDetail> for DxMusicRecord {
|
||||||
type Error = ConversionError;
|
type Error = ConversionError;
|
||||||
|
|
||||||
fn try_from(value: &MusicRating) -> Result<Self, Self::Error> {
|
fn try_from(
|
||||||
let music_title = query_music(&value.music_id)
|
&UserMusicDetail {
|
||||||
|
music_id,
|
||||||
|
level,
|
||||||
|
achievement,
|
||||||
|
..
|
||||||
|
}: &UserMusicDetail,
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
let music_title = query_music(music_id)
|
||||||
.map(|info| info.name.clone())
|
.map(|info| info.name.clone())
|
||||||
.ok_or(ConversionError::MusicNotInDB)?;
|
.ok_or(ConversionError::MusicNotInDB)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
sheet_id: DxSheetId {
|
sheet_id: DxSheetId {
|
||||||
music_title,
|
music_title,
|
||||||
level: DxLevelName::try_from(value.level)?,
|
level: DxLevelName::try_from(level)?,
|
||||||
dx_version: value.music_id >= 10000,
|
dx_version: music_id >= 10000,
|
||||||
},
|
},
|
||||||
achievement_rate: (value.achievement as f64) / 10000.0,
|
achievement_rate: (achievement as f64) / 10000.0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&MusicRating> for DxMusicRecord {
|
||||||
|
type Error = ConversionError;
|
||||||
|
|
||||||
|
fn try_from(
|
||||||
|
&MusicRating {
|
||||||
|
music_id,
|
||||||
|
level,
|
||||||
|
achievement,
|
||||||
|
..
|
||||||
|
}: &MusicRating,
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
let music_title = query_music(music_id)
|
||||||
|
.map(|info| info.name.clone())
|
||||||
|
.ok_or(ConversionError::MusicNotInDB)?;
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
sheet_id: DxSheetId {
|
||||||
|
music_title,
|
||||||
|
level: DxLevelName::try_from(level)?,
|
||||||
|
dx_version: music_id >= 10000,
|
||||||
|
},
|
||||||
|
achievement_rate: (achievement as f64) / 10000.0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@ pub struct UserMusicDetail {
|
|||||||
|
|
||||||
impl Display for UserMusicDetail {
|
impl Display for UserMusicDetail {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
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) {
|
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{music_title}\n"))?;
|
||||||
}
|
}
|
||||||
f.write_fmt(format_args!("难度名称: \t{}\n", level_name(self.level)))?;
|
f.write_fmt(format_args!("难度名称: \t{}\n", level_name(self.level)))?;
|
||||||
|
|||||||
@@ -151,12 +151,10 @@ impl Display for MusicRating {
|
|||||||
|
|
||||||
impl MusicRating {
|
impl MusicRating {
|
||||||
pub fn music_title(&self) -> Option<String> {
|
pub fn music_title(&self) -> Option<String> {
|
||||||
Some(query_music(&self.music_id).as_ref()?.name.clone())
|
Some(query_music(self.music_id).as_ref()?.name.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dx_rating(&self) -> Option<u32> {
|
pub fn dx_rating(&self) -> Option<u32> {
|
||||||
Some(query_music_level(self.music_id, self.level)?.dx_rating(self.achievement))
|
Some(query_music_level(self.music_id, self.level)?.dx_rating(self.achievement))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod dxrating;
|
|
||||||
|
|||||||
@@ -14,14 +14,6 @@ mod get_user_data_api;
|
|||||||
pub use get_user_data_api::{GetUserDataApi, GetUserDataApiResp, UserData};
|
pub use get_user_data_api::{GetUserDataApi, GetUserDataApiResp, UserData};
|
||||||
|
|
||||||
mod get_user_rating_api;
|
mod get_user_rating_api;
|
||||||
pub use get_user_rating_api::dxrating::{
|
|
||||||
DataVersion,
|
|
||||||
DxCalculatedEntries, // entries
|
|
||||||
DxLevelName, // level name
|
|
||||||
DxMusicRecord,
|
|
||||||
DxRatingNet,
|
|
||||||
DxSheetId,
|
|
||||||
};
|
|
||||||
pub use get_user_rating_api::{
|
pub use get_user_rating_api::{
|
||||||
GetUserRatingApi,
|
GetUserRatingApi,
|
||||||
GetUserRatingApiResp, // api
|
GetUserRatingApiResp, // api
|
||||||
@@ -32,3 +24,14 @@ pub use get_user_rating_api::{
|
|||||||
|
|
||||||
mod get_user_music_api;
|
mod get_user_music_api;
|
||||||
pub use get_user_music_api::{GetUserMusicApi, GetUserMusicApiResp, UserMusic};
|
pub use get_user_music_api::{GetUserMusicApi, GetUserMusicApiResp, UserMusic};
|
||||||
|
|
||||||
|
|
||||||
|
mod dxrating;
|
||||||
|
pub use dxrating::{
|
||||||
|
DataVersion,
|
||||||
|
DxCalculatedEntries, // entries
|
||||||
|
DxLevelName, // level name
|
||||||
|
DxMusicRecord,
|
||||||
|
DxRatingNet,
|
||||||
|
DxSheetId,
|
||||||
|
};
|
||||||
@@ -62,7 +62,7 @@ impl UserLoginApiResp {
|
|||||||
100 => Some(LoginError::AlreadyLogged),
|
100 => Some(LoginError::AlreadyLogged),
|
||||||
102 => Some(LoginError::QRCodeExpired),
|
102 => Some(LoginError::QRCodeExpired),
|
||||||
103 => Some(LoginError::AccountUnregistered),
|
103 => Some(LoginError::AccountUnregistered),
|
||||||
error @ _ => Some(LoginError::Unknown { error }),
|
error => Some(LoginError::Unknown { error }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,13 @@ pub enum Commands {
|
|||||||
MusicDetail {
|
MusicDetail {
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
user_id: u32,
|
user_id: u32,
|
||||||
|
|
||||||
|
/// JSON format.
|
||||||
|
///
|
||||||
|
/// - `origin`: official json response
|
||||||
|
/// - `dx_rating_net`: DxRatingNet Format
|
||||||
|
#[arg(short, long, default_value_t = RatingFormat::default())]
|
||||||
|
format: RatingFormat,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Retrieve full userdata
|
/// Retrieve full userdata
|
||||||
@@ -89,7 +96,7 @@ pub enum Commands {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, EnumString)]
|
#[derive(Debug, Default, EnumString)]
|
||||||
#[strum(serialize_all = "snake_case")]
|
#[strum(serialize_all = "snake_case")]
|
||||||
pub enum RatingFormat {
|
pub enum RatingFormat {
|
||||||
#[default]
|
#[default]
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ use sdgb_api::{
|
|||||||
MaiVersionExt, Sdgb1_50,
|
MaiVersionExt, Sdgb1_50,
|
||||||
methods::APIMethod,
|
methods::APIMethod,
|
||||||
model::{
|
model::{
|
||||||
DataVersion, DxCalculatedEntries, DxRatingNet, GetUserDataApi, GetUserDataApiResp,
|
DataVersion, DxCalculatedEntries, DxMusicRecord, DxRatingNet, GetUserDataApi,
|
||||||
GetUserMusicApi, GetUserMusicApiResp, GetUserPreviewApi, GetUserPreviewApiResp,
|
GetUserDataApiResp, GetUserMusicApi, GetUserMusicApiResp, GetUserPreviewApi,
|
||||||
GetUserRatingApi, GetUserRatingApiResp, Ping, PingResp, UserLogoutApi,
|
GetUserPreviewApiResp, GetUserRatingApi, GetUserRatingApiResp, Ping, PingResp,
|
||||||
UserLogoutApiResp,
|
UserLogoutApi, UserLogoutApiResp,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -80,7 +80,7 @@ async fn main() -> Result<(), Box<dyn snafu::Error>> {
|
|||||||
|
|
||||||
// TODO: refactor via enum_dispatch
|
// TODO: refactor via enum_dispatch
|
||||||
match command {
|
match command {
|
||||||
Commands::MusicDetail { user_id } => {
|
Commands::MusicDetail { user_id, format } => {
|
||||||
let mut music_detail = Vec::new();
|
let mut music_detail = Vec::new();
|
||||||
let mut index = None;
|
let mut index = None;
|
||||||
|
|
||||||
@@ -111,13 +111,31 @@ async fn main() -> Result<(), Box<dyn snafu::Error>> {
|
|||||||
index = Some(next_index);
|
index = Some(next_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if human_readable {
|
match (human_readable, format) {
|
||||||
for detail in music_detail {
|
(true, _) => {
|
||||||
println!("{detail}");
|
for detail in music_detail {
|
||||||
println!("----------");
|
println!("{detail}");
|
||||||
|
println!("----------");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(false, RatingFormat::Origin) => json_display(music_detail)?,
|
||||||
|
(false, RatingFormat::DxRatingNet) => {
|
||||||
|
let dx_export = Vec::from_iter(
|
||||||
|
music_detail
|
||||||
|
.iter()
|
||||||
|
.map(|music| {
|
||||||
|
DxMusicRecord::try_from(music).inspect_err(|e| {
|
||||||
|
warn!("failed to process {}: {e}", music.music_id)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.flatten(),
|
||||||
|
);
|
||||||
|
json_display(dx_export)?;
|
||||||
|
}
|
||||||
|
(_, format) => {
|
||||||
|
error!("{format:?} was not supported yet");
|
||||||
|
json_display(())?;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
json_display(music_detail)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Commands::Rating { user_id, format } => {
|
Commands::Rating { user_id, format } => {
|
||||||
|
|||||||
Reference in New Issue
Block a user