cargo fmt + clippy
Build and test / check (push) Successful in 1m55s Details
Build and test / build (push) Successful in 1m59s Details
Build and test / test (push) Successful in 2m30s Details

This commit is contained in:
Oystein Kristoffer Tveit 2024-04-30 02:13:57 +02:00
parent 7bcd3fc1ec
commit 3be7b2bda6
Signed by: oysteikt
GPG Key ID: 9F2F7D8250F35146
10 changed files with 134 additions and 138 deletions

View File

@ -1,4 +1,3 @@
use env_logger;
use mpvipc::{Error as MpvError, Mpv, MpvExt}; use mpvipc::{Error as MpvError, Mpv, MpvExt};
#[tokio::main] #[tokio::main]

View File

@ -1,6 +1,4 @@
use env_logger; use mpvipc::{Error, Mpv, MpvExt};
use mpvipc::{Error, Event, Mpv, MpvExt, MpvDataType, Property};
use std::io::{self, Write};
fn seconds_to_hms(total: f64) -> String { fn seconds_to_hms(total: f64) -> String {
let total = total as u64; let total = total as u64;
@ -15,10 +13,10 @@ fn seconds_to_hms(total: f64) -> String {
async fn main() -> Result<(), Error> { async fn main() -> Result<(), Error> {
env_logger::init(); env_logger::init();
let mut mpv = Mpv::connect("/tmp/mpv.sock").await?; let mpv = Mpv::connect("/tmp/mpv.sock").await?;
let mut pause = false; let pause = false;
let mut playback_time = std::f64::NAN; let playback_time = std::f64::NAN;
let mut duration = std::f64::NAN; let duration = std::f64::NAN;
mpv.observe_property(1, "path").await?; mpv.observe_property(1, "path").await?;
mpv.observe_property(2, "pause").await?; mpv.observe_property(2, "pause").await?;
mpv.observe_property(3, "playback-time").await?; mpv.observe_property(3, "playback-time").await?;

View File

@ -321,13 +321,14 @@ impl Mpv {
} }
pub async fn get_event_stream(&self) -> impl futures::Stream<Item = Result<Event, Error>> { pub async fn get_event_stream(&self) -> impl futures::Stream<Item = Result<Event, Error>> {
tokio_stream::wrappers::BroadcastStream::new(self.broadcast_channel.subscribe()) tokio_stream::wrappers::BroadcastStream::new(self.broadcast_channel.subscribe()).map(
.map(|event| { |event| match event {
match event { Ok(event) => Mpv::map_event(event),
Ok(event) => Mpv::map_event(event), Err(_) => Err(Error(ErrorCode::ConnectError(
Err(_) => Err(Error(ErrorCode::ConnectError("Failed to receive event".to_string()))), "Failed to receive event".to_string(),
} ))),
}) },
)
} }
fn map_event(raw_event: MpvIpcEvent) -> Result<Event, Error> { fn map_event(raw_event: MpvIpcEvent) -> Result<Event, Error> {
@ -373,43 +374,43 @@ impl Mpv {
.ok_or(Error(ErrorCode::ValueDoesNotContainString))?; .ok_or(Error(ErrorCode::ValueDoesNotContainString))?;
match property_name { match property_name {
"path" => { "path" => {
let path = event let path = event
.get("data") .get("data")
.ok_or(Error(ErrorCode::MissingValue))? .ok_or(Error(ErrorCode::MissingValue))?
.as_str() .as_str()
.map(|s| s.to_string()); .map(|s| s.to_string());
Ok(Event::PropertyChange { Ok(Event::PropertyChange {
id, id,
property: Property::Path(path), property: Property::Path(path),
}) })
} }
"pause" => { "pause" => {
let pause = event let pause = event
.get("data") .get("data")
.ok_or(Error(ErrorCode::MissingValue))? .ok_or(Error(ErrorCode::MissingValue))?
.as_bool() .as_bool()
.ok_or(Error(ErrorCode::ValueDoesNotContainBool))?; .ok_or(Error(ErrorCode::ValueDoesNotContainBool))?;
Ok(Event::PropertyChange { Ok(Event::PropertyChange {
id, id,
property: Property::Pause(pause), property: Property::Pause(pause),
}) })
} }
// TODO: missing cases // TODO: missing cases
_ => { _ => {
let data = event let data = event
.get("data") .get("data")
.ok_or(Error(ErrorCode::MissingValue))? .ok_or(Error(ErrorCode::MissingValue))?
.clone(); .clone();
Ok(Event::PropertyChange { Ok(Event::PropertyChange {
id, id,
property: Property::Unknown { property: Property::Unknown {
name: property_name.to_string(), name: property_name.to_string(),
// TODO: fix // TODO: fix
data: MpvDataType::Double(data.as_f64().unwrap_or(0.0)), data: MpvDataType::Double(data.as_f64().unwrap_or(0.0)),
}, },
}) })
} }
} }
} }
"chapter-change" => Ok(Event::ChapterChange), "chapter-change" => Ok(Event::ChapterChange),

View File

@ -1,4 +1,7 @@
use crate::{Error, IntoRawCommandPart, Mpv, MpvCommand, MpvDataType, Playlist, PlaylistAddOptions, PlaylistAddTypeOptions, PlaylistEntry, SeekOptions}; use crate::{
Error, IntoRawCommandPart, Mpv, MpvCommand, MpvDataType, Playlist, PlaylistAddOptions,
PlaylistAddTypeOptions, PlaylistEntry, SeekOptions,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
@ -31,7 +34,8 @@ pub enum Switch {
pub trait MpvExt { pub trait MpvExt {
async fn toggle(&self) -> Result<(), Error>; async fn toggle(&self) -> Result<(), Error>;
async fn stop(&self) -> Result<(), Error>; async fn stop(&self) -> Result<(), Error>;
async fn set_volume(&self, input_volume: f64, option: NumberChangeOptions) -> Result<(), Error>; async fn set_volume(&self, input_volume: f64, option: NumberChangeOptions)
-> Result<(), Error>;
async fn set_speed(&self, input_speed: f64, option: NumberChangeOptions) -> Result<(), Error>; async fn set_speed(&self, input_speed: f64, option: NumberChangeOptions) -> Result<(), Error>;
async fn set_mute(&self, option: Switch) -> Result<(), Error>; async fn set_mute(&self, option: Switch) -> Result<(), Error>;
async fn set_loop_playlist(&self, option: Switch) -> Result<(), Error>; async fn set_loop_playlist(&self, option: Switch) -> Result<(), Error>;
@ -43,7 +47,12 @@ pub trait MpvExt {
async fn playlist_play_id(&self, id: usize) -> Result<(), Error>; async fn playlist_play_id(&self, id: usize) -> Result<(), Error>;
async fn playlist_move_id(&self, from: usize, to: usize) -> Result<(), Error>; async fn playlist_move_id(&self, from: usize, to: usize) -> Result<(), Error>;
async fn playlist_clear(&self) -> Result<(), Error>; async fn playlist_clear(&self) -> Result<(), Error>;
async fn playlist_add(&self, file: &str, file_type: PlaylistAddTypeOptions, option: PlaylistAddOptions) -> Result<(), Error>; async fn playlist_add(
&self,
file: &str,
file_type: PlaylistAddTypeOptions,
option: PlaylistAddOptions,
) -> Result<(), Error>;
async fn restart(&self) -> Result<(), Error>; async fn restart(&self) -> Result<(), Error>;
async fn prev(&self) -> Result<(), Error>; async fn prev(&self) -> Result<(), Error>;
async fn pause(&self) -> Result<(), Error>; async fn pause(&self) -> Result<(), Error>;
@ -53,7 +62,6 @@ pub trait MpvExt {
async fn kill(&self) -> Result<(), Error>; async fn kill(&self) -> Result<(), Error>;
async fn get_playlist(&self) -> Result<Playlist, Error>; async fn get_playlist(&self) -> Result<Playlist, Error>;
async fn get_metadata(&self) -> Result<HashMap<String, MpvDataType>, Error>; async fn get_metadata(&self) -> Result<HashMap<String, MpvDataType>, Error>;
} }
impl MpvExt for Mpv { impl MpvExt for Mpv {
@ -64,7 +72,7 @@ impl MpvExt for Mpv {
async fn get_playlist(&self) -> Result<Playlist, Error> { async fn get_playlist(&self) -> Result<Playlist, Error> {
self.get_property::<Vec<PlaylistEntry>>("playlist") self.get_property::<Vec<PlaylistEntry>>("playlist")
.await .await
.map(|entries| Playlist(entries)) .map(Playlist)
} }
async fn kill(&self) -> Result<(), Error> { async fn kill(&self) -> Result<(), Error> {
@ -217,11 +225,7 @@ impl MpvExt for Mpv {
self.set_property("mute", enabled).await self.set_property("mute", enabled).await
} }
async fn set_speed( async fn set_speed(&self, input_speed: f64, option: NumberChangeOptions) -> Result<(), Error> {
&self,
input_speed: f64,
option: NumberChangeOptions,
) -> Result<(), Error> {
match self.get_property::<f64>("speed").await { match self.get_property::<f64>("speed").await {
Ok(speed) => match option { Ok(speed) => match option {
NumberChangeOptions::Increase => { NumberChangeOptions::Increase => {
@ -266,4 +270,4 @@ impl MpvExt for Mpv {
async fn toggle(&self) -> Result<(), Error> { async fn toggle(&self) -> Result<(), Error> {
self.run_command_raw("cycle", &["pause"]).await.map(|_| ()) self.run_command_raw("cycle", &["pause"]).await.map(|_| ())
} }
} }

View File

@ -115,7 +115,7 @@ impl MpvIpc {
.as_ref() .as_ref()
.map_err(|why| Error(ErrorCode::ConnectError(why.to_string()))) .map_err(|why| Error(ErrorCode::ConnectError(why.to_string())))
.and_then(|event| { .and_then(|event| {
serde_json::from_str::<Value>(&event) serde_json::from_str::<Value>(event)
.map_err(|why| Error(ErrorCode::JsonParseError(why.to_string()))) .map_err(|why| Error(ErrorCode::JsonParseError(why.to_string())))
}); });
@ -192,5 +192,5 @@ fn parse_mpv_response_data(value: Value) -> Result<Option<Value>, Error> {
Ok(v) => log::trace!("Successfully parsed mpv response data: {:?}", v), Ok(v) => log::trace!("Successfully parsed mpv response data: {:?}", v),
Err(e) => log::trace!("Error parsing mpv response data: {:?}", e), Err(e) => log::trace!("Error parsing mpv response data: {:?}", e),
} }
result.map(|opt| opt.map(|val| val.clone())) result.map(|opt| opt.cloned())
} }

View File

@ -1,7 +1,7 @@
mod api; mod api;
mod api_extension;
mod ipc; mod ipc;
mod message_parser; mod message_parser;
mod api_extension;
pub use api::*; pub use api::*;
pub use api_extension::*; pub use api_extension::*;

View File

@ -24,7 +24,9 @@ impl TypeHandler for String {
impl TypeHandler for bool { impl TypeHandler for bool {
fn get_value(value: Value) -> Result<bool, Error> { fn get_value(value: Value) -> Result<bool, Error> {
value.as_bool().ok_or(Error(ErrorCode::ValueDoesNotContainBool)) value
.as_bool()
.ok_or(Error(ErrorCode::ValueDoesNotContainBool))
} }
fn as_string(&self) -> String { fn as_string(&self) -> String {
@ -38,7 +40,9 @@ impl TypeHandler for bool {
impl TypeHandler for f64 { impl TypeHandler for f64 {
fn get_value(value: Value) -> Result<f64, Error> { fn get_value(value: Value) -> Result<f64, Error> {
value.as_f64().ok_or(Error(ErrorCode::ValueDoesNotContainF64)) value
.as_f64()
.ok_or(Error(ErrorCode::ValueDoesNotContainF64))
} }
fn as_string(&self) -> String { fn as_string(&self) -> String {
@ -48,9 +52,10 @@ impl TypeHandler for f64 {
impl TypeHandler for usize { impl TypeHandler for usize {
fn get_value(value: Value) -> Result<usize, Error> { fn get_value(value: Value) -> Result<usize, Error> {
value.as_u64() value
.as_u64()
.map(|u| u as usize) .map(|u| u as usize)
.ok_or(Error(ErrorCode::ValueDoesNotContainUsize)) .ok_or(Error(ErrorCode::ValueDoesNotContainUsize))
} }
fn as_string(&self) -> String { fn as_string(&self) -> String {
@ -60,8 +65,9 @@ impl TypeHandler for usize {
impl TypeHandler for HashMap<String, MpvDataType> { impl TypeHandler for HashMap<String, MpvDataType> {
fn get_value(value: Value) -> Result<HashMap<String, MpvDataType>, Error> { fn get_value(value: Value) -> Result<HashMap<String, MpvDataType>, Error> {
value.as_object() value
.ok_or(Error(ErrorCode::ValueDoesNotContainHashMap)) .as_object()
.ok_or(Error(ErrorCode::ValueDoesNotContainHashMap))
.map(json_map_to_hashmap) .map(json_map_to_hashmap)
} }
@ -72,9 +78,10 @@ impl TypeHandler for HashMap<String, MpvDataType> {
impl TypeHandler for Vec<PlaylistEntry> { impl TypeHandler for Vec<PlaylistEntry> {
fn get_value(value: Value) -> Result<Vec<PlaylistEntry>, Error> { fn get_value(value: Value) -> Result<Vec<PlaylistEntry>, Error> {
value.as_array() value
.ok_or(Error(ErrorCode::ValueDoesNotContainPlaylist)) .as_array()
.map(json_array_to_playlist) .ok_or(Error(ErrorCode::ValueDoesNotContainPlaylist))
.map(|array| json_array_to_playlist(array))
} }
fn as_string(&self) -> String { fn as_string(&self) -> String {
@ -86,8 +93,8 @@ pub(crate) fn json_map_to_hashmap(
map: &serde_json::map::Map<String, Value>, map: &serde_json::map::Map<String, Value>,
) -> HashMap<String, MpvDataType> { ) -> HashMap<String, MpvDataType> {
let mut output_map: HashMap<String, MpvDataType> = HashMap::new(); let mut output_map: HashMap<String, MpvDataType> = HashMap::new();
for (ref key, ref value) in map.iter() { for (ref key, value) in map.iter() {
match **value { match *value {
Value::Array(ref array) => { Value::Array(ref array) => {
output_map.insert( output_map.insert(
key.to_string(), key.to_string(),
@ -126,9 +133,9 @@ pub(crate) fn json_map_to_hashmap(
output_map output_map
} }
pub(crate) fn json_array_to_vec(array: &Vec<Value>) -> Vec<MpvDataType> { pub(crate) fn json_array_to_vec(array: &[Value]) -> Vec<MpvDataType> {
let mut output: Vec<MpvDataType> = Vec::new(); let mut output: Vec<MpvDataType> = Vec::new();
if array.len() > 0 { if !array.is_empty() {
match array[0] { match array[0] {
Value::Array(_) => { Value::Array(_) => {
for entry in array { for entry in array {
@ -184,7 +191,7 @@ pub(crate) fn json_array_to_vec(array: &Vec<Value>) -> Vec<MpvDataType> {
output output
} }
pub(crate) fn json_array_to_playlist(array: &Vec<Value>) -> Vec<PlaylistEntry> { pub(crate) fn json_array_to_playlist(array: &[Value]) -> Vec<PlaylistEntry> {
let mut output: Vec<PlaylistEntry> = Vec::new(); let mut output: Vec<PlaylistEntry> = Vec::new();
for (id, entry) in array.iter().enumerate() { for (id, entry) in array.iter().enumerate() {
let mut filename: String = String::new(); let mut filename: String = String::new();

View File

@ -1,7 +1,7 @@
use std::panic; use std::panic;
use futures::{stream::StreamExt, SinkExt}; use futures::{stream::StreamExt, SinkExt};
use mpvipc::{Mpv, MpvExt, MpvDataType, Property}; use mpvipc::{Mpv, MpvDataType, MpvExt, Property};
use serde_json::json; use serde_json::json;
use test_log::test; use test_log::test;
use tokio::{net::UnixStream, task::JoinHandle}; use tokio::{net::UnixStream, task::JoinHandle};

View File

@ -89,32 +89,27 @@ async fn test_get_property_simultaneous_requests() {
let mut framed = Framed::new(socket, LinesCodec::new()); let mut framed = Framed::new(socket, LinesCodec::new());
while let Some(request) = framed.next().await { while let Some(request) = framed.next().await {
match serde_json::from_str::<Value>(&request.unwrap()) { if let Ok(json) = serde_json::from_str::<Value>(&request.unwrap()) {
Ok(json) => { let property = json["command"][1].as_str().unwrap();
let property = json["command"][1].as_str().unwrap(); log::info!("Received request for property: {:?}", property);
log::info!("Received request for property: {:?}", property); match property {
match property { "volume" => {
"volume" => { let response =
let response = json!({ "data": 100.0, "request_id": 0, "error": "success" })
json!({ "data": 100.0, "request_id": 0, "error": "success" }) .to_string();
.to_string(); framed.send(response).await.unwrap();
framed.send(response).await.unwrap(); }
} "pause" => {
"pause" => { let response = json!({ "data": true, "request_id": 0, "error": "success" })
let response = .to_string();
json!({ "data": true, "request_id": 0, "error": "success" }) framed.send(response).await.unwrap();
.to_string(); }
framed.send(response).await.unwrap(); _ => {
} let response =
_ => { json!({ "error": "property unavailable", "request_id": 0 }).to_string();
let response = framed.send(response).await.unwrap();
json!({ "error": "property unavailable", "request_id": 0 })
.to_string();
framed.send(response).await.unwrap();
}
} }
} }
Err(_) => {}
} }
} }
@ -136,7 +131,7 @@ async fn test_get_property_simultaneous_requests() {
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: bool = mpv_clone_2.get_property("pause").await.unwrap();
assert_eq!(paused, true); assert!(paused);
} }
}); });

View File

@ -79,9 +79,7 @@ async fn test_get_property_error() {
assert_eq!( assert_eq!(
maybe_volume, maybe_volume,
Err(Error(ErrorCode::MpvError( Err(Error(ErrorCode::MpvError("property not found".to_owned())))
"property not found".to_owned()
)))
); );
join_handle.await.unwrap().unwrap(); join_handle.await.unwrap().unwrap();
@ -94,33 +92,29 @@ async fn test_set_property_simultaneous_requests() {
let mut framed = Framed::new(socket, LinesCodec::new()); let mut framed = Framed::new(socket, LinesCodec::new());
while let Some(request) = framed.next().await { while let Some(request) = framed.next().await {
match serde_json::from_str::<Value>(&request.unwrap()) { if let Ok(json) = serde_json::from_str::<Value>(&request.unwrap()) {
Ok(json) => { let property = json["command"][1].as_str().unwrap();
let property = json["command"][1].as_str().unwrap(); let value = &json["command"][2];
let value = &json["command"][2]; log::info!(
log::info!("Received set property command: {:?} => {:?}", property, value); "Received set property command: {:?} => {:?}",
match property { property,
"volume" => { value
let response = );
json!({ "request_id": 0, "error": "success" }) match property {
.to_string(); "volume" => {
framed.send(response).await.unwrap(); let response = json!({ "request_id": 0, "error": "success" }).to_string();
} framed.send(response).await.unwrap();
"pause" => { }
let response = "pause" => {
json!({ "request_id": 0, "error": "success" }) let response = json!({ "request_id": 0, "error": "success" }).to_string();
.to_string(); framed.send(response).await.unwrap();
framed.send(response).await.unwrap(); }
} _ => {
_ => { let response =
let response = json!({ "error":"property not found", "request_id": 0 }).to_string();
json!({ "error":"property not found", "request_id": 0 }) framed.send(response).await.unwrap();
.to_string();
framed.send(response).await.unwrap();
}
} }
} }
Err(_) => {}
} }
} }
@ -153,9 +147,7 @@ async fn test_set_property_simultaneous_requests() {
let maybe_volume = mpv_clone_3.set_property("nonexistent", "a").await; let maybe_volume = mpv_clone_3.set_property("nonexistent", "a").await;
assert_eq!( assert_eq!(
maybe_volume, maybe_volume,
Err(Error(ErrorCode::MpvError( Err(Error(ErrorCode::MpvError("property not found".to_owned())))
"property not found".to_owned()
)))
); );
} }
}); });