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

pull/1/head
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};
#[tokio::main]

View File

@ -1,6 +1,4 @@
use env_logger;
use mpvipc::{Error, Event, Mpv, MpvExt, MpvDataType, Property};
use std::io::{self, Write};
use mpvipc::{Error, Mpv, MpvExt};
fn seconds_to_hms(total: f64) -> String {
let total = total as u64;
@ -15,10 +13,10 @@ fn seconds_to_hms(total: f64) -> String {
async fn main() -> Result<(), Error> {
env_logger::init();
let mut mpv = Mpv::connect("/tmp/mpv.sock").await?;
let mut pause = false;
let mut playback_time = std::f64::NAN;
let mut duration = std::f64::NAN;
let mpv = Mpv::connect("/tmp/mpv.sock").await?;
let pause = false;
let playback_time = std::f64::NAN;
let duration = std::f64::NAN;
mpv.observe_property(1, "path").await?;
mpv.observe_property(2, "pause").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>> {
tokio_stream::wrappers::BroadcastStream::new(self.broadcast_channel.subscribe())
.map(|event| {
match event {
Ok(event) => Mpv::map_event(event),
Err(_) => Err(Error(ErrorCode::ConnectError("Failed to receive event".to_string()))),
}
})
tokio_stream::wrappers::BroadcastStream::new(self.broadcast_channel.subscribe()).map(
|event| match event {
Ok(event) => Mpv::map_event(event),
Err(_) => Err(Error(ErrorCode::ConnectError(
"Failed to receive event".to_string(),
))),
},
)
}
fn map_event(raw_event: MpvIpcEvent) -> Result<Event, Error> {
@ -373,43 +374,43 @@ impl Mpv {
.ok_or(Error(ErrorCode::ValueDoesNotContainString))?;
match property_name {
"path" => {
let path = event
.get("data")
.ok_or(Error(ErrorCode::MissingValue))?
.as_str()
.map(|s| s.to_string());
Ok(Event::PropertyChange {
id,
property: Property::Path(path),
})
}
"pause" => {
let pause = event
.get("data")
.ok_or(Error(ErrorCode::MissingValue))?
.as_bool()
.ok_or(Error(ErrorCode::ValueDoesNotContainBool))?;
Ok(Event::PropertyChange {
id,
property: Property::Pause(pause),
})
}
// TODO: missing cases
_ => {
let data = event
.get("data")
.ok_or(Error(ErrorCode::MissingValue))?
.clone();
Ok(Event::PropertyChange {
id,
property: Property::Unknown {
name: property_name.to_string(),
// TODO: fix
data: MpvDataType::Double(data.as_f64().unwrap_or(0.0)),
},
})
}
"path" => {
let path = event
.get("data")
.ok_or(Error(ErrorCode::MissingValue))?
.as_str()
.map(|s| s.to_string());
Ok(Event::PropertyChange {
id,
property: Property::Path(path),
})
}
"pause" => {
let pause = event
.get("data")
.ok_or(Error(ErrorCode::MissingValue))?
.as_bool()
.ok_or(Error(ErrorCode::ValueDoesNotContainBool))?;
Ok(Event::PropertyChange {
id,
property: Property::Pause(pause),
})
}
// TODO: missing cases
_ => {
let data = event
.get("data")
.ok_or(Error(ErrorCode::MissingValue))?
.clone();
Ok(Event::PropertyChange {
id,
property: Property::Unknown {
name: property_name.to_string(),
// TODO: fix
data: MpvDataType::Double(data.as_f64().unwrap_or(0.0)),
},
})
}
}
}
"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 std::collections::HashMap;
@ -31,7 +34,8 @@ pub enum Switch {
pub trait MpvExt {
async fn toggle(&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_mute(&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_move_id(&self, from: usize, to: usize) -> 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 prev(&self) -> Result<(), Error>;
async fn pause(&self) -> Result<(), Error>;
@ -53,7 +62,6 @@ pub trait MpvExt {
async fn kill(&self) -> Result<(), Error>;
async fn get_playlist(&self) -> Result<Playlist, Error>;
async fn get_metadata(&self) -> Result<HashMap<String, MpvDataType>, Error>;
}
impl MpvExt for Mpv {
@ -64,7 +72,7 @@ impl MpvExt for Mpv {
async fn get_playlist(&self) -> Result<Playlist, Error> {
self.get_property::<Vec<PlaylistEntry>>("playlist")
.await
.map(|entries| Playlist(entries))
.map(Playlist)
}
async fn kill(&self) -> Result<(), Error> {
@ -217,11 +225,7 @@ impl MpvExt for Mpv {
self.set_property("mute", enabled).await
}
async fn set_speed(
&self,
input_speed: f64,
option: NumberChangeOptions,
) -> Result<(), Error> {
async fn set_speed(&self, input_speed: f64, option: NumberChangeOptions) -> Result<(), Error> {
match self.get_property::<f64>("speed").await {
Ok(speed) => match option {
NumberChangeOptions::Increase => {
@ -266,4 +270,4 @@ impl MpvExt for Mpv {
async fn toggle(&self) -> Result<(), Error> {
self.run_command_raw("cycle", &["pause"]).await.map(|_| ())
}
}
}

View File

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

View File

@ -1,7 +1,7 @@
use std::panic;
use futures::{stream::StreamExt, SinkExt};
use mpvipc::{Mpv, MpvExt, MpvDataType, Property};
use mpvipc::{Mpv, MpvDataType, MpvExt, Property};
use serde_json::json;
use test_log::test;
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());
while let Some(request) = framed.next().await {
match serde_json::from_str::<Value>(&request.unwrap()) {
Ok(json) => {
let property = json["command"][1].as_str().unwrap();
log::info!("Received request for property: {:?}", property);
match property {
"volume" => {
let response =
json!({ "data": 100.0, "request_id": 0, "error": "success" })
.to_string();
framed.send(response).await.unwrap();
}
"pause" => {
let response =
json!({ "data": true, "request_id": 0, "error": "success" })
.to_string();
framed.send(response).await.unwrap();
}
_ => {
let response =
json!({ "error": "property unavailable", "request_id": 0 })
.to_string();
framed.send(response).await.unwrap();
}
if let Ok(json) = serde_json::from_str::<Value>(&request.unwrap()) {
let property = json["command"][1].as_str().unwrap();
log::info!("Received request for property: {:?}", property);
match property {
"volume" => {
let response =
json!({ "data": 100.0, "request_id": 0, "error": "success" })
.to_string();
framed.send(response).await.unwrap();
}
"pause" => {
let response = json!({ "data": true, "request_id": 0, "error": "success" })
.to_string();
framed.send(response).await.unwrap();
}
_ => {
let response =
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 {
tokio::time::sleep(Duration::from_millis(1)).await;
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!(
maybe_volume,
Err(Error(ErrorCode::MpvError(
"property not found".to_owned()
)))
Err(Error(ErrorCode::MpvError("property not found".to_owned())))
);
join_handle.await.unwrap().unwrap();
@ -94,33 +92,29 @@ async fn test_set_property_simultaneous_requests() {
let mut framed = Framed::new(socket, LinesCodec::new());
while let Some(request) = framed.next().await {
match serde_json::from_str::<Value>(&request.unwrap()) {
Ok(json) => {
let property = json["command"][1].as_str().unwrap();
let value = &json["command"][2];
log::info!("Received set property command: {:?} => {:?}", property, value);
match property {
"volume" => {
let response =
json!({ "request_id": 0, "error": "success" })
.to_string();
framed.send(response).await.unwrap();
}
"pause" => {
let response =
json!({ "request_id": 0, "error": "success" })
.to_string();
framed.send(response).await.unwrap();
}
_ => {
let response =
json!({ "error":"property not found", "request_id": 0 })
.to_string();
framed.send(response).await.unwrap();
}
if let Ok(json) = serde_json::from_str::<Value>(&request.unwrap()) {
let property = json["command"][1].as_str().unwrap();
let value = &json["command"][2];
log::info!(
"Received set property command: {:?} => {:?}",
property,
value
);
match property {
"volume" => {
let response = json!({ "request_id": 0, "error": "success" }).to_string();
framed.send(response).await.unwrap();
}
"pause" => {
let response = json!({ "request_id": 0, "error": "success" }).to_string();
framed.send(response).await.unwrap();
}
_ => {
let response =
json!({ "error":"property not found", "request_id": 0 }).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;
assert_eq!(
maybe_volume,
Err(Error(ErrorCode::MpvError(
"property not found".to_owned()
)))
Err(Error(ErrorCode::MpvError("property not found".to_owned())))
);
}
});