Skip to content

Commit 7bcd311

Browse files
committed
tie mpris session to cluster topo
consume cluster topology updates to emit session dis/connect events (+ stopped on disconnect) so spotifyd dis/appears in mpris based on remote active device presence
1 parent aabac18 commit 7bcd311

1 file changed

Lines changed: 54 additions & 24 deletions

File tree

src/main_loop.rs

Lines changed: 54 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use futures::{
1313
future::{self, Fuse, FusedFuture},
1414
stream::Peekable,
1515
};
16-
use librespot_connect::{ConnectConfig, Spirc};
16+
use librespot_connect::{ClusterUpdateInfo, ConnectConfig, Spirc};
1717
use librespot_core::{
1818
Error, SessionConfig, SpotifyUri, authentication::Credentials, cache::Cache,
1919
config::DeviceType, session::Session,
@@ -30,6 +30,10 @@ use log::{error, info};
3030
use std::pin::Pin;
3131
use std::sync::Arc;
3232

33+
const SPECTATOR_CONNECTION_ID: &str = "spectator-remote";
34+
const SPECTATOR_USER_NAME: &str = "spectator";
35+
const SPECTATOR_PLAY_REQUEST_ID: u64 = 0;
36+
3337
#[cfg(not(feature = "dbus_mpris"))]
3438
type DbusServer = Pending<()>;
3539

@@ -222,16 +226,20 @@ impl MainLoop {
222226
let mut running_event_program = Box::pin(Fuse::terminated());
223227

224228
let mut event_channel = connection.player.get_player_event_channel();
225-
let mut state_channel = self
229+
let mut cluster_update_channel = self
226230
.spectator
227-
.then(|| shared_spirc.as_ref().get_state_update_channel());
231+
.then(|| shared_spirc.as_ref().get_cluster_update_channel());
228232

229233
let mut last_track_uri: Option<String> = None;
230-
let mut last_play_request_id: u64 = 0;
234+
#[cfg(feature = "dbus_mpris")]
235+
let mut spectator_connected = false;
231236

232-
let mut emit_spectator_state =
233-
|track_uri: String, is_playing: bool, position_ms: u32, play_request_id: u64| {
234-
let track_changed = if let Some(ref last_uri) = last_track_uri {
237+
let emit_spectator_state = |last_track_uri: &mut Option<String>,
238+
track_uri: String,
239+
is_playing: bool,
240+
position_ms: u32,
241+
play_request_id: u64| {
242+
let track_changed = if let Some(ref last_uri) = *last_track_uri {
235243
last_uri != &track_uri && !track_uri.is_empty()
236244
} else {
237245
!track_uri.is_empty()
@@ -274,7 +282,7 @@ impl MainLoop {
274282
}
275283
}
276284

277-
last_track_uri = Some(track_uri);
285+
*last_track_uri = Some(track_uri);
278286
};
279287

280288
loop {
@@ -308,30 +316,52 @@ impl MainLoop {
308316
result // unused variable
309317
}
310318
state = async {
311-
match state_channel.as_mut() {
319+
match cluster_update_channel.as_mut() {
312320
Some(channel) => channel.recv().await,
313321
None => future::pending().await
314322
}
315323
}, if self.spectator => {
316-
if let Ok(player_state) = state {
317-
let track_uri = player_state.track
318-
.as_ref()
319-
.map(|t| t.uri.clone())
320-
.unwrap_or_default();
324+
if let Ok(ClusterUpdateInfo { active_device_id, track_uri, is_playing, position_ms }) = state {
325+
let has_active_remote = !active_device_id.is_empty();
321326

322-
let is_playing = player_state.is_playing;
323-
let position_ms = player_state.position_as_of_timestamp as u32;
327+
#[cfg(feature = "dbus_mpris")]
328+
if let Some(ref tx) = mpris_event_tx {
329+
if has_active_remote && !spectator_connected {
330+
let _ = tx.send(PlayerEvent::SessionConnected {
331+
connection_id: SPECTATOR_CONNECTION_ID.to_string(),
332+
user_name: SPECTATOR_USER_NAME.to_string(),
333+
});
334+
spectator_connected = true;
335+
} else if !has_active_remote && spectator_connected {
336+
if let Some(ref uri) = last_track_uri
337+
&& let Ok(track_id) = SpotifyUri::from_uri(uri)
338+
{
339+
let _ = tx.send(PlayerEvent::Stopped {
340+
play_request_id: SPECTATOR_PLAY_REQUEST_ID,
341+
track_id,
342+
});
343+
}
344+
let _ = tx.send(PlayerEvent::SessionDisconnected {
345+
connection_id: SPECTATOR_CONNECTION_ID.to_string(),
346+
user_name: SPECTATOR_USER_NAME.to_string(),
347+
});
348+
spectator_connected = false;
349+
}
350+
}
324351

325-
if let Ok(playback_id) = player_state.playback_id.parse::<u64>() {
326-
last_play_request_id = playback_id;
352+
if !has_active_remote {
353+
continue;
327354
}
328355

329-
emit_spectator_state(
330-
track_uri,
331-
is_playing,
332-
position_ms,
333-
last_play_request_id,
334-
);
356+
if let Some(track_uri) = track_uri {
357+
emit_spectator_state(
358+
&mut last_track_uri,
359+
track_uri,
360+
is_playing.unwrap_or(false),
361+
position_ms.unwrap_or(0),
362+
SPECTATOR_PLAY_REQUEST_ID,
363+
);
364+
}
335365
}
336366
}
337367
// a new player event is available and no program is running

0 commit comments

Comments
 (0)