diff options
author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2025-02-14 17:15:18 +0100 |
---|---|---|
committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2025-02-14 17:15:18 +0100 |
commit | 66c739237cc352fedf6276a3163097c1f1f32bd4 (patch) | |
tree | efdc61c079473e4d86f38454cd1568337e39f219 | |
parent | fix(yt/watch): Always open a `mpv` window (diff) | |
download | yt-66c739237cc352fedf6276a3163097c1f1f32bd4.zip |
fix(crates/libmpv2/Mpv::command): Correctly escape arguments
This allows us to avoid all these ad-hoc command escaping `format!` invocations.
-rw-r--r-- | crates/libmpv2/src/mpv.rs | 26 | ||||
-rw-r--r-- | yt/src/watch/events/handlers/mod.rs | 2 | ||||
-rw-r--r-- | yt/src/watch/events/mod.rs | 9 | ||||
-rw-r--r-- | yt/src/watch/mod.rs | 16 |
4 files changed, 21 insertions, 32 deletions
diff --git a/crates/libmpv2/src/mpv.rs b/crates/libmpv2/src/mpv.rs index 07d0976..6f26d0f 100644 --- a/crates/libmpv2/src/mpv.rs +++ b/crates/libmpv2/src/mpv.rs @@ -526,19 +526,6 @@ impl Mpv { }) } - /// Execute a command - pub fn execute(&self, name: &str, args: &[&str]) -> Result<()> { - if args.is_empty() { - debug!("Running mpv command: '{}'", name); - } else { - debug!("Running mpv command: '{} {}'", name, args.join(" ")); - } - - self.command(name, args)?; - - Ok(()) - } - /// Load a configuration file. The path has to be absolute, and a file. pub fn load_config(&self, path: &str) -> Result<()> { let file = CString::new(path)?.into_raw(); @@ -562,7 +549,7 @@ impl Mpv { /// Send a command to the `Mpv` instance. This uses `mpv_command_string` internally, /// so that the syntax is the same as described in the [manual for the input.conf](https://mpv.io/manual/master/#list-of-input-commands). /// - /// Note that you may have to escape strings with `""` when they contain spaces. + /// Note that this function escapes the arguments for you. /// /// # Examples /// @@ -583,12 +570,19 @@ impl Mpv { /// # } /// ``` pub fn command(&self, name: &str, args: &[&str]) -> Result<()> { - let mut cmd = name.to_owned(); + fn escape(input: &str) -> String { + input.replace('"', "\\\"") + } + + let mut cmd = escape(name); for elem in args { cmd.push(' '); - cmd.push_str(elem); + cmd.push('"'); + cmd.push_str(&escape(elem)); + cmd.push('"'); } + debug!("Running mpv command: '{}'", cmd); let raw = CString::new(cmd)?; mpv_err((), unsafe { diff --git a/yt/src/watch/events/handlers/mod.rs b/yt/src/watch/events/handlers/mod.rs index 715896d..3f30812 100644 --- a/yt/src/watch/events/handlers/mod.rs +++ b/yt/src/watch/events/handlers/mod.rs @@ -178,7 +178,7 @@ impl MpvEventHandler { /// # Panics /// Only if internal assertions fail. pub fn handle_client_message_yt_mark_watch_later(&mut self, mpv: &Mpv) -> Result<()> { - mpv.execute("write-watch-later-config", &[])?; + mpv.command("write-watch-later-config", &[])?; let hash = self.remove_cvideo_from_playlist(mpv)?; assert!( diff --git a/yt/src/watch/events/mod.rs b/yt/src/watch/events/mod.rs index b63b33b..10e8bc8 100644 --- a/yt/src/watch/events/mod.rs +++ b/yt/src/watch/events/mod.rs @@ -113,11 +113,8 @@ impl MpvEventHandler { orig_cache_path.display() ) })?; - let fmt_cache_path = format!("\"{cache_path}\""); - let args = &[&fmt_cache_path, "append-play"]; - - mpv.execute("loadfile", args)?; + mpv.command("loadfile", &[cache_path, "append-play"])?; self.playlist_handler .add(cache_path.to_owned(), play_thing.extractor_hash); } @@ -133,7 +130,7 @@ impl MpvEventHandler { } fn message(mpv: &Mpv, message: &str, time: &str) -> Result<()> { - mpv.execute("show-text", &[format!("\"{message}\"").as_str(), time])?; + mpv.command("show-text", &[message, time])?; Ok(()) } @@ -215,7 +212,7 @@ impl MpvEventHandler { /// This also returns the hash of the current video fn remove_cvideo_from_playlist(&mut self, mpv: &Mpv) -> Result<ExtractorHash> { let hash = self.get_cvideo_hash(mpv, 0)?; - mpv.execute("playlist-remove", &["current"])?; + mpv.command("playlist-remove", &["current"])?; Ok(hash) } diff --git a/yt/src/watch/mod.rs b/yt/src/watch/mod.rs index 9b2cbef..7247999 100644 --- a/yt/src/watch/mod.rs +++ b/yt/src/watch/mod.rs @@ -13,7 +13,7 @@ use std::{collections::HashMap, time::Duration}; use anyhow::{Context, Result}; use events::{IdleCheckOutput, MpvEventHandler}; use libmpv2::{events::EventContext, Mpv}; -use log::{debug, info, warn}; +use log::{debug, info, trace, warn}; use tokio::time; use crate::{ @@ -47,12 +47,13 @@ pub async fn watch(app: &App) -> Result<()> { // As mpv does not have cli access, no window means no control and no user feedback. mpv.set_option("force-window", "yes")?; Ok(()) - })?; + }) + .context("Failed to initialize mpv")?; let config_path = &app.config.paths.mpv_config_path; if config_path.try_exists()? { info!("Found mpv.conf at '{}'!", config_path.display()); - mpv.execute( + mpv.command( "load-config-file", &[config_path .to_str() @@ -68,7 +69,7 @@ pub async fn watch(app: &App) -> Result<()> { let input_path = &app.config.paths.mpv_input_path; if input_path.try_exists()? { info!("Found mpv.input.conf at '{}'!", input_path.display()); - mpv.execute( + mpv.command( "load-input-conf", &[input_path .to_str() @@ -103,11 +104,8 @@ pub async fn watch(app: &App) -> Result<()> { orig_cache_path.display() ) })?; - let fmt_cache_path = format!("\"{cache_path}\""); - let args = &[&fmt_cache_path, "append-play"]; - - mpv.execute("loadfile", args)?; + mpv.command("loadfile", &[&cache_path, "append-play"])?; playlist_cache.insert(cache_path.to_owned(), play_thing.extractor_hash); } @@ -145,7 +143,7 @@ pub async fn watch(app: &App) -> Result<()> { if let Some(ev) = ev_ctx.wait_event(600.) { match ev { Ok(event) => { - debug!("Mpv event triggered: {:#?}", event); + trace!("Mpv event triggered: {:#?}", event); if mpv_event_handler.handle_mpv_event(app, &mpv, event).await? { break; } |