1mod command;
2mod responses;
3
4use crate::error::Error;
5use command::Command;
6use reqwest::Response;
7use responses::StateResponse;
8pub use responses::{Browse, IdResponse, Playlist, PlaylistEntry, State, Status};
9use serde::Deserialize;
10use std::net::{Ipv4Addr, SocketAddr};
11
12#[cfg(feature = "discover")]
13use crate::DiscoveredBluOSDevice;
14
15#[derive(Debug)]
18pub struct BluOS {
19 hostname: String,
20 port: u16,
21
22 client: reqwest::Client,
23}
24
25impl BluOS {
26 pub fn new(addr: Ipv4Addr, custom_port: Option<u16>) -> Result<BluOS, Error> {
30 let port = match custom_port {
31 Some(v) => v,
32 None => 11000,
33 };
34
35 Ok(BluOS {
36 hostname: addr.to_string(),
37 port,
38 client: reqwest::Client::new(),
39 })
40 }
41
42 pub fn with_socket_addr(addr: SocketAddr) -> Result<BluOS, Error> {
43 Ok(BluOS {
44 hostname: addr.ip().to_string(),
45 port: addr.port(),
46 client: reqwest::Client::new(),
47 })
48 }
49
50 #[cfg(feature = "discover")]
52 pub fn new_from_discovered(d: DiscoveredBluOSDevice) -> Result<BluOS, Error> {
53 Ok(BluOS {
54 hostname: d.hostname,
55 port: d.port,
56 client: reqwest::Client::new(),
57 })
58 }
59
60 fn cmd(&self, action: &str) -> Command {
61 Command::new(&self.hostname, self.port, action)
62 }
63
64 async fn command(&self, cmd: Command) -> Result<Response, Error> {
66 Ok(self.client.get(cmd.build()).send().await?)
67 }
68
69 async fn command_response<'a, T: Deserialize<'a>>(&self, cmd: Command) -> Result<T, Error> {
72 let t = self.client.get(cmd.build()).send().await?.text().await?;
73 Ok(serde_xml_rs::from_str(&t)?)
74 }
75
76 pub async fn status(&self) -> Result<Status, Error> {
78 let status: Status = self.command_response(self.cmd("Status")).await?;
79
80 Ok(status)
81 }
82
83 pub async fn browse(&self, key: Option<&str>) -> Result<Browse, Error> {
84 let mut cmd = self.cmd("Browse");
85 cmd.add_optional("key", key);
86 let browse: Browse = self.command_response(cmd).await?;
87 Ok(browse)
88 }
89
90 pub async fn update_library(&self) -> Result<(), Error> {
95 self.command(self.cmd("Reindex")).await?;
96
97 Ok(())
98 }
99
100 pub async fn play(&self) -> Result<State, Error> {
106 Ok(self.play_with_options(None, None, None).await?)
107 }
108
109 pub async fn play_with_options(
116 &self,
117 seek: Option<i64>,
118 input_type: Option<String>,
119 index: Option<i64>,
120 ) -> Result<State, Error> {
121 let mut cmd = self.cmd("Play");
122
123 cmd.add_optional("seek", seek);
124 cmd.add_optional("inputType", input_type);
125 cmd.add_optional("index", index);
126
127 let state: StateResponse = self.command_response(cmd).await?;
128 Ok(state.state)
129 }
130 pub async fn pause(&self, toggle: bool) -> Result<State, Error> {
133 let mut cmd = self.cmd("Pause");
134 if toggle {
135 cmd.add_param("toggle", 1);
136 }
137 let state: StateResponse = self.command_response(cmd).await?;
138 Ok(state.state)
139 }
140 pub async fn stop(&self) -> Result<State, Error> {
142 let state: StateResponse = self.command_response(self.cmd("Stop")).await?;
143 Ok(state.state)
144 }
145 pub async fn skip(&self) -> Result<IdResponse, Error> {
147 let id: IdResponse = self.command_response(self.cmd("Skip")).await?;
148 Ok(id)
149 }
150 pub async fn back(&self) -> Result<IdResponse, Error> {
155 let id: IdResponse = self.command_response(self.cmd("Back")).await?;
156 Ok(id)
157 }
158
159 pub async fn shuffle(&self, enable: bool) -> Result<(), Error> {
163 let mut cmd = self.cmd("Shuffle");
164 if enable {
165 cmd.add_param("state", 1 as u8);
166 } else {
167 cmd.add_param("state", 0 as u8);
168 }
169 self.command(cmd).await?;
170 Ok(())
171 }
172
173 pub async fn repeat(&self, setting: RepeatSetting) -> Result<(), Error> {
177 let mut cmd = self.cmd("Repeat");
178
179 cmd.add_param("state", setting as u8);
180
181 self.command(cmd).await?;
182 Ok(())
183 }
184
185 pub async fn queue(&self, pagination: Option<Pagination>) -> Result<Playlist, Error> {
191 let mut cmd = self.cmd("Playlist");
192 match pagination {
193 Some(p) => {
194 cmd.add_param("start", p.start);
195 cmd.add_param("end", p.end);
196 }
197 None => {}
198 };
199 let pl: Playlist = self.command_response(cmd).await?;
200
201 Ok(pl)
202 }
203
204 pub async fn queue_delete_song(&self, position: u64) -> Result<(), Error> {
206 let mut cmd = self.cmd("Delete");
207
208 cmd.add_param("id", position);
209
210 self.command(cmd).await?;
211 Ok(())
212 }
213
214 pub async fn queue_clear(&self) -> Result<(), Error> {
216 let cmd = self.cmd("Clear");
217
218 self.command(cmd).await?;
219 Ok(())
220 }
221}
222
223pub struct Pagination {
224 start: u64,
225 end: u64,
226}
227
228pub enum RepeatSetting {
229 EntireQueue = 0,
230 CurrentTrack = 1,
231 Disable = 2,
232}