1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use super::INTERFACE;
use crate::{Player, Result};
use dbus::nonblock::stdintf::org_freedesktop_dbus::Properties;
use dbus::{
    arg::{Append, Arg, Get, PropMap},
    strings::Path,
};
use std::time::Duration;

/// Retrieves track metadata from a `Player`.
/// The [`prop_cast`](crate::prop_cast) function may be used
/// to get specific values out of the resulting metadata.
///
/// # Errors
/// May `Err` if there is a failure in getting the metadata.
pub async fn get_metadata(player: &mut Player<'_>) -> Result<PropMap> {
    let proxy = player.get_proxy()?;
    let metadata: PropMap = proxy.get(INTERFACE, "Metadata").await?;
    Ok(metadata)
}

/// Retrieves the value of an MPRIS property.
/// Available properties can be found [here].
///
/// [here]: https://specifications.freedesktop.org/mpris-spec/latest/Player_Interface.html#Property:PlaybackStatus
///
/// # Errors
/// May return an `Err` variant if:
/// * An invalid type was provided for the property
/// * An invalid property was provided
pub async fn get_property<T>(player: &mut Player<'_>, property: &str) -> Result<T>
where
    T: for<'a> Get<'a> + 'static,
{
    let proxy = player.get_proxy()?;
    let value: T = proxy.get(INTERFACE, property).await?;

    Ok(value)
}

/// Sets the value of a writable MPRIS property.
/// Available properties can be found [here].
///
/// [here]: https://specifications.freedesktop.org/mpris-spec/latest/Player_Interface.html#Property:PlaybackStatus
///
/// # Errors
/// May return an `Err` variant if:
/// * An invalid type was provided for the property
/// * An invalid property was provided
pub async fn set_property<T>(player: &mut Player<'_>, property: &str, value: T) -> Result<()>
where
    T: Arg + Append,
{
    let proxy = player.get_proxy()?;
    proxy.set(INTERFACE, property, value).await?;

    Ok(())
}

/// Seeks the position of the active track.
pub async fn seek(player: &mut Player<'_>, offset: Duration) -> Result<()> {
    let proxy = player.get_proxy()?;
    let offset = offset.as_micros() as i64;
    proxy.method_call(INTERFACE, "Seek", (offset,)).await?;

    Ok(())
}

/// Same as `seek`, but in reverse.
pub async fn seek_reverse(player: &mut Player<'_>, offset: Duration) -> Result<()> {
    let proxy = player.get_proxy()?;
    let offset = offset.as_micros() as i64;
    proxy.method_call(INTERFACE, "Seek", (-offset,)).await?;

    Ok(())
}

/// Sets the position of the current track, by microseconds.
pub async fn set_position(player: &mut Player<'_>, position: i64) -> Result<()> {
    let mut player_clone = player.clone();

    let proxy = player.get_proxy()?;
    let metadata = get_metadata(&mut player_clone).await?;
    let track_id: &Path = crate::prop_cast(&metadata, "mpris:trackid").unwrap();

    proxy
        .method_call(INTERFACE, "SetPosition", (track_id, position))
        .await?;

    Ok(())
}

/// Opens a track by its URI.
///
/// # Errors
/// May return an `Err` variant if the provided URI is invalid.
pub async fn open_uri(player: &mut Player<'_>, uri: &str) -> Result<()> {
    let proxy = player.get_proxy()?;
    proxy.method_call(INTERFACE, "OpenUri", (uri,)).await?;

    Ok(())
}