use std::path::Path;
use std::sync::Arc;
use std::time::Duration;
use parking_lot::Mutex;
pub(crate) mod play;
pub(crate) mod player_structs;
pub(crate) mod metadata;
pub(crate) mod info;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PlaybackState {
Playing,
Paused,
Stopped,
Finished,
}
pub struct LocalPlayer {
player: player_structs::Player,
play_handle: Option<Arc<Mutex<play::MusicPlay>>>,
state: Arc<Mutex<PlaybackState>>,
}
impl LocalPlayer {
pub fn new<P: AsRef<Path>>(path: P) -> crate::Result<Self> {
let player = player_structs::Player::new(path);
Ok(Self {
player,
play_handle: None,
state: Arc::new(Mutex::new(PlaybackState::Stopped)),
})
}
pub fn play(&mut self) -> crate::Result<()> {
let music_play = self.player.clone().play();
self.play_handle = Some(Arc::new(Mutex::new(music_play)));
*self.state.lock() = PlaybackState::Playing;
Ok(())
}
pub fn pause(&self) -> crate::Result<()> {
if let Some(handle) = &self.play_handle {
handle.lock().pause();
*self.state.lock() = PlaybackState::Paused;
}
Ok(())
}
pub fn resume(&self) -> crate::Result<()> {
if let Some(handle) = &self.play_handle {
handle.lock().resume();
*self.state.lock() = PlaybackState::Playing;
}
Ok(())
}
pub fn seek(&self, position: Duration) -> crate::Result<()> {
if let Some(handle) = &self.play_handle {
handle.lock().seek(position)
.map_err(|e| crate::Error::SeekError(e))?;
}
Ok(())
}
pub fn set_volume(&self, volume: f32) -> crate::Result<()> {
if let Some(handle) = &self.play_handle {
handle.lock().set_volume_mut(volume);
}
Ok(())
}
pub fn volume(&self) -> f32 {
self.play_handle
.as_ref()
.map(|h| h.lock().get_volume())
.unwrap_or(1.0)
}
pub fn position(&self) -> Duration {
self.play_handle
.as_ref()
.map(|h| h.lock().get_pos())
.unwrap_or(Duration::ZERO)
}
pub fn state(&self) -> PlaybackState {
if let Some(handle) = &self.play_handle {
if handle.lock().is_empty() {
return PlaybackState::Finished;
}
}
*self.state.lock()
}
pub fn metadata(&self) -> metadata::MetaData {
self.player.metadata()
}
pub fn sample_rate(&self) -> u32 {
self.player.sample_rate()
}
pub fn channels(&self) -> u16 {
self.player.channels()
}
}
pub struct StreamPlayer {
player: Arc<Mutex<crate::play_url::UrlPlayer>>,
url: String,
}
impl StreamPlayer {
pub async fn new(url: &str, volume: f32) -> crate::Result<Self> {
let player = crate::play_url::setup_url_player(url, volume)
.await
.map_err(|e| crate::Error::NetworkError(e.to_string()))?;
Ok(Self {
player: Arc::new(Mutex::new(player)),
url: url.to_string(),
})
}
pub fn pause(&self) {
self.player.lock().pause();
}
pub fn resume(&self) {
self.player.lock().resume();
}
pub fn set_volume(&self, volume: f32) {
self.player.lock().set_volume(volume);
}
pub fn volume(&self) -> f32 {
self.player.lock().get_volume()
}
pub fn is_paused(&self) -> bool {
self.player.lock().is_paused()
}
pub fn is_finished(&self) -> bool {
self.player.lock().is_empty()
}
pub fn download_progress(&self) -> Option<f32> {
self.player.lock().get_download_progress()
}
pub fn downloaded_mb(&self) -> f64 {
self.player.lock().get_downloaded_mb()
}
}
pub enum Player {
Local(LocalPlayer),
Stream(StreamPlayer),
}
impl Player {
pub fn from_file<P: AsRef<Path>>(path: P) -> crate::Result<Self> {
Ok(Player::Local(LocalPlayer::new(path)?))
}
pub async fn from_url(url: &str, volume: f32) -> crate::Result<Self> {
Ok(Player::Stream(StreamPlayer::new(url, volume).await?))
}
pub fn play(&mut self) -> crate::Result<()> {
match self {
Player::Local(p) => p.play(),
Player::Stream(_) => Ok(()), }
}
pub fn set_volume(&self, volume: f32) -> crate::Result<()> {
match self {
Player::Local(p) => p.set_volume(volume),
Player::Stream(p) => {
p.set_volume(volume);
Ok(())
}
}
}
pub fn pause(&self) -> crate::Result<()> {
match self {
Player::Local(p) => p.pause(),
Player::Stream(p) => {
p.pause();
Ok(())
}
}
}
pub fn resume(&self) -> crate::Result<()> {
match self {
Player::Local(p) => p.resume(),
Player::Stream(p) => {
p.resume();
Ok(())
}
}
}
pub fn position(&self) -> Duration {
match self {
Player::Local(p) => p.position(),
Player::Stream(_) => Duration::ZERO, }
}
pub fn state(&self) -> PlaybackState {
match self {
Player::Local(p) => p.state(),
Player::Stream(p) => {
if p.is_finished() {
PlaybackState::Finished
} else if p.is_paused() {
PlaybackState::Paused
} else {
PlaybackState::Playing
}
}
}
}
pub async fn wait_until_finished(&self) {
loop {
if self.state() == PlaybackState::Finished {
break;
}
smol::Timer::after(Duration::from_millis(100)).await;
}
}
}