1use crate::{Image, Payload, Volume};
2
3#[derive(Serialize, Deserialize, Clone, Debug)]
7#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
8#[serde(tag = "type")]
9pub enum Media {
10 GetStatus(GetStatusRequestData),
12 Load(LoadRequestData),
13 Pause(RequestData),
14 Stop(RequestData),
15 Play(RequestData),
16 SkipAd(RequestData),
17 PlayAgain(RequestData),
18 Seek(SeekRequestData),
19 SetPlaybackRate(SetPlaybackRateRequestData),
20 SetVolume(VolumeRequestData),
21 EditTracksInfo(EditTracksInfoRequestData),
22 EditAudioTracks(EditAudioTracksRequestData),
23 Precache(PrecacheRequestData),
24 Preload(PreloadRequestData),
25 QueueLoad(QueueLoadRequestData),
26 QueueInsert(QueueInsertRequestData),
27 QueueUpdate(QueueUpdateRequestData),
28 QueueRemove(QueueRemoveRequestData),
29 QueueReorder(QueueReorderRequestData),
30 QueueNext(RequestData),
31 QueuePrev(RequestData),
32 QueueGetItemRange(FetchItemsRequestData),
33 QueueGetItems(GetItemsInfoRequestData),
34 QueueGetItemIds(RequestData),
35 QueueShuffle(RequestData),
36 SetCredentials(SetCredentialsRequestData),
37 LoadByEntity(LoadByEntityRequestData),
38 UserAction(UserActionRequestData),
39 DisplayStatus(DisplayStatusRequestData),
40 FocusState(FocusStateRequestData),
41 StoreSession(StoreSessionRequestData),
42 ResumeSession(ResumeSessionRequestData),
43
44 MediaStatus(ResponseData<MediaStatus>),
46 CloudStatus(ResponseData<CloudMediaStatus>),
47 QueueChange(ResponseData<QueueChange>),
48 QueueItems(ResponseData<ItemsInfo>),
49 QueueItemIds(ResponseData<QueueIds>),
50 SessionState(StoreSessionResponseData),
51
52 InvalidRequest(ErrorResponseData),
53 InvalidPlayerState,
54 LoadFailed,
55 LoadCancelled,
56}
57
58impl From<Media> for Payload {
59 fn from(val: Media) -> Self {
60 Payload::Media(val.clone())
61 }
62}
63
64#[skip_serializing_none]
67#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
68#[serde(rename_all = "camelCase")]
69#[builder(setter(strip_option, into), default)]
70pub struct DisplayStatusRequestData {}
71
72#[skip_serializing_none]
73#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
74#[serde(rename_all = "camelCase")]
75#[builder(setter(strip_option, into), default)]
76pub struct EditAudioTracksRequestData {
77 pub is_suggested_language: Option<bool>,
78 pub language: Option<String>,
79 pub media_session_id: Option<i32>,
80}
81
82#[skip_serializing_none]
83#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
84#[serde(rename_all = "camelCase")]
85#[builder(setter(strip_option, into), default)]
86pub struct EditTracksInfoRequestData {
87 pub active_track_ids: Option<Vec<i32>>,
88 pub enable_text_tracks: Option<bool>,
89 pub is_suggested_language: Option<bool>,
90 pub language: Option<String>,
91 pub media_session_id: Option<i32>,
92 pub text_track_style: Option<TextTrackStyle>,
93}
94
95#[skip_serializing_none]
96#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
97#[serde(rename_all = "camelCase")]
98#[builder(setter(strip_option, into), default)]
99pub struct FetchItemsRequestData {
100 pub item_id: i32,
101 pub media_session_id: Option<i32>,
102 pub next_count: i32,
103 pub prev_count: i32,
104}
105
106#[skip_serializing_none]
107#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
108#[serde(rename_all = "camelCase")]
109#[builder(setter(strip_option, into), default)]
110pub struct FocusStateRequestData {
111 pub state: FocusState,
112}
113
114#[skip_serializing_none]
115#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
116#[serde(rename_all = "camelCase")]
117#[builder(setter(strip_option, into), default)]
118pub struct GetItemsInfoRequestData {
119 pub item_ids: Vec<i32>,
120 pub media_session_id: Option<i32>,
121}
122
123#[skip_serializing_none]
124#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
125#[serde(rename_all = "camelCase")]
126#[builder(setter(strip_option, into), default)]
127pub struct GetStatusRequestData {
128 pub media_session_id: Option<i32>,
129 pub options: Option<GetStatusOptions>,
130}
131
132#[skip_serializing_none]
133#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
134#[serde(rename_all = "camelCase")]
135#[builder(setter(strip_option, into), default)]
136pub struct LoadByEntityRequestData {
137 pub entity: String,
138 pub shuffle: Option<bool>,
139}
140
141#[skip_serializing_none]
142#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
143#[serde(rename_all = "camelCase")]
144#[builder(setter(strip_option, into), default)]
145pub struct LoadRequestData {
146 pub active_track_ids: Option<Vec<i32>>,
147 pub autoplay: Option<bool>,
148 pub credentials: Option<String>,
149 pub credentials_type: Option<String>,
150 pub current_time: Option<f64>,
151 pub media: MediaInformation,
152 pub media_session_id: Option<i32>,
153 pub playback_rate: Option<f64>,
154 pub queue_data: Option<QueueData>,
155}
156
157#[skip_serializing_none]
158#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
159#[serde(rename_all = "camelCase")]
160#[builder(setter(strip_option, into), default)]
161pub struct PrecacheRequestData {
162 pub active_track_ids: Option<Vec<i32>>,
163 pub autoplay: Option<bool>,
164 pub credentials: Option<String>,
165 pub credentials_type: Option<String>,
166 pub current_time: Option<f64>,
167 pub media: MediaInformation,
168 pub media_session_id: Option<i32>,
169 pub playback_rate: Option<f64>,
170 pub precache_data: Option<String>,
171 pub queue_data: Option<QueueData>,
172}
173
174#[skip_serializing_none]
175#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
176#[serde(rename_all = "camelCase")]
177#[builder(setter(strip_option, into), default)]
178pub struct PreloadRequestData {
179 pub active_track_ids: Option<Vec<i32>>,
180 pub autoplay: Option<bool>,
181 pub credentials: Option<String>,
182 pub credentials_type: Option<String>,
183 pub current_time: Option<f64>,
184 pub item_id: i32,
185 pub media: MediaInformation,
186 pub media_session_id: Option<i32>,
187 pub playback_rate: Option<f64>,
188 pub queue_data: Option<QueueData>,
189}
190
191#[skip_serializing_none]
192#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
193#[serde(rename_all = "camelCase")]
194#[builder(setter(strip_option, into), default)]
195pub struct QueueInsertRequestData {
196 pub current_item_id: Option<i32>,
197 pub current_item_index: Option<i32>,
198 pub current_time: Option<f64>,
199 pub insert_before: Option<bool>,
200 pub items: Vec<QueueItem>,
201 pub media_session_id: Option<i32>,
202}
203
204#[skip_serializing_none]
205#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
206#[serde(rename_all = "camelCase")]
207#[builder(setter(strip_option, into), default)]
208pub struct QueueLoadRequestData {
209 pub current_time: Option<f64>,
210 pub items: Vec<QueueItem>,
211 pub media_session_id: Option<i32>,
212 pub repeat_mode: Option<RepeatMode>,
213 pub start_index: Option<i32>,
214}
215
216#[skip_serializing_none]
217#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
218#[serde(rename_all = "camelCase")]
219#[builder(setter(strip_option, into), default)]
220pub struct QueueRemoveRequestData {
221 pub current_item_id: Option<i32>,
222 pub current_time: Option<f64>,
223 pub item_ids: Vec<i32>,
224 pub media_session_id: Option<i32>,
225}
226
227#[skip_serializing_none]
228#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
229#[serde(rename_all = "camelCase")]
230#[builder(setter(strip_option, into), default)]
231pub struct QueueReorderRequestData {
232 pub current_item_id: Option<i32>,
233 pub current_time: Option<f64>,
234 pub insert_before: Option<bool>,
235 pub item_ids: Vec<i32>,
236 pub media_session_id: Option<i32>,
237}
238
239#[skip_serializing_none]
240#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
241#[serde(rename_all = "camelCase")]
242#[builder(setter(strip_option, into), default)]
243pub struct QueueUpdateRequestData {
244 pub current_item_id: Option<i32>,
245 pub current_time: Option<f64>,
246 pub items: Option<Vec<QueueItem>>,
247 pub jump: Option<i32>,
248 pub media_session_id: Option<i32>,
249 pub repeat_mode: Option<RepeatMode>,
250 pub shuffle: Option<bool>,
251}
252
253#[skip_serializing_none]
254#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
255#[serde(rename_all = "camelCase")]
256#[builder(setter(strip_option, into), default)]
257pub struct RefreshCredentialsRequestData {}
258
259#[skip_serializing_none]
260#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
261#[serde(rename_all = "camelCase")]
262#[builder(setter(strip_option, into), default)]
263pub struct RequestData {
264 pub media_session_id: Option<i32>,
265}
266
267#[skip_serializing_none]
268#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
269#[serde(rename_all = "camelCase")]
270#[builder(setter(strip_option, into), default)]
271pub struct ResumeSessionRequestData {
272 pub session_state: SessionState,
273}
274
275#[skip_serializing_none]
276#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
277#[serde(rename_all = "camelCase")]
278#[builder(setter(strip_option, into), default)]
279pub struct SeekRequestData {
280 pub current_time: Option<f64>,
281 pub media_session_id: Option<i32>,
282 pub relative_time: Option<f64>,
283}
284
285#[skip_serializing_none]
286#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
287#[serde(rename_all = "camelCase")]
288#[builder(setter(strip_option, into), default)]
289pub struct SetCredentialsRequestData {
290 pub credentials: String,
291 pub for_request: Option<i32>,
292 pub is_likely_3p_account_linked_user: Option<bool>,
293}
294
295#[skip_serializing_none]
296#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
297#[serde(rename_all = "camelCase")]
298#[builder(setter(strip_option, into), default)]
299pub struct SetPlaybackRateRequestData {
300 pub media_session_id: Option<i32>,
301 pub playback_rate: Option<u32>,
302 pub relative_playback_rate: Option<i32>,
303}
304
305#[skip_serializing_none]
306#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
307#[serde(rename_all = "camelCase")]
308#[builder(setter(strip_option, into), default)]
309pub struct StoreSessionRequestData {}
310
311#[skip_serializing_none]
312#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
313#[serde(rename_all = "camelCase")]
314#[builder(setter(strip_option, into), default)]
315pub struct UserActionRequestData {
316 pub clear: Option<bool>,
317 pub user_action: UserAction,
318 pub user_action_context: Option<UserActionContext>,
319}
320
321#[skip_serializing_none]
322#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
323#[serde(rename_all = "camelCase")]
324#[builder(setter(strip_option, into), default)]
325pub struct VolumeRequestData {
326 pub media_session_id: Option<i32>,
327 pub volume: Volume,
328}
329
330#[skip_serializing_none]
333#[derive(Serialize, Deserialize, Clone, Debug, Default)]
334#[serde(rename_all = "camelCase")]
335pub struct ResponseData<T> {
336 pub status: Vec<T>,
337}
338
339impl<T: Clone + Default> ResponseData<T> {
340 pub fn first(&self) -> T {
341 self.status.first().cloned().unwrap()
342 }
343}
344
345#[skip_serializing_none]
346#[derive(Serialize, Deserialize, Clone, Debug, Default)]
347#[serde(rename_all = "camelCase")]
348pub struct ErrorResponseData {
349 pub reason: ErrorReason,
350}
351
352#[skip_serializing_none]
353#[derive(Serialize, Deserialize, Clone, Debug, Default)]
354#[serde(rename_all = "camelCase")]
355pub struct StoreSessionResponseData {
356 pub session_state: SessionState,
357}
358
359#[skip_serializing_none]
362#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
363#[serde(rename_all = "camelCase")]
364#[builder(setter(strip_option, into), default)]
365pub struct AduioTrackInfo {
366 pub audio_codec: Option<String>,
367 pub num_audio_channels: Option<i32>,
368 pub spatial_audio: Option<bool>,
369}
370
371#[skip_serializing_none]
372#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
373#[serde(rename_all = "camelCase")]
374#[serde(tag = "type")]
375#[serde(rename = "AUDIOBOOK_CHAPTER")]
376#[builder(setter(strip_option, into), default)]
377pub struct AudiobookChapterMediaMetadata {
378 pub book_title: Option<String>,
379 pub chapter_number: Option<i32>,
380 pub chapter_title: Option<String>,
381 pub images: Option<Vec<Image>>,
382 pub subtitle: Option<String>,
383 pub title: Option<String>,
384}
385
386impl From<AudiobookChapterMediaMetadata> for MediaMetadata {
387 fn from(val: AudiobookChapterMediaMetadata) -> Self {
388 MediaMetadata {
389 metadata_type: MetadataType::AudiobookChapter(val),
390 ..Default::default()
391 }
392 }
393}
394
395#[skip_serializing_none]
396#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
397#[serde(rename_all = "camelCase")]
398#[builder(setter(strip_option, into), default)]
399pub struct AudiobookContainerMetadata {
400 pub authors: Option<Vec<String>>,
401 pub narrators: Option<Vec<String>>,
402 pub publisher: Option<String>,
403 pub release_date: Option<String>,
404}
405
406#[skip_serializing_none]
407#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
408#[serde(rename_all = "camelCase")]
409#[builder(setter(strip_option, into), default)]
410pub struct Break {
411 pub break_clip_ids: Vec<String>,
412 pub duration: Option<f64>,
413 pub id: String,
414 pub is_embedded: Option<bool>,
415 pub is_watched: bool,
416 pub position: f64,
417}
418
419#[skip_serializing_none]
420#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
421#[serde(rename_all = "camelCase")]
422#[builder(setter(strip_option, into), default)]
423pub struct BreakClip {
424 pub click_through_url: Option<String>,
425 pub content_id: Option<String>,
426 pub content_type: Option<String>,
427 pub content_url: Option<String>,
428 pub duration: Option<f64>,
429 pub hls_segment_format: Option<HlsSegmentFormat>,
430 pub id: String,
431 pub poster_url: Option<String>,
432 pub title: Option<String>,
433 pub vast_ads_request: Option<VastAdsRequest>,
434 pub when_skippable: Option<f64>,
435}
436
437#[skip_serializing_none]
438#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
439#[serde(rename_all = "camelCase")]
440#[builder(setter(strip_option, into), default)]
441pub struct BreakStatus {
442 pub break_clip_id: Option<String>,
443 pub break_id: Option<String>,
444 pub current_break_clip_time: Option<f64>,
445 pub current_break_time: Option<f64>,
446 pub when_skippable: Option<f64>,
447}
448
449#[skip_serializing_none]
450#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
451#[serde(rename_all = "camelCase")]
452#[builder(setter(strip_option, into), default)]
453pub struct CloudMediaStatus {}
454
455#[skip_serializing_none]
456#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
457#[serde(rename_all = "camelCase")]
458#[builder(setter(strip_option, into), default)]
459pub struct ContainerMetadata {
460 pub container_duration: Option<f64>,
461 pub container_images: Option<Vec<Image>>,
462 pub container_type: ContainerType,
463 pub sections: Option<Vec<MediaMetadata>>,
464 pub title: Option<String>,
465}
466
467#[skip_serializing_none]
468#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
469#[serde(rename_all = "camelCase")]
470#[builder(setter(strip_option, into), default)]
471pub struct ExtendedMediaStatus {
472 pub player_state: ExtendedPlayerState,
473 pub media: Option<MediaInformation>,
474 pub media_session_id: Option<i32>,
475}
476
477#[skip_serializing_none]
478#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
479#[serde(rename_all = "camelCase")]
480#[serde(tag = "type")]
481#[serde(rename = "GENERIC")]
482#[builder(setter(strip_option, into), default)]
483pub struct GenericMediaMetadata {
484 pub images: Option<Vec<Image>>,
485 pub release_date: Option<String>,
486 pub subtitle: Option<String>,
487 pub title: Option<String>,
488}
489
490impl From<GenericMediaMetadata> for MediaMetadata {
491 fn from(val: GenericMediaMetadata) -> Self {
492 MediaMetadata {
493 metadata_type: MetadataType::Generic(val),
494 ..Default::default()
495 }
496 }
497}
498
499#[skip_serializing_none]
500#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
501#[serde(rename_all = "camelCase")]
502#[builder(setter(strip_option, into), default)]
503pub struct ItemsInfo {
504 pub items: Option<Vec<QueueItem>>,
505}
506
507#[skip_serializing_none]
508#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
509#[serde(rename_all = "camelCase")]
510#[builder(setter(strip_option, into), default)]
511pub struct LiveSeekableRange {
512 pub end: Option<f64>,
513 pub is_live_done: Option<bool>,
514 pub is_moving_window: Option<bool>,
515 pub start: Option<f64>,
516}
517
518#[skip_serializing_none]
519#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
520#[serde(rename_all = "camelCase")]
521#[builder(setter(strip_option, into), default)]
522pub struct MediaInformation {
523 pub atv_entity: Option<String>,
524 pub break_clips: Option<Vec<BreakClip>>,
525 pub breaks: Option<Vec<Break>>,
526 pub content_id: String,
527 pub content_type: String,
528 pub duration: Option<f64>,
529 pub entity: Option<String>,
530 pub hls_segment_format: Option<HlsSegmentFormat>,
531 pub hls_video_segment_format: Option<HlsVideoSegmentFormat>,
532 pub metadata: Option<MediaMetadata>,
533 pub start_absolute_time: Option<f64>,
534 pub stream_type: StreamType,
535 pub text_track_style: Option<TextTrackStyle>,
536 pub tracks: Option<Vec<Track>>,
537 pub user_action_states: Option<Vec<UserActionState>>,
538 pub vmap_ads_request: Option<VastAdsRequest>,
539}
540
541impl From<MediaInformation> for LoadRequestData {
542 fn from(val: MediaInformation) -> Self {
543 LoadRequestData {
544 media: val,
545 autoplay: Some(true),
546 ..Default::default()
547 }
548 }
549}
550
551#[skip_serializing_none]
552#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
553#[serde(rename_all = "camelCase")]
554#[builder(setter(strip_option, into), default)]
555pub struct MediaMetadata {
556 #[serde(flatten)]
557 pub metadata_type: MetadataType,
558 pub poster_url: Option<String>,
559 pub queue_item_id: Option<i32>,
560 pub section_duration: Option<f64>,
561 pub section_start_absolute_time: Option<f64>,
562 pub section_start_time_in_container: Option<f64>,
563 pub section_start_time_in_media: Option<f64>,
564}
565
566#[skip_serializing_none]
567#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
568#[serde(rename_all = "camelCase")]
569#[builder(setter(strip_option, into), default)]
570pub struct MediaStatus {
571 pub active_track_ids: Option<Vec<i32>>,
572 pub break_status: Option<BreakStatus>,
573 pub current_item_id: Option<i32>,
574 pub current_time: f64,
575 pub extended_status: Option<ExtendedMediaStatus>,
576 pub idle_reason: Option<IdleReason>,
577 pub items: Option<Vec<QueueItem>>,
578 pub live_seekable_range: Option<LiveSeekableRange>,
579 pub loading_item_id: Option<i32>,
580 pub media: Option<MediaInformation>,
581 pub media_session_id: i32,
582 pub playback_rate: i32,
583 pub player_state: PlayerState,
584 pub preloaded_item_id: Option<i32>,
585 pub queue_data: Option<QueueData>,
586 pub repeat_mode: Option<RepeatMode>,
587 pub supported_media_commands: Command,
588 pub video_info: Option<VideoInformation>,
589 pub volume: Volume,
590}
591
592#[skip_serializing_none]
593#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
594#[serde(rename_all = "camelCase")]
595#[serde(tag = "type")]
596#[serde(rename = "MOVIE")]
597#[builder(setter(strip_option, into), default)]
598pub struct MovieMediaMetadata {
599 pub images: Option<Vec<Image>>,
600 pub release_date: Option<String>,
601 pub studio: Option<String>,
602 pub subtitle: Option<String>,
603 pub title: Option<String>,
604}
605
606impl From<MovieMediaMetadata> for MediaMetadata {
607 fn from(val: MovieMediaMetadata) -> Self {
608 MediaMetadata {
609 metadata_type: MetadataType::Movie(val),
610 ..Default::default()
611 }
612 }
613}
614
615#[skip_serializing_none]
616#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
617#[serde(rename_all = "camelCase")]
618#[serde(tag = "type")]
619#[serde(rename = "MUSIC_TRACK")]
620#[builder(setter(strip_option, into), default)]
621pub struct MusicTrackMediaMetadata {
622 pub album_artist: Option<String>,
623 pub album_name: Option<String>,
624 pub artist: Option<String>,
625 pub composer: Option<String>,
626 pub disc_number: Option<i32>,
627 pub images: Option<Vec<Image>>,
628 pub release_date: Option<String>,
629 pub secondary_image: Option<Image>,
630 pub title: Option<String>,
631 pub track_number: Option<i32>,
632}
633
634impl From<MusicTrackMediaMetadata> for MediaMetadata {
635 fn from(val: MusicTrackMediaMetadata) -> Self {
636 MediaMetadata {
637 metadata_type: MetadataType::MusicTrack(val),
638 ..Default::default()
639 }
640 }
641}
642
643#[skip_serializing_none]
644#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
645#[serde(rename_all = "camelCase")]
646#[serde(tag = "type")]
647#[serde(rename = "PHOTO")]
648#[builder(setter(strip_option, into), default)]
649pub struct PhotoMediaMetadata {
650 pub artist: Option<String>,
651 pub creation_date_time: Option<String>,
652 pub height: Option<u32>,
653 pub images: Option<Vec<Image>>,
654 pub latitude: Option<i32>,
655 pub location: Option<String>,
656 pub longitude: Option<i32>,
657 pub width: Option<u32>,
658}
659
660impl From<PhotoMediaMetadata> for MediaMetadata {
661 fn from(val: PhotoMediaMetadata) -> Self {
662 MediaMetadata {
663 metadata_type: MetadataType::Photo(val),
664 ..Default::default()
665 }
666 }
667}
668
669#[skip_serializing_none]
670#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
671#[serde(rename_all = "camelCase")]
672#[builder(setter(strip_option, into), default)]
673pub struct QueueChange {
674 pub change_type: Option<QueueChangeType>,
675 pub insert_before: Option<i32>,
676 pub item_ids: Option<Vec<i32>>,
677 pub reorder_item_ids: Option<Vec<i32>>,
678}
679
680#[skip_serializing_none]
681#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
682#[serde(rename_all = "camelCase")]
683#[builder(setter(strip_option, into), default)]
684pub struct QueueData {
685 pub container_metadata: Option<ContainerMetadata>,
686 pub description: Option<String>,
687 pub entity: Option<String>,
688 pub id: Option<String>,
689 pub items: Option<Vec<QueueItem>>,
690 pub name: Option<String>,
691 pub queue_type: Option<QueueType>,
692 pub repeat_mode: Option<RepeatMode>,
693 pub shuffle: Option<bool>,
694 pub start_index: Option<i32>,
695 pub start_time: Option<f64>,
696}
697
698#[skip_serializing_none]
699#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
700#[serde(rename_all = "camelCase")]
701#[builder(setter(strip_option, into), default)]
702pub struct QueueIds {
703 pub item_ids: Option<Vec<i32>>,
704}
705
706#[skip_serializing_none]
707#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
708#[serde(rename_all = "camelCase")]
709#[builder(setter(strip_option, into), default)]
710pub struct SeekableRange {
711 pub end: Option<f64>,
712 pub start: Option<f64>,
713}
714
715#[skip_serializing_none]
716#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
717#[serde(rename_all = "camelCase")]
718#[builder(setter(strip_option, into), default)]
719pub struct SessionState {
720 pub load_request_data: Option<LoadRequestData>,
721}
722
723#[skip_serializing_none]
724#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
725#[serde(rename_all = "camelCase")]
726#[builder(setter(strip_option, into), default)]
727pub struct QueueItem {
728 pub active_track_ids: Option<Vec<i32>>,
729 pub autoplay: Option<bool>,
730 pub item_id: Option<i32>,
731 pub media: Option<MediaInformation>,
732 pub playback_duration: Option<f64>,
733 pub preload_time: Option<f64>,
734 pub start_time: Option<f64>,
735}
736
737#[skip_serializing_none]
738#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
739#[serde(rename_all = "camelCase")]
740#[builder(setter(strip_option, into), default)]
741pub struct TextTrackStyle {
742 pub background_color: Option<String>,
743 pub edge_color: Option<String>,
744 pub edge_type: Option<TextTrackEdgeType>,
745 pub font_family: Option<String>,
746 pub font_generic_family: Option<TextTrackFontGenericFamily>,
747 pub font_scale: Option<i32>,
748 pub font_style: Option<TextTrackFontStyle>,
749 pub foreground_color: Option<String>,
750 pub window_color: Option<String>,
751 pub window_rounded_corner_radius: Option<f64>,
752 pub window_type: Option<TextTrackWindowType>,
753}
754
755#[skip_serializing_none]
756#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
757#[serde(rename_all = "camelCase")]
758#[builder(setter(strip_option, into), default)]
759pub struct Track {
760 pub audio_track_info: Option<AduioTrackInfo>,
761 pub is_inband: Option<bool>,
762 pub language: Option<String>,
763 pub name: Option<String>,
764 pub roles: Option<Vec<String>>,
765 pub subtype: Option<TextTrackType>,
766 pub track_content_id: Option<String>,
767 pub track_content_type: Option<CaptionMimeType>,
768 pub track_id: i32,
769 #[serde(rename = "type")]
770 pub type_: TrackType,
771}
772
773#[skip_serializing_none]
774#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
775#[serde(rename_all = "camelCase")]
776#[builder(setter(strip_option, into), default)]
777pub struct TracksInfo {
778 pub active_track_ids: Option<Vec<i32>>,
779 pub language: Option<String>,
780 pub text_track_style: Option<TextTrackStyle>,
781 pub tracks: Option<Vec<Track>>,
782}
783
784#[skip_serializing_none]
785#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
786#[serde(rename_all = "camelCase")]
787#[serde(tag = "type")]
788#[serde(rename = "TV_SHOW")]
789#[builder(setter(strip_option, into), default)]
790pub struct TvShowMediaMetadata {
791 pub episode: Option<i32>,
792 pub episode_title: Option<String>,
793 pub images: Option<Vec<Image>>,
794 pub original_airdate: Option<String>,
795 pub season: Option<i32>,
796 pub series_title: Option<String>,
797 pub title: Option<String>,
798}
799
800impl From<TvShowMediaMetadata> for MediaMetadata {
801 fn from(val: TvShowMediaMetadata) -> Self {
802 MediaMetadata {
803 metadata_type: MetadataType::TvShow(val),
804 ..Default::default()
805 }
806 }
807}
808
809#[skip_serializing_none]
810#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
811#[serde(rename_all = "camelCase")]
812#[builder(setter(strip_option, into), default)]
813pub struct UserActionState {
814 pub user_action: UserAction,
815}
816
817#[derive(Serialize, Deserialize, Clone, Debug, Default)]
818#[serde(rename_all = "camelCase")]
819pub struct VastAdsRequest {
820 pub ads_response: Option<String>,
821 pub ad_tag_url: Option<String>,
822}
823
824#[skip_serializing_none]
825#[derive(Serialize, Deserialize, Clone, Debug, Default, Builder)]
826#[serde(rename_all = "camelCase")]
827#[builder(setter(strip_option, into), default)]
828pub struct VideoInformation {
829 pub hdr_type: HdrType,
830 pub height: i32,
831 pub width: i32,
832}
833
834#[derive(Serialize, Deserialize, Clone, Debug, Default)]
837#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
838pub enum CaptionMimeType {
839 #[default]
840 #[serde(alias = "cea608")]
841 Cea608,
842 #[serde(alias = "ttml")]
843 Ttml,
844 #[serde(alias = "vtt")]
845 Vtt,
846 #[serde(alias = "ttmlmp3")]
847 TtmlMp3,
848 #[serde(untagged)]
849 Other(String),
850}
851
852#[derive(Serialize, Deserialize, Default)]
853#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
854pub enum CommandOld {
855 #[default]
856 Pause,
857 Seek,
858 StreamVolume,
859 StreamMute,
860 AllBasicMedia,
861 QueueNext,
862 QueuePrev,
863 QueueShuffle,
864 QueueRepeatAll,
865 QueueRepeatOne,
866 QueueRepeat,
867 SkipAd,
868 EditTracks,
869 PlaybackRate,
870 Like,
871 Dislike,
872 Follow,
873 Unfollow,
874 StreamTransfer,
875 Lyrics,
876}
877
878bitflags::bitflags! {
879 #[derive(Debug, PartialEq, Eq, Clone, Default)]
880 pub struct Command: u32 {
881 const Pause = 1;
882 const Seek = 2;
883 const StreamVolume = 4;
884 const StreamMute = 8;
885 const AllBasicMedia = 12303;
886 const QueueNext = 64;
887 const QueuePrev = 128;
888 const QueueShuffle = 256;
889 const QueueRepeatAll = 1024;
890 const QueueRepeatOne = 2048;
891 const QueueRepeat = 3072;
892 const SkipAd = 512;
893 const EditTracks = 4096;
894 const PlaybackRate = 8192;
895 const Like = 16384;
896 const Dislike = 32768;
897 const Follow = 65536;
898 const Unfollow = 131072;
899 const StreamTransfer = 262144;
900 const Lyrics = 524288;
901 }
902}
903
904impl serde::Serialize for Command {
905 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
906 where
907 S: serde::Serializer,
908 {
909 serializer.serialize_u32(self.bits())
910 }
911}
912
913impl<'de> serde::Deserialize<'de> for Command {
914 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
915 where
916 D: serde::Deserializer<'de>,
917 {
918 let bits = u32::deserialize(deserializer)?;
919 Command::from_bits(bits).ok_or_else(|| serde::de::Error::custom("invalid bitflags value"))
920 }
921}
922
923#[derive(Serialize, Deserialize, Clone, Debug, Default)]
924#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
925pub enum ContainerType {
926 #[default]
927 GenericContainer,
928 AudiobookContainer,
929}
930
931#[derive(Serialize, Deserialize, Clone, Debug, Default)]
932#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
933pub enum ContentFilteringMode {
934 #[default]
935 FilterExplicit,
936}
937
938#[derive(Serialize, Deserialize, Clone, Debug, Default)]
939#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
940pub enum ErrorReason {
941 #[default]
942 None,
943 InvalidCommand,
944 InvalidParams,
945 InvalidMediaSessionId,
946 InvalidRequestId,
947 SkipLimitReached,
948 NotSupported,
949 LanguageNotSupported,
950 EndOfQueue,
951 DuplicateRequestId,
952 VideoDeviceRequired,
953 PremiumAccountRequired,
954 AppError,
955 AuthenticationExpired,
956 ConcurrentStreamLimit,
957 ParentalControlRestricted,
958 ContentFiltered,
959 NotAvailableInRegion,
960 ContentAlreadyPlaying,
961 InvalidRequest,
962 GenericLoadError,
963}
964
965#[derive(Serialize, Deserialize, Clone, Debug, Default)]
966#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
967pub enum ExtendedPlayerState {
968 #[default]
969 Loading,
970}
971
972#[derive(Serialize, Deserialize, Clone, Debug, Default)]
973#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
974pub enum FocusState {
975 #[default]
976 InFocus,
977 NotInFocus,
978}
979
980#[derive(Serialize, Deserialize, Clone, Debug, Default)]
981#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
982pub enum GetStatusOptions {
983 #[default]
984 NoMetadata,
985 NoQueueItems,
986}
987
988#[derive(Serialize, Deserialize, Clone, Debug, Default)]
989#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
990pub enum HdrType {
991 #[default]
992 #[serde(alias = "sdr")]
993 Sdr,
994 #[serde(alias = "hdr")]
995 Hdr,
996 #[serde(alias = "dv")]
997 Dv,
998}
999
1000#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1001#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1002pub enum HlsSegmentFormat {
1003 #[default]
1004 Aac,
1005 Ac3,
1006 Mp3,
1007 Ts,
1008 TsAac,
1009 EAc3,
1010 Fmp4,
1011}
1012
1013#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1014#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1015pub enum HlsVideoSegmentFormat {
1016 #[default]
1017 Mpeg2Ts,
1018 Fmp4,
1019}
1020
1021#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1022#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1023pub enum IdleReason {
1024 #[default]
1025 Cancelled,
1026 Interrupted,
1027 Finished,
1028 Error,
1029}
1030
1031#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1032#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1033pub enum MediaCategory {
1034 #[default]
1035 Audio,
1036 Video,
1037 Image,
1038}
1039
1040#[derive(Serialize, Deserialize, Clone, Debug)]
1041#[serde(untagged)]
1042pub enum MetadataType {
1043 Generic(GenericMediaMetadata),
1044 Movie(MovieMediaMetadata),
1045 TvShow(TvShowMediaMetadata),
1046 MusicTrack(MusicTrackMediaMetadata),
1047 Photo(PhotoMediaMetadata),
1048 AudiobookChapter(AudiobookChapterMediaMetadata),
1049}
1050
1051impl Default for MetadataType {
1052 fn default() -> Self {
1053 Self::Generic(GenericMediaMetadata::default())
1054 }
1055}
1056
1057#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1058#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1059pub enum PlayerState {
1060 #[default]
1061 Idle,
1062 Playing,
1063 Paused,
1064 Buffering,
1065}
1066
1067#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1068#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1069pub enum QueueChangeType {
1070 #[default]
1071 Insert,
1072 Remove,
1073 ItemsChange,
1074 Update,
1075 NoChange,
1076}
1077
1078#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1079#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1080pub enum QueueType {
1081 #[default]
1082 Album,
1083 Playlist,
1084 Audiobook,
1085 RadioStation,
1086 PodcastSeries,
1087 TvSeries,
1088 VideoPlaylist,
1089 LiveTv,
1090 Movie,
1091}
1092
1093#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1094#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1095pub enum RepeatMode {
1096 #[default]
1097 RepeatOff,
1098 RepeatAll,
1099 RepeatSingle,
1100 RepeatAllAndShuffle,
1101}
1102
1103#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1104#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1105pub enum SeekResumeState {
1106 #[default]
1107 PlaybackStart,
1108 PlaybackPause,
1109}
1110
1111#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1112#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1113pub enum StreamingProtocolType {
1114 #[default]
1115 Unknown,
1116 MpegDash,
1117 Hls,
1118 SmoothStreaming,
1119}
1120
1121#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1122#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1123pub enum StreamType {
1124 #[default]
1125 None,
1126 Buffered,
1127 Live,
1128}
1129
1130#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1131#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1132pub enum TextTrackEdgeType {
1133 #[default]
1134 None,
1135 Outline,
1136 DropShadow,
1137 Raised,
1138 Depressed,
1139}
1140
1141#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1142#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1143pub enum TextTrackFontGenericFamily {
1144 #[default]
1145 SansSerif,
1146 MonospacedSansSerif,
1147 Serif,
1148 MonospacedSerif,
1149 Casual,
1150 Cursive,
1151 SmallCapitals,
1152}
1153
1154#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1155#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1156pub enum TextTrackFontStyle {
1157 #[default]
1158 Normal,
1159 Bold,
1160 BoldItalic,
1161 Italic,
1162}
1163
1164#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1165#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1166pub enum TextTrackType {
1167 #[default]
1168 Subtitles,
1169 Captions,
1170 Descriptions,
1171 Chapters,
1172 Metadata,
1173}
1174
1175#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1176#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1177pub enum TextTrackWindowType {
1178 #[default]
1179 None,
1180 Normal,
1181 RoundedCorners,
1182}
1183
1184#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1185#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1186pub enum TrackType {
1187 #[default]
1188 Text,
1189 Audio,
1190 Video,
1191}
1192
1193#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1194#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1195pub enum UserAction {
1196 #[default]
1197 Like,
1198 Dislike,
1199 Follow,
1200 Unfollow,
1201 Flag,
1202 SkipAd,
1203 Lyrics,
1204}
1205
1206#[derive(Serialize, Deserialize, Clone, Debug, Default)]
1207#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
1208pub enum UserActionContext {
1209 #[default]
1210 UnknownContext,
1211 Track,
1212 Album,
1213 Artist,
1214 Playlist,
1215 Episode,
1216 Series,
1217 Movie,
1218 Channel,
1219 Team,
1220 Player,
1221 Coach,
1222}
1223
1224#[cfg(test)]
1225mod test {
1226 use crate::namespace::media::{CaptionMimeType, Media};
1227
1228 #[test]
1229 fn test_deserialize_media() {
1230 let payload: Media = serde_json::from_str(
1231 r#"
1232 {
1233 "type": "MEDIA_STATUS",
1234 "status": [
1235 {
1236 "activeTrackIds": [7],
1237 "currentItemId": 1,
1238 "currentTime": 0,
1239 "items": [
1240 {
1241 "activeTrackIds": [2, 7],
1242 "autoplay": true,
1243 "itemId": 1,
1244 "media": {
1245 "contentId": "http://host.com/stream",
1246 "contentType": "video/x-matroska",
1247 "duration": 1422.004,
1248 "mediaCategory": "VIDEO",
1249 "streamType": "BUFFERED",
1250 "tracks": [
1251 {
1252 "language": "eng",
1253 "name": "Audio",
1254 "trackContentId": "trk0001",
1255 "trackContentType": "audio/aac",
1256 "trackId": 2,
1257 "type": "AUDIO"
1258 },
1259 {
1260 "language": "eng",
1261 "name": "Subtitle",
1262 "subtype": "SUBTITLES",
1263 "trackContentId": "http://host.com/stream/subtitle",
1264 "trackContentType": "text/vtt",
1265 "trackId": 7,
1266 "type": "TEXT"
1267 }
1268 ]
1269 },
1270 "orderId": 0
1271 }],
1272 "mediaSessionId": 29,
1273 "playbackRate": 1,
1274 "playerState": "PLAYING",
1275 "repeatMode": "REPEAT_OFF",
1276 "supportedMediaCommands": 274447,
1277 "videoInfo": {"hdrType": "sdr", "height": 1080, "width": 1920},
1278 "volume": {"level": 1, "muted": false}
1279 }
1280 ]
1281 }
1282 "#,
1283 )
1284 .unwrap();
1285 assert!(
1286 matches!(payload, Media::MediaStatus(_)),
1287 "Failed: {payload:#?}"
1288 );
1289 }
1290
1291 #[test]
1292 fn test_caption_mime() {
1293 let cap: CaptionMimeType = serde_json::from_str(r#""garbage""#).unwrap();
1294 let _garbage = "garbage".to_string();
1295 assert!(matches!(cap, CaptionMimeType::Other(_garbage)));
1296
1297 let cap: CaptionMimeType = serde_json::from_str(r#""VTT""#).unwrap();
1298 assert!(matches!(cap, CaptionMimeType::Vtt));
1299
1300 let cap: CaptionMimeType = serde_json::from_str(r#""vtt""#).unwrap();
1301 assert!(matches!(cap, CaptionMimeType::Vtt));
1302 }
1303}