begin refactoring common logic into lib target

This commit is contained in:
raf 2024-12-12 23:34:23 +03:00
commit 21b7df991b
Signed by: NotAShelf
GPG key ID: AF26552424E53993
2 changed files with 76 additions and 73 deletions

54
src/lib.rs Normal file
View file

@ -0,0 +1,54 @@
use serde_json::{Value, json};
use std::io::{self};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::UnixStream;
use tracing::{debug, error};
pub const SOCKET_PATH: &str = "/tmp/mpvsocket";
/// Sends an IPC command to the MPV socket and returns the parsed response data.
pub async fn send_ipc_command(command: &str, args: &[Value]) -> io::Result<Option<Value>> {
debug!(
"Sending IPC command: {} with arguments: {:?}",
command, args
);
match UnixStream::connect(SOCKET_PATH).await {
Ok(mut socket) => {
debug!("Found MPV socket at {}", SOCKET_PATH);
let mut command_array = vec![json!(command)];
command_array.extend_from_slice(args);
let message = json!({ "command": command_array });
let message_str = format!("{}\n", serde_json::to_string(&message)?);
debug!("Serialized message to send with newline: {}", message_str);
socket.write_all(message_str.as_bytes()).await?;
socket.flush().await?;
debug!("Message sent and flushed");
let mut response = vec![0; 1024];
let n = socket.read(&mut response).await?;
let response_str = String::from_utf8_lossy(&response[..n]);
debug!("Raw response: {}", response_str);
match serde_json::from_str::<Value>(&response_str) {
Ok(json_response) => {
debug!("Parsed IPC response: {:?}", json_response);
Ok(json_response.get("data").cloned())
}
Err(e) => {
error!("Failed to parse response: {}", e);
Ok(None)
}
}
}
Err(e) => {
error!("Failed to connect to MPV socket: {}", e);
Err(e)
}
}
}

View file

@ -1,11 +1,14 @@
use clap::{Parser, Subcommand};
use serde_json::json;
use serde_json::{Value, json};
use std::io::{self};
use std::path::PathBuf;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::UnixStream;
use tracing::{debug, error, info};
// TODO: SOCKET_PATH should be an argument to send_ipc_command
// and in the CLI, it should be expected as a command line argument
// or/and environment variable.
use mrc::{SOCKET_PATH, send_ipc_command};
#[derive(Parser)]
#[command(author, version, about)]
struct Cli {
@ -86,61 +89,8 @@ enum CommandOptions {
},
}
const SOCKET_PATH: &str = "/tmp/mpvsocket";
async fn send_ipc_command(
command: &str,
args: &[serde_json::Value],
) -> io::Result<Option<serde_json::Value>> {
debug!(
"Sending IPC command: {} with arguments: {:?}",
command, args
);
match UnixStream::connect(SOCKET_PATH).await {
Ok(mut socket) => {
debug!("Connected to MPV socket successfully");
let mut command_array = vec![json!(command)];
command_array.extend_from_slice(args);
let message = json!({ "command": command_array });
let message_str = format!("{}\n", serde_json::to_string(&message)?);
debug!("Serialized message to send with newline: {}", message_str);
socket.write_all(message_str.as_bytes()).await?;
socket.flush().await?;
debug!("Message sent and flushed");
let mut response = vec![0; 1024];
let n = socket.read(&mut response).await?;
let response_str = String::from_utf8_lossy(&response[..n]);
debug!("Raw response: {}", response_str);
match serde_json::from_str::<serde_json::Value>(&response_str) {
Ok(json_response) => {
debug!("Parsed IPC response: {:?}", json_response);
Ok(json_response.get("data").cloned())
}
Err(e) => {
error!("Failed to parse response: {}", e);
Ok(None)
}
}
}
Err(e) => {
error!("Failed to connect to MPV socket: {}", e);
Err(e)
}
}
}
async fn ipc_command(command: &str, args: &[serde_json::Value]) -> io::Result<()> {
if (send_ipc_command(command, args).await?).is_some() {
Ok(())
} else {
Err(io::Error::new(
io::ErrorKind::Other,
"Failed to execute command",
))
}
pub async fn execute_command(command: &str, args: &[Value]) -> io::Result<Option<Value>> {
send_ipc_command(command, args).await
}
#[tokio::main]
@ -158,55 +108,55 @@ async fn main() -> io::Result<()> {
CommandOptions::Play { index } => {
if let Some(idx) = index {
info!("Playing media at index: {}", idx);
ipc_command("set_property", &[json!("playlist-pos"), json!(idx)]).await?;
execute_command("set_property", &[json!("playlist-pos"), json!(idx)]).await?;
}
info!("Unpausing playback");
ipc_command("set_property", &[json!("pause"), json!(false)]).await?;
execute_command("set_property", &[json!("pause"), json!(false)]).await?;
}
CommandOptions::Pause => {
info!("Pausing playback");
ipc_command("set_property", &[json!("pause"), json!(true)]).await?;
execute_command("set_property", &[json!("pause"), json!(true)]).await?;
}
CommandOptions::Stop => {
info!("Stopping playback and quitting MPV");
ipc_command("quit", &[]).await?;
execute_command("quit", &[]).await?;
}
CommandOptions::Next => {
info!("Skipping to next item in the playlist");
ipc_command("playlist-next", &[]).await?;
execute_command("playlist-next", &[]).await?;
}
CommandOptions::Prev => {
info!("Skipping to previous item in the playlist");
ipc_command("playlist-prev", &[]).await?;
execute_command("playlist-prev", &[]).await?;
}
CommandOptions::Seek { seconds } => {
info!("Seeking to {} seconds", seconds);
ipc_command("seek", &[json!(seconds)]).await?;
execute_command("seek", &[json!(seconds)]).await?;
}
CommandOptions::Move { index1, index2 } => {
info!("Moving item from index {} to {}", index1, index2);
ipc_command("playlist-move", &[json!(index1), json!(index2)]).await?;
execute_command("playlist-move", &[json!(index1), json!(index2)]).await?;
}
CommandOptions::Remove { index } => {
if let Some(idx) = index {
info!("Removing item at index {}", idx);
ipc_command("playlist-remove", &[json!(idx)]).await?;
execute_command("playlist-remove", &[json!(idx)]).await?;
} else {
info!("Removing current item from playlist");
ipc_command("playlist-remove", &[json!("current")]).await?;
execute_command("playlist-remove", &[json!("current")]).await?;
}
}
CommandOptions::Clear => {
info!("Clearing the playlist");
ipc_command("playlist-clear", &[]).await?;
execute_command("playlist-clear", &[]).await?;
}
CommandOptions::List => {
@ -222,19 +172,18 @@ async fn main() -> io::Result<()> {
error!("{}", e);
return Err(io::Error::new(io::ErrorKind::InvalidInput, e));
}
info!("Adding {} files to the playlist", filenames.len());
for filename in filenames {
ipc_command("loadfile", &[json!(filename), json!("append-play")]).await?;
execute_command("loadfile", &[json!(filename), json!("append-play")]).await?;
}
}
CommandOptions::Replace { filenames } => {
info!("Replacing current playlist with {} files", filenames.len());
if let Some(first_file) = filenames.first() {
ipc_command("loadfile", &[json!(first_file), json!("replace")]).await?;
execute_command("loadfile", &[json!(first_file), json!("replace")]).await?;
for filename in &filenames[1..] {
ipc_command("loadfile", &[json!(filename), json!("append-play")]).await?;
execute_command("loadfile", &[json!(filename), json!("append-play")]).await?;
}
}
}