Skip to content

Commit 20b3694

Browse files
committed
feat: Use Spirc for player logic
**Heavily WIP, only compiles so far.** The idea is to use librespot `Spirc` instead of handling the player logic within ncspot. This should reduce complexity a bit, but also allows us to integrate with Spotify Connect, which in turn would enable ncspot to be controlled via Spotify Apps.
1 parent 2d4507d commit 20b3694

File tree

4 files changed

+61
-19
lines changed

4 files changed

+61
-19
lines changed

Cargo.lock

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ fern = "0.7"
5252
futures = "0.3"
5353
ioctl-rs = {version = "0.2", optional = true}
5454
libc = "0.2.175"
55+
librespot-connect = "0.7.0"
5556
librespot-core = "0.7.0"
5657
librespot-oauth = "0.7.0"
5758
librespot-playback = {version = "0.7.0", default-features = false, features = ["native-tls"]}

src/spotify.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ impl Spotify {
243243
..Default::default()
244244
};
245245

246-
let session = Self::create_session(&cfg, credentials)
246+
let session = Self::create_session(&cfg, credentials.clone())
247247
.await
248248
.expect("Could not create session");
249249
user_tx.map(|tx| tx.send(session.username()));
@@ -265,12 +265,13 @@ impl Spotify {
265265

266266
let mut worker = Worker::new(
267267
events.clone(),
268+
credentials,
268269
player_events,
269270
commands,
270271
session,
271272
player,
272273
mixer,
273-
);
274+
).await;
274275
debug!("worker thread ready.");
275276
worker.run_loop().await;
276277

src/spotify_worker.rs

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ use crate::model::playable::Playable;
33
use crate::queue::QueueEvent;
44
use crate::spotify::PlayerEvent;
55
use futures::Future;
6+
use librespot_connect::{ConnectConfig, LoadRequest, LoadRequestOptions, Spirc};
67
use librespot_core::session::Session;
78
use librespot_core::spotify_id::SpotifyId;
89
use librespot_core::token::Token;
910
use librespot_playback::mixer::Mixer;
1011
use librespot_playback::player::{Player, PlayerEvent as LibrespotPlayerEvent};
12+
use librespot_protocol::credentials;
1113
use log::{debug, error, info, warn};
1214
use std::sync::Arc;
1315
use std::sync::mpsc::Sender;
@@ -41,31 +43,37 @@ pub struct Worker {
4143
events: EventManager,
4244
player_events: UnboundedReceiverStream<LibrespotPlayerEvent>,
4345
commands: UnboundedReceiverStream<WorkerCommand>,
44-
session: Session,
45-
player: Arc<Player>,
4646
token_task: Pin<Box<dyn Future<Output = ()> + Send>>,
4747
player_status: PlayerStatus,
48-
mixer: Arc<dyn Mixer>,
48+
session: Session,
49+
spirc: Spirc,
50+
spirc_task: Pin<Box<dyn Future<Output = ()> + Send>>,
4951
}
5052

5153
impl Worker {
52-
pub(crate) fn new(
54+
pub(crate) async fn new(
5355
events: EventManager,
56+
credentials: librespot_core::authentication::Credentials,
5457
player_events: mpsc::UnboundedReceiver<LibrespotPlayerEvent>,
5558
commands: mpsc::UnboundedReceiver<WorkerCommand>,
5659
session: Session,
5760
player: Arc<Player>,
5861
mixer: Arc<dyn Mixer>,
5962
) -> Self {
63+
let config = ConnectConfig {
64+
name: "ncspot".to_string(),
65+
..Default::default()
66+
};
67+
let spirc = Spirc::new(config, session.clone(), credentials, player, mixer).await.expect("Spirc should be initialized");
6068
Self {
6169
events,
6270
player_events: UnboundedReceiverStream::new(player_events),
6371
commands: UnboundedReceiverStream::new(commands),
64-
player,
65-
session,
6672
token_task: Box::pin(futures::future::pending()),
6773
player_status: PlayerStatus::Stopped,
68-
mixer,
74+
session,
75+
spirc: spirc.0,
76+
spirc_task: Box::pin(spirc.1),
6977
}
7078
}
7179

@@ -105,7 +113,14 @@ impl Worker {
105113
warn!("track is not playable");
106114
self.events.send(Event::Player(PlayerEvent::FinishedTrack));
107115
} else {
108-
self.player.load(id, start_playing, position_ms);
116+
let options = LoadRequestOptions {
117+
start_playing,
118+
seek_to: position_ms,
119+
context_options: None,
120+
playing_track: None,
121+
};
122+
let req = LoadRequest::from_tracks(vec![id.to_uri().expect("uri")], options);
123+
self.spirc.load(req);
109124
}
110125
}
111126
Err(e) => {
@@ -115,32 +130,31 @@ impl Worker {
115130
}
116131
}
117132
Some(WorkerCommand::Play) => {
118-
self.player.play();
133+
self.spirc.play();
119134
}
120135
Some(WorkerCommand::Pause) => {
121-
self.player.pause();
136+
self.spirc.pause();
122137
}
123138
Some(WorkerCommand::Stop) => {
124-
self.player.stop();
139+
todo!("stop spirc");
125140
}
126141
Some(WorkerCommand::Seek(pos)) => {
127-
self.player.seek(pos);
142+
self.spirc.set_position_ms(pos);
128143
}
129144
Some(WorkerCommand::SetVolume(volume)) => {
130-
self.mixer.set_volume(volume);
145+
self.spirc.set_volume(volume);
131146
}
132147
Some(WorkerCommand::RequestToken(sender)) => {
133148
self.token_task = Box::pin(Self::get_token(self.session.clone(), sender));
134149
}
135150
Some(WorkerCommand::Preload(playable)) => {
136151
if let Ok(id) = SpotifyId::from_uri(&playable.uri()) {
137152
debug!("Preloading {id:?}");
138-
self.player.preload(id);
153+
// self.player.preload(id);
139154
}
140155
}
141156
Some(WorkerCommand::Shutdown) => {
142-
self.player.stop();
143-
self.session.shutdown();
157+
self.spirc.shutdown();
144158
}
145159
None => info!("empty stream")
146160
},
@@ -197,6 +211,9 @@ impl Worker {
197211
break
198212
},
199213
},
214+
_ = self.spirc_task.as_mut() => {
215+
info!("spirc task tick");
216+
},
200217
// Update animated parts of the UI (e.g. statusbar during playback).
201218
_ = ui_refresh.tick() => {
202219
if !matches!(self.player_status, PlayerStatus::Stopped) {
@@ -215,6 +232,6 @@ impl Worker {
215232
impl Drop for Worker {
216233
fn drop(&mut self) {
217234
debug!("Worker thread is shutting down, stopping player");
218-
self.player.stop();
235+
self.spirc.shutdown();
219236
}
220237
}

0 commit comments

Comments
 (0)