Skip to content

Commit 8b0857c

Browse files
aome510bbzylstra
andauthored
Upgrade librespot to 0.7.0, fixing audio, authentication, DNS lookup issues (#808)
Resolves #802 Resolves #799 Resolves #796 Resolves #787 This PR was based on #807 with a few updates --------- Co-authored-by: Bradley Zylstra <[email protected]>
1 parent b92c737 commit 8b0857c

File tree

11 files changed

+548
-1077
lines changed

11 files changed

+548
-1077
lines changed

Cargo.lock

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

spotify_player/Cargo.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ clap = { version = "4.5.41", features = ["derive", "string"] }
1515
config_parser2 = "0.1.6"
1616
crossterm = "0.29.0"
1717
dirs-next = "2.0.0"
18-
librespot-connect = { version = "0.6.0", optional = true }
19-
librespot-core = "0.6.0"
20-
librespot-oauth = "0.6.0"
21-
librespot-playback = { version = "0.6.0", optional = true }
22-
librespot-metadata = "0.6.0"
18+
librespot-connect = { version = "0.7.0", optional = true }
19+
librespot-core = "0.7.0"
20+
librespot-oauth = "0.7.0"
21+
librespot-playback = { version = "0.7.0", optional = true }
22+
librespot-metadata = "0.7.0"
2323
log = "0.4.27"
2424
chrono = "0.4.41"
2525
reqwest = { version = "0.12.22", features = ["json"] }

spotify_player/src/auth.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1+
use crate::config;
12
use anyhow::Result;
23
use librespot_core::{authentication::Credentials, cache::Cache, config::SessionConfig, Session};
3-
use librespot_oauth::get_access_token;
4-
5-
use crate::config;
4+
use librespot_oauth::OAuthClientBuilder;
65

76
pub const SPOTIFY_CLIENT_ID: &str = "65b708073fc0480ea92a077233ca87bd";
87
// based on https://github.com/librespot-org/librespot/blob/f96f36c064795011f9fee912291eecb1aa46fff6/src/main.rs#L173
@@ -96,12 +95,16 @@ pub fn get_creds(auth_config: &AuthConfig, reauth: bool, use_cached: bool) -> Re
9695
let msg = "No cached credentials found, please authenticate the application first.";
9796
if reauth {
9897
eprintln!("{msg}");
99-
get_access_token(
98+
99+
let client_builder = OAuthClientBuilder::new(
100100
SPOTIFY_CLIENT_ID,
101101
&auth_config.login_redirect_uri,
102102
OAUTH_SCOPES.to_vec(),
103-
)
104-
.map(|t| Credentials::with_access_token(t.access_token))?
103+
);
104+
let oauth_client = client_builder.build()?;
105+
oauth_client
106+
.get_access_token()
107+
.map(|t| Credentials::with_access_token(t.access_token))?
105108
} else {
106109
anyhow::bail!(msg);
107110
}

spotify_player/src/client/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ pub struct Client {
4646
spotify: Arc<spotify::Spotify>,
4747
auth_config: AuthConfig,
4848
#[cfg(feature = "streaming")]
49-
stream_conn: Arc<Mutex<Option<librespot_connect::spirc::Spirc>>>,
49+
stream_conn: Arc<Mutex<Option<librespot_connect::Spirc>>>,
5050
}
5151

5252
impl Deref for Client {

spotify_player/src/config/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ pub struct AppConfig {
101101
#[cfg(feature = "media-control")]
102102
pub enable_media_control: bool,
103103

104-
#[cfg(feature = "streaming")]
105104
pub enable_streaming: StreamingType,
106105

107106
#[cfg(feature = "notify")]
@@ -323,7 +322,6 @@ impl Default for AppConfig {
323322
#[cfg(all(unix, not(target_os = "macos")))]
324323
enable_media_control: true,
325324

326-
#[cfg(feature = "streaming")]
327325
enable_streaming: StreamingType::Always,
328326

329327
#[cfg(feature = "notify")]

spotify_player/src/event/clipboard.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ pub fn get_clipboard_provider() -> Box<dyn ClipboardProvider> {
109109
#[cfg(not(target_os = "windows"))]
110110
{
111111
tracing::warn!("No clipboard provider found! Fallback to a NOP clipboard provider.");
112-
return Box::new(NopProvider {});
112+
Box::new(NopProvider {})
113113
}
114114
}
115115
}

spotify_player/src/state/ui/page.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ impl PageState {
164164
}
165165

166166
/// The currently focused window state of the page.
167-
pub fn focus_window_state_mut(&mut self) -> Option<MutableWindowState> {
167+
pub fn focus_window_state_mut(&mut self) -> Option<MutableWindowState<'_>> {
168168
match self {
169169
Self::Library {
170170
state:

spotify_player/src/streaming.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{client::Client, config, state::SharedState};
22
use anyhow::Context;
3-
use librespot_connect::{config::ConnectConfig, spirc::Spirc};
3+
use librespot_connect::{ConnectConfig, Spirc};
44
use librespot_core::authentication::Credentials;
55
use librespot_core::Session;
66
use librespot_core::{config::DeviceType, spotify_id};
@@ -156,17 +156,20 @@ pub async fn new_connection(
156156
let connect_config = ConnectConfig {
157157
name: device.name.clone(),
158158
device_type: device.device_type.parse::<DeviceType>().unwrap_or_default(),
159-
initial_volume: Some(volume),
159+
initial_volume: volume,
160160

161161
// non-configurable fields, use default values.
162162
// We may allow users to configure these fields in a future release
163-
has_volume_ctrl: true,
164163
is_group: false,
164+
disable_volume: false,
165+
volume_steps: 64,
165166
};
166167

167168
tracing::info!("Application's connect configurations: {:?}", connect_config);
168169

169-
let mixer = Arc::new(mixer::softmixer::SoftMixer::open(MixerConfig::default()));
170+
let mixer = Arc::new(
171+
mixer::softmixer::SoftMixer::open(MixerConfig::default()).context("opening softmixer")?,
172+
);
170173
mixer.set_volume(volume);
171174

172175
let backend = audio_backend::find(None).expect("should be able to find an audio backend");

spotify_player/src/token.rs

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,43 +6,16 @@ use librespot_core::session::Session;
66

77
const TIMEOUT_IN_SECS: u64 = 5;
88

9-
/// The application authentication token's permission scopes
10-
const SCOPES: [&str; 15] = [
11-
"user-read-recently-played",
12-
"user-top-read",
13-
"user-read-playback-position",
14-
"user-read-playback-state",
15-
"user-modify-playback-state",
16-
"user-read-currently-playing",
17-
"streaming",
18-
"playlist-read-private",
19-
"playlist-modify-private",
20-
"playlist-modify-public",
21-
"playlist-read-collaborative",
22-
"user-follow-read",
23-
"user-follow-modify",
24-
"user-library-read",
25-
"user-library-modify",
26-
];
27-
289
pub async fn get_token_librespot(
2910
session: &Session,
30-
client_id: &str,
11+
_client_id: &str,
3112
) -> Result<librespot_core::token::Token> {
32-
let query_uri = format!(
33-
"hm://keymaster/token/authenticated?scope={}&client_id={}&device_id={}",
34-
SCOPES.join(","),
35-
client_id,
36-
session.device_id(),
37-
);
38-
let request = session.mercury().get(query_uri)?;
39-
let response = request.await?;
40-
let data = response
41-
.payload
42-
.first()
43-
.ok_or(librespot_core::token::TokenError::Empty)?
44-
.clone();
45-
let token = librespot_core::token::Token::from_json(String::from_utf8(data)?)?;
13+
// TODO: figure out how to support custom client_id for Spotify Connect
14+
let auth_data = session.auth_data();
15+
if auth_data.is_empty() {
16+
anyhow::bail!("Session has no stored credentials for login5 token acquisition");
17+
}
18+
let token = session.login5().auth_token().await.unwrap();
4619
Ok(token)
4720
}
4821

spotify_player/src/ui/page.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -276,15 +276,12 @@ pub fn render_context_page(
276276
);
277277

278278
// 3+4. Construct and render the page's widgets
279-
let id = match id {
280-
None => {
281-
frame.render_widget(
282-
Paragraph::new("Cannot determine the current page's context"),
283-
rect,
284-
);
285-
return;
286-
}
287-
Some(id) => id,
279+
let Some(id) = id else {
280+
frame.render_widget(
281+
Paragraph::new("Cannot determine the current page's context"),
282+
rect,
283+
);
284+
return;
288285
};
289286

290287
let data = state.data.read();

0 commit comments

Comments
 (0)