1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[serde_with::skip_serializing_none]
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
8pub struct Stream {
9 pub id: String,
10 pub properties: Option<StreamProperties>,
11 pub status: StreamStatus,
12 pub uri: StreamUri,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
16#[serde(rename_all = "camelCase")]
17pub enum StreamStatus {
18 Idle,
19 Playing,
20 Disabled,
21 Unknown,
22}
23
24impl From<&str> for StreamStatus {
25 fn from(s: &str) -> Self {
26 match s {
27 "idle" => StreamStatus::Idle,
28 "playing" => StreamStatus::Playing,
29 "disabled" => StreamStatus::Disabled,
30 _ => StreamStatus::Unknown,
31 }
32 }
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
36pub struct StreamUri {
37 pub fragment: String,
38 pub host: String,
39 pub path: String,
40 pub query: HashMap<String, String>,
41 pub raw: String,
42 pub scheme: String,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
46#[serde(rename_all = "camelCase")]
47pub enum StreamPlaybackStatus {
48 Playing,
49 Paused,
50 Stopped,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
54#[serde(rename_all = "camelCase")]
55pub enum StreamLoopStatus {
56 None,
57 Track,
58 Playlist,
59}
60
61#[serde_with::skip_serializing_none]
62#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
63#[serde(rename_all = "camelCase")]
64pub struct StreamProperties {
65 pub playback_status: Option<StreamPlaybackStatus>,
66 pub loop_status: Option<StreamLoopStatus>,
67 pub shuffle: Option<bool>,
68 pub volume: Option<usize>,
69 pub mute: Option<bool>,
70 pub rate: Option<f64>,
71 pub position: Option<f64>,
72 pub can_go_next: bool,
73 pub can_go_previous: bool,
74 pub can_play: bool,
75 pub can_pause: bool,
76 pub can_seek: bool,
77 pub can_control: bool,
78 pub metadata: Option<StreamMetadata>,
79}
80
81#[serde_with::skip_serializing_none]
82#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
83#[serde(rename_all = "camelCase")]
84pub struct StreamMetadata {
85 track_id: Option<String>,
86 file: Option<String>,
87 duration: Option<f64>,
88 artist: Option<Vec<String>>,
89 artist_sort: Option<Vec<String>>,
90 album: Option<String>,
91 album_sort: Option<String>,
92 album_artist: Option<Vec<String>>,
93 album_artist_sort: Option<Vec<String>>,
94 name: Option<String>,
95 date: Option<String>,
96 original_date: Option<String>,
97 composer: Option<Vec<String>>,
98 performer: Option<String>,
99 work: Option<String>,
100 grouping: Option<String>,
101 label: Option<String>,
102 musicbrainz_artist_id: Option<String>,
103 musicbrainz_album_id: Option<String>,
104 musicbrainz_album_artist_id: Option<String>,
105 musicbrainz_track_id: Option<String>,
106 musicbrainz_release_track_id: Option<String>,
107 musicbrainz_work_id: Option<String>,
108 lyrics: Option<Vec<String>>,
109 bpm: Option<usize>,
110 auto_rating: Option<f64>,
111 comment: Option<Vec<String>>,
112 content_created: Option<String>,
113 disc_number: Option<usize>,
114 first_used: Option<String>,
115 genre: Option<Vec<String>>,
116 last_used: Option<String>,
117 lyricist: Option<Vec<String>>,
118 title: Option<String>,
119 track_number: Option<usize>,
120 url: Option<String>,
121 art_url: Option<String>,
122 art_data: Option<ArtData>,
123 use_count: Option<usize>,
124 user_rating: Option<f64>,
125 spotify_artist_id: Option<String>,
126 spotify_track_id: Option<String>,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
130pub struct ArtData {
131 pub data: String,
132 pub extension: String,
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
137pub struct AddStreamParams {
138 #[serde(rename = "streamUri")]
139 pub stream_uri: String,
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
143pub struct AddStreamResult {
144 pub id: String,
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
148pub struct RemoveStreamParams {
149 pub id: String,
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
153pub struct RemoveStreamResult {
154 pub id: String,
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
158pub struct ControlParams {
159 pub id: String,
160 #[serde(flatten)]
161 pub command: ControlCommand,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
165#[serde(rename_all = "camelCase", tag = "command", content = "params")]
166pub enum ControlCommand {
167 Play,
168 Pause,
169 PlayPause,
170 Stop,
171 Next,
172 Previous,
173 Seek { offset: f64 },
174 SetPosition { position: f64 },
175}
176
177pub type ControlResult = String;
178
179#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
180pub struct SetPropertyParams {
181 pub id: String,
182 #[serde(flatten)]
183 pub properties: SetPropertyProperties,
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
187#[serde(rename_all = "camelCase", tag = "property", content = "value")]
188pub enum SetPropertyProperties {
189 LoopStatus(StreamLoopStatus),
190 Shuffle(bool),
191 Volume(usize),
192 Mute(bool),
193 Rate(f64),
194}
195
196pub type SetPropertiesResult = String;
197
198#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
200pub struct OnUpdateParams {
201 pub id: String,
202 pub stream: Stream,
203}
204
205#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
206pub struct OnPropertiesParams {
207 pub id: String,
208 pub properties: StreamProperties,
209}
210
211#[cfg(test)]
212mod tests {
213 use std::collections::HashMap;
214
215 use super::*;
216
217 #[test]
218 fn serialize_stream() {
219 let stream = Stream {
220 id: "stream 1".to_string(),
221 status: "idle".into(),
222 properties: None,
223 uri: StreamUri {
224 fragment: "".to_string(),
225 host: "".to_string(),
226 path: "/tmp/snapfifo".to_string(),
227 query: HashMap::new(),
228 raw: "pipe:///tmp/snapfifo?name=stream 1".to_string(),
229 scheme: "pipe".to_string(),
230 },
231 };
232
233 let json = serde_json::to_string(&stream).unwrap();
234 let expected = r#"{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}}"#;
235
236 assert_eq!(json, expected);
237 }
238
239 #[test]
240 fn deserialize_stream() {
241 let json = r#"{"id":"stream 1","status":"idle","uri":{"fragment":"","host":"","path":"/tmp/snapfifo","query":{"chunk_ms":"20","codec":"flac","name":"stream 1","sampleformat":"48000:16:2"},"raw":"pipe:///tmp/snapfifo?name=stream 1","scheme":"pipe"}}"#;
242 let stream: Stream = serde_json::from_str(json).unwrap();
243
244 assert_eq!(stream.id, "stream 1");
245 }
246}