A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1use local_ip_addr::get_local_ip_address;
2use mdns_sd::ServiceInfo;
3use serde::{Deserialize, Serialize};
4
5pub const CHROMECAST_SERVICE_NAME: &str = "_googlecast._tcp.local.";
6pub const AIRPLAY_SERVICE_NAME: &str = "_raop._tcp.local.";
7pub const ROCKBOX_SERVICE_NAME: &str = "_rockbox._tcp.local.";
8pub const XBMC_SERVICE_NAME: &str = "_xbmc-jsonrpc-h._tcp.local.";
9
10pub const AIRPLAY_DEVICE: &str = "AirPlay";
11pub const CHROMECAST_DEVICE: &str = "Chromecast";
12pub const XBMC_DEVICE: &str = "XBMC";
13pub const MUSIC_PLAYER_DEVICE: &str = "MusicPlayer";
14pub const UPNP_DLNA_DEVICE: &str = "UPnP/DLNA";
15pub const ROCKBOX_DEVICE: &str = "Rockbox";
16
17#[derive(Default, Clone, Serialize, Deserialize)]
18pub struct Device {
19 pub id: String,
20 pub name: String,
21 pub host: String,
22 pub ip: String,
23 pub port: u16,
24 pub service: String,
25 pub app: String,
26 pub is_connected: bool,
27 pub base_url: Option<String>,
28 pub is_cast_device: bool,
29 pub is_source_device: bool,
30 pub is_current_device: bool,
31}
32
33impl Device {
34 pub fn with_base_url(&mut self, base_url: Option<String>) -> Self {
35 self.base_url = base_url;
36 self.clone()
37 }
38}
39
40impl From<ServiceInfo> for Device {
41 fn from(srv: ServiceInfo) -> Self {
42 if srv.get_fullname().contains("xbmc") {
43 return Self {
44 id: srv.get_fullname().to_owned(),
45 name: srv
46 .get_fullname()
47 .replace(XBMC_SERVICE_NAME, "")
48 .replace(".", "")
49 .to_owned(),
50 host: srv
51 .get_hostname()
52 .split_at(srv.get_hostname().len() - 1)
53 .0
54 .to_owned(),
55 ip: srv.get_addresses().iter().next().unwrap().to_string(),
56 port: srv.get_port(),
57 service: srv.get_fullname().to_owned(),
58 app: "xbmc".to_owned(),
59 is_connected: false,
60 base_url: None,
61 is_cast_device: true,
62 is_source_device: true,
63 is_current_device: false,
64 };
65 }
66
67 if srv.get_fullname().contains(ROCKBOX_SERVICE_NAME) {
68 let device_id = srv
69 .get_fullname()
70 .replace(ROCKBOX_SERVICE_NAME, "")
71 .split("-")
72 .collect::<Vec<&str>>()[1]
73 .replace(".", "")
74 .to_owned();
75
76 let is_current_device = device_id == "device_id"
77 && srv.get_fullname().split("-").collect::<Vec<&str>>()[0].to_owned() == "http";
78
79 let mut addresses = srv.get_addresses().iter();
80 let mut ip = addresses.next().unwrap().to_string();
81
82 if is_current_device {
83 ip = get_local_ip_address().unwrap();
84 }
85
86 return Self {
87 id: device_id.clone(),
88 name: srv
89 .get_properties()
90 .get("device_name")
91 .unwrap_or(&device_id.clone())
92 .to_string(),
93 host: srv
94 .get_hostname()
95 .split_at(srv.get_hostname().len() - 1)
96 .0
97 .to_owned(),
98 ip,
99 port: srv.get_port(),
100 service: srv.get_fullname().split("-").collect::<Vec<&str>>()[0].to_owned(),
101 app: "rockbox".to_owned(),
102 is_connected: false,
103 base_url: None,
104 is_cast_device: true,
105 is_source_device: true,
106 is_current_device,
107 };
108 }
109
110 if srv.get_fullname().contains(CHROMECAST_SERVICE_NAME) {
111 return Self {
112 id: srv.get_properties().get("id").unwrap().to_owned(),
113 name: srv.get_properties().get("fn").unwrap().to_owned(),
114 host: srv
115 .get_hostname()
116 .split_at(srv.get_hostname().len() - 1)
117 .0
118 .to_owned(),
119 ip: srv.get_addresses().iter().next().unwrap().to_string(),
120 port: srv.get_port(),
121 service: srv.get_fullname().to_owned(),
122 app: "chromecast".to_owned(),
123 is_connected: false,
124 base_url: None,
125 is_cast_device: true,
126 is_source_device: false,
127 is_current_device: false,
128 };
129 }
130
131 if srv.get_fullname().contains(AIRPLAY_SERVICE_NAME) {
132 let name = srv.get_fullname().split("@").collect::<Vec<&str>>()[1]
133 .replace(AIRPLAY_SERVICE_NAME, "")
134 .to_owned();
135 let name = name.split_at(name.len() - 1).0.to_owned();
136 return Self {
137 id: srv.get_fullname().to_owned(),
138 name,
139 host: srv
140 .get_hostname()
141 .split_at(srv.get_hostname().len() - 1)
142 .0
143 .to_owned(),
144 ip: srv.get_addresses().iter().next().unwrap().to_string(),
145 port: srv.get_port(),
146 service: srv.get_fullname().to_owned(),
147 app: "airplay".to_owned(),
148 is_connected: false,
149 base_url: None,
150 is_cast_device: true,
151 is_source_device: false,
152 is_current_device: false,
153 };
154 }
155
156 Self {
157 ..Default::default()
158 }
159 }
160}