Update zeroconf fields and publish active user

This commit is contained in:
Roderick van Domburg 2022-10-02 00:00:30 +02:00
parent f10b8f69f8
commit bae304fdb0
No known key found for this signature in database
GPG key ID: FE2585E713F9F30A
3 changed files with 43 additions and 17 deletions

View file

@ -77,13 +77,14 @@ impl From<DiscoveryError> for Error {
}
impl Builder {
/// Starts a new builder using the provided device id.
pub fn new(device_id: impl Into<String>) -> Self {
/// Starts a new builder using the provided device and client IDs.
pub fn new<T: Into<String>>(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<String>) -> Builder {
Builder::new(device_id)
pub fn builder<T: Into<String>>(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<String>) -> Result<Self, Error> {
Self::builder(device_id).launch()
pub fn new<T: Into<String>>(device_id: T, client_id: T) -> Result<Self, Error> {
Self::builder(device_id, client_id).launch()
}
}

View file

@ -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<String>,
keys: DhLocalKeys,
tx: mpsc::UnboundedSender<Credentials>,
}
@ -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<hyper::Body> {
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();

View file

@ -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)