Skip to content

Commit 5bf1c5b

Browse files
Ralph von der Heydenralph
authored andcommitted
Make SetQueue an opt-in event
Other expensive events might be added to `OptInPlayerEvents` in the future.
1 parent 64edaf8 commit 5bf1c5b

3 files changed

Lines changed: 58 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111

1212
- [connect] Add method `add_to_queue` to `Spirc` to add tracks, episodes, albums and playlists to the queue
13-
- [playback] Add `SetQueue` player event, emitting when the queue changes (context loaded, track added to queue, or queue set via Spotify Connect)
13+
- [playback] Add `SetQueue` player event (opt-in), emitting when the queue changes (context loaded, track added to queue, or queue set via Spotify Connect)
1414

1515
### Changed
1616

playback/src/player.rs

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ struct PlayerInternal {
8080
sink_status: SinkStatus,
8181
sink_event_callback: Option<SinkEventCallback>,
8282
volume_getter: Box<dyn VolumeGetter + Send>,
83-
event_senders: Vec<mpsc::UnboundedSender<PlayerEvent>>,
83+
event_senders: Vec<EventSubscriber>,
8484
converter: Converter,
8585

8686
normalisation_integrators: [f64; 2],
@@ -113,7 +113,10 @@ enum PlayerCommand {
113113
Stop,
114114
Seek(u32),
115115
SetSession(Session),
116-
AddEventSender(mpsc::UnboundedSender<PlayerEvent>),
116+
AddEventSender {
117+
sender: mpsc::UnboundedSender<PlayerEvent>,
118+
opt_in_events: OptInPlayerEvents,
119+
},
117120
SetSinkEventCallback(Option<SinkEventCallback>),
118121
EmitVolumeChangedEvent(u16),
119122
SetAutoNormaliseAsAlbum(bool),
@@ -153,6 +156,20 @@ pub struct QueueTrack {
153156
pub provider: String,
154157
}
155158

159+
/// Opt-in player events that are not delivered to subscribers by default.
160+
///
161+
/// Use [`Player::get_player_event_channel_with`] to subscribe to these.
162+
#[derive(Clone, Copy, Debug, Default)]
163+
pub struct OptInPlayerEvents {
164+
/// Subscribe to [`PlayerEvent::SetQueue`] events.
165+
pub set_queue: bool,
166+
}
167+
168+
struct EventSubscriber {
169+
sender: mpsc::UnboundedSender<PlayerEvent>,
170+
opt_in_events: OptInPlayerEvents,
171+
}
172+
156173
#[derive(Debug, Clone)]
157174
pub enum PlayerEvent {
158175
// Play request id changed
@@ -304,6 +321,14 @@ impl PlayerEvent {
304321
_ => None,
305322
}
306323
}
324+
325+
/// Whether this event should be sent to a subscriber with the given opt-in events.
326+
fn should_send(&self, opt_in: &OptInPlayerEvents) -> bool {
327+
match self {
328+
PlayerEvent::SetQueue { .. } => opt_in.set_queue,
329+
_ => true,
330+
}
331+
}
307332
}
308333

309334
pub type PlayerEventChannel = mpsc::UnboundedReceiver<PlayerEvent>;
@@ -594,8 +619,18 @@ impl Player {
594619
}
595620

596621
pub fn get_player_event_channel(&self) -> PlayerEventChannel {
622+
self.get_player_event_channel_with(OptInPlayerEvents::default())
623+
}
624+
625+
pub fn get_player_event_channel_with(
626+
&self,
627+
opt_in_events: OptInPlayerEvents,
628+
) -> PlayerEventChannel {
597629
let (event_sender, event_receiver) = mpsc::unbounded_channel();
598-
self.command(PlayerCommand::AddEventSender(event_sender));
630+
self.command(PlayerCommand::AddEventSender {
631+
sender: event_sender,
632+
opt_in_events,
633+
});
599634
event_receiver
600635
}
601636

@@ -2318,7 +2353,15 @@ impl PlayerInternal {
23182353

23192354
PlayerCommand::SetSession(session) => self.session = session,
23202355

2321-
PlayerCommand::AddEventSender(sender) => self.event_senders.push(sender),
2356+
PlayerCommand::AddEventSender {
2357+
sender,
2358+
opt_in_events,
2359+
} => {
2360+
self.event_senders.push(EventSubscriber {
2361+
sender,
2362+
opt_in_events,
2363+
});
2364+
}
23222365

23232366
PlayerCommand::SetSinkEventCallback(callback) => self.sink_event_callback = callback,
23242367

@@ -2419,8 +2462,12 @@ impl PlayerInternal {
24192462
}
24202463

24212464
fn send_event(&mut self, event: PlayerEvent) {
2422-
self.event_senders
2423-
.retain(|sender| sender.send(event.clone()).is_ok());
2465+
self.event_senders.retain(|sub| {
2466+
if !event.should_send(&sub.opt_in_events) {
2467+
return true; // keep subscriber, skip this event
2468+
}
2469+
sub.sender.send(event.clone()).is_ok()
2470+
});
24242471
}
24252472

24262473
fn load_track(
@@ -2526,7 +2573,7 @@ impl fmt::Debug for PlayerCommand {
25262573
PlayerCommand::Stop => f.debug_tuple("Stop").finish(),
25272574
PlayerCommand::Seek(position) => f.debug_tuple("Seek").field(&position).finish(),
25282575
PlayerCommand::SetSession(_) => f.debug_tuple("SetSession").finish(),
2529-
PlayerCommand::AddEventSender(_) => f.debug_tuple("AddEventSender").finish(),
2576+
PlayerCommand::AddEventSender { .. } => f.debug_tuple("AddEventSender").finish(),
25302577
PlayerCommand::SetSinkEventCallback(_) => {
25312578
f.debug_tuple("SetSinkEventCallback").finish()
25322579
}

src/main.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use librespot::{
1616
},
1717
dither,
1818
mixer::{self, MixerConfig, MixerFn},
19-
player::{Player, coefficient_to_duration, duration_to_coefficient},
19+
player::{OptInPlayerEvents, Player, coefficient_to_duration, duration_to_coefficient},
2020
},
2121
};
2222
use librespot_oauth::OAuthClientBuilder;
@@ -1994,8 +1994,9 @@ async fn main() {
19941994
});
19951995

19961996
if let Some(player_event_program) = setup.player_event_program.clone() {
1997+
let opt_in_events = OptInPlayerEvents { set_queue: true };
19971998
_event_handler = Some(EventHandler::new(
1998-
player.get_player_event_channel(),
1999+
player.get_player_event_channel_with(opt_in_events),
19992000
&player_event_program,
20002001
));
20012002

0 commit comments

Comments
 (0)