Skip to content

Commit 180ffac

Browse files
committed
adding flag to show connect device as group
1 parent c10d29b commit 180ffac

5 files changed

Lines changed: 49 additions & 1 deletion

File tree

connect/src/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::core::config::DeviceType;
44
pub struct ConnectConfig {
55
pub name: String,
66
pub device_type: DeviceType,
7+
pub is_group: bool,
78
pub initial_volume: Option<u16>,
89
pub has_volume_ctrl: bool,
910
}
@@ -13,6 +14,7 @@ impl Default for ConnectConfig {
1314
ConnectConfig {
1415
name: "Librespot".to_string(),
1516
device_type: DeviceType::default(),
17+
is_group: false,
1618
initial_volume: Some(50),
1719
has_volume_ctrl: true,
1820
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use futures::StreamExt;
2+
use librespot_core::SessionConfig;
3+
use librespot_discovery::DeviceType;
4+
use sha1::{Digest, Sha1};
5+
6+
#[tokio::main(flavor = "current_thread")]
7+
async fn main() {
8+
let name = "Librespot Group";
9+
let device_id = hex::encode(Sha1::digest(name.as_bytes()));
10+
11+
let mut server =
12+
librespot_discovery::Discovery::builder(device_id, SessionConfig::default().client_id)
13+
.name(name)
14+
.device_type(DeviceType::Speaker)
15+
.is_group(true)
16+
.launch()
17+
.unwrap();
18+
19+
while let Some(x) = server.next().await {
20+
println!("Received {:?}", x);
21+
}
22+
}

discovery/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ impl Builder {
8484
server_config: server::Config {
8585
name: "Librespot".into(),
8686
device_type: DeviceType::default(),
87+
is_group: false,
8788
device_id: device_id.into(),
8889
client_id: client_id.into(),
8990
},
@@ -104,6 +105,12 @@ impl Builder {
104105
self
105106
}
106107

108+
/// Sets whether the device is a group. This affects the icon in Spotify clients. Default is `false`.
109+
pub fn is_group(mut self, is_group: bool) -> Self {
110+
self.server_config.is_group = is_group;
111+
self
112+
}
113+
107114
/// Set the ip addresses on which it should listen to incoming connections. The default is all interfaces.
108115
pub fn zeroconf_ip(mut self, zeroconf_ip: Vec<std::net::IpAddr>) -> Self {
109116
self.zeroconf_ip = zeroconf_ip;

discovery/src/server.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub struct Config {
3939
pub name: Cow<'static, str>,
4040
pub device_type: DeviceType,
4141
pub device_id: String,
42+
pub is_group: bool,
4243
pub client_id: String,
4344
}
4445

@@ -70,6 +71,12 @@ impl RequestHandler {
7071
if let Some(username) = &self.username {
7172
active_user = username.to_string();
7273
}
74+
// options based on zeroconf guide, search for `groupStatus` on page
75+
let group_status = if self.config.is_group {
76+
"GROUP"
77+
} else {
78+
"NONE"
79+
};
7380

7481
// See: https://developer.spotify.com/documentation/commercial-hardware/implementation/guides/zeroconf/
7582
let body = json!({
@@ -87,7 +94,8 @@ impl RequestHandler {
8794
"modelDisplayName": "librespot",
8895
"libraryVersion": crate::core::version::SEMVER,
8996
"resolverVersion": "1",
90-
"groupStatus": "NONE",
97+
// valid values are "GROUP" and "NONE"
98+
"groupStatus": group_status,
9199
// valid value documented & seen in the wild: "accesstoken"
92100
// Using it will cause clients to fail to connect.
93101
"tokenType": "default",

src/main.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ fn get_setup() -> Setup {
203203
const CACHE_SIZE_LIMIT: &str = "cache-size-limit";
204204
const DEVICE: &str = "device";
205205
const DEVICE_TYPE: &str = "device-type";
206+
const DEVICE_IS_GROUP: &str = "group";
206207
const DISABLE_AUDIO_CACHE: &str = "disable-audio-cache";
207208
const DISABLE_CREDENTIAL_CACHE: &str = "disable-credential-cache";
208209
const DISABLE_DISCOVERY: &str = "disable-discovery";
@@ -409,6 +410,10 @@ fn get_setup() -> Setup {
409410
DEVICE_TYPE,
410411
"Displayed device type. Defaults to speaker.",
411412
"TYPE",
413+
).optflag(
414+
"",
415+
DEVICE_IS_GROUP,
416+
"Whether the device represents a group. Defaults to false.",
412417
)
413418
.optopt(
414419
TEMP_DIR_SHORT,
@@ -1312,11 +1317,14 @@ fn get_setup() -> Setup {
13121317
})
13131318
.unwrap_or_default();
13141319

1320+
let is_group = opt_present(DEVICE_IS_GROUP);
1321+
13151322
let has_volume_ctrl = !matches!(mixer_config.volume_ctrl, VolumeCtrl::Fixed);
13161323

13171324
ConnectConfig {
13181325
name,
13191326
device_type,
1327+
is_group,
13201328
initial_volume,
13211329
has_volume_ctrl,
13221330
}
@@ -1685,6 +1693,7 @@ async fn main() {
16851693
match librespot::discovery::Discovery::builder(device_id, client_id)
16861694
.name(setup.connect_config.name.clone())
16871695
.device_type(setup.connect_config.device_type)
1696+
.is_group(setup.connect_config.is_group)
16881697
.port(setup.zeroconf_port)
16891698
.zeroconf_ip(setup.zeroconf_ip.clone())
16901699
.launch()

0 commit comments

Comments
 (0)