Skip to content

Commit

Permalink
update connect example and link in docs
Browse files Browse the repository at this point in the history
  • Loading branch information
photovoltex committed Jan 31, 2025
1 parent 7dc4bf0 commit 8fac548
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 66 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ spotify_appkey.key
.vagrant/
.project
.history
.cache
*.save
*.*~
23 changes: 11 additions & 12 deletions connect/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@ and stream to it like any other official spotify client.

The [`Spirc`] is the entrypoint to creating your own connect device. It can be
configured with the given [`ConnectConfig`] options and requires some additional data
to start up the device.
to start up the device.

When creating a new [`Spirc`] it returns two items. The [`Spirc`] itself, which is can
be used as to control the local connect device. And a [`Future`](std::future::Future),
lets name it `SpircTask`, that starts and executes the event loop of the connect device
When creating a new [`Spirc`] it returns two items. The [`Spirc`] itself, which is can
be used as to control the local connect device. And a [`Future`](std::future::Future),
lets name it `SpircTask`, that starts and executes the event loop of the connect device
when awaited.

To get an understanding how to handle the `SpircTask`, it is recommended to take look
at the code of the `librespot` binary. As the [`src/main.rs`](https://github.com/librespot-org/librespot/blob/dev/src/main.rs#L1943)
file is quite overwhelming to just understand how to handle the `SpircTask` it is
recommended to ignore all setup code and skip to the main-loop (around line 1940).
A basic example in which the `Spirc` and `SpircTask` is used can be found here:
[`examples/play_connect.rs`](../examples/play_connect.rs).

# Example

Expand All @@ -33,8 +31,7 @@ use librespot_playback::{
player::Player
};

async fn create_basic_spirc() -> Result<(Spirc, impl Future<Output=()>), Error> {
// when using a cache you can acquire the credentials from there
async fn create_basic_spirc() -> Result<(), Error> {
let credentials = Credentials::with_access_token("access-token-here");
let session = Session::new(SessionConfig::default(), None);

Expand All @@ -53,12 +50,14 @@ async fn create_basic_spirc() -> Result<(Spirc, impl Future<Output=()>), Error>

let mixer = mixer::find(None).expect("will default to SoftMixer");

Spirc::new(
let (spirc, spirc_task): (Spirc, _) = Spirc::new(
ConnectConfig::default(),
session,
credentials,
player,
mixer(MixerConfig::default())
).await
).await?;

Ok(())
}
```
98 changes: 44 additions & 54 deletions examples/play_connect.rs
Original file line number Diff line number Diff line change
@@ -1,84 +1,74 @@
use librespot::{
connect::{ConnectConfig, LoadRequest, LoadRequestOptions, Spirc},
core::{
authentication::Credentials, config::SessionConfig, session::Session, spotify_id::SpotifyId,
authentication::Credentials, cache::Cache, config::SessionConfig, session::Session, Error,
},
metadata::{Album, Metadata},
playback::mixer::{softmixer::SoftMixer, Mixer, MixerConfig},
playback::mixer::MixerConfig,
playback::{
audio_backend,
config::{AudioFormat, PlayerConfig},
mixer::NoOpVolume,
mixer,
player::Player,
},
};

use std::{env, sync::Arc};
use tokio::join;
use log::LevelFilter;

const CACHE: &str = ".cache";
const CACHE_FILES: &str = ".cache/files";

#[tokio::main]
async fn main() {
async fn main() -> Result<(), Error> {
env_logger::builder()
.filter_module("librespot", LevelFilter::Debug)
.init();

let session_config = SessionConfig::default();
let player_config = PlayerConfig::default();
let audio_format = AudioFormat::default();
let connect_config = ConnectConfig::default();
let mixer_config = MixerConfig::default();
let request_options = LoadRequestOptions::default();

let mut args: Vec<_> = env::args().collect();
let context_uri = if args.len() == 3 {
args.pop().unwrap()
} else if args.len() == 2 {
String::from("spotify:album:79dL7FLiJFOO0EoehUHQBv")
} else {
eprintln!("Usage: {} ACCESS_TOKEN (ALBUM URI)", args[0]);
return;
};
let sink_builder = audio_backend::find(None).unwrap();
let mixer_builder = mixer::find(None).unwrap();

let credentials = Credentials::with_access_token(&args[1]);
let backend = audio_backend::find(None).unwrap();
let cache = Cache::new(Some(CACHE), Some(CACHE), Some(CACHE_FILES), None)?;
let credentials = cache
.credentials()
.ok_or(Error::unavailable("credentials not cached"))
.or_else(|_| {
librespot_oauth::get_access_token(
&session_config.client_id,
"http://127.0.0.1:8898/login",
vec!["streaming"],
)
.map(|t| Credentials::with_access_token(t.access_token))
})?;

println!("Connecting...");
let session = Session::new(session_config, None);
let session = Session::new(session_config, Some(cache));
let mixer = mixer_builder(mixer_config);

let player = Player::new(
player_config,
session.clone(),
Box::new(NoOpVolume),
move || backend(None, audio_format),
mixer.get_soft_volume(),
move || sink_builder(None, audio_format),
);

let (spirc, spirc_task) = Spirc::new(
connect_config,
session.clone(),
credentials,
player,
Arc::new(SoftMixer::open(MixerConfig::default())),
)
.await
.unwrap();
let (spirc, spirc_task) =
Spirc::new(connect_config, session.clone(), credentials, player, mixer).await?;

join!(spirc_task, async {
let album = Album::get(&session, &SpotifyId::from_uri(&context_uri).unwrap())
.await
.unwrap();
// these calls can be seen as "queued"
spirc.activate()?;
spirc.load(LoadRequest::from_context_uri(
format!("spotify:user:{}:collection", session.username()),
request_options,
))?;
spirc.play()?;

println!(
"Playing album: {} by {}",
&album.name,
album
.artists
.first()
.map_or("unknown", |artist| &artist.name)
);
// starting the connect device and processing the previously "queued" calls
spirc_task.await;

spirc.activate().unwrap();
spirc
.load(LoadRequest::from_context_uri(
context_uri,
LoadRequestOptions {
start_playing: true,
..Default::default()
},
))
.unwrap();
});
Ok(())
}

0 comments on commit 8fac548

Please sign in to comment.