Skip to content

Commit 09b4aa4

Browse files
authored
Add rustdoc to connect crate (#1455)
* restructure connect and add initial docs * replace inline crate rustdoc with README.md * connect: make metadata trait less visible * connect: add some more docs * chore: remove clippy warning * update CHANGELOG.md * revert unrelated changes * enforce separation of autoplay and options * hide and improve docs of uid * remove/rename remarks * update connect example and link in docs * fixup rebase and clippy warnings
1 parent f497806 commit 09b4aa4

File tree

14 files changed

+411
-191
lines changed

14 files changed

+411
-191
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ spotify_appkey.key
44
.vagrant/
55
.project
66
.history
7+
.cache
78
*.save
89
*.*~

CHANGELOG.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- [core] MSRV is now 1.81 (breaking)
1313
- [core] AP connect and handshake have a combined 5 second timeout.
14-
- [connect] Replaced `ConnectConfig` with `ConnectStateConfig` (breaking)
15-
- [connect] Replaced `playing_track_index` field of `SpircLoadCommand` with `playing_track` (breaking)
14+
- [connect] Replaced `has_volume_ctrl` with `disable_volume` in `ConnectConfig` (breaking)
15+
- [connect] Changed `initial_volume` from `Option<u16>` to `u16` in `ConnectConfig` (breaking)
16+
- [connect] Replaced `SpircLoadCommand` with `LoadRequest`, `LoadRequestOptions` and `LoadContextOptions` (breaking)
17+
- [connect] Moved all public items to the highest level (breaking)
1618
- [connect] Replaced Mercury usage in `Spirc` with Dealer
1719

1820
### Added
1921

20-
- [connect] Add `seek_to` field to `SpircLoadCommand` (breaking)
21-
- [connect] Add `repeat_track` field to `SpircLoadCommand` (breaking)
22-
- [connect] Add `autoplay` field to `SpircLoadCommand` (breaking)
22+
- [connect] Add support for `seek_to`, `repeat_track` and `autoplay` for `Spirc` loading
2323
- [connect] Add `pause` parameter to `Spirc::disconnect` method (breaking)
24+
- [connect] Add `volume_steps` to `ConnectConfig` (breaking)
25+
- [connect] Add and enforce rustdoc
2426
- [playback] Add `track` field to `PlayerEvent::RepeatChanged` (breaking)
2527
- [core] Add `request_with_options` and `request_with_protobuf_and_options` to `SpClient`
2628
- [oauth] Add `OAuthClient` and `OAuthClientBuilder` structs to achieve a more customizable login process

connect/README.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
[//]: # (This readme is optimized for inline rustdoc, if some links don't work, they will when included in lib.rs)
2+
3+
# Connect
4+
5+
The connect module of librespot. Provides the option to create your own connect device
6+
and stream to it like any other official spotify client.
7+
8+
The [`Spirc`] is the entrypoint to creating your own connect device. It can be
9+
configured with the given [`ConnectConfig`] options and requires some additional data
10+
to start up the device.
11+
12+
When creating a new [`Spirc`] it returns two items. The [`Spirc`] itself, which is can
13+
be used as to control the local connect device. And a [`Future`](std::future::Future),
14+
lets name it `SpircTask`, that starts and executes the event loop of the connect device
15+
when awaited.
16+
17+
A basic example in which the `Spirc` and `SpircTask` is used can be found here:
18+
[`examples/play_connect.rs`](../examples/play_connect.rs).
19+
20+
# Example
21+
22+
```rust
23+
use std::{future::Future, thread};
24+
25+
use librespot_connect::{ConnectConfig, Spirc};
26+
use librespot_core::{authentication::Credentials, Error, Session, SessionConfig};
27+
use librespot_playback::{
28+
audio_backend, mixer,
29+
config::{AudioFormat, PlayerConfig},
30+
mixer::{MixerConfig, NoOpVolume},
31+
player::Player
32+
};
33+
34+
async fn create_basic_spirc() -> Result<(), Error> {
35+
let credentials = Credentials::with_access_token("access-token-here");
36+
let session = Session::new(SessionConfig::default(), None);
37+
38+
let backend = audio_backend::find(None).expect("will default to rodio");
39+
40+
let player = Player::new(
41+
PlayerConfig::default(),
42+
session.clone(),
43+
Box::new(NoOpVolume),
44+
move || {
45+
let format = AudioFormat::default();
46+
let device = None;
47+
backend(device, format)
48+
},
49+
);
50+
51+
let mixer = mixer::find(None).expect("will default to SoftMixer");
52+
53+
let (spirc, spirc_task): (Spirc, _) = Spirc::new(
54+
ConnectConfig::default(),
55+
session,
56+
credentials,
57+
player,
58+
mixer(MixerConfig::default())
59+
).await?;
60+
61+
Ok(())
62+
}
63+
```

connect/src/lib.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#![warn(missing_docs)]
2+
#![doc=include_str!("../README.md")]
3+
14
#[macro_use]
25
extern crate log;
36

@@ -7,6 +10,10 @@ use librespot_protocol as protocol;
710

811
mod context_resolver;
912
mod model;
10-
pub mod shuffle_vec;
11-
pub mod spirc;
12-
pub mod state;
13+
mod shuffle_vec;
14+
mod spirc;
15+
mod state;
16+
17+
pub use model::*;
18+
pub use spirc::*;
19+
pub use state::*;

connect/src/model.rs

Lines changed: 93 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,111 @@
1-
use librespot_core::dealer::protocol::SkipTo;
1+
use crate::{
2+
core::dealer::protocol::SkipTo, protocol::context_player_options::ContextPlayerOptionOverrides,
3+
};
24

5+
use std::ops::Deref;
6+
7+
/// Request for loading playback
38
#[derive(Debug)]
4-
pub struct SpircLoadCommand {
5-
pub context_uri: String,
9+
pub struct LoadRequest {
10+
pub(super) context_uri: String,
11+
pub(super) options: LoadRequestOptions,
12+
}
13+
14+
impl Deref for LoadRequest {
15+
type Target = LoadRequestOptions;
16+
17+
fn deref(&self) -> &Self::Target {
18+
&self.options
19+
}
20+
}
21+
22+
/// The parameters for creating a load request
23+
#[derive(Debug, Default)]
24+
pub struct LoadRequestOptions {
625
/// Whether the given tracks should immediately start playing, or just be initially loaded.
726
pub start_playing: bool,
27+
/// Start the playback at a specific point of the track.
28+
///
29+
/// The provided value is used as milliseconds. Providing a value greater
30+
/// than the track duration will start the track at the beginning.
831
pub seek_to: u32,
9-
pub shuffle: bool,
10-
pub repeat: bool,
11-
pub repeat_track: bool,
12-
/// Decides if the context or the autoplay of the context is played
32+
/// Options that decide how the context starts playing
33+
pub context_options: Option<LoadContextOptions>,
34+
/// Decides the starting position in the given context.
1335
///
14-
/// ## Remarks:
15-
/// If `true` is provided, the option values (`shuffle`, `repeat` and `repeat_track`) are ignored
16-
pub autoplay: bool,
17-
/// Decides the starting position in the given context
36+
/// If the provided item doesn't exist or is out of range,
37+
/// the playback starts at the beginning of the context.
1838
///
19-
/// ## Remarks:
2039
/// If `None` is provided and `shuffle` is `true`, a random track is played, otherwise the first
2140
pub playing_track: Option<PlayingTrack>,
2241
}
2342

43+
/// The options which decide how the playback is started
44+
///
45+
/// Separated into an `enum` to exclude the other variants from being used
46+
/// simultaneously, as they are not compatible.
47+
#[derive(Debug)]
48+
pub enum LoadContextOptions {
49+
/// Starts the context with options
50+
Options(Options),
51+
/// Starts the playback as the autoplay variant of the context
52+
///
53+
/// This is the same as finishing a context and
54+
/// automatically continuing playback of similar tracks
55+
Autoplay,
56+
}
57+
58+
/// The available options that indicate how to start the context
59+
#[derive(Debug, Default)]
60+
pub struct Options {
61+
/// Start the context in shuffle mode
62+
pub shuffle: bool,
63+
/// Start the context in repeat mode
64+
pub repeat: bool,
65+
/// Start the context, repeating the first track until skipped or manually disabled
66+
pub repeat_track: bool,
67+
}
68+
69+
impl From<ContextPlayerOptionOverrides> for Options {
70+
fn from(value: ContextPlayerOptionOverrides) -> Self {
71+
Self {
72+
shuffle: value.shuffling_context.unwrap_or_default(),
73+
repeat: value.repeating_context.unwrap_or_default(),
74+
repeat_track: value.repeating_track.unwrap_or_default(),
75+
}
76+
}
77+
}
78+
79+
impl LoadRequest {
80+
/// Create a load request from a `context_uri`
81+
///
82+
/// For supported `context_uri` see [`SpClient::get_context`](librespot_core::spclient::SpClient::get_context)
83+
pub fn from_context_uri(context_uri: String, options: LoadRequestOptions) -> Self {
84+
Self {
85+
context_uri,
86+
options,
87+
}
88+
}
89+
}
90+
91+
/// An item that represent a track to play
2492
#[derive(Debug)]
2593
pub enum PlayingTrack {
94+
/// Represent the track at a given index.
2695
Index(u32),
96+
/// Represent the uri of a track.
2797
Uri(String),
98+
#[doc(hidden)]
99+
/// Represent an internal identifier from spotify.
100+
///
101+
/// The internal identifier is not the id contained in the uri. And rather
102+
/// an unrelated id probably unique in spotify's internal database. But that's
103+
/// just speculation.
104+
///
105+
/// This identifier is not available by any public api. It's used for varies in
106+
/// any spotify client, like sorting, displaying which track is currently played
107+
/// and skipping to a track. Mobile uses it pretty intensively but also web and
108+
/// desktop seem to make use of it.
28109
Uid(String),
29110
}
30111

connect/src/shuffle_vec.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,6 @@ impl<T> From<Vec<T>> for ShuffleVec<T> {
4646
}
4747

4848
impl<T> ShuffleVec<T> {
49-
pub fn new() -> Self {
50-
Self {
51-
vec: Vec::new(),
52-
indices: None,
53-
}
54-
}
55-
5649
pub fn shuffle_with_seed(&mut self, seed: u64) {
5750
self.shuffle_with_rng(SmallRng::seed_from_u64(seed))
5851
}

0 commit comments

Comments
 (0)