use std::fmt::{Display, Formatter, Result as FmtResult};
use crate::library::{Playlist, Song, PlaylistStore};
#[cfg(feature = "client")]
use {
std::{
env,
os::unix::net::UnixStream,
io::{Write, BufReader, Read},
net::Shutdown
},
serde::Deserialize,
lazy_static::lazy_static,
rust_utils::logging::{Log, LogLevel}
};
#[cfg(feature = "client")]
lazy_static! {
static ref TMP_DIR: String = format!("/tmp/mlounge-{}/", env::var("USER").expect("What is your name again?"));
}
pub type PlayerResult<T> = Result<T, String>;
#[derive(PartialEq, Eq, Copy, Clone, serde_derive::Serialize, serde_derive::Deserialize)]
pub enum RepeatMode {
One,
All,
Once
}
impl RepeatMode {
pub fn disp_width(self) -> usize {
match self {
Self::One => 12,
Self::All => 3,
Self::Once => 9
}
}
}
impl Display for RepeatMode {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
match *self {
RepeatMode::All => write!(f, "All"),
RepeatMode::One => write!(f, "Current Song"),
RepeatMode::Once => write!(f, "No Repeat")
}
}
}
#[derive(PartialEq, Eq, Copy, Clone, serde_derive::Serialize, serde_derive::Deserialize)]
pub enum PlayerState {
Playing,
Paused(u64),
Stopped
}
impl PlayerState {
pub fn disp_width(self) -> usize {
match self {
Self::Paused(_) => 8,
_ => 9
}
}
}
impl Display for PlayerState {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
match *self {
PlayerState::Paused(_) => write!(f, "[paused]"),
PlayerState::Playing => write!(f, "[playing]"),
PlayerState::Stopped => write!(f, "[stopped]")
}
}
}
#[derive(Copy, Clone, serde_derive::Serialize, serde_derive::Deserialize)]
pub struct PlayerStatus {
pub stopped: bool,
pub paused: bool,
pub position: usize,
pub repeat_mode: RepeatMode,
pub state: PlayerState,
pub song_id: u64
}
#[doc(hidden)]
#[derive(Clone, serde_derive::Serialize, serde_derive::Deserialize, PartialEq, Eq, Debug)]
pub enum PlayerCommand {
Load(Playlist),
CycleRepeat,
Play,
Restart,
Next,
Prev,
Resume,
Pause,
Stop,
Seek(u64),
SetQueue(Playlist),
Shuffle,
SetPos(Song),
ProcessID,
CurrentTime,
Status,
GetQueue,
GetLibrary,
RescanLibrary,
GetPlaylists,
UpdatePlaylists(PlaylistStore)
}
impl PlayerCommand {
pub fn is_mut(&self) -> bool {
matches!(*self, Self::Load(_) | Self::CycleRepeat | Self::Play | Self::Restart | Self::Next | Self::Prev | Self::Resume | Self::Pause | Self::Stop | Self::Seek(_) | Self::SetQueue(_) | Self::Shuffle | Self::SetPos(_))
}
}
#[cfg(feature = "client")]
#[doc(hidden)]
pub fn audio_cmd<T: for <'de> Deserialize<'de>>(log: Option<&Log>, cmd: PlayerCommand) -> PlayerResult<T> {
let socket_file = format!("{}/socket", *TMP_DIR);
match UnixStream::connect(socket_file) {
Ok(mut stream) => {
let encoded = bincode::serialize(&cmd).expect("What went wrong?!");
stream.write_all(&encoded).expect("Unable to write to socket!");
stream.shutdown(Shutdown::Write).expect("What went wrong?!");
let buffer = BufReader::new(&stream);
let encoded: Vec<u8> = buffer.bytes().map(Result::unwrap_or_default).collect();
bincode::deserialize(&encoded).map_err(|why| why.to_string())
}
Err(why) => {
if let Some(log) = log {
log.line(LogLevel::Error, format!("Unable to connect to socket: {why}"), true);
}
Err(why.to_string())
}
}
}