From bae304fdb0f656a31d73f13d0b130d0df33b97b9 Mon Sep 17 00:00:00 2001 From: Roderick van Domburg Date: Sun, 2 Oct 2022 00:00:30 +0200 Subject: [PATCH] Update zeroconf fields and publish active user --- discovery/src/lib.rs | 13 ++++++------ discovery/src/server.rs | 44 +++++++++++++++++++++++++++++++---------- src/main.rs | 3 ++- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/discovery/src/lib.rs b/discovery/src/lib.rs index 718d9dec..3c01003b 100644 --- a/discovery/src/lib.rs +++ b/discovery/src/lib.rs @@ -77,13 +77,14 @@ impl From for Error { } impl Builder { - /// Starts a new builder using the provided device id. - pub fn new(device_id: impl Into) -> Self { + /// Starts a new builder using the provided device and client IDs. + pub fn new>(device_id: T, client_id: T) -> Self { Self { server_config: server::Config { name: "Librespot".into(), device_type: DeviceType::default(), device_id: device_id.into(), + client_id: client_id.into(), }, port: 0, } @@ -141,13 +142,13 @@ impl Builder { impl Discovery { /// Starts a [`Builder`] with the provided device id. - pub fn builder(device_id: impl Into) -> Builder { - Builder::new(device_id) + pub fn builder>(device_id: T, client_id: T) -> Builder { + Builder::new(device_id, client_id) } /// Create a new instance with the specified device id and default paramaters. - pub fn new(device_id: impl Into) -> Result { - Self::builder(device_id).launch() + pub fn new>(device_id: T, client_id: T) -> Result { + Self::builder(device_id, client_id).launch() } } diff --git a/discovery/src/server.rs b/discovery/src/server.rs index 3edc2fb6..faea33a1 100644 --- a/discovery/src/server.rs +++ b/discovery/src/server.rs @@ -36,10 +36,12 @@ pub struct Config { pub name: Cow<'static, str>, pub device_type: DeviceType, pub device_id: String, + pub client_id: String, } struct RequestHandler { config: Config, + username: Option, keys: DhLocalKeys, tx: mpsc::UnboundedSender, } @@ -50,6 +52,7 @@ impl RequestHandler { let discovery = Self { config, + username: None, keys: DhLocalKeys::random(&mut rand::thread_rng()), tx, }; @@ -60,24 +63,45 @@ impl RequestHandler { fn handle_get_info(&self) -> Response { let public_key = base64::encode(&self.keys.public_key()); let device_type: &str = self.config.device_type.into(); + let mut active_user = String::new(); + if let Some(username) = &self.username { + active_user = username.to_string(); + } + // See: https://developer.spotify.com/documentation/commercial-hardware/implementation/guides/zeroconf/ let body = json!({ "status": 101, - "statusString": "ERROR-OK", + "statusString": "OK", "spotifyError": 0, - "version": crate::core::version::SEMVER, + // departing from the Spotify documentation, Google Cast uses "5.0.0" + "version": "2.9.0", "deviceID": (self.config.device_id), - "remoteName": (self.config.name), - "activeUser": "", - "publicKey": (public_key), "deviceType": (device_type), - "libraryVersion": crate::core::version::SEMVER, - "accountReq": "PREMIUM", + "remoteName": (self.config.name), + // valid value seen in the wild: "empty" + "publicKey": (public_key), "brandDisplayName": "librespot", "modelDisplayName": "librespot", - "resolverVersion": "0", + "libraryVersion": crate::core::version::SEMVER, + "resolverVersion": "1", "groupStatus": "NONE", - "voiceSupport": "NO", + // valid value documented & seen in the wild: "accesstoken" + // Using it will cause clients to fail to connect. + "tokenType": "default", + "clientID": (self.config.client_id), + "productID": 0, + // Other known scope: client-authorization-universal + // Comma-separated. + "scope": "streaming", + "availability": "", + "supported_drm_media_formats": [], + // TODO: bitmask but what are the flags? + "supported_capabilities": 1, + // undocumented but should still work + "accountReq": "PREMIUM", + "activeUser": active_user, + // others seen-in-the-wild: + // - "deviceAPI_isGroup": False }) .to_string(); @@ -162,7 +186,7 @@ impl RequestHandler { let result = json!({ "status": 101, "spotifyError": 0, - "statusString": "ERROR-OK" + "statusString": "OK", }); let body = result.to_string(); diff --git a/src/main.rs b/src/main.rs index 5cd19bd2..d5c53925 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1635,7 +1635,8 @@ async fn main() { if setup.enable_discovery { let device_id = setup.session_config.device_id.clone(); - match librespot::discovery::Discovery::builder(device_id) + let client_id = setup.session_config.client_id.clone(); + match librespot::discovery::Discovery::builder(device_id, client_id) .name(setup.connect_config.name.clone()) .device_type(setup.connect_config.device_type) .port(setup.zeroconf_port)