feat: convert music detail to dxrating

This commit is contained in:
mokurin000
2025-08-02 10:03:02 +08:00
parent d337c48ff1
commit 9e17df0624
10 changed files with 96 additions and 36 deletions

View File

@@ -0,0 +1,99 @@
use crate::{
helper::query_music,
title::model::{
dxrating::{DxCalculatedEntries, DxLevelName, DxMusicRecord, DxSheetId},
get_user_music_api::UserMusicDetail,
get_user_rating_api::{MusicRating, UserRating},
},
};
impl DxCalculatedEntries {
pub fn from_user_rating_lossy(rating: &UserRating) -> DxCalculatedEntries {
let b35 = rating
.rating_list
.iter()
.map(DxMusicRecord::try_from)
.flatten()
.collect();
let b15 = rating
.new_rating_list
.iter()
.map(DxMusicRecord::try_from)
.flatten()
.collect();
DxCalculatedEntries { b35, b15 }
}
}
impl TryFrom<u32> for DxLevelName {
type Error = ConversionError;
fn try_from(level: u32) -> Result<Self, Self::Error> {
Self::from_repr(level).ok_or(ConversionError::UnknownDifficulty { level })
}
}
impl TryFrom<&UserMusicDetail> for DxMusicRecord {
type Error = ConversionError;
fn try_from(
&UserMusicDetail {
music_id,
level,
achievement,
..
}: &UserMusicDetail,
) -> 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,
})
}
}
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,
})
}
}
#[derive(Debug, snafu::Snafu)]
pub enum ConversionError {
#[snafu(display("Music was not found in database"))]
MusicNotInDB,
#[snafu(display("Utage difficulty was disallowed"))]
UtageDifficulty,
#[snafu(display("Unknown difficulty: {level}"))]
UnknownDifficulty { level: u32 },
}

View File

@@ -0,0 +1,95 @@
use serde::Serialize;
/// Full payload for image generate api
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DxRatingNet {
pub calculated_entries: DxCalculatedEntries,
pub version: DataVersion,
/// use `_generic`
pub region: &'static str,
}
/// Export/Import format
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DxCalculatedEntries {
pub b35: Vec<DxMusicRecord>,
pub b15: Vec<DxMusicRecord>,
}
/// full music record
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DxMusicRecord {
pub sheet_id: DxSheetId,
pub achievement_rate: f64,
}
#[derive(Debug, Clone, PartialEq)]
pub struct DxSheetId {
pub music_title: String,
pub dx_version: bool,
pub level: DxLevelName,
}
#[derive(Debug, Clone, Copy, PartialEq, strum::IntoStaticStr, strum::FromRepr)]
#[strum(serialize_all = "lowercase")]
#[repr(u32)]
pub enum DxLevelName {
Basic,
Advanced,
Expert,
Master,
ReMaster,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DataVersion {
Buddies,
BuddiesPlus,
Prism,
PrismPlus,
}
impl Serialize for DataVersion {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(match self {
DataVersion::Buddies => "BUDDiES",
DataVersion::BuddiesPlus => "BUDDiES PLUS",
DataVersion::Prism => "PRiSM",
DataVersion::PrismPlus => "PRiSM PLUS",
})
}
}
impl Serialize for DxSheetId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl ToString for DxSheetId {
fn to_string(&self) -> String {
let mut output = self.music_title.clone();
if self.dx_version {
output += "__dxrt__dx__dxrt__"
} else {
output += "__dxrt__std__dxrt__"
}
output += self.level.into();
output
}
}
mod conversion;