1use crate::{
2 model::{
3 AlbumModel, AutoRepeatMode, MediaModel, PlaybackModel, PlaybackStatus, PlaybackType,
4 TimelineModel,
5 },
6 util::ResultExt,
7};
8use std::convert::{TryFrom, TryInto};
9use windows::{
10 core::HRESULT,
11 Media::{
12 Control::{
13 GlobalSystemMediaTransportControlsSessionMediaProperties,
14 GlobalSystemMediaTransportControlsSessionPlaybackInfo,
15 GlobalSystemMediaTransportControlsSessionPlaybackStatus,
16 GlobalSystemMediaTransportControlsSessionTimelineProperties,
17 },
18 MediaPlaybackAutoRepeatMode, MediaPlaybackType,
19 },
20};
21
22impl TryFrom<GlobalSystemMediaTransportControlsSessionPlaybackInfo> for PlaybackModel {
23 type Error = windows::core::Error;
24
25 fn try_from(
26 value: GlobalSystemMediaTransportControlsSessionPlaybackInfo,
27 ) -> Result<Self, Self::Error> {
28 Ok(Self {
29 status: value.PlaybackStatus()?.try_into()?,
30 r#type: value
31 .PlaybackType()?
32 .Value()
33 .map(From::from)
34 .unwrap_or_default(),
35 auto_repeat: value
36 .AutoRepeatMode()
37 .and_then(|r| r.Value())
38 .map(From::from)
39 .unwrap_or_default(),
40 rate: value.PlaybackRate().and_then(|r| r.Value()).unwrap_or(1.0),
41 shuffle: value
42 .IsShuffleActive()
43 .and_then(|r| r.Value())
44 .unwrap_or_default(),
45 })
46 }
47}
48
49impl TryFrom<GlobalSystemMediaTransportControlsSessionTimelineProperties> for TimelineModel {
50 type Error = windows::core::Error;
51
52 fn try_from(
53 value: GlobalSystemMediaTransportControlsSessionTimelineProperties,
54 ) -> Result<Self, Self::Error> {
55 Ok(Self {
56 start: value.StartTime()?.Duration,
57 end: value.EndTime()?.Duration,
58 position: value.Position()?.Duration,
59 last_updated_at_ms: filetime_to_unix_ms(value.LastUpdatedTime()?.UniversalTime),
60 })
61 }
62}
63
64impl TryFrom<GlobalSystemMediaTransportControlsSessionMediaProperties> for MediaModel {
65 type Error = windows::core::Error;
66
67 fn try_from(
68 value: GlobalSystemMediaTransportControlsSessionMediaProperties,
69 ) -> Result<Self, Self::Error> {
70 Ok(Self {
71 title: value.Title()?.to_string(),
72 subtitle: value.Subtitle()?.to_string(),
73 artist: value.Artist()?.to_string(),
74 track_number: value
75 .TrackNumber()
76 .opt()?
77 .and_then(|v: i32| v.try_into().ok()),
78 album: (&value).try_into().ok(),
79 genres: value.Genres()?.into_iter().map(|s| s.to_string()).collect(),
80 playback_type: value
81 .PlaybackType()?
82 .Value()
83 .map(Into::into)
84 .unwrap_or_default(),
85 })
86 }
87}
88
89impl TryFrom<&GlobalSystemMediaTransportControlsSessionMediaProperties> for AlbumModel {
90 type Error = ();
91
92 fn try_from(
93 value: &GlobalSystemMediaTransportControlsSessionMediaProperties,
94 ) -> Result<Self, Self::Error> {
95 Ok(Self {
96 artist: value
97 .AlbumArtist()
98 .opt()
99 .map_err(|_| ())?
100 .ok_or(())?
101 .to_string(),
102 title: value
103 .AlbumTitle()
104 .opt()
105 .map_err(|_| ())?
106 .ok_or(())?
107 .to_string(),
108 track_count: value
109 .AlbumTrackCount()
110 .opt()
111 .map_err(|_| ())?
112 .and_then(|v: i32| v.try_into().ok())
113 .ok_or(())?,
114 })
115 }
116}
117
118impl TryFrom<GlobalSystemMediaTransportControlsSessionPlaybackStatus> for PlaybackStatus {
119 type Error = windows::core::Error;
120
121 fn try_from(
122 value: GlobalSystemMediaTransportControlsSessionPlaybackStatus,
123 ) -> Result<Self, Self::Error> {
124 match value {
125 GlobalSystemMediaTransportControlsSessionPlaybackStatus::Closed => Ok(Self::Closed),
126 GlobalSystemMediaTransportControlsSessionPlaybackStatus::Opened => Ok(Self::Opened),
127 GlobalSystemMediaTransportControlsSessionPlaybackStatus::Changing => Ok(Self::Changing),
128 GlobalSystemMediaTransportControlsSessionPlaybackStatus::Stopped => Ok(Self::Stopped),
129 GlobalSystemMediaTransportControlsSessionPlaybackStatus::Playing => Ok(Self::Playing),
130 GlobalSystemMediaTransportControlsSessionPlaybackStatus::Paused => Ok(Self::Paused),
131 _ => Err(HRESULT(0x1fe2).into()),
132 }
133 }
134}
135
136impl From<MediaPlaybackType> for PlaybackType {
137 fn from(value: MediaPlaybackType) -> Self {
138 match value {
139 MediaPlaybackType::Unknown => Self::Unknown,
140 MediaPlaybackType::Image => Self::Image,
141 MediaPlaybackType::Music => Self::Music,
142 MediaPlaybackType::Video => Self::Video,
143 _ => Self::Unknown,
144 }
145 }
146}
147
148impl From<MediaPlaybackAutoRepeatMode> for AutoRepeatMode {
149 fn from(value: MediaPlaybackAutoRepeatMode) -> Self {
150 match value {
151 MediaPlaybackAutoRepeatMode::None => Self::None,
152 MediaPlaybackAutoRepeatMode::List => Self::List,
153 MediaPlaybackAutoRepeatMode::Track => Self::Track,
154 _ => Self::None,
155 }
156 }
157}
158
159fn filetime_to_unix_ms(filetime: i64) -> i64 {
160 (filetime / 10000).checked_sub(11644473600000).unwrap_or(0)
161}