User quit handling, playlist extending

This commit is contained in:
Muaz Ahmad 2024-11-28 12:16:58 +05:00
parent 85ae8d1624
commit 35184a76b9
6 changed files with 67 additions and 6 deletions

View file

@ -8,6 +8,8 @@ use crate::utils::Error;
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct Settings { pub struct Settings {
pub subsonic: Subsonic, pub subsonic: Subsonic,
#[serde(default = "default_controls")]
pub controls: Controls,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -20,6 +22,15 @@ pub struct Subsonic {
pub random_limit: i32, pub random_limit: i32,
} }
#[derive(Deserialize)]
pub struct Controls {
pub quit: char,
}
fn default_controls() -> Controls {
Controls { quit: 'q' }
}
fn default_random_limit() -> i32 { fn default_random_limit() -> i32 {
10 10
} }

View file

@ -1,7 +1,11 @@
use std::ops::Deref;
use std::process::exit; use std::process::exit;
use std::sync::mpsc::{channel, Receiver}; use std::sync::mpsc::{channel, Receiver};
use player::errors::PlayerError;
use ssonic::response::PlayQueue;
mod audio; mod audio;
mod config; mod config;
mod player; mod player;
@ -22,6 +26,7 @@ fn init() -> Result<Receiver<utils::Error>, utils::Error> {
api_event_chan, api_event_chan,
error_in.clone(), error_in.clone(),
player_events_out, player_events_out,
player_events_in,
)?; )?;
Ok(error_out) Ok(error_out)
} }
@ -36,8 +41,20 @@ fn main() {
Ok(err_chan) => err_chan, Ok(err_chan) => err_chan,
}; };
match err_chan.recv() { match err_chan.recv() {
Err(_) => exit(0), Err(_) => {
utils::restore();
exit(0)
}
Ok(err) => { Ok(err) => {
if let Some(e) = err.downcast_ref::<PlayerError>() {
match e {
PlayerError::UserQuit => {
utils::restore();
exit(0)
}
_ => (),
}
}
utils::restore(); utils::restore();
eprintln!("{}", err); eprintln!("{}", err);
exit(1) exit(1)

View file

@ -1,6 +1,7 @@
#[derive(Debug)] #[derive(Debug)]
pub enum PlayerError { pub enum PlayerError {
PlaylistEmpty, PlaylistEmpty,
UserQuit,
} }
impl std::error::Error for PlayerError {} impl std::error::Error for PlayerError {}
@ -9,6 +10,7 @@ impl std::fmt::Display for PlayerError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::PlaylistEmpty => write!(f, "Playlist empty"), Self::PlaylistEmpty => write!(f, "Playlist empty"),
Self::UserQuit => write!(f, "User quit signalled"),
} }
} }
} }

View file

@ -17,6 +17,7 @@ use crate::{
pub enum PlayerEvent { pub enum PlayerEvent {
AddSongList(Vec<Song>), AddSongList(Vec<Song>),
UserQuit,
} }
pub struct Player { pub struct Player {
@ -26,6 +27,7 @@ pub struct Player {
api_chan: Sender<APIEvent>, api_chan: Sender<APIEvent>,
error_chan: Sender<Error>, error_chan: Sender<Error>,
player_chan: Receiver<PlayerEvent>, player_chan: Receiver<PlayerEvent>,
player_chan_in: Sender<PlayerEvent>,
playlist: playlist::Playlist, playlist: playlist::Playlist,
} }
@ -35,6 +37,7 @@ pub fn init(
api_chan: Sender<APIEvent>, api_chan: Sender<APIEvent>,
error_chan: Sender<Error>, error_chan: Sender<Error>,
player_chan: Receiver<PlayerEvent>, player_chan: Receiver<PlayerEvent>,
player_chan_in: Sender<PlayerEvent>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let terminal = ratatui::init(); let terminal = ratatui::init();
thread::spawn(move || { thread::spawn(move || {
@ -45,6 +48,7 @@ pub fn init(
api_chan, api_chan,
error_chan: error_chan.clone(), error_chan: error_chan.clone(),
player_chan, player_chan,
player_chan_in,
playlist: playlist::Playlist::new(), playlist: playlist::Playlist::new(),
}; };
match player.begin() { match player.begin() {
@ -59,6 +63,6 @@ pub fn init(
Ok(()) Ok(())
} }
mod errors; pub mod errors;
mod player; mod player;
mod playlist; mod playlist;

View file

@ -1,8 +1,10 @@
use std::{thread, time::Duration}; use std::{sync::mpsc::TryRecvError, time::Duration};
use crossterm::event::{poll, read, Event, KeyCode};
use crate::{ssonic::APIEvent, utils::Error}; use crate::{ssonic::APIEvent, utils::Error};
use super::Player; use super::{errors::PlayerError, Player, PlayerEvent};
impl Player { impl Player {
pub fn begin(&mut self) -> Result<(), Error> { pub fn begin(&mut self) -> Result<(), Error> {
@ -22,15 +24,36 @@ impl Player {
self.handle_events()?; self.handle_events()?;
self.handle_inputs()?; self.handle_inputs()?;
self.update()?; self.update()?;
thread::sleep(Duration::from_millis(100));
} }
} }
fn handle_events(&mut self) -> Result<(), Error> { fn handle_events(&mut self) -> Result<(), Error> {
loop {
let e = match self.player_chan.try_recv() {
Err(err) if err == TryRecvError::Empty => break,
Err(err) => return Err(Box::new(err)),
Ok(x) => x,
};
match e {
PlayerEvent::UserQuit => return Err(Box::new(PlayerError::UserQuit)),
PlayerEvent::AddSongList(list) => self.playlist.append(list),
_ => unimplemented!(),
}
}
Ok(()) Ok(())
} }
fn handle_inputs(&mut self) -> Result<(), Error> { fn handle_inputs(&mut self) -> Result<(), Error> {
if poll(Duration::from_millis(100))? {
match read()? {
Event::Key(e) => {
if e.code == KeyCode::Char(self.settings.controls.quit) {
self.player_chan_in.send(PlayerEvent::UserQuit)?
}
}
_ => (),
}
}
Ok(()) Ok(())
} }

View file

@ -1,4 +1,4 @@
use std::collections::VecDeque; use std::{borrow::BorrowMut, collections::VecDeque};
use crate::{ssonic::response::Song, utils::Error}; use crate::{ssonic::response::Song, utils::Error};
@ -16,6 +16,10 @@ impl Playlist {
} }
} }
pub fn append(&mut self, list: Vec<Song>) {
self.song_list.append(VecDeque::from(list).borrow_mut());
}
pub fn new() -> Playlist { pub fn new() -> Playlist {
Playlist { Playlist {
song_list: VecDeque::new(), song_list: VecDeque::new(),