use std::env;
use lazy_static::lazy_static;
use rust_utils::logging::Log;
use mlounge_core::{
library::{Playlist, Song, Library, PlaylistStore},
player::{PlayerResult, audio_cmd}
};
pub use mlounge_core::player::{PlayerCommand, PlayerState, PlayerStatus, RepeatMode};
lazy_static! {
static ref TMP_DIR: String = format!("/tmp/mlounge-{}/", env::var("USER").expect("What is your name again?"));
static ref LOG: Log = Log::new("mlounge", "music-lounge");
}
pub struct MLoungeClient {
pub queue: Playlist,
pub song: Song,
pub state: PlayerState,
pub repeat: RepeatMode,
position: usize,
id: u64
}
impl MLoungeClient {
pub fn new() -> MLoungeClient {
let list: Playlist = audio_cmd(Some(&LOG), PlayerCommand::GetQueue).unwrap_or_else(|_| Playlist::new("_"));
let first_song = if !list.songs.is_empty() {
list.songs[0].clone()
}
else {
Song::empty()
};
let mut player = MLoungeClient {
song: first_song,
queue: list,
position: usize::MAX,
state: PlayerState::Stopped,
repeat: RepeatMode::Once,
id: 0
};
player.quick_sync();
player
}
pub fn load_list(&mut self, list: &Playlist, first_song: &Song) -> PlayerResult<()> {
self.queue = list.clone();
audio_cmd::<()>(None, PlayerCommand::Load(list.clone()))?;
self.set_pos(first_song)
}
pub fn is_empty(&self) -> bool { self.song.duration == 0 }
pub fn cycle_repeat(&mut self) -> PlayerResult<()> {
audio_cmd(None, PlayerCommand::CycleRepeat)?;
self.quick_sync();
Ok(())
}
pub fn restart(&mut self) -> PlayerResult<()> {
if self.state != PlayerState::Stopped {
audio_cmd(None, PlayerCommand::Restart)?;
self.quick_sync();
}
Ok(())
}
pub fn next_song(&mut self) -> PlayerResult<()> {
audio_cmd(None, PlayerCommand::Next)?;
self.quick_sync();
Ok(())
}
pub fn prev_song(&mut self) -> PlayerResult<()> {
audio_cmd(None, PlayerCommand::Prev)?;
self.quick_sync();
Ok(())
}
pub fn play_pause(&mut self) -> PlayerResult<()> {
if self.state == PlayerState::Playing {
audio_cmd(None, PlayerCommand::Pause)?;
}
else if let PlayerState::Paused(_) = self.state {
audio_cmd(None, PlayerCommand::Resume)?;
}
self.quick_sync();
Ok(())
}
pub fn stop(&mut self) -> PlayerResult<()> {
self.queue.songs.clear();
audio_cmd(None, PlayerCommand::Stop)?;
self.position = usize::MAX;
self.sync(true)
}
pub fn shuffle_queue(&mut self) -> PlayerResult<()> {
audio_cmd(None, PlayerCommand::Shuffle)?;
self.sync(true)
}
pub fn cur_time(&self) -> String {
let seconds = self.cur_time_secs();
let sec_rem = seconds % 60;
let minutes = (seconds - (seconds % 60)) / 60;
format!("{minutes}:{sec_rem:02}")
}
pub fn cur_time_secs(&self) -> u64 { audio_cmd(None, PlayerCommand::CurrentTime).unwrap_or(0) }
pub fn set_pos(&mut self, song: &Song) -> PlayerResult<()> {
audio_cmd(None, PlayerCommand::SetPos(song.clone()))?;
self.quick_sync();
Ok(())
}
pub fn song_changed(&mut self) -> bool {
if let Ok(status) = audio_cmd::<PlayerStatus>(None, PlayerCommand::Status) {
return status.song_id != self.id;
}
false
}
pub fn sync(&mut self, reverse: bool) -> PlayerResult<()> {
if reverse {
let queue: Playlist = audio_cmd(None, PlayerCommand::GetQueue)?;
self.queue = queue;
}
else {
audio_cmd(None, PlayerCommand::SetQueue(self.queue.clone()))?
}
self.quick_sync();
Ok(())
}
pub fn quick_sync(&mut self) {
if let Ok(status) = audio_cmd::<PlayerStatus>(Some(&LOG), PlayerCommand::Status) {
self.position = status.position;
self.repeat = status.repeat_mode;
self.state = status.state;
if !self.queue.songs.is_empty() {
self.song =
if self.position == usize::MAX {
self.position = 0;
self.queue.songs[0].clone()
}
else { self.queue.songs[self.position].clone() };
}
else {
self.song = Song::empty();
}
self.id = self.song.song_id();
}
}
pub fn seek(&self, time: u64) { audio_cmd(None, PlayerCommand::Seek(time)).expect("What went wrong?!") }
pub fn set_song(&mut self, song: &Song) {
self.song = song.clone();
self.set_pos(song).unwrap();
}
}
impl Default for MLoungeClient {
fn default() -> Self {
Self::new()
}
}
pub fn get_library() -> PlayerResult<Option<Library>> {
audio_cmd(Some(&LOG), PlayerCommand::GetLibrary)
}
pub fn rescan_library() -> PlayerResult<()> {
audio_cmd(Some(&LOG), PlayerCommand::RescanLibrary)
}
pub fn get_playlists() -> PlayerResult<PlaylistStore> {
audio_cmd(Some(&LOG), PlayerCommand::GetPlaylists)
}