1use educe::Educe;
25use serde::{Deserialize, Serialize};
26use std::fmt::{Debug, Formatter};
27use std::str::FromStr;
28use strum::EnumString;
29use url::Url;
30
31use super::*;
32
33#[derive(Deserialize, Serialize, Clone, Copy, PartialEq, Eq, Hash)]
34#[serde(from = "i64", into = "i64")]
35pub enum SourceId {
36 Pandora,
37 Rhapsody,
38 TuneIn,
39 Spotify,
40 Deezer,
41 Napster,
42 IHeartRadio,
43 SiriusXm,
44 Soundcloud,
45 Tidal,
46 AmazonMusic,
47 Moodmix,
48 QQMusic,
49 Qobuz,
50 LocalUsbOrDlna,
51 HeosPlaylists,
52 HeosHistory,
53 HeosAuxInputs,
54 HeosFavorites,
55 Unknown(i64),
56}
57
58impl Debug for SourceId {
59 #[inline]
60 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
61 write!(f, "SourceId({:?})", i64::from(*self))
62 }
63}
64
65impl Display for SourceId {
66 #[inline]
67 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
68 Display::fmt(&i64::from(*self), f)
69 }
70}
71
72impl From<i64> for SourceId {
73 #[inline]
74 fn from(value: i64) -> Self {
75 match value {
76 1 => Self::Pandora,
77 2 => Self::Rhapsody,
78 3 => Self::TuneIn,
79 4 => Self::Spotify,
80 5 => Self::Deezer,
81 6 => Self::Napster,
82 7 => Self::IHeartRadio,
83 8 => Self::SiriusXm,
84 9 => Self::Soundcloud,
85 10 => Self::Tidal,
86 13 => Self::AmazonMusic,
87 15 => Self::Moodmix,
88 18 => Self::QQMusic,
89 30 => Self::Qobuz,
90 1024 => Self::LocalUsbOrDlna,
91 1025 => Self::HeosPlaylists,
92 1026 => Self::HeosHistory,
93 1027 => Self::HeosAuxInputs,
94 1028 => Self::HeosFavorites,
95 value => Self::Unknown(value),
96 }
97 }
98}
99
100impl From<SourceId> for i64 {
101 #[inline]
102 fn from(value: SourceId) -> Self {
103 match value {
104 SourceId::Pandora => 1,
105 SourceId::Rhapsody => 2,
106 SourceId::TuneIn => 3,
107 SourceId::Spotify => 4,
108 SourceId::Deezer => 5,
109 SourceId::Napster => 6,
110 SourceId::IHeartRadio => 7,
111 SourceId::SiriusXm => 8,
112 SourceId::Soundcloud => 9,
113 SourceId::Tidal => 10,
114 SourceId::AmazonMusic => 13,
115 SourceId::Moodmix => 15,
116 SourceId::QQMusic => 18,
117 SourceId::Qobuz => 30,
118 SourceId::LocalUsbOrDlna => 1024,
119 SourceId::HeosPlaylists => 1025,
120 SourceId::HeosHistory => 1026,
121 SourceId::HeosAuxInputs => 1027,
122 SourceId::HeosFavorites => 1028,
123 SourceId::Unknown(value) => value,
124 }
125 }
126}
127
128impl FromStr for SourceId {
129 type Err = ParseIntError;
130
131 #[inline]
132 fn from_str(s: &str) -> Result<Self, Self::Err> {
133 let value: i64 = s.parse()?;
134 Ok(value.into())
135 }
136}
137
138impl SourceId {
139 #[inline]
140 pub fn cli_browse(&self) -> bool {
141 match self {
142 Self::Pandora |
143 Self::Rhapsody |
144 Self::TuneIn |
145 Self::Deezer |
146 Self::Napster |
147 Self::IHeartRadio |
148 Self::SiriusXm |
149 Self::Soundcloud |
150 Self::Tidal |
151 Self::AmazonMusic |
152 Self::LocalUsbOrDlna |
153 Self::HeosPlaylists |
154 Self::HeosHistory |
155 Self::HeosAuxInputs |
156 Self::HeosFavorites => true,
157 _ => false,
158 }
159 }
160
161 #[inline]
162 pub fn cli_search(&self) -> bool {
163 match self {
164 Self::Rhapsody |
165 Self::TuneIn |
166 Self::Deezer |
167 Self::Napster |
168 Self::Soundcloud |
169 Self::Tidal |
170 Self::Qobuz |
171 Self::LocalUsbOrDlna |
172 Self::HeosFavorites => true,
173 _ => false,
174 }
175 }
176
177 #[inline]
178 pub fn cli_new_station(&self) -> bool {
179 match self {
180 Self::Pandora |
181 Self::Rhapsody |
182 Self::TuneIn |
183 Self::Deezer |
184 Self::Napster |
185 Self::IHeartRadio |
186 Self::Soundcloud |
187 Self::Tidal => true,
188 _ => false,
189 }
190 }
191}
192
193#[derive(Serialize, Deserialize, EnumString, strum::Display, Debug, Clone, Copy, PartialEq, Eq)]
195#[serde(into = "String", try_from = "String")]
196#[strum(serialize_all = "snake_case")]
197pub enum SourceType {
198 MusicService,
200 HeosService,
202 HeosServer,
204 DlnaServer,
206}
207impl_enum_string_conversions!(SourceType);
208
209#[derive(Serialize, Deserialize, EnumString, strum::Display, Debug, Clone, Copy, PartialEq, Eq)]
211#[serde(into = "String", try_from = "String")]
212#[strum(serialize_all = "lowercase")]
213pub enum SourceAvailable {
214 True,
219 False,
221}
222impl_enum_string_conversions!(SourceAvailable);
223
224#[derive(Serialize, Deserialize, Educe, Clone)]
226#[educe(Debug)]
227pub struct SourceInfo {
228 pub name: String,
230 #[educe(Debug(method(std::fmt::Display::fmt)))]
232 pub image_url: Url,
233 #[serde(rename = "type")]
235 pub source_type: SourceType,
236 #[serde(rename = "sid")]
238 pub source_id: SourceId,
239 pub available: SourceAvailable,
241 #[serde(skip_serializing_if = "Option::is_none")]
244 pub service_username: Option<String>,
245}
246impl_try_from_response_payload!(SourceInfo);
247impl_try_from_response_payload!(Vec<SourceInfo>);
248
249#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
250#[serde(from = "i64", into = "i64")]
251pub enum CriteriaId {
252 Artist,
253 Album,
254 Track,
255 Station,
256 Shows,
257 Playlist,
258 Accounts,
259 Unknown(i64),
260}
261
262impl Debug for CriteriaId {
263 #[inline]
264 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
265 write!(f, "CriteriaId({:?})", i64::from(*self))
266 }
267}
268
269impl Display for CriteriaId {
270 #[inline]
271 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
272 Display::fmt(&i64::from(*self), f)
273 }
274}
275
276impl From<i64> for CriteriaId {
277 #[inline]
278 fn from(value: i64) -> Self {
279 match value {
280 1 => Self::Artist,
281 2 => Self::Album,
282 3 => Self::Track,
283 4 => Self::Station,
284 5 => Self::Shows,
285 6 => Self::Playlist,
286 7 => Self::Accounts,
287 value => Self::Unknown(value),
288 }
289 }
290}
291
292impl From<CriteriaId> for i64 {
293 #[inline]
294 fn from(value: CriteriaId) -> Self {
295 match value {
296 CriteriaId::Artist => 1,
297 CriteriaId::Album => 2,
298 CriteriaId::Track => 3,
299 CriteriaId::Station => 4,
300 CriteriaId::Shows => 5,
301 CriteriaId::Playlist => 6,
302 CriteriaId::Accounts => 7,
303 CriteriaId::Unknown(value) => value,
304 }
305 }
306}
307
308impl FromStr for CriteriaId {
309 type Err = ParseIntError;
310
311 #[inline]
312 fn from_str(s: &str) -> Result<Self, Self::Err> {
313 let value: i64 = s.parse()?;
314 Ok(value.into())
315 }
316}
317
318#[derive(Serialize, Deserialize, Debug, Clone)]
325pub struct SearchCriteria {
326 pub name: String,
330 #[serde(rename = "scid")]
333 pub criteria: CriteriaId,
334 #[serde(default)]
336 #[serde(with = "super::yes_no")]
337 pub wildcard: bool,
338 #[serde(default)]
340 #[serde(with = "super::yes_no")]
341 pub playable: bool,
342 #[serde(rename = "cid")]
344 #[serde(default)]
345 pub search_prefix: Option<String>,
346}
347impl_try_from_response_payload!(Vec<SearchCriteria>);