this repo has no description
1use chrono::{DateTime, FixedOffset};
2use jacquard::{CowStr, smol_str::ToSmolStr, types::string::Datetime};
3
4#[derive(Debug, Default)]
5pub struct Artist {
6 pub artist_name: String,
7 pub artist_mb_id: Option<String>,
8}
9
10#[derive(Debug, Default)]
11pub struct Play {
12 pub track_name: String,
13 pub track_mb_id: Option<String>,
14 pub recording_mb_id: Option<String>,
15 pub duration: Option<i64>,
16 pub artist_names: Option<Vec<String>>,
17 pub artist_mb_ids: Option<Vec<String>>,
18 pub artists: Option<Vec<Artist>>,
19 pub release_name: Option<String>,
20 pub release_mb_id: Option<String>,
21 pub isrc: Option<String>,
22 pub origin_url: Option<String>,
23 pub music_service_base_domain: Option<String>,
24 pub submission_client_agent: Option<String>,
25 pub played_time: Option<DateTime<FixedOffset>>,
26 pub track_discriminant: Option<String>,
27 pub release_discriminant: Option<String>,
28}
29
30#[derive(Debug, Default)]
31pub struct PlayView {
32 pub track_name: String,
33 pub track_mb_id: Option<String>,
34 pub recording_mb_id: Option<String>,
35 pub duration: Option<i64>,
36 pub artists: Vec<Artist>,
37 pub release_name: Option<String>,
38 pub release_mb_id: Option<String>,
39 pub isrc: Option<String>,
40 pub origin_url: Option<String>,
41 pub music_service_base_domain: Option<String>,
42 pub submission_client_agent: Option<String>,
43 pub played_time: Option<DateTime<FixedOffset>>,
44}
45
46#[derive(Debug, Default)]
47pub struct Status {
48 pub time: DateTime<FixedOffset>,
49 pub expiry: Option<DateTime<FixedOffset>>,
50 pub item: PlayView,
51}
52
53impl From<jacquard_api::fm_teal::alpha::feed::Artist<'_>> for Artist {
54 fn from(value: jacquard_api::fm_teal::alpha::feed::Artist) -> Self {
55 Self {
56 artist_name: value.artist_name.to_string(),
57 artist_mb_id: value.artist_mb_id.map(|s| s.to_string()),
58 }
59 }
60}
61
62impl From<Artist> for jacquard_api::fm_teal::alpha::feed::Artist<'static> {
63 fn from(value: Artist) -> Self {
64 Self {
65 artist_name: CowStr::Owned(value.artist_name.to_smolstr()),
66 artist_mb_id: value.artist_mb_id.map(|s| CowStr::Owned(s.to_smolstr())),
67 extra_data: None,
68 }
69 }
70}
71
72impl From<jacquard_api::fm_teal::alpha::feed::play::Play<'_>> for Play {
73 fn from(value: jacquard_api::fm_teal::alpha::feed::play::Play<'_>) -> Self {
74 Self {
75 track_name: value.track_name.to_string(),
76 track_mb_id: value.track_mb_id.map(|s| s.to_string()),
77 recording_mb_id: value.recording_mb_id.map(|s| s.to_string()),
78 duration: value.duration,
79 artist_names: value
80 .artist_names
81 .map(|v| v.iter().map(|a| a.to_string()).collect()),
82 artist_mb_ids: value
83 .artist_mb_ids
84 .map(|v| v.iter().map(|a| a.to_string()).collect()),
85 artists: value
86 .artists
87 .map(|v| v.iter().map(|a| a.clone().into()).collect()),
88 release_name: value.release_name.map(|s| s.to_string()),
89 release_mb_id: value.release_mb_id.map(|s| s.to_string()),
90 isrc: value.isrc.map(|s| s.to_string()),
91 origin_url: value.origin_url.map(|s| s.to_string()),
92 music_service_base_domain: value.music_service_base_domain.map(|s| s.to_string()),
93 submission_client_agent: value.submission_client_agent.map(|s| s.to_string()),
94 played_time: value.played_time.map(|dt| *dt.as_ref()),
95 track_discriminant: value.track_discriminant.map(|s| s.to_string()),
96 release_discriminant: value.release_discriminant.map(|s| s.to_string()),
97 }
98 }
99}
100
101impl From<Play> for jacquard_api::fm_teal::alpha::feed::play::Play<'static> {
102 fn from(val: Play) -> Self {
103 jacquard_api::fm_teal::alpha::feed::play::Play {
104 track_name: CowStr::Owned(val.track_name.to_smolstr()),
105 track_mb_id: val.track_mb_id.map(|s| CowStr::Owned(s.to_smolstr())),
106 recording_mb_id: val.recording_mb_id.map(|s| CowStr::Owned(s.to_smolstr())),
107 duration: val.duration,
108 artist_names: val
109 .artist_names
110 .map(|v| v.iter().map(|s| CowStr::Owned(s.to_smolstr())).collect()),
111 artist_mb_ids: val
112 .artist_mb_ids
113 .map(|v| v.iter().map(|s| CowStr::Owned(s.to_smolstr())).collect()),
114 artists: val
115 .artists
116 .map(|v| v.into_iter().map(|a| a.into()).collect()),
117 release_name: val.release_name.map(|s| CowStr::Owned(s.to_smolstr())),
118 release_mb_id: val.release_mb_id.map(|s| CowStr::Owned(s.to_smolstr())),
119 isrc: val.isrc.map(|s| CowStr::Owned(s.to_smolstr())),
120 origin_url: val.origin_url.map(|s| CowStr::Owned(s.to_smolstr())),
121 music_service_base_domain: val
122 .music_service_base_domain
123 .map(|s| CowStr::Owned(s.to_smolstr())),
124 submission_client_agent: val
125 .submission_client_agent
126 .map(|s| CowStr::Owned(s.to_smolstr())),
127 played_time: val.played_time.map(Datetime::new),
128 track_discriminant: val
129 .track_discriminant
130 .map(|s| CowStr::Owned(s.to_smolstr())),
131 release_discriminant: val
132 .release_discriminant
133 .map(|s| CowStr::Owned(s.to_smolstr())),
134 extra_data: None,
135 }
136 }
137}
138
139impl From<jacquard_api::fm_teal::alpha::feed::PlayView<'_>> for PlayView {
140 fn from(value: jacquard_api::fm_teal::alpha::feed::PlayView<'_>) -> Self {
141 Self {
142 track_name: value.track_name.to_string(),
143 track_mb_id: value.track_mb_id.map(|s| s.to_string()),
144 recording_mb_id: value.recording_mb_id.map(|s| s.to_string()),
145 duration: value.duration,
146 artists: value.artists.iter().map(|a| a.clone().into()).collect(),
147 release_name: value.release_name.map(|s| s.to_string()),
148 release_mb_id: value.release_mb_id.map(|s| s.to_string()),
149 isrc: value.isrc.map(|s| s.to_string()),
150 origin_url: value.origin_url.map(|s| s.to_string()),
151 music_service_base_domain: value.music_service_base_domain.map(|s| s.to_string()),
152 submission_client_agent: value.submission_client_agent.map(|s| s.to_string()),
153 played_time: value.played_time.map(|dt| *dt.as_ref()),
154 }
155 }
156}
157
158impl From<PlayView> for jacquard_api::fm_teal::alpha::feed::PlayView<'static> {
159 fn from(val: PlayView) -> Self {
160 jacquard_api::fm_teal::alpha::feed::PlayView {
161 track_name: CowStr::Owned(val.track_name.to_smolstr()),
162 track_mb_id: val.track_mb_id.map(|s| CowStr::Owned(s.to_smolstr())),
163 recording_mb_id: val.recording_mb_id.map(|s| CowStr::Owned(s.to_smolstr())),
164 duration: val.duration,
165 artists: val.artists.into_iter().map(|a| a.into()).collect(),
166 release_name: val.release_name.map(|s| CowStr::Owned(s.to_smolstr())),
167 release_mb_id: val.release_mb_id.map(|s| CowStr::Owned(s.to_smolstr())),
168 isrc: val.isrc.map(|s| CowStr::Owned(s.to_smolstr())),
169 origin_url: val.origin_url.map(|s| CowStr::Owned(s.to_smolstr())),
170 music_service_base_domain: val
171 .music_service_base_domain
172 .map(|s| CowStr::Owned(s.to_smolstr())),
173 submission_client_agent: val
174 .submission_client_agent
175 .map(|s| CowStr::Owned(s.to_smolstr())),
176 played_time: val.played_time.map(Datetime::new),
177 extra_data: None,
178 }
179 }
180}
181
182impl From<jacquard_api::fm_teal::alpha::actor::status::Status<'_>> for Status {
183 fn from(value: jacquard_api::fm_teal::alpha::actor::status::Status<'_>) -> Self {
184 Self {
185 time: *value.time.as_ref(),
186 expiry: value.expiry.map(|dt| *dt.as_ref()),
187 item: value.item.into(),
188 }
189 }
190}
191
192impl From<Status> for jacquard_api::fm_teal::alpha::actor::status::Status<'static> {
193 fn from(val: Status) -> Self {
194 jacquard_api::fm_teal::alpha::actor::status::Status {
195 time: Datetime::new(val.time),
196 expiry: val.expiry.map(Datetime::new),
197 item: val.item.into(),
198 extra_data: None,
199 }
200 }
201}
202
203impl Status {
204 pub fn display(&self, raw: bool, full: bool) {
205 // if both track name and artists are blank, probably nothing's playing
206 if self.item.track_name.is_empty() && self.item.artists.is_empty() && !raw {
207 println!("nothing playing right now");
208 return;
209 }
210
211 println!("track: {}", self.item.track_name);
212
213 if let Some(track_id) = &self.item.track_mb_id
214 && full
215 {
216 println!("track id: {}", track_id);
217 }
218
219 if let Some(recording_id) = &self.item.recording_mb_id
220 && full
221 {
222 println!("recording id: {}", recording_id);
223 }
224
225 if !self.item.artists.is_empty() || raw {
226 print!("artists: ");
227
228 for i in 0..self.item.artists.len() {
229 print!("{}", self.item.artists[i].artist_name);
230
231 if let Some(artist_id) = &self.item.artists[i].artist_mb_id
232 && full
233 {
234 print!(" [{}]", artist_id);
235 }
236
237 if i != self.item.artists.len() - 1 {
238 print!(", ");
239 }
240 }
241
242 println!();
243 }
244
245 if let Some(release) = &self.item.release_name {
246 println!("release: {}", release);
247 }
248
249 if let Some(release_id) = &self.item.release_mb_id
250 && full
251 {
252 println!("release id: {}", release_id);
253 }
254
255 if let Some(isrc) = &self.item.isrc
256 && full
257 {
258 println!("isrc: {}", isrc);
259 }
260
261 if let Some(played_time) = &self.item.played_time {
262 if raw {
263 println!("played: {}", played_time.format("%Y-%m-%d %H:%M:%S %:z"));
264 } else {
265 let local_dt = played_time.with_timezone(&chrono::Local);
266 println!("played: {}", local_dt.format("%Y-%m-%d %H:%M:%S"));
267 }
268 }
269
270 if let Some(duration) = self.item.duration {
271 if raw {
272 println!("duration: {}", duration);
273 } else {
274 let hours = duration / 3600;
275 let minutes = (duration - (hours * 3600)) / 60;
276 let seconds = duration - (minutes * 60);
277
278 let mut duration_str = "".to_string();
279 if hours > 0 {
280 duration_str = format!("{:02}:", hours);
281 }
282 if minutes > 0 || hours > 0 {
283 duration_str = format!("{}{:02}:", duration_str, minutes);
284 }
285 if seconds > 0 || minutes > 0 || hours > 0 {
286 duration_str = format!("{}{:02}", duration_str, seconds);
287 }
288
289 println!("duration: {}", duration_str);
290 }
291 }
292
293 if let Some(service) = &self.item.music_service_base_domain
294 && full
295 {
296 println!("service: {}", service);
297 }
298
299 if let Some(client) = &self.item.submission_client_agent
300 && full
301 {
302 println!("client: {}", client);
303 }
304
305 if full {
306 if raw {
307 println!("time: {}", self.time.format("%Y-%m-%d %H:%M:%S %:z"));
308 } else {
309 let local_dt = self.time.with_timezone(&chrono::Local);
310 println!("time: {}", local_dt.format("%Y-%m-%d %H:%M:%S"));
311 }
312 }
313
314 if let Some(expiry) = &self.expiry
315 && full
316 {
317 if raw {
318 println!("expiry: {}", expiry.format("%Y-%m-%d %H:%M:%S %:z"));
319 } else {
320 let local_dt = expiry.with_timezone(&chrono::Local);
321 println!("expiry: {}", local_dt.format("%Y-%m-%d %H:%M:%S"));
322 }
323 }
324 }
325}