From 35184a76b932ec3ebdc3e4a585612e1a4d97bd1f Mon Sep 17 00:00:00 2001 From: Muaz Ahmad Date: Thu, 28 Nov 2024 12:16:58 +0500 Subject: [PATCH] User quit handling, playlist extending --- src/config/mod.rs | 11 +++++++++++ src/main.rs | 19 ++++++++++++++++++- src/player/errors.rs | 2 ++ src/player/mod.rs | 6 +++++- src/player/player.rs | 29 ++++++++++++++++++++++++++--- src/player/playlist.rs | 6 +++++- 6 files changed, 67 insertions(+), 6 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 45939e0..9686113 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -8,6 +8,8 @@ use crate::utils::Error; #[derive(Deserialize)] pub struct Settings { pub subsonic: Subsonic, + #[serde(default = "default_controls")] + pub controls: Controls, } #[derive(Deserialize)] @@ -20,6 +22,15 @@ pub struct Subsonic { pub random_limit: i32, } +#[derive(Deserialize)] +pub struct Controls { + pub quit: char, +} + +fn default_controls() -> Controls { + Controls { quit: 'q' } +} + fn default_random_limit() -> i32 { 10 } diff --git a/src/main.rs b/src/main.rs index 83a21ba..8f0eb0f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,11 @@ +use std::ops::Deref; use std::process::exit; use std::sync::mpsc::{channel, Receiver}; +use player::errors::PlayerError; +use ssonic::response::PlayQueue; + mod audio; mod config; mod player; @@ -22,6 +26,7 @@ fn init() -> Result, utils::Error> { api_event_chan, error_in.clone(), player_events_out, + player_events_in, )?; Ok(error_out) } @@ -36,8 +41,20 @@ fn main() { Ok(err_chan) => err_chan, }; match err_chan.recv() { - Err(_) => exit(0), + Err(_) => { + utils::restore(); + exit(0) + } Ok(err) => { + if let Some(e) = err.downcast_ref::() { + match e { + PlayerError::UserQuit => { + utils::restore(); + exit(0) + } + _ => (), + } + } utils::restore(); eprintln!("{}", err); exit(1) diff --git a/src/player/errors.rs b/src/player/errors.rs index 1c8fb90..63317ad 100644 --- a/src/player/errors.rs +++ b/src/player/errors.rs @@ -1,6 +1,7 @@ #[derive(Debug)] pub enum PlayerError { PlaylistEmpty, + UserQuit, } 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 { match self { Self::PlaylistEmpty => write!(f, "Playlist empty"), + Self::UserQuit => write!(f, "User quit signalled"), } } } diff --git a/src/player/mod.rs b/src/player/mod.rs index 9997289..9ed4f2a 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -17,6 +17,7 @@ use crate::{ pub enum PlayerEvent { AddSongList(Vec), + UserQuit, } pub struct Player { @@ -26,6 +27,7 @@ pub struct Player { api_chan: Sender, error_chan: Sender, player_chan: Receiver, + player_chan_in: Sender, playlist: playlist::Playlist, } @@ -35,6 +37,7 @@ pub fn init( api_chan: Sender, error_chan: Sender, player_chan: Receiver, + player_chan_in: Sender, ) -> Result<(), Error> { let terminal = ratatui::init(); thread::spawn(move || { @@ -45,6 +48,7 @@ pub fn init( api_chan, error_chan: error_chan.clone(), player_chan, + player_chan_in, playlist: playlist::Playlist::new(), }; match player.begin() { @@ -59,6 +63,6 @@ pub fn init( Ok(()) } -mod errors; +pub mod errors; mod player; mod playlist; diff --git a/src/player/player.rs b/src/player/player.rs index f606cd5..5ba72ec 100644 --- a/src/player/player.rs +++ b/src/player/player.rs @@ -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 super::Player; +use super::{errors::PlayerError, Player, PlayerEvent}; impl Player { pub fn begin(&mut self) -> Result<(), Error> { @@ -22,15 +24,36 @@ impl Player { self.handle_events()?; self.handle_inputs()?; self.update()?; - thread::sleep(Duration::from_millis(100)); } } 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(()) } 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(()) } diff --git a/src/player/playlist.rs b/src/player/playlist.rs index e1ad362..7f8577c 100644 --- a/src/player/playlist.rs +++ b/src/player/playlist.rs @@ -1,4 +1,4 @@ -use std::collections::VecDeque; +use std::{borrow::BorrowMut, collections::VecDeque}; use crate::{ssonic::response::Song, utils::Error}; @@ -16,6 +16,10 @@ impl Playlist { } } + pub fn append(&mut self, list: Vec) { + self.song_list.append(VecDeque::from(list).borrow_mut()); + } + pub fn new() -> Playlist { Playlist { song_list: VecDeque::new(),