use chrono::{DateTime, Duration, Utc}; use std::fmt; pub mod deser; pub mod mods; pub(crate) mod raw; pub use mods::Mods; #[derive(Debug)] pub enum ApprovalStatus { Loved, Qualified, Approved, Ranked(DateTime), Pending, WIP, Graveyarded, } impl fmt::Display for ApprovalStatus { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if let ApprovalStatus::Ranked(ref d) = self { write!(f, "Ranked on {}", d.format("%F %T")) } else { write!(f, "{:?}", self) } } } #[derive(Debug)] pub struct Difficulty { pub stars: f64, pub aim: Option, pub speed: Option, pub cs: f64, pub od: f64, pub ar: f64, pub hp: f64, pub count_normal: u64, pub count_slider: u64, pub count_spinner: u64, pub max_combo: Option, } #[derive(Debug)] pub enum Genre { Any, Unspecified, VideoGame, Anime, Rock, Pop, Other, Novelty, HipHop, Electronic, } impl fmt::Display for Genre { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use Genre::*; match self { VideoGame => write!(f, "Video Game"), HipHop => write!(f, "Hip Hop"), v => write!(f, "{:?}", v), } } } #[derive(Debug)] pub enum Language { Any, Other, English, Japanese, Chinese, Instrumental, Korean, French, German, Swedish, Spanish, Italian, } impl fmt::Display for Language { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self) } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Mode { Std, Taiko, Catch, Mania, } impl fmt::Display for Mode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use Mode::*; write!( f, "{}", match self { Std => "osu!", Taiko => "osu!taiko", Mania => "osu!mania", Catch => "osu!catch", } ) } } #[derive(Debug)] pub struct Beatmap { // Beatmapset info pub approval: ApprovalStatus, pub submit_date: DateTime, pub last_update: DateTime, pub download_available: bool, pub audio_available: bool, // Media metadata pub artist: String, pub title: String, pub beatmapset_id: u64, pub bpm: f64, pub creator: String, pub creator_id: u64, pub source: Option, pub genre: Genre, pub language: Language, pub tags: Vec, // Beatmap information pub beatmap_id: u64, pub difficulty_name: String, pub difficulty: Difficulty, pub drain_length: Duration, pub total_length: Duration, pub file_hash: String, pub mode: Mode, pub favourite_count: u64, pub rating: f64, pub play_count: u64, pub pass_count: u64, } const NEW_MODE_NAMES: [&'static str; 4] = ["osu", "taiko", "fruits", "mania"]; impl Beatmap { /// Gets a link pointing to the beatmap, in the new format. pub fn link(&self) -> String { format!( "https://osu.ppy.sh/beatmapsets/{}#{}/{}", self.beatmapset_id, NEW_MODE_NAMES[self.mode as usize], self.beatmap_id ) } } #[derive(Debug)] pub struct UserEvent { pub display_html: String, pub beatmap_id: u64, pub beatmapset_id: u64, pub date: DateTime, pub epic_factor: u8, } #[derive(Debug)] pub struct User { pub id: u64, pub username: String, pub joined: DateTime, pub country: String, // History pub count_300: u64, pub count_100: u64, pub count_50: u64, pub play_count: u64, pub played_time: Duration, pub ranked_score: u64, pub total_score: u64, pub count_ss: u64, pub count_ssh: u64, pub count_s: u64, pub count_sh: u64, pub count_a: u64, pub events: Vec, // Rankings pub rank: u64, pub country_rank: u64, pub level: f64, pub pp: Option, pub accuracy: f64, } #[derive(Debug)] pub enum Rank { SS, SSH, S, SH, A, B, C, D, F, } impl std::str::FromStr for Rank { type Err = String; fn from_str(a: &str) -> Result { Ok(match &a.to_uppercase()[..] { "SS" | "X" => Rank::SS, "SSH" | "XH" => Rank::SSH, "S" => Rank::S, "SH" => Rank::SH, "A" => Rank::A, "B" => Rank::B, "C" => Rank::C, "D" => Rank::D, "F" => Rank::F, t => return Err(format!("Invalid value {}", t)), }) } } impl fmt::Display for Rank { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}", self) } } #[derive(Debug)] pub struct Score { pub id: Option, // No id if you fail pub user_id: u64, pub date: DateTime, pub replay_available: bool, pub beatmap_id: u64, pub score: u64, pub pp: f64, pub rank: Rank, pub mods: Mods, // Later pub count_300: u64, pub count_100: u64, pub count_50: u64, pub count_miss: u64, pub count_katu: u64, pub count_geki: u64, pub max_combo: u64, pub perfect: bool, }