Compare commits
3 Commits
ae17032724
...
376936152f
Author | SHA1 | Date |
---|---|---|
Oystein Kristoffer Tveit | 376936152f | |
Oystein Kristoffer Tveit | 3938905f19 | |
Oystein Kristoffer Tveit | 24718c9fc3 |
|
@ -12,8 +12,8 @@ async fn main() -> Result<(), MpvError> {
|
||||||
let playlist = mpv.get_playlist().await?;
|
let playlist = mpv.get_playlist().await?;
|
||||||
println!("playlist: {:?}", playlist);
|
println!("playlist: {:?}", playlist);
|
||||||
|
|
||||||
let playback_time: f64 = mpv.get_property("playback-time").await?;
|
let playback_time: Option<f64> = mpv.get_property("playback-time").await?;
|
||||||
println!("playback-time: {}", playback_time);
|
println!("playback-time: {:?}", playback_time);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
])
|
])
|
||||||
pkgs.mpv
|
pkgs.mpv
|
||||||
pkgs.grcov
|
pkgs.grcov
|
||||||
|
pkgs.cargo-nextest
|
||||||
];
|
];
|
||||||
RUST_SRC_PATH = "${toolchain.rust-src}/lib/rustlib/src/rust/";
|
RUST_SRC_PATH = "${toolchain.rust-src}/lib/rustlib/src/rust/";
|
||||||
});
|
});
|
||||||
|
|
|
@ -134,18 +134,22 @@ impl IntoRawCommandPart for SeekOptions {
|
||||||
pub trait GetPropertyTypeHandler: Sized {
|
pub trait GetPropertyTypeHandler: Sized {
|
||||||
// TODO: fix this
|
// TODO: fix this
|
||||||
#[allow(async_fn_in_trait)]
|
#[allow(async_fn_in_trait)]
|
||||||
async fn get_property_generic(instance: &Mpv, property: &str) -> Result<Self, MpvError>;
|
async fn get_property_generic(instance: &Mpv, property: &str)
|
||||||
|
-> Result<Option<Self>, MpvError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> GetPropertyTypeHandler for T
|
impl<T> GetPropertyTypeHandler for T
|
||||||
where
|
where
|
||||||
T: TypeHandler,
|
T: TypeHandler,
|
||||||
{
|
{
|
||||||
async fn get_property_generic(instance: &Mpv, property: &str) -> Result<T, MpvError> {
|
async fn get_property_generic(instance: &Mpv, property: &str) -> Result<Option<T>, MpvError> {
|
||||||
instance
|
instance
|
||||||
.get_property_value(property)
|
.get_property_value(property)
|
||||||
.await
|
.await
|
||||||
.and_then(T::get_value)
|
.and_then(|value| match value {
|
||||||
|
Some(v) => T::get_value(v).map(|v| Some(v)),
|
||||||
|
None => Ok(None),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +176,7 @@ where
|
||||||
instance
|
instance
|
||||||
.command_sender
|
.command_sender
|
||||||
.send((
|
.send((
|
||||||
MpvIpcCommand::SetProperty(property.to_owned(), value),
|
MpvIpcCommand::SetProperty(property.to_owned(), value.to_owned()),
|
||||||
res_tx,
|
res_tx,
|
||||||
))
|
))
|
||||||
.await
|
.await
|
||||||
|
@ -277,7 +281,7 @@ impl Mpv {
|
||||||
command: &str,
|
command: &str,
|
||||||
args: &[&str],
|
args: &[&str],
|
||||||
) -> Result<Option<Value>, MpvError> {
|
) -> Result<Option<Value>, MpvError> {
|
||||||
let command = Vec::from(
|
let command_vec = Vec::from(
|
||||||
[command]
|
[command]
|
||||||
.iter()
|
.iter()
|
||||||
.chain(args.iter())
|
.chain(args.iter())
|
||||||
|
@ -287,7 +291,7 @@ impl Mpv {
|
||||||
);
|
);
|
||||||
let (res_tx, res_rx) = oneshot::channel();
|
let (res_tx, res_rx) = oneshot::channel();
|
||||||
self.command_sender
|
self.command_sender
|
||||||
.send((MpvIpcCommand::Command(command), res_tx))
|
.send((MpvIpcCommand::Command(command_vec.clone()), res_tx))
|
||||||
.await
|
.await
|
||||||
.map_err(|err| MpvError::InternalConnectionError(err.to_string()))?;
|
.map_err(|err| MpvError::InternalConnectionError(err.to_string()))?;
|
||||||
|
|
||||||
|
@ -462,7 +466,10 @@ impl Mpv {
|
||||||
pub async fn get_property<T: GetPropertyTypeHandler>(
|
pub async fn get_property<T: GetPropertyTypeHandler>(
|
||||||
&self,
|
&self,
|
||||||
property: &str,
|
property: &str,
|
||||||
) -> Result<T, MpvError> {
|
) -> Result<Option<T>, MpvError> {
|
||||||
|
// NOTE: `get_property_generic` is implemented in terms of `get_property_value`,
|
||||||
|
// which wraps errors in `MpvError::GetPropertyFailure`. That is why it is
|
||||||
|
// not needed here.
|
||||||
T::get_property_generic(self, property).await
|
T::get_property_generic(self, property).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,7 +494,7 @@ impl Mpv {
|
||||||
/// Ok(())
|
/// Ok(())
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn get_property_value(&self, property: &str) -> Result<Value, MpvError> {
|
pub async fn get_property_value(&self, property: &str) -> Result<Option<Value>, MpvError> {
|
||||||
let (res_tx, res_rx) = oneshot::channel();
|
let (res_tx, res_rx) = oneshot::channel();
|
||||||
self.command_sender
|
self.command_sender
|
||||||
.send((MpvIpcCommand::GetProperty(property.to_owned()), res_tx))
|
.send((MpvIpcCommand::GetProperty(property.to_owned()), res_tx))
|
||||||
|
@ -495,9 +502,7 @@ impl Mpv {
|
||||||
.map_err(|err| MpvError::InternalConnectionError(err.to_string()))?;
|
.map_err(|err| MpvError::InternalConnectionError(err.to_string()))?;
|
||||||
|
|
||||||
match res_rx.await {
|
match res_rx.await {
|
||||||
Ok(MpvIpcResponse(response)) => {
|
Ok(MpvIpcResponse(response)) => response,
|
||||||
response.and_then(|value| value.ok_or(MpvError::MissingMpvData))
|
|
||||||
}
|
|
||||||
Err(err) => Err(MpvError::InternalConnectionError(err.to_string())),
|
Err(err) => Err(MpvError::InternalConnectionError(err.to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -526,11 +531,10 @@ impl Mpv {
|
||||||
/// Ok(())
|
/// Ok(())
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn set_property<T: SetPropertyTypeHandler<T>>(
|
pub async fn set_property<T>(&self, property: &str, value: T) -> Result<(), MpvError>
|
||||||
&self,
|
where
|
||||||
property: &str,
|
T: SetPropertyTypeHandler<T> + Clone + fmt::Debug,
|
||||||
value: T,
|
{
|
||||||
) -> Result<(), MpvError> {
|
T::set_property_generic(self, property, value.clone()).await
|
||||||
T::set_property_generic(self, property, value).await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
45
src/error.rs
45
src/error.rs
|
@ -46,3 +46,48 @@ pub enum MpvError {
|
||||||
#[error("Unknown error: {0}")]
|
#[error("Unknown error: {0}")]
|
||||||
Other(String),
|
Other(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for MpvError {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(Self::MpvError(l0), Self::MpvError(r0)) => l0 == r0,
|
||||||
|
(Self::MpvSocketConnectionError(l0), Self::MpvSocketConnectionError(r0)) => l0 == r0,
|
||||||
|
(Self::InternalConnectionError(l0), Self::InternalConnectionError(r0)) => l0 == r0,
|
||||||
|
(Self::JsonParseError(l0), Self::JsonParseError(r0)) => {
|
||||||
|
l0.to_string() == r0.to_string()
|
||||||
|
}
|
||||||
|
(
|
||||||
|
Self::ValueContainsUnexpectedType {
|
||||||
|
expected_type: l_expected_type,
|
||||||
|
received: l_received,
|
||||||
|
},
|
||||||
|
Self::ValueContainsUnexpectedType {
|
||||||
|
expected_type: r_expected_type,
|
||||||
|
received: r_received,
|
||||||
|
},
|
||||||
|
) => l_expected_type == r_expected_type && l_received == r_received,
|
||||||
|
(
|
||||||
|
Self::DataContainsUnexpectedType {
|
||||||
|
expected_type: l_expected_type,
|
||||||
|
received: l_received,
|
||||||
|
},
|
||||||
|
Self::DataContainsUnexpectedType {
|
||||||
|
expected_type: r_expected_type,
|
||||||
|
received: r_received,
|
||||||
|
},
|
||||||
|
) => l_expected_type == r_expected_type && l_received == r_received,
|
||||||
|
(
|
||||||
|
Self::MissingKeyInObject {
|
||||||
|
key: l_key,
|
||||||
|
map: l_map,
|
||||||
|
},
|
||||||
|
Self::MissingKeyInObject {
|
||||||
|
key: r_key,
|
||||||
|
map: r_map,
|
||||||
|
},
|
||||||
|
) => l_key == r_key && l_map == r_map,
|
||||||
|
|
||||||
|
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
//! JSON parsing logic for properties returned in [`Event::PropertyChange`]
|
//! JSON parsing logic for properties returned either by
|
||||||
|
//! [`Mpv::get_property`] or [`Event::PropertyChange`]
|
||||||
//!
|
//!
|
||||||
//! This module is used to parse the json data from the `data` field of the
|
//! This module is used to parse the json data from the `data` field of
|
||||||
//! [`Event::PropertyChange`] variant. Mpv has about 1000 different properties
|
//! known properties. Mpv has about 1000 different properties
|
||||||
//! as of `v0.38.0`, so this module will only implement the most common ones.
|
//! as of `v0.38.0`, so this module will only implement the most common ones.
|
||||||
|
|
||||||
|
// TODO: reuse this logic for providing a more typesafe response API to `Mpv::get_property()`
|
||||||
|
// Although this data is currently of type `Option<`
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -129,14 +133,19 @@ pub fn parse_event_property(event: Event) -> Result<(usize, Property), MpvError>
|
||||||
};
|
};
|
||||||
Ok((id, Property::Metadata(metadata)))
|
Ok((id, Property::Metadata(metadata)))
|
||||||
}
|
}
|
||||||
// "playlist" => {
|
"playlist" => {
|
||||||
// let playlist = match data {
|
let playlist = match data {
|
||||||
// MpvDataType::Array(a) => json_array_to_playlist(&a),
|
Some(MpvDataType::Array(a)) => mpv_array_to_playlist(&a)?,
|
||||||
// MpvDataType::Null => Vec::new(),
|
None => Vec::new(),
|
||||||
// _ => return Err(Error(ErrorCode::ValueDoesNotContainPlaylist)),
|
Some(data) => {
|
||||||
// };
|
return Err(MpvError::DataContainsUnexpectedType {
|
||||||
// Ok((id, Property::Playlist(playlist)))
|
expected_type: "Array".to_owned(),
|
||||||
// }
|
received: data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok((id, Property::Playlist(playlist)))
|
||||||
|
}
|
||||||
"playlist-pos" => {
|
"playlist-pos" => {
|
||||||
let playlist_pos = match data {
|
let playlist_pos = match data {
|
||||||
Some(MpvDataType::Usize(u)) => Some(u),
|
Some(MpvDataType::Usize(u)) => Some(u),
|
||||||
|
@ -246,3 +255,59 @@ pub fn parse_event_property(event: Event) -> Result<(usize, Property), MpvError>
|
||||||
_ => Ok((id, Property::Unknown { name, data })),
|
_ => Ok((id, Property::Unknown { name, data })),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mpv_data_to_playlist_entry(
|
||||||
|
map: &HashMap<String, MpvDataType>,
|
||||||
|
) -> Result<PlaylistEntry, MpvError> {
|
||||||
|
let filename = match map.get("filename") {
|
||||||
|
Some(MpvDataType::String(s)) => s.to_string(),
|
||||||
|
Some(data) => {
|
||||||
|
return Err(MpvError::DataContainsUnexpectedType {
|
||||||
|
expected_type: "String".to_owned(),
|
||||||
|
received: data.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None => return Err(MpvError::MissingMpvData),
|
||||||
|
};
|
||||||
|
let title = match map.get("title") {
|
||||||
|
Some(MpvDataType::String(s)) => s.to_string(),
|
||||||
|
Some(data) => {
|
||||||
|
return Err(MpvError::DataContainsUnexpectedType {
|
||||||
|
expected_type: "String".to_owned(),
|
||||||
|
received: data.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None => return Err(MpvError::MissingMpvData),
|
||||||
|
};
|
||||||
|
let current = match map.get("current") {
|
||||||
|
Some(MpvDataType::Bool(b)) => *b,
|
||||||
|
Some(data) => {
|
||||||
|
return Err(MpvError::DataContainsUnexpectedType {
|
||||||
|
expected_type: "bool".to_owned(),
|
||||||
|
received: data.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None => return Err(MpvError::MissingMpvData),
|
||||||
|
};
|
||||||
|
Ok(PlaylistEntry {
|
||||||
|
id: 0,
|
||||||
|
filename,
|
||||||
|
title,
|
||||||
|
current,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mpv_array_to_playlist(array: &[MpvDataType]) -> Result<Vec<PlaylistEntry>, MpvError> {
|
||||||
|
array
|
||||||
|
.iter()
|
||||||
|
.map(|value| match value {
|
||||||
|
MpvDataType::HashMap(map) => mpv_data_to_playlist_entry(map),
|
||||||
|
_ => Err(MpvError::DataContainsUnexpectedType {
|
||||||
|
expected_type: "HashMap".to_owned(),
|
||||||
|
received: value.clone(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.enumerate()
|
||||||
|
.map(|(id, entry)| entry.map(|entry| PlaylistEntry { id, ..entry }))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
|
@ -141,12 +141,15 @@ pub trait MpvExt {
|
||||||
|
|
||||||
impl MpvExt for Mpv {
|
impl MpvExt for Mpv {
|
||||||
async fn get_metadata(&self) -> Result<HashMap<String, MpvDataType>, MpvError> {
|
async fn get_metadata(&self) -> Result<HashMap<String, MpvDataType>, MpvError> {
|
||||||
self.get_property("metadata").await
|
self.get_property("metadata")
|
||||||
|
.await?
|
||||||
|
.ok_or(MpvError::MissingMpvData)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_playlist(&self) -> Result<Playlist, MpvError> {
|
async fn get_playlist(&self) -> Result<Playlist, MpvError> {
|
||||||
self.get_property::<Vec<PlaylistEntry>>("playlist")
|
self.get_property::<Vec<PlaylistEntry>>("playlist")
|
||||||
.await
|
.await?
|
||||||
|
.ok_or(MpvError::MissingMpvData)
|
||||||
.map(Playlist)
|
.map(Playlist)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,15 +177,15 @@ impl MpvExt for Mpv {
|
||||||
let enabled = match option {
|
let enabled = match option {
|
||||||
Switch::On => "yes",
|
Switch::On => "yes",
|
||||||
Switch::Off => "no",
|
Switch::Off => "no",
|
||||||
Switch::Toggle => {
|
Switch::Toggle => self
|
||||||
self.get_property::<String>("pause")
|
.get_property::<String>("pause")
|
||||||
.await
|
.await?
|
||||||
.map(|s| match s.as_str() {
|
.ok_or(MpvError::MissingMpvData)
|
||||||
"yes" => "no",
|
.map(|s| match s.as_str() {
|
||||||
"no" => "yes",
|
"yes" => "no",
|
||||||
_ => "no",
|
"no" => "yes",
|
||||||
})?
|
_ => "no",
|
||||||
}
|
})?,
|
||||||
};
|
};
|
||||||
self.set_property("pause", enabled).await
|
self.set_property("pause", enabled).await
|
||||||
}
|
}
|
||||||
|
@ -238,16 +241,16 @@ impl MpvExt for Mpv {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn playlist_play_next(&self, id: usize) -> Result<(), MpvError> {
|
async fn playlist_play_next(&self, id: usize) -> Result<(), MpvError> {
|
||||||
match self.get_property::<usize>("playlist-pos").await {
|
let current_id = self
|
||||||
Ok(current_id) => {
|
.get_property::<usize>("playlist-pos")
|
||||||
self.run_command(MpvCommand::PlaylistMove {
|
.await?
|
||||||
from: id,
|
.ok_or(MpvError::MissingMpvData)?;
|
||||||
to: current_id + 1,
|
|
||||||
})
|
self.run_command(MpvCommand::PlaylistMove {
|
||||||
.await
|
from: id,
|
||||||
}
|
to: current_id + 1,
|
||||||
Err(msg) => Err(msg),
|
})
|
||||||
}
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn playlist_remove_id(&self, id: usize) -> Result<(), MpvError> {
|
async fn playlist_remove_id(&self, id: usize) -> Result<(), MpvError> {
|
||||||
|
@ -266,15 +269,15 @@ impl MpvExt for Mpv {
|
||||||
let enabled = match option {
|
let enabled = match option {
|
||||||
Switch::On => "inf",
|
Switch::On => "inf",
|
||||||
Switch::Off => "no",
|
Switch::Off => "no",
|
||||||
Switch::Toggle => {
|
Switch::Toggle => self
|
||||||
self.get_property::<String>("loop-file")
|
.get_property::<String>("loop-file")
|
||||||
.await
|
.await?
|
||||||
.map(|s| match s.as_str() {
|
.ok_or(MpvError::MissingMpvData)
|
||||||
"inf" => "no",
|
.map(|s| match s.as_str() {
|
||||||
"no" => "inf",
|
"inf" => "no",
|
||||||
_ => "no",
|
"no" => "inf",
|
||||||
})?
|
_ => "no",
|
||||||
}
|
})?,
|
||||||
};
|
};
|
||||||
self.set_property("loop-file", enabled).await
|
self.set_property("loop-file", enabled).await
|
||||||
}
|
}
|
||||||
|
@ -283,32 +286,32 @@ impl MpvExt for Mpv {
|
||||||
let enabled = match option {
|
let enabled = match option {
|
||||||
Switch::On => "inf",
|
Switch::On => "inf",
|
||||||
Switch::Off => "no",
|
Switch::Off => "no",
|
||||||
Switch::Toggle => {
|
Switch::Toggle => self
|
||||||
self.get_property::<String>("loop-playlist")
|
.get_property::<String>("loop-playlist")
|
||||||
.await
|
.await?
|
||||||
.map(|s| match s.as_str() {
|
.ok_or(MpvError::MissingMpvData)
|
||||||
"inf" => "no",
|
.map(|s| match s.as_str() {
|
||||||
"no" => "inf",
|
"inf" => "no",
|
||||||
_ => "no",
|
"no" => "inf",
|
||||||
})?
|
_ => "no",
|
||||||
}
|
})?,
|
||||||
};
|
};
|
||||||
self.set_property("loo-playlist", enabled).await
|
self.set_property("loop-playlist", enabled).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_mute(&self, option: Switch) -> Result<(), MpvError> {
|
async fn set_mute(&self, option: Switch) -> Result<(), MpvError> {
|
||||||
let enabled = match option {
|
let enabled = match option {
|
||||||
Switch::On => "yes",
|
Switch::On => "yes",
|
||||||
Switch::Off => "no",
|
Switch::Off => "no",
|
||||||
Switch::Toggle => {
|
Switch::Toggle => self
|
||||||
self.get_property::<String>("mute")
|
.get_property::<String>("mute")
|
||||||
.await
|
.await?
|
||||||
.map(|s| match s.as_str() {
|
.ok_or(MpvError::MissingMpvData)
|
||||||
"yes" => "no",
|
.map(|s| match s.as_str() {
|
||||||
"no" => "yes",
|
"yes" => "no",
|
||||||
_ => "no",
|
"no" => "yes",
|
||||||
})?
|
_ => "no",
|
||||||
}
|
})?,
|
||||||
};
|
};
|
||||||
self.set_property("mute", enabled).await
|
self.set_property("mute", enabled).await
|
||||||
}
|
}
|
||||||
|
@ -318,19 +321,15 @@ impl MpvExt for Mpv {
|
||||||
input_speed: f64,
|
input_speed: f64,
|
||||||
option: NumberChangeOptions,
|
option: NumberChangeOptions,
|
||||||
) -> Result<(), MpvError> {
|
) -> Result<(), MpvError> {
|
||||||
match self.get_property::<f64>("speed").await {
|
let speed = self
|
||||||
Ok(speed) => match option {
|
.get_property::<f64>("speed")
|
||||||
NumberChangeOptions::Increase => {
|
.await?
|
||||||
self.set_property("speed", speed + input_speed).await
|
.ok_or(MpvError::MissingMpvData)?;
|
||||||
}
|
|
||||||
|
|
||||||
NumberChangeOptions::Decrease => {
|
match option {
|
||||||
self.set_property("speed", speed - input_speed).await
|
NumberChangeOptions::Increase => self.set_property("speed", speed + input_speed).await,
|
||||||
}
|
NumberChangeOptions::Decrease => self.set_property("speed", speed - input_speed).await,
|
||||||
|
NumberChangeOptions::Absolute => self.set_property("speed", input_speed).await,
|
||||||
NumberChangeOptions::Absolute => self.set_property("speed", input_speed).await,
|
|
||||||
},
|
|
||||||
Err(msg) => Err(msg),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,19 +338,19 @@ impl MpvExt for Mpv {
|
||||||
input_volume: f64,
|
input_volume: f64,
|
||||||
option: NumberChangeOptions,
|
option: NumberChangeOptions,
|
||||||
) -> Result<(), MpvError> {
|
) -> Result<(), MpvError> {
|
||||||
match self.get_property::<f64>("volume").await {
|
let volume = self
|
||||||
Ok(volume) => match option {
|
.get_property::<f64>("volume")
|
||||||
NumberChangeOptions::Increase => {
|
.await?
|
||||||
self.set_property("volume", volume + input_volume).await
|
.ok_or(MpvError::MissingMpvData)?;
|
||||||
}
|
|
||||||
|
|
||||||
NumberChangeOptions::Decrease => {
|
match option {
|
||||||
self.set_property("volume", volume - input_volume).await
|
NumberChangeOptions::Increase => {
|
||||||
}
|
self.set_property("volume", volume + input_volume).await
|
||||||
|
}
|
||||||
NumberChangeOptions::Absolute => self.set_property("volume", input_volume).await,
|
NumberChangeOptions::Decrease => {
|
||||||
},
|
self.set_property("volume", volume - input_volume).await
|
||||||
Err(msg) => Err(msg),
|
}
|
||||||
|
NumberChangeOptions::Absolute => self.set_property("volume", input_volume).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@ impl TypeHandler for Vec<PlaylistEntry> {
|
||||||
expected_type: "Array<Value>".to_string(),
|
expected_type: "Array<Value>".to_string(),
|
||||||
received: value.clone(),
|
received: value.clone(),
|
||||||
})
|
})
|
||||||
.map(|array| json_array_to_playlist(array))
|
.and_then(|array| json_array_to_playlist(array))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_string(&self) -> String {
|
fn as_string(&self) -> String {
|
||||||
|
@ -155,29 +155,65 @@ pub(crate) fn json_array_to_vec(array: &[Value]) -> Result<Vec<MpvDataType>, Mpv
|
||||||
array.iter().map(json_to_value).collect()
|
array.iter().map(json_to_value).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn json_array_to_playlist(array: &[Value]) -> Vec<PlaylistEntry> {
|
fn json_map_to_playlist_entry(
|
||||||
let mut output: Vec<PlaylistEntry> = Vec::new();
|
map: &serde_json::map::Map<String, Value>,
|
||||||
for (id, entry) in array.iter().enumerate() {
|
) -> Result<PlaylistEntry, MpvError> {
|
||||||
let mut filename: String = String::new();
|
let filename = match map.get("filename") {
|
||||||
let mut title: String = String::new();
|
Some(Value::String(s)) => s.to_string(),
|
||||||
let mut current: bool = false;
|
Some(data) => {
|
||||||
if let Value::String(ref f) = entry["filename"] {
|
return Err(MpvError::ValueContainsUnexpectedType {
|
||||||
filename = f.to_string();
|
expected_type: "String".to_owned(),
|
||||||
|
received: data.clone(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if let Value::String(ref t) = entry["title"] {
|
None => return Err(MpvError::MissingMpvData),
|
||||||
title = t.to_string();
|
};
|
||||||
|
let title = match map.get("title") {
|
||||||
|
Some(Value::String(s)) => s.to_string(),
|
||||||
|
Some(data) => {
|
||||||
|
return Err(MpvError::ValueContainsUnexpectedType {
|
||||||
|
expected_type: "String".to_owned(),
|
||||||
|
received: data.clone(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
if let Value::Bool(ref b) = entry["current"] {
|
None => return Err(MpvError::MissingMpvData),
|
||||||
current = *b;
|
};
|
||||||
|
let current = match map.get("current") {
|
||||||
|
Some(Value::Bool(b)) => *b,
|
||||||
|
Some(data) => {
|
||||||
|
return Err(MpvError::ValueContainsUnexpectedType {
|
||||||
|
expected_type: "bool".to_owned(),
|
||||||
|
received: data.clone(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
output.push(PlaylistEntry {
|
None => return Err(MpvError::MissingMpvData),
|
||||||
id,
|
};
|
||||||
filename,
|
Ok(PlaylistEntry {
|
||||||
title,
|
id: 0,
|
||||||
current,
|
filename,
|
||||||
});
|
title,
|
||||||
}
|
current,
|
||||||
output
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn json_array_to_playlist(array: &[Value]) -> Result<Vec<PlaylistEntry>, MpvError> {
|
||||||
|
array
|
||||||
|
.iter()
|
||||||
|
.map(|entry| match entry {
|
||||||
|
Value::Object(map) => json_map_to_playlist_entry(map),
|
||||||
|
data => Err(MpvError::ValueContainsUnexpectedType {
|
||||||
|
expected_type: "Map<String, Value>".to_owned(),
|
||||||
|
received: data.clone(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.enumerate()
|
||||||
|
.map(|(id, entry)| {
|
||||||
|
entry.map(|mut entry| {
|
||||||
|
entry.id = id;
|
||||||
|
entry
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -277,7 +313,7 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_json_array_to_playlist() {
|
fn test_json_array_to_playlist() -> Result<(), MpvError> {
|
||||||
let json = json!([
|
let json = json!([
|
||||||
{
|
{
|
||||||
"filename": "file1",
|
"filename": "file1",
|
||||||
|
@ -306,6 +342,8 @@ mod test {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_eq!(json_array_to_playlist(json.as_array().unwrap()), expected);
|
assert_eq!(json_array_to_playlist(json.as_array().unwrap())?, expected);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,30 @@
|
||||||
use mpvipc::MpvExt;
|
use mpvipc::{MpvError, MpvExt};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[cfg(target_family = "unix")]
|
#[cfg(target_family = "unix")]
|
||||||
async fn test_get_mpv_version() {
|
async fn test_get_mpv_version() -> Result<(), MpvError> {
|
||||||
let (mut proc, mpv) = spawn_headless_mpv().await.unwrap();
|
let (mut proc, mpv) = spawn_headless_mpv().await.unwrap();
|
||||||
let version: String = mpv.get_property("mpv-version").await.unwrap();
|
let version: String = mpv.get_property("mpv-version").await?.unwrap();
|
||||||
assert!(version.starts_with("mpv"));
|
assert!(version.starts_with("mpv"));
|
||||||
|
|
||||||
mpv.kill().await.unwrap();
|
mpv.kill().await.unwrap();
|
||||||
proc.kill().await.unwrap();
|
proc.kill().await.unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[cfg(target_family = "unix")]
|
#[cfg(target_family = "unix")]
|
||||||
async fn test_set_property() {
|
async fn test_set_property() -> Result<(), MpvError> {
|
||||||
let (mut proc, mpv) = spawn_headless_mpv().await.unwrap();
|
let (mut proc, mpv) = spawn_headless_mpv().await.unwrap();
|
||||||
mpv.set_property("pause", true).await.unwrap();
|
mpv.set_property("pause", true).await.unwrap();
|
||||||
let paused: bool = mpv.get_property("pause").await.unwrap();
|
let paused: bool = mpv.get_property("pause").await?.unwrap();
|
||||||
assert!(paused);
|
assert!(paused);
|
||||||
|
|
||||||
mpv.kill().await.unwrap();
|
mpv.kill().await.unwrap();
|
||||||
proc.kill().await.unwrap();
|
proc.kill().await.unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,73 +22,77 @@ fn test_socket(answers: Vec<String>) -> (UnixStream, JoinHandle<Result<(), Lines
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test(tokio::test)]
|
#[test(tokio::test)]
|
||||||
async fn test_get_property_successful() {
|
async fn test_get_property_successful() -> Result<(), MpvError> {
|
||||||
let (server, join_handle) = test_socket(vec![
|
let (server, join_handle) = test_socket(vec![
|
||||||
json!({ "data": 100.0, "request_id": 0, "error": "success" }).to_string(),
|
json!({ "data": 100.0, "request_id": 0, "error": "success" }).to_string(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
let mpv = Mpv::connect_socket(server).await?;
|
||||||
let volume: f64 = mpv.get_property("volume").await.unwrap();
|
let volume: Option<f64> = mpv.get_property("volume").await?;
|
||||||
|
|
||||||
assert_eq!(volume, 100.0);
|
assert_eq!(volume, Some(100.0));
|
||||||
join_handle.await.unwrap().unwrap();
|
join_handle.await.unwrap().unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test(tokio::test)]
|
#[test(tokio::test)]
|
||||||
async fn test_get_property_broken_pipe() {
|
async fn test_get_property_broken_pipe() -> Result<(), MpvError> {
|
||||||
let (server, join_handle) = test_socket(vec![]);
|
let (server, join_handle) = test_socket(vec![]);
|
||||||
|
|
||||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
let mpv = Mpv::connect_socket(server).await.unwrap();
|
||||||
let maybe_volume = mpv.get_property::<f64>("volume").await;
|
let maybe_volume = mpv.get_property::<f64>("volume").await;
|
||||||
|
|
||||||
match maybe_volume {
|
assert_eq!(
|
||||||
Err(MpvError::MpvSocketConnectionError(err)) => {
|
maybe_volume,
|
||||||
assert_eq!(err.to_string(), "Broken pipe (os error 32)");
|
Err(MpvError::MpvSocketConnectionError(
|
||||||
}
|
"Broken pipe (os error 32)".to_string()
|
||||||
_ => panic!("Unexpected result: {:?}", maybe_volume),
|
))
|
||||||
}
|
);
|
||||||
|
|
||||||
join_handle.await.unwrap().unwrap();
|
join_handle.await.unwrap().unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test(tokio::test)]
|
#[test(tokio::test)]
|
||||||
async fn test_get_property_wrong_type() {
|
async fn test_get_property_wrong_type() -> Result<(), MpvError> {
|
||||||
let (server, join_handle) = test_socket(vec![
|
let (server, join_handle) = test_socket(vec![
|
||||||
json!({ "data": 100.0, "request_id": 0, "error": "success" }).to_string(),
|
json!({ "data": 100.0, "request_id": 0, "error": "success" }).to_string(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
let mpv = Mpv::connect_socket(server).await?;
|
||||||
let maybe_volume = mpv.get_property::<bool>("volume").await;
|
let maybe_volume = mpv.get_property::<bool>("volume").await;
|
||||||
|
|
||||||
match maybe_volume {
|
assert_eq!(
|
||||||
|
maybe_volume,
|
||||||
Err(MpvError::ValueContainsUnexpectedType {
|
Err(MpvError::ValueContainsUnexpectedType {
|
||||||
expected_type,
|
expected_type: "bool".to_string(),
|
||||||
received,
|
received: json!(100.0)
|
||||||
}) => {
|
})
|
||||||
assert_eq!(expected_type, "bool");
|
);
|
||||||
assert_eq!(received, json!(100.0));
|
|
||||||
}
|
|
||||||
_ => panic!("Unexpected result: {:?}", maybe_volume),
|
|
||||||
}
|
|
||||||
join_handle.await.unwrap().unwrap();
|
join_handle.await.unwrap().unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test(tokio::test)]
|
#[test(tokio::test)]
|
||||||
async fn test_get_property_error() {
|
async fn test_get_property_error() -> Result<(), MpvError> {
|
||||||
let (server, join_handle) = test_socket(vec![
|
let (server, join_handle) = test_socket(vec![
|
||||||
json!({ "error": "property unavailable", "request_id": 0 }).to_string(),
|
json!({ "error": "property unavailable", "request_id": 0 }).to_string(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
let mpv = Mpv::connect_socket(server).await?;
|
||||||
let maybe_volume = mpv.get_property::<f64>("volume").await;
|
let maybe_volume = mpv.get_property::<f64>("volume").await;
|
||||||
|
|
||||||
match maybe_volume {
|
assert_eq!(
|
||||||
Err(MpvError::MpvError(err)) => {
|
maybe_volume,
|
||||||
assert_eq!(err, "property unavailable");
|
Err(MpvError::MpvError("property unavailable".to_string()))
|
||||||
}
|
);
|
||||||
_ => panic!("Unexpected result: {:?}", maybe_volume),
|
|
||||||
}
|
|
||||||
|
|
||||||
join_handle.await.unwrap().unwrap();
|
join_handle.await.unwrap().unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test(tokio::test)]
|
#[test(tokio::test)]
|
||||||
|
@ -130,8 +134,8 @@ async fn test_get_property_simultaneous_requests() {
|
||||||
let mpv_clone_1 = mpv.clone();
|
let mpv_clone_1 = mpv.clone();
|
||||||
let mpv_poller_1 = tokio::spawn(async move {
|
let mpv_poller_1 = tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
let volume: f64 = mpv_clone_1.get_property("volume").await.unwrap();
|
let volume: Option<f64> = mpv_clone_1.get_property("volume").await.unwrap();
|
||||||
assert_eq!(volume, 100.0);
|
assert_eq!(volume, Some(100.0));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -139,8 +143,8 @@ async fn test_get_property_simultaneous_requests() {
|
||||||
let mpv_poller_2 = tokio::spawn(async move {
|
let mpv_poller_2 = tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
tokio::time::sleep(Duration::from_millis(1)).await;
|
tokio::time::sleep(Duration::from_millis(1)).await;
|
||||||
let paused: bool = mpv_clone_2.get_property("pause").await.unwrap();
|
let paused: Option<bool> = mpv_clone_2.get_property("pause").await.unwrap();
|
||||||
assert!(paused);
|
assert_eq!(paused, Some(true));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -173,7 +177,7 @@ async fn test_get_property_simultaneous_requests() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test(tokio::test)]
|
#[test(tokio::test)]
|
||||||
async fn test_get_playlist() {
|
async fn test_get_playlist() -> Result<(), MpvError> {
|
||||||
let expected = Playlist(vec![
|
let expected = Playlist(vec![
|
||||||
PlaylistEntry {
|
PlaylistEntry {
|
||||||
id: 0,
|
id: 0,
|
||||||
|
@ -208,22 +212,26 @@ async fn test_get_playlist() {
|
||||||
})
|
})
|
||||||
.to_string()]);
|
.to_string()]);
|
||||||
|
|
||||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
let mpv = Mpv::connect_socket(server).await?;
|
||||||
let playlist = mpv.get_playlist().await.unwrap();
|
let playlist = mpv.get_playlist().await?;
|
||||||
|
|
||||||
assert_eq!(playlist, expected);
|
assert_eq!(playlist, expected);
|
||||||
join_handle.await.unwrap().unwrap();
|
join_handle.await.unwrap().unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test(tokio::test)]
|
#[test(tokio::test)]
|
||||||
async fn test_get_playlist_empty() {
|
async fn test_get_playlist_empty() -> Result<(), MpvError> {
|
||||||
let (server, join_handle) = test_socket(vec![
|
let (server, join_handle) = test_socket(vec![
|
||||||
json!({ "data": [], "request_id": 0, "error": "success" }).to_string(),
|
json!({ "data": [], "request_id": 0, "error": "success" }).to_string(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
let mpv = Mpv::connect_socket(server).await?;
|
||||||
let playlist = mpv.get_playlist().await.unwrap();
|
let playlist = mpv.get_playlist().await?;
|
||||||
|
|
||||||
assert_eq!(playlist, Playlist(vec![]));
|
assert_eq!(playlist, Playlist(vec![]));
|
||||||
join_handle.await.unwrap().unwrap();
|
join_handle.await.unwrap().unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{panic, time::Duration};
|
use std::{panic, time::Duration};
|
||||||
|
|
||||||
use futures::{stream::FuturesUnordered, SinkExt, StreamExt};
|
use futures::{stream::FuturesUnordered, SinkExt, StreamExt};
|
||||||
use mpvipc::{Mpv, MpvError, MpvExt, Playlist, PlaylistEntry};
|
use mpvipc::{Mpv, MpvError};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use test_log::test;
|
use test_log::test;
|
||||||
use tokio::{net::UnixStream, task::JoinHandle};
|
use tokio::{net::UnixStream, task::JoinHandle};
|
||||||
|
@ -22,69 +22,76 @@ fn test_socket(answers: Vec<String>) -> (UnixStream, JoinHandle<Result<(), Lines
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test(tokio::test)]
|
#[test(tokio::test)]
|
||||||
async fn test_set_property_successful() {
|
async fn test_set_property_successful() -> Result<(), MpvError> {
|
||||||
let (server, join_handle) = test_socket(vec![
|
let (server, join_handle) = test_socket(vec![
|
||||||
json!({ "data": null, "request_id": 0, "error": "success" }).to_string(),
|
json!({ "data": null, "request_id": 0, "error": "success" }).to_string(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
let mpv = Mpv::connect_socket(server).await?;
|
||||||
let volume = mpv.set_property("volume", 64.0).await;
|
mpv.set_property("volume", 64.0).await?;
|
||||||
|
|
||||||
assert!(volume.is_ok());
|
|
||||||
join_handle.await.unwrap().unwrap();
|
join_handle.await.unwrap().unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test(tokio::test)]
|
#[test(tokio::test)]
|
||||||
async fn test_set_property_broken_pipe() {
|
async fn test_set_property_broken_pipe() -> Result<(), MpvError> {
|
||||||
let (server, join_handle) = test_socket(vec![]);
|
let (server, join_handle) = test_socket(vec![]);
|
||||||
|
|
||||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
let mpv = Mpv::connect_socket(server).await?;
|
||||||
let maybe_set_volume = mpv.set_property("volume", 64.0).await;
|
let maybe_set_volume = mpv.set_property("volume", 64.0).await;
|
||||||
|
|
||||||
match maybe_set_volume {
|
assert_eq!(
|
||||||
Err(MpvError::MpvSocketConnectionError(err)) => {
|
maybe_set_volume,
|
||||||
assert_eq!(err.to_string(), "Broken pipe (os error 32)");
|
Err(MpvError::MpvSocketConnectionError(
|
||||||
}
|
"Broken pipe (os error 32)".to_string()
|
||||||
_ => panic!("Unexpected result: {:?}", maybe_set_volume),
|
))
|
||||||
}
|
);
|
||||||
|
|
||||||
join_handle.await.unwrap().unwrap();
|
join_handle.await.unwrap().unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test(tokio::test)]
|
#[test(tokio::test)]
|
||||||
async fn test_set_property_wrong_type() {
|
async fn test_set_property_wrong_type() -> Result<(), MpvError> {
|
||||||
let (server, join_handle) = test_socket(vec![
|
let (server, join_handle) = test_socket(vec![
|
||||||
json!({"request_id":0,"error":"unsupported format for accessing property"}).to_string(),
|
json!({"request_id":0,"error":"unsupported format for accessing property"}).to_string(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
let mpv = Mpv::connect_socket(server).await?;
|
||||||
let maybe_volume = mpv.set_property::<bool>("volume", true).await;
|
let maybe_volume = mpv.set_property::<bool>("volume", true).await;
|
||||||
|
|
||||||
match maybe_volume {
|
assert_eq!(
|
||||||
Err(MpvError::MpvError(err)) => {
|
maybe_volume,
|
||||||
assert_eq!(err, "unsupported format for accessing property");
|
Err(MpvError::MpvError(
|
||||||
}
|
"unsupported format for accessing property".to_string()
|
||||||
_ => panic!("Unexpected result: {:?}", maybe_volume),
|
))
|
||||||
}
|
);
|
||||||
|
|
||||||
join_handle.await.unwrap().unwrap();
|
join_handle.await.unwrap().unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test(tokio::test)]
|
#[test(tokio::test)]
|
||||||
async fn test_get_property_error() {
|
async fn test_get_property_error() -> Result<(), MpvError> {
|
||||||
let (server, join_handle) = test_socket(vec![
|
let (server, join_handle) = test_socket(vec![
|
||||||
json!({"request_id":0,"error":"property not found"}).to_string(),
|
json!({"request_id":0,"error":"property not found"}).to_string(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
let mpv = Mpv::connect_socket(server).await?;
|
||||||
let maybe_volume = mpv.set_property("nonexistent", true).await;
|
let maybe_volume = mpv.set_property("nonexistent", true).await;
|
||||||
|
|
||||||
match maybe_volume {
|
assert_eq!(
|
||||||
Err(MpvError::MpvError(err)) => {
|
maybe_volume,
|
||||||
assert_eq!(err, "property not found");
|
Err(MpvError::MpvError("property not found".to_string()))
|
||||||
}
|
);
|
||||||
_ => panic!("Unexpected result: {:?}", maybe_volume),
|
|
||||||
}
|
|
||||||
|
|
||||||
join_handle.await.unwrap().unwrap();
|
join_handle.await.unwrap().unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test(tokio::test)]
|
#[test(tokio::test)]
|
||||||
|
@ -175,59 +182,3 @@ async fn test_set_property_simultaneous_requests() {
|
||||||
panic!("One of the pollers quit unexpectedly");
|
panic!("One of the pollers quit unexpectedly");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test(tokio::test)]
|
|
||||||
async fn test_get_playlist() {
|
|
||||||
let expected = Playlist(vec![
|
|
||||||
PlaylistEntry {
|
|
||||||
id: 0,
|
|
||||||
filename: "file1".to_string(),
|
|
||||||
title: "title1".to_string(),
|
|
||||||
current: false,
|
|
||||||
},
|
|
||||||
PlaylistEntry {
|
|
||||||
id: 1,
|
|
||||||
filename: "file2".to_string(),
|
|
||||||
title: "title2".to_string(),
|
|
||||||
current: true,
|
|
||||||
},
|
|
||||||
PlaylistEntry {
|
|
||||||
id: 2,
|
|
||||||
filename: "file3".to_string(),
|
|
||||||
title: "title3".to_string(),
|
|
||||||
current: false,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
let (server, join_handle) = test_socket(vec![json!({
|
|
||||||
"data": expected.0.iter().map(|entry| {
|
|
||||||
json!({
|
|
||||||
"filename": entry.filename,
|
|
||||||
"title": entry.title,
|
|
||||||
"current": entry.current
|
|
||||||
})
|
|
||||||
}).collect::<Vec<Value>>(),
|
|
||||||
"request_id": 0,
|
|
||||||
"error": "success"
|
|
||||||
})
|
|
||||||
.to_string()]);
|
|
||||||
|
|
||||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
|
||||||
let playlist = mpv.get_playlist().await.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(playlist, expected);
|
|
||||||
join_handle.await.unwrap().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test(tokio::test)]
|
|
||||||
async fn test_get_playlist_empty() {
|
|
||||||
let (server, join_handle) = test_socket(vec![
|
|
||||||
json!({ "data": [], "request_id": 0, "error": "success" }).to_string(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
|
||||||
let playlist = mpv.get_playlist().await.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(playlist, Playlist(vec![]));
|
|
||||||
join_handle.await.unwrap().unwrap();
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue