2020-06-20 22:21:21 +02:00
use helpers ::* ;
use serde ::Deserialize ;
use std ::time ::Duration ;
2020-06-20 22:50:33 +02:00
#[ derive(Deserialize, Clone, Debug, Default, PartialEq) ]
2020-06-20 22:21:21 +02:00
pub struct Track {
pub file : String ,
pub artist_sort : Option < String > ,
pub album_artist : Option < String > ,
pub album_sort : Option < String > ,
pub album_artist_sort : Option < String > ,
#[ serde(deserialize_with = " string_or_vec " ) ]
#[ serde(default) ]
#[ serde(rename = " performer " ) ]
pub performers : Vec < String > ,
pub genre : Option < String > ,
pub title : Option < String > ,
pub track : Option < u32 > ,
pub album : Option < String > ,
pub artist : Option < String > ,
2020-06-20 22:50:33 +02:00
pub pos : u32 ,
pub id : u32 ,
2020-06-20 22:21:21 +02:00
// TODO: use proper time here
2020-06-20 22:50:33 +02:00
#[ serde(rename = " last-modified " ) ]
2020-06-20 22:21:21 +02:00
pub last_modified : Option < String > ,
2020-06-20 22:50:33 +02:00
pub original_date : Option < u16 > ,
// probably not needed. it’s just the duration but as an int
// pub time: u16,
2020-06-20 22:21:21 +02:00
pub format : Option < String > ,
#[ serde(deserialize_with = " de_time_float " ) ]
pub duration : Duration ,
pub label : Option < String > ,
2020-06-20 22:50:33 +02:00
pub date : Option < u16 > ,
pub disc : Option < u16 > ,
2020-06-20 22:21:21 +02:00
pub musicbraiz_trackid : Option < String > ,
pub musicbrainz_albumid : Option < String > ,
pub musicbrainz_albumartistid : Option < String > ,
pub musicbrainz_artistid : Option < String > ,
pub musicbraiz_releasetrackid : Option < String > ,
pub composer : Option < String > ,
}
/// Deserialization helpers to handle the quirks of mpd’s output.
mod helpers {
use crate ::SEPARATOR ;
use serde ::de ;
use serde ::Deserialize ;
use std ::time ::Duration ;
/// Deserialize time from an integer that represents the seconds.
/// mpd uses int for the database stats (e.g. total time played).
pub fn de_time_int < ' de , D > ( deserializer : D ) -> Result < Duration , D ::Error >
where
D : de ::Deserializer < ' de > ,
{
u64 ::deserialize ( deserializer ) . map ( Duration ::from_secs )
}
/// Deserialize time from a float that represents the seconds.
/// mpd uses floats for the current status (e.g. time elapsed in song).
pub fn de_time_float < ' de , D > ( deserializer : D ) -> Result < Duration , D ::Error >
where
D : de ::Deserializer < ' de > ,
{
f64 ::deserialize ( deserializer ) . map ( Duration ::from_secs_f64 )
}
pub fn string_or_vec < ' de , D > ( deserializer : D ) -> Result < Vec < String > , D ::Error >
where
D : de ::Deserializer < ' de > ,
{
String ::deserialize ( deserializer )
. map ( | s | s . split ( SEPARATOR ) . map ( std ::string ::String ::from ) . collect ( ) )
}
/// mpd uses bints (0 or 1) to represent booleans,
/// so we need a special parser for those.
pub fn de_bint < ' de , D > ( deserializer : D ) -> Result < bool , D ::Error >
where
D : de ::Deserializer < ' de > ,
{
match u8 ::deserialize ( deserializer ) ? {
0 = > Ok ( false ) ,
1 = > Ok ( true ) ,
n = > Err ( de ::Error ::invalid_value (
de ::Unexpected ::Unsigned ( n as u64 ) ,
& " zero or one " ,
) ) ,
}
}
}