~aleteoryx/lfm_embed

d796f6762acb52cf2ab202d76382915064f0d534 — alyx 1 year, 4 months ago
API deserialization structs
5 files changed, 189 insertions(+), 0 deletions(-)

A .gitignore
A Cargo.toml
A src/deserialize.rs
A src/lib.rs
A src/main.rs
A  => .gitignore +4 -0
@@ 1,4 @@
/target
*~
.#*
\#*

A  => Cargo.toml +8 -0
@@ 1,8 @@
[package]
name = "lfm_embed"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

A  => src/deserialize.rs +173 -0
@@ 1,173 @@
use serde::{Deserialize, Deserializer, de};
use serde_json::Value;

use std::collections::HashMap;
use std::sync::Arc;

fn str_num<'de, D, T>(d: D) -> Result<T, D::Error> where D: Deserializer<'de>, T: From<u64> {
    struct Visitor;
    impl<'v> de::Visitor<'v> for Visitor {
        type Value = u64;
        fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
            write!(f, "a value which can be interpreted as a uint")
        }
        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where
            E: de::Error
        {
            v.parse().map_err(|_| de::Error::invalid_value(de::Unexpected::Str(v), &"a string which can be parsed as a uint"))
        }
        fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
        where
            E: de::Error
        {
            Ok(v)
        }
    }
    d.deserialize_any(Visitor).map(Into::into)
}
fn str_bool<'de, D, T>(d: D) -> Result<T, D::Error> where D: Deserializer<'de>, T: From<bool>{
    struct Visitor;
    impl<'v> de::Visitor<'v> for Visitor {
        type Value = bool;
        fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
            write!(f, "a value which can be interpreted as a uint")
        }
        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where
            E: de::Error
        {
            match v.to_ascii_lowercase().as_str() {
                "true" | "1" => Ok(true),
                "false" | "0" => Ok(false),
                _ => Err(de::Error::invalid_value(de::Unexpected::Str(v), &"a string which can be parsed as a bool"))
            }
        }
        fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
        where
            E: de::Error
        {
            Ok(v)
        }
    }
    d.deserialize_any(Visitor).map(Into::into)
}


#[derive(Deserialize, Debug)]
pub struct TimeStamp {
    #[serde(alias = "unixtime")]
    #[serde(alias = "uts")]
    #[serde(deserialize_with = "str_num")]
    pub unix_timestamp: u64,
    #[serde(rename = "#text")]
    pub text: Value
}

#[derive(Deserialize, Debug)]
pub struct Artist {
    #[serde(rename = "mbid")]
    pub uuid: Arc<str>,
    #[serde(alias = "#text")]
    pub name: Arc<str>,
    
    #[serde(default)]
    #[serde(rename = "image")]
    pub images: Vec<Image>,
    pub #[serde(default)]
    url: Option<Arc<str>>
}

#[derive(Deserialize, Debug)]
#[serde(rename_all = "lowercase")]
pub enum ImageSize {
    Small,
    Medium,
    Large,
    ExtraLarge
}

#[derive(Deserialize, Debug)]
pub struct Image {
    pub size: ImageSize,
    #[serde(rename = "#text")]
    pub url: Arc<str>,
}

#[derive(Deserialize, Debug)]
pub struct Album {
    #[serde(rename = "mbid")]
    pub uuid: Arc<str>,
    #[serde(rename = "#text")]
    pub name: Arc<str>,
}

#[derive(Default, Deserialize, Debug)]
pub struct TrackAttr {
    #[serde(default)]
    #[serde(deserialize_with = "str_bool")]
    pub nowplaying: bool,
    #[serde(flatten)]
    pub rest: HashMap<Arc<str>, Value>,
}

#[derive(Deserialize, Debug)]
pub struct Track {
    pub artist: Artist,
    #[serde(deserialize_with = "str_bool")]
    pub streamable: bool,
    #[serde(rename = "image")]
    pub images: Vec<Image>,
    #[serde(rename = "mbid")]
    pub uuid: Arc<str>,
    pub album: Album,
    pub name: Arc<str>,
    #[serde(rename = "@attr")]
    #[serde(default)]
    pub attr: TrackAttr,
    pub url: Arc<str>,
    
    #[serde(default)]
    #[serde(deserialize_with = "str_bool")]
    pub loved: Option<bool>,
    #[serde(default)]
    pub date: Option<TimeStamp>
}

#[derive(Deserialize, Debug)]
pub struct RecentTracks {
    pub track: Vec<Track>
}
#[derive(Deserialize, Debug)]
pub struct GetRecentTracks {
    pub recenttracks: RecentTracks
}

#[derive(Deserialize, Debug)]
pub struct User {
    pub name: Arc<str>,
    #[serde(deserialize_with = "str_bool")]
    pub subscriber: bool,
    pub realname: Arc<str>,
    #[serde(deserialize_with = "str_num")]
    pub playcount: u64,
    #[serde(deserialize_with = "str_num")]
    pub artist_count: u64,
    #[serde(deserialize_with = "str_num")]
    pub playlists: u64,
    #[serde(deserialize_with = "str_num")]
    pub track_count: u64,
    #[serde(deserialize_with = "str_num")]
    pub album_count: u64,
    
    #[serde(rename = "image")]
    pub images: Vec<Image>,
    
    pub registered: TimeStamp,
    pub url: Arc<str>
}

#[derive(Deserialize, Debug)]
pub struct GetUserInfo {
    pub user: User
}

A  => src/lib.rs +1 -0
@@ 1,1 @@
mod deserialize;

A  => src/main.rs +3 -0
@@ 1,3 @@
fn main() {
    println!("Hello, world!");
}