use std::{ fs, io::{BufReader, Cursor}, path::Path, time::Duration, }; use rodio::{Decoder, Sink}; use crate::{database::tracks::Track, proto::player::PlayerStatus}; pub struct AudioPlayer { sink: Sink, currently_playing: Option, } impl AudioPlayer { pub fn new(sink: Sink) -> Self { sink.set_volume(0.5); Self { sink, currently_playing: None, } } pub fn play_track

(&mut self, track: Track, path: P) -> Result<(), Box> where P: AsRef, { self.sink.clear(); let file = BufReader::new(Cursor::new(fs::read(path)?)); let source = Decoder::new(file)?; self.currently_playing = Some(track); self.sink.append(source); self.sink.play(); Ok(()) } pub fn resume(&self) { self.sink.play(); } pub fn pause(&self) { self.sink.pause(); } /// Toggles the player's pause state and returns the new value pub fn toggle_pause(&self) -> bool { if self.is_paused() { self.resume(); false } else { self.pause(); true } } pub fn volume(&self) -> f32 { self.sink.volume() } pub fn set_volume(&self, value: f32) { self.sink.set_volume(value); } pub fn position(&self) -> u128 { self.sink.get_pos().as_millis() } pub fn set_position(&self, position: u64) { let _ = self.sink.try_seek(Duration::from_millis(position)); } pub fn is_paused(&self) -> bool { self.sink.is_paused() } pub fn currently_playing(&self) -> Option { self.currently_playing.clone() } pub fn get_snapshot(&self) -> StatusSnapshot { StatusSnapshot { volume: self.volume(), position: self.position(), is_paused: self.is_paused(), currently_playing: self.currently_playing(), } } } #[derive(Debug, Clone, PartialEq)] pub struct StatusSnapshot { pub volume: f32, pub position: u128, pub is_paused: bool, pub currently_playing: Option, } impl Into for StatusSnapshot { fn into(self) -> PlayerStatus { PlayerStatus { volume: self.volume, is_paused: self.is_paused, progress: self.position as u64, currently_playing: self.currently_playing.clone().map(|t| t.into()), } } }