api: move highlevel functions into extension

This commit is contained in:
Oystein Kristoffer Tveit 2024-04-30 00:41:16 +02:00
parent 30c72f1ad8
commit a0888b9386
Signed by: oysteikt
GPG Key ID: 9F2F7D8250F35146
8 changed files with 277 additions and 261 deletions

View File

@ -1,5 +1,5 @@
use env_logger; use env_logger;
use mpvipc::{Error as MpvError, Mpv}; use mpvipc::{Error as MpvError, Mpv, MpvExt};
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), MpvError> { async fn main() -> Result<(), MpvError> {

View File

@ -1,5 +1,5 @@
use env_logger; use env_logger;
use mpvipc::{Error, Event, Mpv, MpvDataType, Property}; use mpvipc::{Error, Event, Mpv, MpvExt, MpvDataType, Property};
use std::io::{self, Write}; use std::io::{self, Write};
fn seconds_to_hms(total: f64) -> String { fn seconds_to_hms(total: f64) -> String {

View File

@ -83,7 +83,7 @@ pub enum MpvCommand {
Unobserve(isize), Unobserve(isize),
} }
trait IntoRawCommandPart { pub(crate) trait IntoRawCommandPart {
fn into_raw_command_part(self) -> String; fn into_raw_command_part(self) -> String;
} }
@ -99,23 +99,6 @@ pub enum MpvDataType {
Usize(usize), Usize(usize),
} }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum NumberChangeOptions {
Absolute,
Increase,
Decrease,
}
impl IntoRawCommandPart for NumberChangeOptions {
fn into_raw_command_part(self) -> String {
match self {
NumberChangeOptions::Absolute => "absolute".to_string(),
NumberChangeOptions::Increase => "increase".to_string(),
NumberChangeOptions::Decrease => "decrease".to_string(),
}
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum PlaylistAddOptions { pub enum PlaylistAddOptions {
Replace, Replace,
@ -156,13 +139,6 @@ impl IntoRawCommandPart for SeekOptions {
} }
} }
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum Switch {
On,
Off,
Toggle,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ErrorCode { pub enum ErrorCode {
MpvError(String), MpvError(String),
@ -457,16 +433,6 @@ impl Mpv {
}) })
} }
pub async fn get_metadata(&self) -> Result<HashMap<String, MpvDataType>, Error> {
self.get_property("metadata").await
}
pub async fn get_playlist(&self) -> Result<Playlist, Error> {
self.get_property::<Vec<PlaylistEntry>>("playlist")
.await
.map(|entries| Playlist(entries))
}
/// # Description /// # Description
/// ///
/// Retrieves the property value from mpv. /// Retrieves the property value from mpv.
@ -537,63 +503,6 @@ impl Mpv {
} }
} }
pub async fn kill(&self) -> Result<(), Error> {
self.run_command(MpvCommand::Quit).await
}
/// # Description
///
/// Waits until an mpv event occurs and returns the Event.
///
/// # Example
///
/// ```ignore
/// let mut mpv = Mpv::connect("/tmp/mpvsocket")?;
/// loop {
/// let event = mpv.event_listen()?;
/// println!("{:?}", event);
/// }
/// ```
// pub fn event_listen(&mut self) -> Result<Event, Error> {
// listen(self)
// }
// pub fn event_listen_raw(&mut self) -> String {
// listen_raw(self)
// }
pub async fn next(&self) -> Result<(), Error> {
self.run_command(MpvCommand::PlaylistNext).await
}
pub async fn observe_property(&self, id: isize, property: &str) -> Result<(), Error> {
self.run_command(MpvCommand::Observe {
id,
property: property.to_string(),
})
.await
}
pub async fn unobserve_property(&self, id: isize) -> Result<(), Error> {
self.run_command(MpvCommand::Unobserve(id)).await
}
pub async fn pause(&self) -> Result<(), Error> {
self.set_property("pause", true).await
}
pub async fn prev(&self) -> Result<(), Error> {
self.run_command(MpvCommand::PlaylistPrev).await
}
pub async fn restart(&self) -> Result<(), Error> {
self.run_command(MpvCommand::Seek {
seconds: 0f64,
option: SeekOptions::Absolute,
})
.await
}
/// # Description /// # Description
/// ///
/// Runs mpv commands. The arguments are passed as a String-Vector reference: /// Runs mpv commands. The arguments are passed as a String-Vector reference:
@ -760,120 +669,6 @@ impl Mpv {
self.run_command_raw(command, args).await.map(|_| ()) self.run_command_raw(command, args).await.map(|_| ())
} }
pub async fn playlist_add(
&self,
file: &str,
file_type: PlaylistAddTypeOptions,
option: PlaylistAddOptions,
) -> Result<(), Error> {
match file_type {
PlaylistAddTypeOptions::File => {
self.run_command(MpvCommand::LoadFile {
file: file.to_string(),
option,
})
.await
}
PlaylistAddTypeOptions::Playlist => {
self.run_command(MpvCommand::LoadList {
file: file.to_string(),
option,
})
.await
}
}
}
pub async fn playlist_clear(&self) -> Result<(), Error> {
self.run_command(MpvCommand::PlaylistClear).await
}
pub async fn playlist_move_id(&self, from: usize, to: usize) -> Result<(), Error> {
self.run_command(MpvCommand::PlaylistMove { from, to })
.await
}
pub async fn playlist_play_id(&self, id: usize) -> Result<(), Error> {
self.set_property("playlist-pos", id).await
}
pub async fn playlist_play_next(&self, id: usize) -> Result<(), Error> {
match self.get_property::<usize>("playlist-pos").await {
Ok(current_id) => {
self.run_command(MpvCommand::PlaylistMove {
from: id,
to: current_id + 1,
})
.await
}
Err(msg) => Err(msg),
}
}
pub async fn playlist_remove_id(&self, id: usize) -> Result<(), Error> {
self.run_command(MpvCommand::PlaylistRemove(id)).await
}
pub async fn playlist_shuffle(&self) -> Result<(), Error> {
self.run_command(MpvCommand::PlaylistShuffle).await
}
pub async fn seek(&self, seconds: f64, option: SeekOptions) -> Result<(), Error> {
self.run_command(MpvCommand::Seek { seconds, option }).await
}
pub async fn set_loop_file(&self, option: Switch) -> Result<(), Error> {
let enabled = match option {
Switch::On => "inf",
Switch::Off => "no",
Switch::Toggle => {
self.get_property::<String>("loop-file")
.await
.map(|s| match s.as_str() {
"inf" => "no",
"no" => "inf",
_ => "no",
})?
}
};
self.set_property("loop-file", enabled).await
}
pub async fn set_loop_playlist(&self, option: Switch) -> Result<(), Error> {
let enabled = match option {
Switch::On => "inf",
Switch::Off => "no",
Switch::Toggle => {
self.get_property::<String>("loop-playlist")
.await
.map(|s| match s.as_str() {
"inf" => "no",
"no" => "inf",
_ => "no",
})?
}
};
self.set_property("loo-playlist", enabled).await
}
pub async fn set_mute(&self, option: Switch) -> Result<(), Error> {
let enabled = match option {
Switch::On => "yes",
Switch::Off => "no",
Switch::Toggle => {
self.get_property::<String>("mute")
.await
.map(|s| match s.as_str() {
"yes" => "no",
"no" => "yes",
_ => "no",
})?
}
};
self.set_property("mute", enabled).await
}
/// # Description /// # Description
/// ///
/// Sets the mpv property _<property>_ to _<value>_. /// Sets the mpv property _<property>_ to _<value>_.
@ -905,54 +700,4 @@ impl Mpv {
) -> Result<(), Error> { ) -> Result<(), Error> {
T::set_property_generic(self, property, value).await T::set_property_generic(self, property, value).await
} }
pub 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 => {
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,
},
Err(msg) => Err(msg),
}
}
pub async fn set_volume(
&self,
input_volume: f64,
option: NumberChangeOptions,
) -> Result<(), Error> {
match self.get_property::<f64>("volume").await {
Ok(volume) => match option {
NumberChangeOptions::Increase => {
self.set_property("volume", volume + input_volume).await
}
NumberChangeOptions::Decrease => {
self.set_property("volume", volume - input_volume).await
}
NumberChangeOptions::Absolute => self.set_property("volume", input_volume).await,
},
Err(msg) => Err(msg),
}
}
pub async fn stop(&self) -> Result<(), Error> {
self.run_command(MpvCommand::Stop).await
}
pub async fn toggle(&self) -> Result<(), Error> {
self.run_command_raw("cycle", &["pause"]).await.map(|_| ())
}
} }

