Add Status struct

This commit is contained in:
kageru 2020-06-21 14:50:25 +02:00
parent ce5b87769c
commit fe2730a7d6
Signed by: kageru
GPG Key ID: 8282A2BEA4ADA3D2
2 changed files with 97 additions and 8 deletions

View File

@ -3,7 +3,7 @@ use std::collections::HashMap;
mod error;
use error::{Error, MpdResult};
mod structs;
pub use structs::{Position, Track};
pub use structs::{Position, Status, Track};
/// some unprintable character to separate repeated keys
const SEPARATOR: char = '\x02';
@ -38,6 +38,7 @@ pub fn deserialize_response<'a, I: Iterator<Item = &'a str>, T: de::DeserializeO
mod tests {
use super::*;
use chrono::DateTime;
use std::time::Duration;
#[test]
fn track_de_test() {
@ -69,7 +70,7 @@ OK";
item_position: 1,
total_items: None,
}),
duration: std::time::Duration::from_secs_f64(512.380),
duration: Some(Duration::from_secs_f64(512.380)),
pos: 1367,
id: 1368,
..Track::default()
@ -129,7 +130,7 @@ OK"#;
item_position: 6,
total_items: Some(6),
}),
duration: std::time::Duration::from_secs_f64(682.840),
duration: Some(Duration::from_secs_f64(682.840)),
pos: 3439,
id: 3440,
performers: vec!["Royal Philharmonic Orchestra".to_string(), "Jane Glover".to_string()],
@ -142,4 +143,47 @@ OK"#;
}
);
}
#[test]
fn de_status_test() {
let input_str = "volume: 74
repeat: 0
random: 1
single: 0
consume: 0
playlist: 6
playlistlength: 5364
mixrampdb: 0.000000
state: play
song: 3833
songid: 3834
time: 70:164
elapsed: 69.642
bitrate: 702
duration: 163.760
audio: 44100:16:2
nextsong: 4036
nextsongid: 4037
OK";
let s: Status = deserialize_response(input_str.lines()).unwrap();
assert_eq!(
s,
Status {
volume: Some(74),
random: true,
playlist: 6,
playlistlength: 5364,
mixrampdb: 0.0,
state: String::from("play"),
song: Some(3833),
songid: Some(3834),
elapsed: Some(Duration::from_secs_f64(69.642)),
bitrate: Some(702),
duration: Some(Duration::from_secs_f64(163.760)),
audio: Some(String::from("44100:16:2")),
nextsong: Some(4036),
nextsongid: Some(4037),
..Status::default()
}
);
}
}

View File

@ -3,6 +3,7 @@ use helpers::*;
use serde::Deserialize;
use std::time::Duration;
/// All information about a track. This is returned by the `currentsong` or `queue` commands.
#[derive(Deserialize, Clone, Debug, Default, PartialEq)]
#[serde(default)]
pub struct Track {
@ -30,11 +31,9 @@ pub struct Track {
pub last_modified: Option<DateTime<FixedOffset>>,
#[serde(rename = "originaldate")]
pub original_date: Option<u16>,
// probably not needed. it’s just the duration but as an int
// pub time: u16,
pub format: Option<String>,
#[serde(deserialize_with = "de_time_float")]
pub duration: Duration,
pub duration: Option<Duration>,
pub label: Option<String>,
pub date: Option<u16>,
#[serde(deserialize_with = "de_position")]
@ -58,6 +57,52 @@ pub struct Position {
pub total_items: Option<u16>,
}
/// Current status as returned by `status`.
///
/// Regarding optional `volume`:
/// The volume is None if mpd is running without local audio output,
/// i.e. on a server with no pulse or alsa output configured.
/// Output via httpd might be used instead
/// but will result in empty `volume` and `audio` fields.
#[derive(Deserialize, Clone, Debug, Default, PartialEq)]
#[serde(default)]
pub struct Status {
pub volume: Option<u8>,
#[serde(deserialize_with = "de_bint")]
pub repeat: bool,
#[serde(deserialize_with = "de_bint")]
pub random: bool,
// TODO: make enum
pub single: u8,
#[serde(deserialize_with = "de_bint")]
pub consume: bool,
// an empty playlist still has an ID
pub playlist: u32,
// mpd returns 0 if there is no current playlist
pub playlistlength: u32,
// play, stop, pause. TODO: make an enum
pub state: String,
pub song: Option<u32>,
pub songid: Option<u32>,
pub nextsong: Option<u32>,
pub nextsongid: Option<u32>,
#[serde(deserialize_with = "de_time_float")]
pub elapsed: Option<Duration>,
#[serde(deserialize_with = "de_time_float")]
pub duration: Option<Duration>,
pub bitrate: Option<u16>,
pub xfade: Option<u8>,
// 0 if unset
pub mixrampdb: f32,
pub mixrampdelay: Option<u8>,
// “audio: The format emitted by the decoder plugin during playback, format: samplerate:bits:channels.
// See Global Audio Format for a detailed explanation.”
// TODO: make struct
pub audio: Option<String>,
pub updating_db: Option<u32>,
pub error: Option<String>,
}
/// Deserialization helpers to handle the quirks of mpd’s output.
mod helpers {
use super::*;
@ -74,9 +119,9 @@ mod helpers {
/// 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>
pub fn de_time_float<'de, D>(deserializer: D) -> Result<Option<Duration>, D::Error>
where D: de::Deserializer<'de> {
f64::deserialize(deserializer).map(Duration::from_secs_f64)
f64::deserialize(deserializer).map(Duration::from_secs_f64).map(Some)
}
pub fn de_string_or_vec<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>