Implement some more commands
This commit is contained in:
parent
1561ae2e80
commit
08104b3537
@ -7,6 +7,7 @@ mod client_to_client;
|
|||||||
mod controlling_playback;
|
mod controlling_playback;
|
||||||
mod playback_options;
|
mod playback_options;
|
||||||
mod querying_mpd_status;
|
mod querying_mpd_status;
|
||||||
|
mod queue;
|
||||||
|
|
||||||
pub use querying_mpd_status::clearerror::ClearError;
|
pub use querying_mpd_status::clearerror::ClearError;
|
||||||
pub use querying_mpd_status::idle::Idle;
|
pub use querying_mpd_status::idle::Idle;
|
||||||
|
@ -29,7 +29,7 @@ impl Command for Outputs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_response(
|
fn parse_response(
|
||||||
parts: ResponseAttributes<'_>,
|
_parts: ResponseAttributes<'_>,
|
||||||
) -> Result<Self::Response, ResponseParserError> {
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
@ -87,4 +87,4 @@ mod tests {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ impl Command for GetVol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_response(
|
fn parse_response(
|
||||||
parts: ResponseAttributes<'_>,
|
_parts: ResponseAttributes<'_>,
|
||||||
) -> Result<Self::Response, ResponseParserError> {
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
// let volume = get_property!(parts, Volume, "volume");
|
// let volume = get_property!(parts, Volume, "volume");
|
||||||
|
@ -2,6 +2,7 @@ use crate::commands::{
|
|||||||
Command, Request, RequestParserResult, ResponseAttributes, ResponseParserError,
|
Command, Request, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Clears the current error message in status (this is also accomplished by any command that starts playback)
|
||||||
pub struct ClearError;
|
pub struct ClearError;
|
||||||
|
|
||||||
impl Command for ClearError {
|
impl Command for ClearError {
|
||||||
|
@ -4,6 +4,7 @@ use crate::commands::{
|
|||||||
Command, Request, RequestParserResult, ResponseAttributes, ResponseParserError,
|
Command, Request, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Displays the song info of the current song (same song that is identified in status)
|
||||||
pub struct CurrentSong;
|
pub struct CurrentSong;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
@ -20,7 +21,7 @@ impl Command for CurrentSong {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_response(
|
fn parse_response(
|
||||||
parts: ResponseAttributes<'_>,
|
_parts: ResponseAttributes<'_>,
|
||||||
) -> Result<Self::Response, ResponseParserError> {
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
22
src/commands/queue.rs
Normal file
22
src/commands/queue.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
pub mod add;
|
||||||
|
pub mod addid;
|
||||||
|
pub mod addtagid;
|
||||||
|
pub mod clear;
|
||||||
|
pub mod cleartagid;
|
||||||
|
pub mod delete;
|
||||||
|
pub mod deleteid;
|
||||||
|
pub mod move_;
|
||||||
|
pub mod moveid;
|
||||||
|
pub mod playlist;
|
||||||
|
pub mod playlistfind;
|
||||||
|
pub mod playlistid;
|
||||||
|
pub mod playlistinfo;
|
||||||
|
pub mod playlistsearch;
|
||||||
|
pub mod plchanges;
|
||||||
|
pub mod plchangesposid;
|
||||||
|
pub mod prio;
|
||||||
|
pub mod prioid;
|
||||||
|
pub mod rangeid;
|
||||||
|
pub mod shuffle;
|
||||||
|
pub mod swap;
|
||||||
|
pub mod swapid;
|
40
src/commands/queue/add.rs
Normal file
40
src/commands/queue/add.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, Request, RequestParserError, RequestParserResult, ResponseAttributes,
|
||||||
|
ResponseParserError,
|
||||||
|
},
|
||||||
|
common::SongPosition,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Add;
|
||||||
|
|
||||||
|
impl Command for Add {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "add";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let uri = match parts.next() {
|
||||||
|
Some(s) => s,
|
||||||
|
None => return Err(RequestParserError::UnexpectedEOF),
|
||||||
|
};
|
||||||
|
|
||||||
|
let position = match parts.next() {
|
||||||
|
Some(s) => Some(
|
||||||
|
s.parse::<SongPosition>()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(1, s.to_owned()))?,
|
||||||
|
),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::Add(uri.to_string(), position), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
debug_assert!(parts.is_empty());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
55
src/commands/queue/addid.rs
Normal file
55
src/commands/queue/addid.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, GenericResponseValue, Request, RequestParserError, RequestParserResult,
|
||||||
|
ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
common::{SongId, SongPosition},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct AddId;
|
||||||
|
|
||||||
|
pub struct AddIdResponse {
|
||||||
|
pub id: SongId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command for AddId {
|
||||||
|
type Response = AddIdResponse;
|
||||||
|
const COMMAND: &'static str = "addid";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let uri = match parts.next() {
|
||||||
|
Some(s) => s,
|
||||||
|
None => return Err(RequestParserError::UnexpectedEOF),
|
||||||
|
};
|
||||||
|
|
||||||
|
let position = match parts.next() {
|
||||||
|
Some(s) => Some(
|
||||||
|
s.parse::<SongPosition>()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(1, s.to_owned()))?,
|
||||||
|
),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::AddId(uri.to_string(), position), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
let parts: Vec<_> = parts.into();
|
||||||
|
let (key, value) = parts.first().ok_or(ResponseParserError::UnexpectedEOF)?;
|
||||||
|
debug_assert!(key == &"Id");
|
||||||
|
let value = match value {
|
||||||
|
GenericResponseValue::Text(value) => value,
|
||||||
|
GenericResponseValue::Binary(_) => {
|
||||||
|
return Err(ResponseParserError::UnexpectedPropertyType("Id", "Binary"))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let id = value
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| ResponseParserError::InvalidProperty("Id", value.to_owned()))?;
|
||||||
|
Ok(AddIdResponse { id })
|
||||||
|
}
|
||||||
|
}
|
41
src/commands/queue/addtagid.rs
Normal file
41
src/commands/queue/addtagid.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct AddTagId;
|
||||||
|
|
||||||
|
impl Command for AddTagId {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "addtagid";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let songid = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let songid = songid
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, songid.to_string()))?;
|
||||||
|
|
||||||
|
let tag_name = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let tag_name = tag_name
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, tag_name.to_string()))?;
|
||||||
|
|
||||||
|
let tag_value = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let tag_value = tag_value
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, tag_value.to_string()))?;
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::AddTagId(songid, tag_name, tag_value), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
debug_assert!(parts.is_empty());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
22
src/commands/queue/clear.rs
Normal file
22
src/commands/queue/clear.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use crate::commands::{
|
||||||
|
Command, Request, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Clear;
|
||||||
|
|
||||||
|
impl Command for Clear {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "clear";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
Ok((Request::Clear, ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
debug_assert!(parts.is_empty());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
36
src/commands/queue/cleartagid.rs
Normal file
36
src/commands/queue/cleartagid.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct ClearTagId;
|
||||||
|
|
||||||
|
impl Command for ClearTagId {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "cleartagid";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let songid = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let songid = songid
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, songid.to_string()))?;
|
||||||
|
|
||||||
|
let tag_name = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let tag_name = tag_name
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, tag_name.to_string()))?;
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::ClearTagId(songid, tag_name), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
debug_assert!(parts.is_empty());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
33
src/commands/queue/delete.rs
Normal file
33
src/commands/queue/delete.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
common::OneOrRange,
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Delete;
|
||||||
|
|
||||||
|
impl Command for Delete {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "delete";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let pos_or_range = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let one_or_range = OneOrRange::from_str(pos_or_range)
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, pos_or_range.to_string()))?;
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::Delete(one_or_range), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
debug_assert!(parts.is_empty());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
31
src/commands/queue/deleteid.rs
Normal file
31
src/commands/queue/deleteid.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct DeleteId;
|
||||||
|
|
||||||
|
impl Command for DeleteId {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "deleteid";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let id = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let id = id
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, id.to_string()))?;
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::DeleteId(id), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
debug_assert!(parts.is_empty());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
36
src/commands/queue/move_.rs
Normal file
36
src/commands/queue/move_.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Move;
|
||||||
|
|
||||||
|
impl Command for Move {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "move";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let from_or_range = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let from_or_range = from_or_range
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, from_or_range.to_string()))?;
|
||||||
|
|
||||||
|
let to = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let to = to
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, to.to_string()))?;
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::Move(from_or_range, to), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
debug_assert!(parts.is_empty());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
36
src/commands/queue/moveid.rs
Normal file
36
src/commands/queue/moveid.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct MoveId;
|
||||||
|
|
||||||
|
impl Command for MoveId {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "moveid";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let id = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let id = id
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, id.to_string()))?;
|
||||||
|
|
||||||
|
let to = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let to = to
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, to.to_string()))?;
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::MoveId(id, to), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
debug_assert!(parts.is_empty());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
22
src/commands/queue/playlist.rs
Normal file
22
src/commands/queue/playlist.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{Command, RequestParserResult, ResponseAttributes, ResponseParserError},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Playlist;
|
||||||
|
|
||||||
|
impl Command for Playlist {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "playlist";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
Ok((Request::Playlist, ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
_parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
49
src/commands/queue/playlistfind.rs
Normal file
49
src/commands/queue/playlistfind.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct PlaylistFind;
|
||||||
|
|
||||||
|
impl Command for PlaylistFind {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "playlistfind";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let filter = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let filter = filter.to_string();
|
||||||
|
|
||||||
|
let mut sort_or_window = parts.next();
|
||||||
|
let mut sort = None;
|
||||||
|
if let Some("sort") = sort_or_window {
|
||||||
|
sort = Some(
|
||||||
|
parts
|
||||||
|
.next()
|
||||||
|
.ok_or(RequestParserError::UnexpectedEOF)?
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
sort_or_window = parts.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut window = None;
|
||||||
|
if let Some("window") = sort_or_window {
|
||||||
|
let w = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
window = Some(
|
||||||
|
w.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::PlaylistFind(filter, sort, window), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
_parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
30
src/commands/queue/playlistid.rs
Normal file
30
src/commands/queue/playlistid.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct PlaylistId;
|
||||||
|
|
||||||
|
impl Command for PlaylistId {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "playlistid";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let id = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let id = id
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, id.to_string()))?;
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::PlaylistId(id), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
_parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
33
src/commands/queue/playlistinfo.rs
Normal file
33
src/commands/queue/playlistinfo.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct PlaylistInfo;
|
||||||
|
|
||||||
|
impl Command for PlaylistInfo {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "playlistinfo";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let one_or_range = parts
|
||||||
|
.next()
|
||||||
|
.map(|s| {
|
||||||
|
s.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, s.to_string()))
|
||||||
|
})
|
||||||
|
.transpose()?;
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::PlaylistInfo(one_or_range), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
_parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
51
src/commands/queue/playlistsearch.rs
Normal file
51
src/commands/queue/playlistsearch.rs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct PlaylistSearch;
|
||||||
|
|
||||||
|
impl Command for PlaylistSearch {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "playlistsearch";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let filter = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let filter = filter
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, filter.to_string()))?;
|
||||||
|
|
||||||
|
let mut sort_or_window = parts.next();
|
||||||
|
let mut sort = None;
|
||||||
|
if let Some("sort") = sort_or_window {
|
||||||
|
sort = Some(
|
||||||
|
parts
|
||||||
|
.next()
|
||||||
|
.ok_or(RequestParserError::UnexpectedEOF)?
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
sort_or_window = parts.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut window = None;
|
||||||
|
if let Some("window") = sort_or_window {
|
||||||
|
let w = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
window = Some(
|
||||||
|
w.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::PlaylistSearch(filter, sort, window), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
_parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
38
src/commands/queue/plchanges.rs
Normal file
38
src/commands/queue/plchanges.rs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct PlChanges;
|
||||||
|
|
||||||
|
impl Command for PlChanges {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "plchanges";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let version = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let version = version
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, version.to_string()))?;
|
||||||
|
|
||||||
|
let window = parts
|
||||||
|
.next()
|
||||||
|
.map(|w| {
|
||||||
|
w.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))
|
||||||
|
})
|
||||||
|
.transpose()?;
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::PlChanges(version, window), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
38
src/commands/queue/plchangesposid.rs
Normal file
38
src/commands/queue/plchangesposid.rs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct PlChangesPosId;
|
||||||
|
|
||||||
|
impl Command for PlChangesPosId {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "plchangesposid";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let version = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let version = version
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, version.to_string()))?;
|
||||||
|
|
||||||
|
let window = parts
|
||||||
|
.next()
|
||||||
|
.map(|w| {
|
||||||
|
w.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))
|
||||||
|
})
|
||||||
|
.transpose()?;
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::PlChangesPosId(version, window), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
36
src/commands/queue/prio.rs
Normal file
36
src/commands/queue/prio.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Prio;
|
||||||
|
|
||||||
|
impl Command for Prio {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "prio";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let prio = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let prio = prio
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, prio.to_string()))?;
|
||||||
|
|
||||||
|
let window = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let window = window
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, window.to_string()))?;
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::Prio(prio, window), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
debug_assert!(parts.is_empty());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
41
src/commands/queue/prioid.rs
Normal file
41
src/commands/queue/prioid.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct PrioId;
|
||||||
|
|
||||||
|
impl Command for PrioId {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "prioid";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let prio = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let prio = prio
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, prio.to_string()))?;
|
||||||
|
|
||||||
|
let songids = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
// TODO: This is just a guess to satisfy compilation, double check it
|
||||||
|
let songids = songids
|
||||||
|
.split(',')
|
||||||
|
.map(|s| {
|
||||||
|
s.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, s.to_string()))
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<u32>, RequestParserError>>()?;
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::PrioId(prio, songids), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
debug_assert!(parts.is_empty());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
36
src/commands/queue/rangeid.rs
Normal file
36
src/commands/queue/rangeid.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct RangeId;
|
||||||
|
|
||||||
|
impl Command for RangeId {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "rangeid";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let songid = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let songid = songid
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, songid.to_string()))?;
|
||||||
|
|
||||||
|
let timeinterval = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let timeinterval = timeinterval
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, timeinterval.to_string()))?;
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::RangeId(songid, timeinterval), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
debug_assert!(parts.is_empty());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
35
src/commands/queue/shuffle.rs
Normal file
35
src/commands/queue/shuffle.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Shuffle;
|
||||||
|
|
||||||
|
impl Command for Shuffle {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "shuffle";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let range = parts
|
||||||
|
.next()
|
||||||
|
.map(|range| {
|
||||||
|
range
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, range.to_string()))
|
||||||
|
})
|
||||||
|
.transpose()?;
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::Shuffle(range), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
debug_assert!(parts.is_empty());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
36
src/commands/queue/swap.rs
Normal file
36
src/commands/queue/swap.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Swap;
|
||||||
|
|
||||||
|
impl Command for Swap {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "swap";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let songpos1 = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let songpos1 = songpos1
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, songpos1.to_string()))?;
|
||||||
|
|
||||||
|
let songpos2 = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let songpos2 = songpos2
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, songpos2.to_string()))?;
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::Swap(songpos1, songpos2), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
debug_assert!(parts.is_empty());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
36
src/commands/queue/swapid.rs
Normal file
36
src/commands/queue/swapid.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use crate::{
|
||||||
|
commands::{
|
||||||
|
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
|
||||||
|
},
|
||||||
|
Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct SwapId;
|
||||||
|
|
||||||
|
impl Command for SwapId {
|
||||||
|
type Response = ();
|
||||||
|
const COMMAND: &'static str = "swapid";
|
||||||
|
|
||||||
|
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
|
||||||
|
let songid1 = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let songid1 = songid1
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, songid1.to_string()))?;
|
||||||
|
|
||||||
|
let songid2 = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||||
|
let songid2 = songid2
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| RequestParserError::SyntaxError(0, songid2.to_string()))?;
|
||||||
|
|
||||||
|
debug_assert!(parts.next().is_none());
|
||||||
|
|
||||||
|
Ok((Request::SwapId(songid1, songid2), ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(
|
||||||
|
parts: ResponseAttributes<'_>,
|
||||||
|
) -> Result<Self::Response, ResponseParserError> {
|
||||||
|
debug_assert!(parts.is_empty());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -3,11 +3,89 @@ use std::str::FromStr;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub type SongPosition = u32;
|
pub type SongPosition = u32;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum AbsouluteRelativeSongPosition {
|
||||||
|
Absolute(SongPosition),
|
||||||
|
RelativePlus(SongPosition),
|
||||||
|
RelativeMinus(SongPosition),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for AbsouluteRelativeSongPosition {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Ok(match s {
|
||||||
|
s if s.starts_with('+') => Self::RelativePlus(s[1..].parse().map_err(|_| ())?),
|
||||||
|
s if s.starts_with('-') => Self::RelativeMinus(s[1..].parse().map_err(|_| ())?),
|
||||||
|
s => Self::Absolute(s.parse().map_err(|_| ())?),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type SongId = u32;
|
pub type SongId = u32;
|
||||||
pub type Seconds = u32;
|
pub type Seconds = u32;
|
||||||
pub type TimeWithFractions = f64;
|
pub type TimeWithFractions = f64;
|
||||||
pub type OneOrRange = (SongPosition, Option<SongPosition>);
|
|
||||||
pub type WindowRange = (Option<SongPosition>, Option<SongPosition>);
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum OneOrRange {
|
||||||
|
One(SongPosition),
|
||||||
|
Range(SongPosition, SongPosition),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for OneOrRange {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let mut parts = s.split(':');
|
||||||
|
let start = parts.next().ok_or(())?.parse().map_err(|_| ())?;
|
||||||
|
Ok(match parts.next() {
|
||||||
|
Some(end) => Self::Range(start, end.parse().map_err(|_| ())?),
|
||||||
|
None => Self::One(start),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct WindowRange {
|
||||||
|
pub start: SongPosition,
|
||||||
|
pub end: Option<SongPosition>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for WindowRange {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let mut parts = s.split(':');
|
||||||
|
let start = parts.next().ok_or(())?.parse().map_err(|_| ())?;
|
||||||
|
let end = parts.next().map(|s| s.parse().map_err(|_| ()));
|
||||||
|
Ok(Self {
|
||||||
|
start,
|
||||||
|
end: end.transpose()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct TimeInterval {
|
||||||
|
pub start: Option<TimeWithFractions>,
|
||||||
|
pub end: Option<TimeWithFractions>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for TimeInterval {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let mut parts = s.split(':');
|
||||||
|
let start = parts.next().map(|s| s.parse().map_err(|_| ()));
|
||||||
|
let end = parts.next().map(|s| s.parse().map_err(|_| ()));
|
||||||
|
Ok(Self {
|
||||||
|
start: start.transpose()?,
|
||||||
|
end: end.transpose()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type Priority = u8;
|
pub type Priority = u8;
|
||||||
pub type PlaylistName = String;
|
pub type PlaylistName = String;
|
||||||
pub type Offset = u32;
|
pub type Offset = u32;
|
||||||
|
@ -52,12 +52,14 @@ pub enum Request {
|
|||||||
Clear,
|
Clear,
|
||||||
Delete(OneOrRange),
|
Delete(OneOrRange),
|
||||||
DeleteId(SongId),
|
DeleteId(SongId),
|
||||||
Move(OneOrRange, SongPosition),
|
// TODO: account for relative moves
|
||||||
MoveId(SongId, SongPosition),
|
Move(OneOrRange, AbsouluteRelativeSongPosition),
|
||||||
|
// TODO: account for relative moves
|
||||||
|
MoveId(SongId, AbsouluteRelativeSongPosition),
|
||||||
Playlist,
|
Playlist,
|
||||||
PlaylistFind(Filter, Option<Sort>, Option<WindowRange>),
|
PlaylistFind(Filter, Option<Sort>, Option<WindowRange>),
|
||||||
PlaylistId(SongId),
|
PlaylistId(SongId),
|
||||||
PlaylistInfo(OneOrRange),
|
PlaylistInfo(Option<OneOrRange>),
|
||||||
PlaylistSearch(Filter, Option<Sort>, Option<WindowRange>),
|
PlaylistSearch(Filter, Option<Sort>, Option<WindowRange>),
|
||||||
// TODO: which type of range?
|
// TODO: which type of range?
|
||||||
PlChanges(Version, Option<WindowRange>),
|
PlChanges(Version, Option<WindowRange>),
|
||||||
@ -66,7 +68,7 @@ pub enum Request {
|
|||||||
// TODO: which type of range?
|
// TODO: which type of range?
|
||||||
Prio(Priority, WindowRange),
|
Prio(Priority, WindowRange),
|
||||||
PrioId(Priority, Vec<SongId>),
|
PrioId(Priority, Vec<SongId>),
|
||||||
RangeId(SongId, WindowRange),
|
RangeId(SongId, TimeInterval),
|
||||||
Shuffle(Option<OneOrRange>),
|
Shuffle(Option<OneOrRange>),
|
||||||
Swap(SongPosition, SongPosition),
|
Swap(SongPosition, SongPosition),
|
||||||
SwapId(SongId, SongId),
|
SwapId(SongId, SongId),
|
||||||
|
Loading…
Reference in New Issue
Block a user