Add playlist info

This is also the first occurence of multiple structs in one response.
The Itertools.batching approach seems to work quite well.
This commit is contained in:
kageru 2020-06-21 15:31:08 +02:00
parent fe2730a7d6
commit c374a04417
Signed by: kageru
GPG Key ID: 8282A2BEA4ADA3D2

View File

@ -2,6 +2,7 @@ use serde::de;
use std::collections::HashMap;
mod error;
use error::{Error, MpdResult};
use itertools::Itertools;
mod structs;
pub use structs::{Position, Status, Track};
@ -34,6 +35,34 @@ pub fn deserialize_response<'a, I: Iterator<Item = &'a str>, T: de::DeserializeO
Ok(envy::from_iter(map).unwrap())
}
pub fn read_playlist_info<'a, I: Iterator<Item = &'a str>>(input: I) -> MpdResult<Vec<Track>> {
input
.peekable()
.batching(|it| {
let mut v = match it.next() {
// if the playlist is empty or we’ve reached the end,
// the response is only the `OK` line.
Some("OK") => return None,
// otherwise this is the file attribute and thus the first key-value of this track
Some(s) => vec![s],
_ => return None,
};
// Only peek here in case we encounter the `file:` line which we still need for the next track.
while let Some(l) = it.peek() {
if l.starts_with("file:") {
return Some(v);
}
if l.starts_with("OK") {
return Some(v);
}
v.push(it.next().unwrap());
}
None
})
.map(|b| deserialize_response(b.into_iter()))
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
@ -186,4 +215,69 @@ OK";
}
);
}
#[test]
fn de_playlist_test() {
let input_str = "file: 137 A New World.mp3
Last-Modified: 2018-03-07T13:11:43Z
Artist: Arata Iiyoshi
Title: A New World
Album: Pokemon Mystery Dungeon: Explorers of Sky
duration: 225.802
Pos: 1000
Id: 6365
file: 139 Thoughts For Friends.mp3
Last-Modified: 2018-03-07T13:11:43Z
Artist: Arata Iiyoshi
Title: Thoughts For Friends
Album: Pokemon Mystery Dungeon: Explorers of Sky
duration: 66.560
Pos: 1001
Id: 6366
file: 140 A Message On the Wind.mp3
Last-Modified: 2018-03-07T13:11:43Z
Artist: Arata Iiyoshi
Title: A Message On the Wind
Album: Pokemon Mystery Dungeon: Explorers of Sky
duration: 50.155
Pos: 1002
Id: 6367
OK";
let queue = read_playlist_info(input_str.lines());
let first_track = Track {
file: "137 A New World.mp3".into(),
title: Some("A New World".into()),
artist: Some("Arata Iiyoshi".into()),
album: Some("Pokemon Mystery Dungeon: Explorers of Sky".into()),
last_modified: Some(DateTime::parse_from_rfc3339("2018-03-07T13:11:43Z").unwrap()),
duration: Some(Duration::from_secs_f64(225.802)),
pos: 1000,
id: 6365,
..Track::default()
};
assert_eq!(
queue,
Ok(vec![
first_track.clone(),
Track {
file: "139 Thoughts For Friends.mp3".into(),
title: Some("Thoughts For Friends".into()),
duration: Some(Duration::from_secs_f64(66.56)),
pos: 1001,
id: 6366,
..first_track.clone()
},
Track {
file: "140 A Message On the Wind.mp3".into(),
title: Some("A Message On the Wind".into()),
duration: Some(Duration::from_secs_f64(50.155)),
pos: 1002,
id: 6367,
..first_track
},
])
);
let queue = read_playlist_info("OK".lines());
assert_eq!(queue, Ok(vec![]));
}
}