mpdclient 0.2.0

Rust interface to MPD using libmpdclient
Documentation
use mpdclient_sys::{
    mpd_run_clearerror, mpd_run_consume, mpd_run_crossfade, mpd_run_mixrampdb,
    mpd_run_mixrampdelay, mpd_run_next, mpd_run_pause, mpd_run_play, mpd_run_play_id,
    mpd_run_play_pos, mpd_run_previous, mpd_run_random, mpd_run_repeat, mpd_run_seek_current,
    mpd_run_seek_id, mpd_run_seek_id_float, mpd_run_seek_pos, mpd_run_single_state, mpd_run_stop,
    mpd_send_current_song,
};

use crate::entity::EntityReceiver;
use crate::entity::Song;
use crate::entity::song::Id;
use crate::error::Result;

#[cfg(feature = "protocol_0_24")]
use super::ConsumeState;
use super::{Connection, SingleState};
#[cfg(feature = "protocol_0_24")]
use mpdclient_sys::mpd_run_consume_state;

/// Intermediate to bundle MPD player functions.
pub struct Player<'a> {
    connection: &'a Connection,
}

impl<'a> Player<'a> {
    pub(super) fn new(connection: &'a Connection) -> Self {
        Player { connection }
    }

    /// Returns the current song (playing/paused).
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn current(&self) -> Result<Song> {
        self.connection
            .get_bool_error(|| unsafe { mpd_send_current_song(self.connection.connection()) })?;
        Song::extract_one(EntityReceiver::new(self.connection))
    }

    /// Starts playing the current song.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn play(&self) -> Result<()> {
        self.connection
            .get_bool_error(|| unsafe { mpd_run_play(self.connection.connection()) })
    }

    /// Starts playing the song from `position` in the queue.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn play_pos(&self, position: u32) -> Result<()> {
        self.connection
            .get_bool_error(|| unsafe { mpd_run_play_pos(self.connection.connection(), position) })
    }

    /// Starts playing the song with `id` in the queue.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn play_id(&self, id: Id) -> Result<()> {
        self.connection
            .get_bool_error(|| unsafe { mpd_run_play_id(self.connection.connection(), id) })
    }

    /// Stops playback.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn stop(&self) -> Result<()> {
        self.connection
            .get_bool_error(|| unsafe { mpd_run_stop(self.connection.connection()) })
    }

    /// Pauses playback.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn pause(&self, mode: bool) -> Result<()> {
        self.connection
            .get_bool_error(|| unsafe { mpd_run_pause(self.connection.connection(), mode) })
    }

    /// Plays the next song in the queue.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn next(&self) -> Result<()> {
        self.connection
            .get_bool_error(|| unsafe { mpd_run_next(self.connection.connection()) })
    }

    /// Plays the previous song in the queue.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn previous(&self) -> Result<()> {
        self.connection
            .get_bool_error(|| unsafe { mpd_run_previous(self.connection.connection()) })
    }

    /// Plays from `time` (in s) in the song at position `song_pos` in the queue.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn seek_pos(&self, song_pos: u32, time: u32) -> Result<()> {
        self.connection.get_bool_error(|| unsafe {
            mpd_run_seek_pos(self.connection.connection(), song_pos, time)
        })
    }

    /// Plays from `time` (in s) in the song with `id` in the queue.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn seek_id(&self, id: Id, time: u32) -> Result<()> {
        self.connection
            .get_bool_error(|| unsafe { mpd_run_seek_id(self.connection.connection(), id, time) })
    }

    /// Plays from `time` in the song with `id` in the queue. Accepts fractional `time` values.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn seek_id_f(&self, id: Id, time: f32) -> Result<()> {
        self.connection.get_bool_error(|| unsafe {
            mpd_run_seek_id_float(self.connection.connection(), id, time)
        })
    }

    /// Plays from `time` in the current song, optionally `relative` to the current time. Accepts
    /// fractional `time` values.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn seek_current(&self, time: f32, relative: bool) -> Result<()> {
        self.connection.get_bool_error(|| unsafe {
            mpd_run_seek_current(self.connection.connection(), time, relative)
        })
    }

    /// Repeat the current song.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn repeat(&self, mode: bool) -> Result<()> {
        self.connection
            .get_bool_error(|| unsafe { mpd_run_repeat(self.connection.connection(), mode) })
    }

    /// Randomize next song selection.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn random(&self, mode: bool) -> Result<()> {
        self.connection
            .get_bool_error(|| unsafe { mpd_run_random(self.connection.connection(), mode) })
    }

    /// Sets [`SingleState`].
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn single(&self, state: SingleState) -> Result<()> {
        self.connection.get_bool_error(|| unsafe {
            mpd_run_single_state(self.connection.connection(), state as u32)
        })
    }

    /// Sets consume mode. If activated, MPD removes the song from the queue after playing.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn consume_bool(&self, mode: bool) -> Result<()> {
        self.connection
            .get_bool_error(|| unsafe { mpd_run_consume(self.connection.connection(), mode) })
    }

    /// Sets consume mode using extended options. If [`ConsumeState::On`], MPD removes the song from
    /// the queue after playing. [`ConsumeState::Oneshot`] enables the mode for a single song, then
    /// deactivates it.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    #[cfg(feature = "protocol_0_24")]
    pub fn consume(&self, state: ConsumeState) -> Result<()> {
        self.connection.get_bool_error(|| unsafe {
            mpd_run_consume_state(self.connection.connection(), state as u32)
        })
    }

    /// Crossfades beetween songs. Only works if song formats are the same.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn crossfade(&self, secs: u32) -> Result<()> {
        self.connection
            .get_bool_error(|| unsafe { mpd_run_crossfade(self.connection.connection(), secs) })
    }

    /// Threshold at which songs will be overlapped. Doesn't fade track volume.
    ///
    /// Tags need to be added by external tool.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn mixrampdb(&self, db: f32) -> Result<()> {
        self.connection
            .get_bool_error(|| unsafe { mpd_run_mixrampdb(self.connection.connection(), db) })
    }

    /// Sets additional time subtracted from the overlap calculated by mixrampdb.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn mixrampdelay(&self, secs: f32) -> Result<()> {
        self.connection
            .get_bool_error(|| unsafe { mpd_run_mixrampdelay(self.connection.connection(), secs) })
    }

    /// Clears current error in the status alternatively to starting playback. Only possible for
    /// some errors.
    ///
    /// # Errors
    ///
    /// Returns [`Error::Mpd`](crate::Error::Mpd) if MPD returns an error.
    pub fn clearerror(&self) -> Result<()> {
        self.connection
            .get_bool_error(|| unsafe { mpd_run_clearerror(self.connection.connection()) })
    }
}