User quit handling, playlist extending
This commit is contained in:
parent
85ae8d1624
commit
35184a76b9
6 changed files with 67 additions and 6 deletions
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
19
src/main.rs
19
src/main.rs
|
@ -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)
|
||||||
|
|
|
@ -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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
Loading…
Reference in a new issue