From 9a3919754e1d962a5deaca05a2372a54f94ec185 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Sun, 29 Oct 2023 17:40:48 -0400 Subject: [PATCH] Add clear and pause-after REPL commands --- player/src/os_controls.rs | 20 +++++++++++++++++++ player/src/player_wrapper.rs | 7 ++++++- src/debug_state.rs | 2 ++ src/help.rs | 6 ++++++ src/repl.rs | 38 ++++++++++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 1 deletion(-) diff --git a/player/src/os_controls.rs b/player/src/os_controls.rs index 5710900..3ce82ab 100644 --- a/player/src/os_controls.rs +++ b/player/src/os_controls.rs @@ -38,6 +38,7 @@ enum DbusControl { Die, SetMetadata(Metadata), SetPosition(i64), + SetPlaybackMode(PlaybackStatus), } #[cfg(all(target_os = "linux", feature = "os-controls", feature = "mpris-player"))] @@ -149,6 +150,9 @@ impl SystemControlWrapper { } Ok(DbusControl::SetPosition(pos)) => { dbus_conn.set_position(pos); + }, + Ok(DbusControl::SetPlaybackMode(mode)) => { + dbus_conn.set_playback_status(mode); } } } @@ -259,6 +263,9 @@ impl SystemControlWrapper { dbus_ctrl .send(DbusControl::SetMetadata(Self::build_metadata(item, duration))) .unwrap_or(()); + dbus_ctrl + .send(DbusControl::SetPlaybackMode(PlaybackStatus::Playing)) + .unwrap_or(()); } fn empty(dbus_ctrl: &Sender) { @@ -277,11 +284,17 @@ impl SystemControlWrapper { url: None, })) .unwrap_or(()); + dbus_ctrl + .send(DbusControl::SetPlaybackMode(PlaybackStatus::Stopped)) + .unwrap_or(()); } fn time(item: Item, duration: &std::time::Duration, dbus_ctrl: &Sender) { let meta = Self::build_metadata(item, Some(duration)); dbus_ctrl.send(DbusControl::SetMetadata(meta)).unwrap_or(()); + dbus_ctrl + .send(DbusControl::SetPlaybackMode(PlaybackStatus::Playing)) + .unwrap_or(()); } fn time_update( @@ -300,6 +313,9 @@ impl SystemControlWrapper { dbus_ctrl .send(DbusControl::SetPosition(new_time * 1_000_000)) .unwrap_or(()); + dbus_ctrl + .send(DbusControl::SetPlaybackMode(PlaybackStatus::Playing)) + .unwrap_or(()); } } } @@ -344,6 +360,10 @@ impl super::EventTap for SystemControlWrapper { state.duration_cache.get(item), self.dbus_ctrl.as_ref().unwrap(), ); + }, + PlaybackAction::Paused => { + self.dbus_ctrl.as_ref().unwrap().send(DbusControl::SetPlaybackMode(PlaybackStatus::Paused)) + .unwrap_or(()); } } None diff --git a/player/src/player_wrapper.rs b/player/src/player_wrapper.rs index 4161a5b..705a7c1 100644 --- a/player/src/player_wrapper.rs +++ b/player/src/player_wrapper.rs @@ -184,11 +184,15 @@ impl>> PlayerServer } } ControlAction::Play { .. } => self.player.resume(), - ControlAction::Pause { .. } => self.player.pause(), + ControlAction::Pause { .. } => { + self.playback.send(PlaybackAction::Paused).unwrap(); + self.player.pause() + }, ControlAction::PlayPause { .. } => { if self.player.is_paused() { self.player.resume(); } else { + self.playback.send(PlaybackAction::Paused).unwrap(); self.player.pause(); } } @@ -321,6 +325,7 @@ pub enum PlaybackAction { Enqueued(Item), Time(Item, std::time::Duration), UpdateTick(Item, u64), // tick sent once every second + Paused, Exit, } diff --git a/src/debug_state.rs b/src/debug_state.rs index 02416ad..67516f0 100644 --- a/src/debug_state.rs +++ b/src/debug_state.rs @@ -19,6 +19,7 @@ pub enum InterpreterDebugFlag { Skip, List, Normal, + Pausing, } #[derive(Clone)] @@ -205,6 +206,7 @@ impl EventTap for DebugEventHandler { }, PlaybackAction::Time(_item, _dur) => {}, PlaybackAction::UpdateTick(_item, _tick) => {}, + PlaybackAction::Paused => {}, } None } diff --git a/src/help.rs b/src/help.rs index 0bb897b..a6cff5c 100644 --- a/src/help.rs +++ b/src/help.rs @@ -184,6 +184,9 @@ REPL-specific operations to help with writing Muss scripts: ?command skip Skip remaining items to be played. If no items are about to be played, skip all items in the next statement. This is a no-output version of ?list. + clear + Skip remaining items to be played, including the remainder of the current item. This is the immediate version of ?skip. + normal Cancel any active ?skip or ?list operation. @@ -196,6 +199,9 @@ REPL-specific operations to help with writing Muss scripts: ?command pause Immediate song control actions to apply to the current item. + pause-after + Pause playback after the current song completes. + volume number Set playback volume to number, in percent (starts at 100% when the cli parameter is not used). diff --git a/src/repl.rs b/src/repl.rs index 67d204f..fb2acba 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -165,6 +165,19 @@ pub fn repl(args: CliArgs) { // NOTE: recursion occurs here } None + }, + crate::debug_state::InterpreterDebugFlag::Pausing => { + controller_debug_clone.control_tx + .lock() + .expect("Failed to get lock for control action sender") + .as_ref() + .expect("Control action sender shouldn't be None") + .send(muss_player::ControlAction::Pause { ack: false }) + .expect("Failed to send control action"); + if let Ok(mut d_state) = controller_debug_clone.interpreter.write() { + d_state.debug_flag = crate::debug_state::InterpreterDebugFlag::Normal; + } + item } crate::debug_state::InterpreterDebugFlag::List => { if let Some(x) = item { @@ -665,6 +678,31 @@ fn repl_commands(command_str: &str, state: &mut ReplState, args: &CliArgs) { debug_state.debug_flag = crate::debug_state::InterpreterDebugFlag::Skip; } writeln!(state.terminal, "Skipping upcoming items").expect(TERMINAL_WRITE_ERROR); + }, + "?pause-after" => { + { + let mut debug_state = state.controller_debug.interpreter + .write() + .expect("Failed to get write lock for debug state"); + debug_state.debug_flag = crate::debug_state::InterpreterDebugFlag::Pausing; + } + writeln!(state.terminal, "Pausing after current item").expect(TERMINAL_WRITE_ERROR); + }, + "?clear" => { + { + let mut debug_state = state.controller_debug.interpreter + .write() + .expect("Failed to get write lock for debug state"); + debug_state.debug_flag = crate::debug_state::InterpreterDebugFlag::Skip; + state.controller_debug.control_tx + .lock() + .expect("Failed to get lock for control action sender") + .as_ref() + .expect("Control action sender shouldn't be None") + .send(muss_player::ControlAction::Next { ack: false }) + .expect("Failed to send control action"); + } + writeln!(state.terminal, "Clearing upcoming items").expect(TERMINAL_WRITE_ERROR); } "?normal" => { {