From 5e3df86a2a287c75f331feceeea54700a8141cc9 Mon Sep 17 00:00:00 2001 From: h7x4 Date: Sun, 20 Oct 2024 00:04:59 +0200 Subject: [PATCH] Split mpv setup to separate module --- src/main.rs | 117 ++--------------------------------------------- src/mpv_setup.rs | 117 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 114 deletions(-) create mode 100644 src/mpv_setup.rs diff --git a/src/main.rs b/src/main.rs index 35fb514..b9c0022 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,12 @@ use anyhow::Context; use axum::{Router, Server}; use clap::Parser; -use mpvipc_async::Mpv; -use std::{ - fs::create_dir_all, - io::Write, - net::{IpAddr, SocketAddr}, - path::Path, -}; +use mpv_setup::{connect_to_mpv, create_mpv_config_file}; +use std::net::{IpAddr, SocketAddr}; use tempfile::NamedTempFile; -use tokio::process::{Child, Command}; mod api; +mod mpv_setup; #[derive(Parser)] struct Args { @@ -45,112 +40,6 @@ struct MpvConnectionArgs<'a> { force_auto_start: bool, } -const DEFAULT_MPV_CONFIG_CONTENT: &str = include_str!("../assets/default-mpv.conf"); - -fn create_mpv_config_file(args_config_file: Option) -> anyhow::Result { - let file_content = if let Some(path) = args_config_file { - if !Path::new(&path).exists() { - anyhow::bail!("Mpv config file not found at {}", &path); - } - - std::fs::read_to_string(&path).context("Failed to read mpv config file")? - } else { - DEFAULT_MPV_CONFIG_CONTENT.to_string() - }; - - let tmpfile = tempfile::Builder::new() - .prefix("mpv-") - .rand_bytes(8) - .suffix(".conf") - .tempfile()?; - - tmpfile.reopen()?.write_all(file_content.as_bytes())?; - - Ok(tmpfile) -} - -async fn connect_to_mpv<'a>(args: &MpvConnectionArgs<'a>) -> anyhow::Result<(Mpv, Option)> { - log::debug!("Connecting to mpv"); - - debug_assert!( - !args.force_auto_start || args.auto_start, - "force_auto_start requires auto_start" - ); - - let socket_path = Path::new(&args.socket_path); - - if !socket_path.exists() { - log::debug!("Mpv socket not found at {}", &args.socket_path); - if !args.auto_start { - panic!("Mpv socket not found at {}", &args.socket_path); - } - - log::debug!("Ensuring parent dir of mpv socket exists"); - let parent_dir = Path::new(&args.socket_path) - .parent() - .context("Failed to get parent dir of mpv socket")?; - - if !parent_dir.is_dir() { - create_dir_all(parent_dir).context("Failed to create parent dir of mpv socket")?; - } - } else { - log::debug!("Existing mpv socket found at {}", &args.socket_path); - if args.force_auto_start { - log::debug!("Removing mpv socket"); - std::fs::remove_file(&args.socket_path)?; - } - } - - let process_handle = if args.auto_start { - log::info!("Starting mpv with socket at {}", &args.socket_path); - - // TODO: try to fetch mpv from PATH - Some( - Command::new(args.executable_path.as_deref().unwrap_or("mpv")) - .arg(format!("--input-ipc-server={}", &args.socket_path)) - .arg("--idle") - .arg("--force-window") - .arg("--fullscreen") - .arg("--no-config") - .arg(format!( - "--include={}", - &args.config_file.path().to_string_lossy() - )) - // .arg("--no-terminal") - .arg("--load-unsafe-playlists") - .arg("--keep-open") // Keep last frame of video on end of video - .spawn() - .context("Failed to start mpv")?, - ) - } else { - None - }; - - // Wait for mpv to create the socket - if tokio::time::timeout(tokio::time::Duration::from_millis(500), async { - while !&socket_path.exists() { - log::debug!("Waiting for mpv socket at {}", &args.socket_path); - tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; - } - }) - .await - .is_err() - { - return Err(anyhow::anyhow!( - "Failed to connect to mpv socket: {}", - &args.socket_path - )); - } - - Ok(( - Mpv::connect(&args.socket_path).await.context(format!( - "Failed to connect to mpv socket: {}", - &args.socket_path - ))?, - process_handle, - )) -} - async fn resolve(host: &str) -> anyhow::Result { let addr = format!("{}:0", host); let addresses = tokio::net::lookup_host(addr).await?; diff --git a/src/mpv_setup.rs b/src/mpv_setup.rs new file mode 100644 index 0000000..6b5d336 --- /dev/null +++ b/src/mpv_setup.rs @@ -0,0 +1,117 @@ +use std::{fs::create_dir_all, io::Write, path::Path}; + +use anyhow::Context; +use mpvipc_async::Mpv; +use tempfile::NamedTempFile; +use tokio::process::{Child, Command}; + +use crate::MpvConnectionArgs; + +const DEFAULT_MPV_CONFIG_CONTENT: &str = include_str!("../assets/default-mpv.conf"); + +pub fn create_mpv_config_file(args_config_file: Option) -> anyhow::Result { + let file_content = if let Some(path) = args_config_file { + if !Path::new(&path).exists() { + anyhow::bail!("Mpv config file not found at {}", &path); + } + + std::fs::read_to_string(&path).context("Failed to read mpv config file")? + } else { + DEFAULT_MPV_CONFIG_CONTENT.to_string() + }; + + let tmpfile = tempfile::Builder::new() + .prefix("mpv-") + .rand_bytes(8) + .suffix(".conf") + .tempfile()?; + + tmpfile.reopen()?.write_all(file_content.as_bytes())?; + + Ok(tmpfile) +} + +pub async fn connect_to_mpv<'a>( + args: &MpvConnectionArgs<'a>, +) -> anyhow::Result<(Mpv, Option)> { + log::debug!("Connecting to mpv"); + + debug_assert!( + !args.force_auto_start || args.auto_start, + "force_auto_start requires auto_start" + ); + + let socket_path = Path::new(&args.socket_path); + + if !socket_path.exists() { + log::debug!("Mpv socket not found at {}", &args.socket_path); + if !args.auto_start { + panic!("Mpv socket not found at {}", &args.socket_path); + } + + log::debug!("Ensuring parent dir of mpv socket exists"); + let parent_dir = Path::new(&args.socket_path) + .parent() + .context("Failed to get parent dir of mpv socket")?; + + if !parent_dir.is_dir() { + create_dir_all(parent_dir).context("Failed to create parent dir of mpv socket")?; + } + } else { + log::debug!("Existing mpv socket found at {}", &args.socket_path); + if args.force_auto_start { + log::debug!("Removing mpv socket"); + std::fs::remove_file(&args.socket_path)?; + } + } + + let process_handle = if args.auto_start { + log::info!("Starting mpv with socket at {}", &args.socket_path); + + // TODO: try to fetch mpv from PATH + Some( + Command::new(args.executable_path.as_deref().unwrap_or("mpv")) + .arg(format!("--input-ipc-server={}", &args.socket_path)) + .arg("--idle") + .arg("--force-window") + .arg("--fullscreen") + .arg("--no-config") + .arg(format!( + "--include={}", + &args.config_file.path().to_string_lossy() + )) + // .arg("--no-terminal") + .arg("--load-unsafe-playlists") + .arg("--keep-open") // Keep last frame of video on end of video + .spawn() + .context("Failed to start mpv")?, + ) + } else { + None + }; + + // Wait for mpv to create the socket + if tokio::time::timeout(tokio::time::Duration::from_millis(500), async { + while !&socket_path.exists() { + log::debug!("Waiting for mpv socket at {}", &args.socket_path); + tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; + } + }) + .await + .is_err() + { + return Err(anyhow::anyhow!( + "Failed to connect to mpv socket: {}", + &args.socket_path + )); + } + + Ok(( + Mpv::connect(&args.socket_path).await.context(format!( + "Failed to connect to mpv socket: {}", + &args.socket_path + ))?, + process_handle, + )) +} +