gsmtc/
conversion.rs

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}