feat: implement full user music fetch

This commit is contained in:
mokurin000
2025-08-02 00:02:57 +08:00
parent 7b4dfbe5b2
commit f000b8636c
5 changed files with 95 additions and 6 deletions

View File

@@ -76,6 +76,7 @@ api_implement!([
"GetUserDataApi", "GetUserDataApi",
"GetUserPreviewApi", "GetUserPreviewApi",
"GetUserRatingApi", "GetUserRatingApi",
"GetUserMusicApi",
]); ]);
#[cfg(test)] #[cfg(test)]

View File

@@ -0,0 +1,41 @@
use serde::Deserialize;
use serde::Serialize;
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetUserMusicApi {
pub user_id: u32,
pub next_index: u32,
pub max_count: u32,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetUserMusicApiResp {
pub user_id: u32,
pub length: u32,
pub next_index: u32,
pub user_music_list: Vec<UserMusic>,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UserMusic {
pub user_music_detail_list: Vec<UserMusicDetail>,
pub length: u32,
}
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UserMusicDetail {
pub music_id: u32,
pub level: u32,
pub play_count: i64,
pub achievement: i64,
pub combo_status: i64,
pub sync_status: i64,
pub deluxscore_max: i64,
pub score_rank: i64,
pub ext_num1: i64,
pub ext_num2: i64,
}

View File

@@ -11,7 +11,7 @@ mod user_login_api;
pub use user_login_api::{LoginError, UserLoginApi, UserLoginApiResp}; pub use user_login_api::{LoginError, UserLoginApi, UserLoginApiResp};
mod get_user_data_api; mod get_user_data_api;
pub use get_user_data_api::{GetUserDataApi, GetUserDataApiResp}; 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::{ pub use get_user_rating_api::dxrating::{
@@ -22,4 +22,13 @@ pub use get_user_rating_api::dxrating::{
DxRatingNet, DxRatingNet,
DxSheetId, DxSheetId,
}; };
pub use get_user_rating_api::{GetUserRatingApi, GetUserRatingApiResp}; pub use get_user_rating_api::{
GetUserRatingApi,
GetUserRatingApiResp, // api
MusicRating,
Udemae,
UserRating,
};
mod get_user_music_api;
pub use get_user_music_api::{GetUserMusicApi, GetUserMusicApiResp, UserMusic};

View File

@@ -51,6 +51,10 @@ pub enum Commands {
#[arg(short, long, default_value_t = RatingFormat::default())] #[arg(short, long, default_value_t = RatingFormat::default())]
format: RatingFormat, format: RatingFormat,
}, },
MusicDetail {
#[arg(short, long)]
user_id: u32,
},
// below requires login // below requires login
Userdata { Userdata {

View File

@@ -16,8 +16,9 @@ use sdgb_api::{
methods::APIMethod, methods::APIMethod,
model::{ model::{
DataVersion, DxCalculatedEntries, DxRatingNet, GetUserDataApi, GetUserDataApiResp, DataVersion, DxCalculatedEntries, DxRatingNet, GetUserDataApi, GetUserDataApiResp,
GetUserPreviewApi, GetUserPreviewApiResp, GetUserRatingApi, GetUserRatingApiResp, Ping, GetUserMusicApi, GetUserMusicApiResp, GetUserPreviewApi, GetUserPreviewApiResp,
PingResp, UserLogoutApi, UserLogoutApiResp, GetUserRatingApi, GetUserRatingApiResp, Ping, PingResp, UserLogoutApi,
UserLogoutApiResp,
}, },
}, },
}; };
@@ -77,6 +78,40 @@ async fn main() -> Result<(), Box<dyn snafu::Error>> {
// TODO: refactor via enum_dispatch // TODO: refactor via enum_dispatch
match command { match command {
commands::Commands::MusicDetail { user_id } => {
let mut music_detail = Vec::new();
let mut index = None;
loop {
let GetUserMusicApiResp {
next_index,
mut user_music_list,
..
} = Sdgb1_50::request::<_, GetUserMusicApiResp>(
&client,
APIMethod::GetUserMusicApi,
user_id,
GetUserMusicApi {
user_id,
next_index: index.unwrap_or_default(),
max_count: 50,
},
)
.await?;
for list in &mut user_music_list {
music_detail.append(&mut list.user_music_detail_list);
}
if next_index == 0 || user_music_list.is_empty() {
break;
}
index = Some(next_index);
}
// TODO: `Display` support for MusicDetail
json_display(music_detail)?;
}
commands::Commands::Rating { user_id, format } => { commands::Commands::Rating { user_id, format } => {
let rating: GetUserRatingApiResp = Sdgb1_50::request( let rating: GetUserRatingApiResp = Sdgb1_50::request(
&client, &client,
@@ -269,8 +304,6 @@ async fn main() -> Result<(), Box<dyn snafu::Error>> {
#[cfg(file_lock_ready)] #[cfg(file_lock_ready)]
file.try_lock()?; file.try_lock()?;
let writer = BufWriter::new(file);
let txn = read_txn()?; let txn = read_txn()?;
let table = open_table_read(&txn)?; let table = open_table_read(&txn)?;
@@ -285,6 +318,7 @@ async fn main() -> Result<(), Box<dyn snafu::Error>> {
.map(|(value, _)| value) .map(|(value, _)| value)
.collect::<Vec<GetUserPreviewApiResp>>(); .collect::<Vec<GetUserPreviewApiResp>>();
let writer = BufWriter::new(file);
serde_json::to_writer(writer, &user_ids)?; serde_json::to_writer(writer, &user_ids)?;
info!("dumped {} user id", user_ids.len()); info!("dumped {} user id", user_ids.len());
} }