From df150a6804f46a8a7bb10ea90a1c2c9e91e72ef7 Mon Sep 17 00:00:00 2001 From: elParaguayo Date: Sun, 4 Aug 2024 08:33:20 +0100 Subject: [PATCH 1/3] Add Seeked signal to Mpris interface The Mpris2 spec includes a `Seeked` signal which should be fired when the track position changes in an unexpected way i.e. when the user seeks to a different part of the track. This PR implements this signal on seek events and also when a new track begins. The latter is not strictly required but has been observed in other players (e.g. VLC). Closes #1492 --- src/mpris.rs | 12 ++++++++++++ src/queue.rs | 4 ++++ src/spotify.rs | 13 +++++++++++++ 3 files changed, 29 insertions(+) diff --git a/src/mpris.rs b/src/mpris.rs index 29fde7d6f..216e703ba 100644 --- a/src/mpris.rs +++ b/src/mpris.rs @@ -1,3 +1,5 @@ +#![allow(clippy::use_self)] + use log::info; use std::collections::HashMap; use std::error::Error; @@ -6,6 +8,7 @@ use std::time::Duration; use tokio::sync::mpsc; use tokio_stream::wrappers::UnboundedReceiverStream; use tokio_stream::StreamExt; +use zbus::object_server::SignalContext; use zbus::zvariant::{ObjectPath, Value}; use zbus::{interface, ConnectionBuilder}; @@ -314,6 +317,9 @@ impl MprisPlayer { self.queue.get_current().is_some() } + #[zbus(signal)] + async fn seeked(context: &SignalContext<'_>, position: &i64) -> zbus::Result<()>; + fn next(&self) { self.queue.next(true) } @@ -472,6 +478,8 @@ pub enum MprisCommand { EmitVolumeStatus, /// Emit metadata EmitMetadataStatus, + /// Emit seeked position + EmitSeekedStatus(i64), } /// An MPRIS server that internally manager a thread which can be sent commands. This is internally @@ -539,6 +547,10 @@ impl MprisManager { Some(MprisCommand::EmitMetadataStatus) => { player_iface.metadata_changed(ctx).await?; } + Some(MprisCommand::EmitSeekedStatus(pos)) => { + info!("sending MPRIS seeked signal"); + MprisPlayer::seeked(ctx, &pos).await?; + } None => break, } } diff --git a/src/queue.rs b/src/queue.rs index ced8ad4b1..64f2a9c23 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -313,6 +313,10 @@ impl Queue { move || send_notification(&summary_txt, &body_txt, cover_url) }); } + + // Send a Seeked signal at start of new track + #[cfg(feature = "mpris")] + self.spotify.notify_seeked(0); } if reshuffle && self.get_shuffle() { diff --git a/src/spotify.rs b/src/spotify.rs index 2e2165aba..10117edfc 100644 --- a/src/spotify.rs +++ b/src/spotify.rs @@ -415,6 +415,8 @@ impl Spotify { /// Seek in the currently played [Playable] played by the [Player]. pub fn seek(&self, position_ms: u32) { self.send_worker(WorkerCommand::Seek(position_ms)); + #[cfg(feature = "mpris")] + self.notify_seeked(position_ms); } /// Seek relatively to the current playback position of the [Player]. @@ -429,6 +431,17 @@ impl Spotify { self.cfg.state().volume } + /// Send a Seeked signal on Mpris interface + #[cfg(feature = "mpris")] + pub fn notify_seeked(&self, position: u32) { + if let Some(mpris_manager) = self.mpris.lock().unwrap().as_ref() { + info!("Seeked event"); + // Mpris spec requires microseconds + let new_position = position * 1000; + mpris_manager.send(MprisCommand::EmitSeekedStatus(new_position.into())); + } + } + /// Set the current volume of the [Player]. If `notify` is true, also notify MPRIS clients about /// the update. pub fn set_volume(&self, volume: u16, notify: bool) { From a1fb795a9580f36ea9b60a612dcbff5de2b96b83 Mon Sep 17 00:00:00 2001 From: Henrik Friedrichsen Date: Sat, 21 Sep 2024 11:48:14 +0200 Subject: [PATCH 2/3] chore: Use `send_mpris()` and `Duration` for conversion --- src/spotify.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/spotify.rs b/src/spotify.rs index 10117edfc..8d098ef1c 100644 --- a/src/spotify.rs +++ b/src/spotify.rs @@ -433,13 +433,15 @@ impl Spotify { /// Send a Seeked signal on Mpris interface #[cfg(feature = "mpris")] - pub fn notify_seeked(&self, position: u32) { - if let Some(mpris_manager) = self.mpris.lock().unwrap().as_ref() { - info!("Seeked event"); - // Mpris spec requires microseconds - let new_position = position * 1000; - mpris_manager.send(MprisCommand::EmitSeekedStatus(new_position.into())); - } + pub fn notify_seeked(&self, position_ms: u32) { + let new_position = Duration::from_millis(position_ms.into()); + let command = MprisCommand::EmitSeekedStatus( + new_position + .as_micros() + .try_into() + .expect("track position exceeds MPRIS datatype"), + ); + self.send_mpris(command); } /// Set the current volume of the [Player]. If `notify` is true, also notify MPRIS clients about From 9ccfa44e0c555b2c6e872d0c84e6721ed546ced5 Mon Sep 17 00:00:00 2001 From: Henrik Friedrichsen Date: Sat, 21 Sep 2024 11:48:58 +0200 Subject: [PATCH 3/3] doc: Update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3768c1d1c..27ce5f951 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Emit MPRIS `Seeked` signal + ### Fixed - Switch to OAuth2 login mechanism