//! # D-Bus interface proxy for: `org.mpris.MediaPlayer2.Player` //! //! This code was generated by `zbus-xmlgen` `4.1.0` from D-Bus introspection data. //! Source: `Interface '/org/mpris/MediaPlayer2' from service 'org.mpris.MediaPlayer2.playerctld' on system bus`. //! //! You may prefer to adapt it, instead of using it verbatim. //! //! More information can be found in the [Writing a client proxy] section of the zbus //! documentation. //! //! This type implements the [D-Bus standard interfaces], (`org.freedesktop.DBus.*`) for which the //! following zbus API can be used: //! //! * [`zbus::fdo::PropertiesProxy`] //! * [`zbus::fdo::IntrospectableProxy`] //! * [`zbus::fdo::PeerProxy`] //! //! Consequently `zbus-xmlgen` did not generate code for the above interfaces. //! //! [Writing a client proxy]: https://dbus2.github.io/zbus/client.html //! [D-Bus standard interfaces]: https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces, use std::collections::HashMap; use serde::{ser::Error, Deserialize, Serialize}; use time::{format_description::well_known::Iso8601, PrimitiveDateTime}; use url::Url; use zbus::{ proxy, zvariant::{OwnedValue, Type}, }; #[proxy( interface = "org.mpris.MediaPlayer2.Player", default_service = "org.mpris.MediaPlayer2.playerctld", default_path = "/org/mpris/MediaPlayer2" )] trait Player { /// Next method fn next(&self) -> zbus::Result<()>; /// OpenUri method fn open_uri(&self, uri: &str) -> zbus::Result<()>; /// Pause method fn pause(&self) -> zbus::Result<()>; /// Play method fn play(&self) -> zbus::Result<()>; /// PlayPause method fn play_pause(&self) -> zbus::Result<()>; /// Previous method fn previous(&self) -> zbus::Result<()>; /// Seek method fn seek(&self, offset: i64) -> zbus::Result<()>; /// SetPosition method fn set_position( &self, track_id: &zbus::zvariant::ObjectPath<'_>, offset: i64, ) -> zbus::Result<()>; /// Stop method fn stop(&self) -> zbus::Result<()>; /// Seeked signal #[zbus(signal)] fn seeked(&self, position: i64) -> zbus::Result<()>; /// CanControl property #[zbus(property)] fn can_control(&self) -> zbus::Result; /// CanGoNext property #[zbus(property)] fn can_go_next(&self) -> zbus::Result; /// CanGoPrevious property #[zbus(property)] fn can_go_previous(&self) -> zbus::Result; /// CanPause property #[zbus(property)] fn can_pause(&self) -> zbus::Result; /// CanPlay property #[zbus(property)] fn can_play(&self) -> zbus::Result; /// CanSeek property #[zbus(property)] fn can_seek(&self) -> zbus::Result; /// LoopStatus property #[zbus(property)] fn loop_status(&self) -> zbus::Result; #[zbus(property)] fn set_loop_status(&self, value: &str) -> zbus::Result<()>; /// MaximumRate property #[zbus(property)] fn maximum_rate(&self) -> zbus::Result; /// Metadata property #[zbus(property)] fn metadata(&self) -> zbus::Result; /// MinimumRate property #[zbus(property)] fn minimum_rate(&self) -> zbus::Result; /// PlaybackStatus property #[zbus(property)] fn playback_status(&self) -> zbus::Result; /// Position property #[zbus(property)] fn position(&self) -> zbus::Result; /// Rate property #[zbus(property)] fn rate(&self) -> zbus::Result; #[zbus(property)] fn set_rate(&self, value: f64) -> zbus::Result<()>; /// Shuffle property #[zbus(property)] fn shuffle(&self) -> zbus::Result; #[zbus(property)] fn set_shuffle(&self, value: bool) -> zbus::Result<()>; /// Volume property #[zbus(property)] fn volume(&self) -> zbus::Result; #[zbus(property)] fn set_volume(&self, value: f64) -> zbus::Result<()>; } /// MPRIS metadata recomended fields /// /// Found here: [https://www.freedesktop.org/wiki/Specifications/mpris-spec/metadata] #[derive(Debug, Default, PartialEq, Type, Serialize, Deserialize)] #[zvariant(signature = "dict")] pub struct Metadata { /// D-Bus path: A unique identity for this track within the context of an MPRIS object (eg: tracklist). #[zvariant(rename = "mpris:trackid")] pub trackid: Option, /// 64-bit integer: The duration of the track in microseconds. #[zvariant(rename = "mpris:length")] pub length: Option, /// URI: The location of an image representing the track or album. Clients should not assume this will continue to exist when the media player stops giving out the URL. #[zvariant(rename = "mpris:artUrl")] pub art_url: Option, /// String: The album name. #[zvariant(rename = "xesam:album")] pub album: Option, /// List of Strings: The album artist(s). #[zvariant(rename = "xesam:albumArtist")] pub album_artist: Option>, /// List of Strings: The track artist(s). #[zvariant(rename = "xesam:artist")] pub artist: Option>, /// String: The track lyrics. #[zvariant(rename = "xesam:asText")] pub as_text: Option, /// Integer: The speed of the music, in beats per minute. #[zvariant(rename = "xesam:audioBPM")] pub audio_bpm: Option, /// Float: An automatically-generated rating, based on things such as how often it has been played. This should be in the range 0.0 to 1.0. #[zvariant(rename = "xesam:autoRating")] pub auto_rating: Option, /// List of Strings: A (list of) freeform comment(s). #[zvariant(rename = "xesam:comment")] pub comment: Option>, /// List of Strings: The composer(s) of the track. #[zvariant(rename = "xesam:composer")] pub composer: Option>, /// Date/Time: When the track was created. Usually only the year component will be useful. #[zvariant(rename = "xesam:contentCreated")] pub content_created: Option, /// Integer: The disc number on the album that this track is from. #[zvariant(rename = "xesam:discNumber")] pub disc_number: Option, /// Date/Time: When the track was first played. #[zvariant(rename = "xesam:firstUsed")] pub first_used: Option, /// List of Strings: The genre(s) of the track. #[zvariant(rename = "xesam:genre")] pub genre: Option>, /// Date/Time: When the track was last played. #[zvariant(rename = "xesam:lastUsed")] pub last_used: Option, /// List of Strings: The lyricist(s) of the track. #[zvariant(rename = "xesam:lyricist")] pub lyricist: Option>, /// String: The track title. #[zvariant(rename = "xesam:title")] pub title: Option, /// Integer: The track number on the album disc. #[zvariant(rename = "xesam:trackNumber")] pub track_number: Option, /// URI: The location of the media file. #[zvariant(rename = "xesam:url")] pub url: Option, /// Integer: The number of times the track has been played. #[zvariant(rename = "xesam:useCount")] pub use_count: Option, /// Float: A user-specified rating. This should be in the range 0.0 to 1.0. #[zvariant(rename = "xesam:userRating")] pub user_rating: Option, } impl TryFrom for Metadata { type Error = zbus::zvariant::Error; fn try_from(value: OwnedValue) -> Result { let map: HashMap = value.try_into()?; macro_rules! get_field { ($n:literal, PrimitiveDateTime) => { get_field!($n) .map(|s: String| PrimitiveDateTime::parse(&s, &Iso8601::DEFAULT)) .transpose() .map_err(Self::Error::custom)? }; ($n:literal, Url) => { get_field!($n) .map(|s: String| Url::parse(&s)) .transpose() .map_err(Self::Error::custom)? }; ($n:literal) => { map.get($n) .map(|o| o.try_to_owned()) .transpose()? .map(|o| o.try_into()) .transpose()? }; } Ok(Metadata { trackid: get_field!("mpris:trackid"), length: get_field!("mpris:length"), art_url: get_field!("mpris:artUrl", Url), album: get_field!("xesam:album"), album_artist: get_field!("xesam:albumArtist"), artist: get_field!("xesam:artist"), as_text: get_field!("xesam:asText"), audio_bpm: get_field!("xesam:audioBPM"), auto_rating: get_field!("xesam:autoRating"), comment: get_field!("xesam:comment"), composer: get_field!("xesam:composer"), content_created: get_field!("xesam:contentCreated", PrimitiveDateTime), disc_number: get_field!("xesam:discNumber"), first_used: get_field!("xesam:firstUsed", PrimitiveDateTime), genre: get_field!("xesam:genre"), last_used: get_field!("xesam:lastUsed", PrimitiveDateTime), lyricist: get_field!("xesam:lyricist"), title: get_field!("xesam:title"), track_number: get_field!("xesam:trackNumber"), url: get_field!("xesam:url", Url), use_count: get_field!("xesam:useCount"), user_rating: get_field!("xesam:userRating"), }) } } #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Type)] pub enum PlaybackStatus { Playing, Paused, #[default] Stopped, } impl TryFrom for PlaybackStatus { type Error = zbus::Error; fn try_from(value: OwnedValue) -> Result { match value.downcast_ref()? { "Playing" => Ok(Self::Playing), "Paused" => Ok(Self::Paused), "Stopped" => Ok(Self::Stopped), _ => Err(zbus::Error::InvalidField), } } }