269
src/api_extension.rs Normal file
View File

@ -0,0 +1,269 @@
use crate::{Error, IntoRawCommandPart, Mpv, MpvCommand, MpvDataType, Playlist, PlaylistAddOptions, PlaylistAddTypeOptions, PlaylistEntry, SeekOptions};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum NumberChangeOptions {
Absolute,
Increase,
Decrease,
}
impl IntoRawCommandPart for NumberChangeOptions {
fn into_raw_command_part(self) -> String {
match self {
NumberChangeOptions::Absolute => "absolute".to_string(),
NumberChangeOptions::Increase => "increase".to_string(),
NumberChangeOptions::Decrease => "decrease".to_string(),
}
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum Switch {
On,
Off,
Toggle,
}
// TODO: fix this
#[allow(async_fn_in_trait)]
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_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>;
async fn set_loop_file(&self, option: Switch) -> Result<(), Error>;
async fn seek(&self, seconds: f64, option: SeekOptions) -> Result<(), Error>;
async fn playlist_shuffle(&self) -> Result<(), Error>;
async fn playlist_remove_id(&self, id: usize) -> Result<(), Error>;
async fn playlist_play_next(&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_clear(&self) -> 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>;
async fn unobserve_property(&self, id: isize) -> Result<(), Error>;
async fn observe_property(&self, id: isize, property: &str) -> Result<(), Error>;
async fn next(&self) -> Result<(), Error>;
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 {
async fn get_metadata(&self) -> Result<HashMap<String, MpvDataType>, Error> {
self.get_property("metadata").await
}
async fn get_playlist(&self) -> Result<Playlist, Error> {
self.get_property::<Vec<PlaylistEntry>>("playlist")
.await
.map(|entries| Playlist(entries))
}
async fn kill(&self) -> Result<(), Error> {
self.run_command(MpvCommand::Quit).await
}
async fn next(&self) -> Result<(), Error> {
self.run_command(MpvCommand::PlaylistNext).await
}
async fn observe_property(&self, id: isize, property: &str) -> Result<(), Error> {
self.run_command(MpvCommand::Observe {
id,
property: property.to_string(),
})
.await
}
async fn unobserve_property(&self, id: isize) -> Result<(), Error> {
self.run_command(MpvCommand::Unobserve(id)).await
}
async fn pause(&self) -> Result<(), Error> {
self.set_property("pause", true).await
}
async fn prev(&self) -> Result<(), Error> {
self.run_command(MpvCommand::PlaylistPrev).await
}
async fn restart(&self) -> Result<(), Error> {
self.run_command(MpvCommand::Seek {
seconds: 0f64,
option: SeekOptions::Absolute,
})
.await
}
async fn playlist_add(
&self,
file: &str,
file_type: PlaylistAddTypeOptions,
option: PlaylistAddOptions,
) -> Result<(), Error> {
match file_type {
PlaylistAddTypeOptions::File => {
self.run_command(MpvCommand::LoadFile {
file: file.to_string(),
option,
})
.await
}
PlaylistAddTypeOptions::Playlist => {
self.run_command(MpvCommand::LoadList {
file: file.to_string(),
option,
})
.await
}
}
}
async fn playlist_clear(&self) -> Result<(), Error> {
self.run_command(MpvCommand::PlaylistClear).await
}
async fn playlist_move_id(&self, from: usize, to: usize) -> Result<(), Error> {
self.run_command(MpvCommand::PlaylistMove { from, to })
.await
}
async fn playlist_play_id(&self, id: usize) -> Result<(), Error> {
self.set_property("playlist-pos", id).await
}
async fn playlist_play_next(&self, id: usize) -> Result<(), Error> {
match self.get_property::<usize>("playlist-pos").await {
Ok(current_id) => {
self.run_command(MpvCommand::PlaylistMove {
from: id,
to: current_id + 1,
})
.await
}
Err(msg) => Err(msg),
}
}
async fn playlist_remove_id(&self, id: usize) -> Result<(), Error> {
self.run_command(MpvCommand::PlaylistRemove(id)).await
}
async fn playlist_shuffle(&self) -> Result<(), Error> {
self.run_command(MpvCommand::PlaylistShuffle).await
}
async fn seek(&self, seconds: f64, option: SeekOptions) -> Result<(), Error> {
self.run_command(MpvCommand::Seek { seconds, option }).await
}
async fn set_loop_file(&self, option: Switch) -> Result<(), Error> {
let enabled = match option {
Switch::On => "inf",
Switch::Off => "no",
Switch::Toggle => {
self.get_property::<String>("loop-file")
.await
.map(|s| match s.as_str() {
"inf" => "no",
"no" => "inf",
_ => "no",
})?
}
};
self.set_property("loop-file", enabled).await
}
async fn set_loop_playlist(&self, option: Switch) -> Result<(), Error> {
let enabled = match option {
Switch::On => "inf",
Switch::Off => "no",
Switch::Toggle => {
self.get_property::<String>("loop-playlist")
.await
.map(|s| match s.as_str() {
"inf" => "no",
"no" => "inf",
_ => "no",
})?
}
};
self.set_property("loo-playlist", enabled).await
}
async fn set_mute(&self, option: Switch) -> Result<(), Error> {
let enabled = match option {
Switch::On => "yes",
Switch::Off => "no",
Switch::Toggle => {
self.get_property::<String>("mute")
.await
.map(|s| match s.as_str() {
"yes" => "no",
"no" => "yes",
_ => "no",
})?
}
};
self.set_property("mute", enabled).await
}
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 => {
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,
},
Err(msg) => Err(msg),
}
}
async fn set_volume(
&self,
input_volume: f64,
option: NumberChangeOptions,
) -> Result<(), Error> {
match self.get_property::<f64>("volume").await {
Ok(volume) => match option {
NumberChangeOptions::Increase => {
self.set_property("volume", volume + input_volume).await
}
NumberChangeOptions::Decrease => {
self.set_property("volume", volume - input_volume).await
}
NumberChangeOptions::Absolute => self.set_property("volume", input_volume).await,
},
Err(msg) => Err(msg),
}
}
async fn stop(&self) -> Result<(), Error> {
self.run_command(MpvCommand::Stop).await
}
async fn toggle(&self) -> Result<(), Error> {
self.run_command_raw("cycle", &["pause"]).await.map(|_| ())
}
}

View File

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

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, MpvDataType, Property}; use mpvipc::{Mpv, MpvExt, MpvDataType, 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

@ -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::{Error, ErrorCode, Mpv, Playlist, PlaylistEntry}; use mpvipc::{Error, ErrorCode, Mpv, MpvExt, Playlist, PlaylistEntry};
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};

View File

@ -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::{Error, ErrorCode, Mpv, Playlist, PlaylistEntry}; use mpvipc::{Error, ErrorCode, Mpv, MpvExt, Playlist, PlaylistEntry};
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};