diff --git a/src/lib.rs b/src/lib.rs index a50e2cb..4867ad6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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, T: de::DeserializeO Ok(envy::from_iter(map).unwrap()) } +pub fn read_playlist_info<'a, I: Iterator>(input: I) -> MpdResult> { + 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![])); + } }