Improve song duration reporting, change to fork of playback library with duration fix
This commit is contained in:
parent
a3a00543f4
commit
9f5f8959fc
8 changed files with 126 additions and 124 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -1898,8 +1898,6 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rodio"
|
name = "rodio"
|
||||||
version = "0.17.1"
|
version = "0.17.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bdf1d4dea18dff2e9eb6dca123724f8b60ef44ad74a9ad283cdfe025df7e73fa"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cpal",
|
"cpal",
|
||||||
"symphonia",
|
"symphonia",
|
||||||
|
|
|
@ -10,9 +10,7 @@ rust-version = "1.59"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rusqlite = { version = "0.27", features = ["bundled"], optional = true }
|
rusqlite = { version = "0.27", features = ["bundled"], optional = true }
|
||||||
sqlparser = { version = "0.23", optional = true }
|
sqlparser = { version = "0.23", optional = true }
|
||||||
symphonia = { version = "0.5", optional = true, features = [
|
symphonia = { version = "0.5", optional = true, features = ["all"] }
|
||||||
"aac", "alac", "flac", "mp3", "pcm", "vorbis", "isomp4", "ogg", "wav"
|
|
||||||
] }
|
|
||||||
dirs = { version = "4" }
|
dirs = { version = "4" }
|
||||||
regex = { version = "1" }
|
regex = { version = "1" }
|
||||||
rand = { version = "0.8" }
|
rand = { version = "0.8" }
|
||||||
|
|
|
@ -7,7 +7,7 @@ repository = "https://git.ngni.us/NGnius/muss"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rodio = { version = "^0.17", features = ["symphonia-all"], default-features = false}
|
rodio = { version = "0.17", features = ["symphonia-all"], path = "../../rodio", default-features = false}
|
||||||
m3u8-rs = { version = "^3.0" }
|
m3u8-rs = { version = "^3.0" }
|
||||||
mpd = { version = "0.1", optional = true }
|
mpd = { version = "0.1", optional = true }
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,8 @@ impl SystemControlWrapper {
|
||||||
state: std::sync::Mutex::new(
|
state: std::sync::Mutex::new(
|
||||||
State {
|
State {
|
||||||
playback_time: 0,
|
playback_time: 0,
|
||||||
duration_cache: None,
|
duration_cache: std::collections::HashMap::new(),
|
||||||
|
current_item: None,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
@ -164,7 +165,7 @@ impl SystemControlWrapper {
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_metadata(item: Item) -> Metadata {
|
fn build_metadata(item: Item, duration: Option<&std::time::Duration>) -> Metadata {
|
||||||
let file_uri = item.field("filename").and_then(|x| x.to_owned().to_str());
|
let file_uri = item.field("filename").and_then(|x| x.to_owned().to_str());
|
||||||
let cover_art = item.field("cover").and_then(|x| x.to_owned().to_str());
|
let cover_art = item.field("cover").and_then(|x| x.to_owned().to_str());
|
||||||
let cover_url = if let Some(art) = &cover_art {
|
let cover_url = if let Some(art) = &cover_art {
|
||||||
|
@ -200,7 +201,7 @@ impl SystemControlWrapper {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
Metadata {
|
Metadata {
|
||||||
length: None, // populated separately
|
length: duration.map(|duration| duration.as_secs_f64().round() as i64 * 1_000_000),
|
||||||
art_url: cover_url,
|
art_url: cover_url,
|
||||||
album: item.field("album").and_then(|x| x.to_owned().to_str()),
|
album: item.field("album").and_then(|x| x.to_owned().to_str()),
|
||||||
album_artist: item
|
album_artist: item
|
||||||
|
@ -232,10 +233,10 @@ impl SystemControlWrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enqueued(item: Item, dbus_ctrl: &Sender<DbusControl>) {
|
fn enqueued(item: Item, dbus_ctrl: &Sender<DbusControl>, duration: Option<&std::time::Duration>) {
|
||||||
//println!("Got enqueued item {}", &item.title);
|
//println!("Got enqueued item {}", &item.title);
|
||||||
dbus_ctrl
|
dbus_ctrl
|
||||||
.send(DbusControl::SetMetadata(Self::build_metadata(item)))
|
.send(DbusControl::SetMetadata(Self::build_metadata(item, duration)))
|
||||||
.unwrap_or(());
|
.unwrap_or(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,16 +258,15 @@ impl SystemControlWrapper {
|
||||||
.unwrap_or(());
|
.unwrap_or(());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn time(item: Item, duration: std::time::Duration, dbus_ctrl: &Sender<DbusControl>) {
|
fn time(item: Item, duration: &std::time::Duration, dbus_ctrl: &Sender<DbusControl>) {
|
||||||
let mut meta = Self::build_metadata(item);
|
let meta = Self::build_metadata(item, Some(duration));
|
||||||
meta.length = Some(duration.as_secs_f64().round() as i64 * 1_000_000);
|
|
||||||
dbus_ctrl.send(DbusControl::SetMetadata(meta)).unwrap_or(());
|
dbus_ctrl.send(DbusControl::SetMetadata(meta)).unwrap_or(());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn time_update(
|
fn time_update(
|
||||||
_item: Item,
|
_item: Item,
|
||||||
new_time: i64,
|
new_time: i64,
|
||||||
duration: &Option<std::time::Duration>,
|
duration: Option<&std::time::Duration>,
|
||||||
dbus_ctrl: &Sender<DbusControl>,
|
dbus_ctrl: &Sender<DbusControl>,
|
||||||
) {
|
) {
|
||||||
//println!("Position update tick");
|
//println!("Position update tick");
|
||||||
|
@ -286,7 +286,8 @@ impl SystemControlWrapper {
|
||||||
#[cfg(all(target_os = "linux", feature = "os-controls", feature = "mpris-player"))]
|
#[cfg(all(target_os = "linux", feature = "os-controls", feature = "mpris-player"))]
|
||||||
struct State {
|
struct State {
|
||||||
playback_time: i64,
|
playback_time: i64,
|
||||||
duration_cache: Option<std::time::Duration>,
|
duration_cache: std::collections::HashMap<Item, std::time::Duration>,
|
||||||
|
current_item: Option<Item>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(target_os = "linux", feature = "os-controls", feature = "mpris-player"))]
|
#[cfg(all(target_os = "linux", feature = "os-controls", feature = "mpris-player"))]
|
||||||
|
@ -299,24 +300,29 @@ impl super::EventTap for SystemControlWrapper {
|
||||||
PlaybackAction::Enqueued(item) => {
|
PlaybackAction::Enqueued(item) => {
|
||||||
let mut state = self.state.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
state.playback_time = 0;
|
state.playback_time = 0;
|
||||||
state.duration_cache = None;
|
state.current_item = Some(item.to_owned());
|
||||||
Self::enqueued(item.to_owned(), self.dbus_ctrl.as_ref().unwrap());
|
Self::enqueued(item.to_owned(), self.dbus_ctrl.as_ref().unwrap(), state.duration_cache.get(item));
|
||||||
|
},
|
||||||
|
PlaybackAction::Empty => {
|
||||||
|
Self::empty(self.dbus_ctrl.as_ref().unwrap());
|
||||||
|
let mut state = self.state.lock().unwrap();
|
||||||
|
state.playback_time = 0;
|
||||||
|
state.current_item = None;
|
||||||
},
|
},
|
||||||
PlaybackAction::Empty => Self::empty(self.dbus_ctrl.as_ref().unwrap()),
|
|
||||||
PlaybackAction::Time(item, duration) => {
|
PlaybackAction::Time(item, duration) => {
|
||||||
let mut state = self.state.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
state.duration_cache = Some(duration.to_owned());
|
state.duration_cache.insert(item.to_owned(), duration.to_owned());
|
||||||
Self::time(item.to_owned(), duration.to_owned(), self.dbus_ctrl.as_ref().unwrap());
|
Self::time(item.to_owned(), duration, self.dbus_ctrl.as_ref().unwrap());
|
||||||
}
|
}
|
||||||
PlaybackAction::UpdateTick(item) => {
|
PlaybackAction::UpdateTick(item, tick) => {
|
||||||
let mut state = self.state.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
|
state.playback_time = *tick as i64;
|
||||||
Self::time_update(
|
Self::time_update(
|
||||||
item.to_owned(),
|
item.to_owned(),
|
||||||
state.playback_time,
|
state.playback_time,
|
||||||
&state.duration_cache,
|
state.duration_cache.get(item),
|
||||||
self.dbus_ctrl.as_ref().unwrap(),
|
self.dbus_ctrl.as_ref().unwrap(),
|
||||||
);
|
);
|
||||||
state.playback_time += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
|
|
@ -47,7 +47,9 @@ impl<I: std::iter::Iterator<Item = Result<Item, InterpreterError>>> PlayerServer
|
||||||
let event = std::sync::Arc::new(std::sync::Mutex::new(self.playback.clone()));
|
let event = std::sync::Arc::new(std::sync::Mutex::new(self.playback.clone()));
|
||||||
move |source_in, item| {
|
move |source_in, item| {
|
||||||
let event2 = event.clone();
|
let event2 = event.clone();
|
||||||
|
let mut update_tick_num = 0;
|
||||||
if let Some(duration) = source_in.total_duration() {
|
if let Some(duration) = source_in.total_duration() {
|
||||||
|
//println!("Got duration {:?}", duration);
|
||||||
event
|
event
|
||||||
.lock()
|
.lock()
|
||||||
.map(|event| {
|
.map(|event| {
|
||||||
|
@ -62,8 +64,9 @@ impl<I: std::iter::Iterator<Item = Result<Item, InterpreterError>>> PlayerServer
|
||||||
event2
|
event2
|
||||||
.lock()
|
.lock()
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
x.send(PlaybackAction::UpdateTick(item.clone()))
|
x.send(PlaybackAction::UpdateTick(item.clone(), update_tick_num))
|
||||||
.unwrap_or(())
|
.unwrap_or(());
|
||||||
|
update_tick_num += 1;
|
||||||
})
|
})
|
||||||
.unwrap_or(());
|
.unwrap_or(());
|
||||||
}),
|
}),
|
||||||
|
@ -96,8 +99,9 @@ impl<I: std::iter::Iterator<Item = Result<Item, InterpreterError>>> PlayerServer
|
||||||
event2
|
event2
|
||||||
.lock()
|
.lock()
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
x.send(PlaybackAction::UpdateTick(item.clone()))
|
x.send(PlaybackAction::UpdateTick(item.clone(), update_tick_num))
|
||||||
.unwrap_or(())
|
.unwrap_or(());
|
||||||
|
update_tick_num += 1;
|
||||||
})
|
})
|
||||||
.unwrap_or(());
|
.unwrap_or(());
|
||||||
}),
|
}),
|
||||||
|
@ -316,7 +320,7 @@ pub enum PlaybackAction {
|
||||||
Empty,
|
Empty,
|
||||||
Enqueued(Item),
|
Enqueued(Item),
|
||||||
Time(Item, std::time::Duration),
|
Time(Item, std::time::Duration),
|
||||||
UpdateTick(Item), // tick sent once every second
|
UpdateTick(Item, u64), // tick sent once every second
|
||||||
Exit,
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,26 +3,46 @@ use muss_interpreter::Item;
|
||||||
use muss_player::EventTap;
|
use muss_player::EventTap;
|
||||||
use muss_player::{PlaybackAction, PlayerAction, ControlAction};
|
use muss_player::{PlaybackAction, PlayerAction, ControlAction};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct InterpreterDebugState {
|
||||||
|
pub debug_flag: InterpreterDebugFlag,
|
||||||
|
pub verbose: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum InterpreterDebugFlag {
|
||||||
|
Skip,
|
||||||
|
List,
|
||||||
|
Normal,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct DebugState {
|
pub struct DebugState {
|
||||||
pub now_playing: Option<Item>,
|
pub now_playing: std::sync::Arc<std::sync::RwLock<Option<Item>>>,
|
||||||
pub control_tx: Option<std::sync::Mutex<std::sync::mpsc::Sender<ControlAction>>>,
|
pub control_tx: std::sync::Arc<std::sync::Mutex<Option<std::sync::mpsc::Sender<ControlAction>>>>,
|
||||||
|
pub interpreter: std::sync::Arc<std::sync::RwLock<InterpreterDebugState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugState {
|
impl DebugState {
|
||||||
pub fn new() -> std::sync::Arc<std::sync::RwLock<Self>> {
|
pub fn new() -> Self {
|
||||||
std::sync::Arc::new(std::sync::RwLock::new(Self {
|
Self {
|
||||||
now_playing: None,
|
now_playing: std::sync::Arc::new(std::sync::RwLock::new(None)),
|
||||||
control_tx: None,
|
control_tx: std::sync::Arc::new(std::sync::Mutex::new(None)),
|
||||||
}))
|
interpreter: std::sync::Arc::new(std::sync::RwLock::new(InterpreterDebugState {
|
||||||
|
debug_flag: InterpreterDebugFlag::Normal,
|
||||||
|
verbose: false,
|
||||||
|
})),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DebugEventHandler {
|
pub struct DebugEventHandler {
|
||||||
state: std::sync::Arc<std::sync::RwLock<DebugState>>,
|
state: DebugState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugEventHandler {
|
impl DebugEventHandler {
|
||||||
pub fn new(debug_state: std::sync::Arc<std::sync::RwLock<DebugState>>) -> Self {
|
pub fn new(debug_state: DebugState) -> Self {
|
||||||
Self {
|
Self {
|
||||||
state: debug_state,
|
state: debug_state,
|
||||||
}
|
}
|
||||||
|
@ -33,15 +53,15 @@ impl EventTap for DebugEventHandler {
|
||||||
fn on_playback(&self, playback: &PlaybackAction) -> Option<ControlAction> {
|
fn on_playback(&self, playback: &PlaybackAction) -> Option<ControlAction> {
|
||||||
match playback {
|
match playback {
|
||||||
PlaybackAction::Enqueued(item) => {
|
PlaybackAction::Enqueued(item) => {
|
||||||
let mut state = self.state.write().unwrap();
|
let mut now_playing = self.state.now_playing.write().unwrap();
|
||||||
state.now_playing = Some(item.to_owned());
|
*now_playing = Some(item.to_owned());
|
||||||
},
|
},
|
||||||
PlaybackAction::Empty | PlaybackAction::Exit => {
|
PlaybackAction::Empty | PlaybackAction::Exit => {
|
||||||
let mut state = self.state.write().unwrap();
|
let mut now_playing = self.state.now_playing.write().unwrap();
|
||||||
state.now_playing = None;
|
*now_playing = None;
|
||||||
},
|
},
|
||||||
PlaybackAction::Time(_item, _dur) => {},
|
PlaybackAction::Time(_item, _dur) => {},
|
||||||
PlaybackAction::UpdateTick(_item) => {},
|
PlaybackAction::UpdateTick(_item, _tick) => {},
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -51,6 +71,6 @@ impl EventTap for DebugEventHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_control(&mut self, control: &std::sync::mpsc::Sender<ControlAction>) {
|
fn init_control(&mut self, control: &std::sync::mpsc::Sender<ControlAction>) {
|
||||||
self.state.write().expect("Failed to get write lock on controller debug state").control_tx = Some(std::sync::Mutex::new(control.clone()));
|
*self.state.control_tx.lock().expect("Failed to get write lock on controller debug state") = Some(control.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,6 @@ fn music_filename(item: &Item) -> Option<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_current_item(state: &mut ReplState) -> Option<muss_interpreter::Item> {
|
pub fn get_current_item(state: &mut ReplState) -> Option<muss_interpreter::Item> {
|
||||||
let data = state.controller_debug.read().expect("Failed to get read lock for debug player data");
|
let now_playing = state.controller_debug.now_playing.read().expect("Failed to get read lock for debug now_playing data");
|
||||||
data.now_playing.clone()
|
now_playing.clone()
|
||||||
}
|
}
|
||||||
|
|
124
src/repl.rs
124
src/repl.rs
|
@ -2,9 +2,6 @@
|
||||||
#![allow(clippy::single_match)]
|
#![allow(clippy::single_match)]
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::sync::mpsc::{self, Receiver};
|
use std::sync::mpsc::{self, Receiver};
|
||||||
use std::sync::RwLock;
|
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
|
|
||||||
use console::{Key, Term};
|
use console::{Key, Term};
|
||||||
|
|
||||||
|
@ -15,13 +12,6 @@ use muss_player::{Controller, Player};
|
||||||
use super::channel_io::{channel_io, ChannelWriter};
|
use super::channel_io::{channel_io, ChannelWriter};
|
||||||
use super::cli::CliArgs;
|
use super::cli::CliArgs;
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref DEBUG_STATE: RwLock<DebugState> = RwLock::new(DebugState {
|
|
||||||
debug_flag: DebugFlag::Normal,
|
|
||||||
verbose: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const TERMINAL_WRITE_ERROR: &str = "Failed to write to terminal output";
|
pub const TERMINAL_WRITE_ERROR: &str = "Failed to write to terminal output";
|
||||||
const INTERPRETER_WRITE_ERROR: &str = "Failed to write to interpreter";
|
const INTERPRETER_WRITE_ERROR: &str = "Failed to write to interpreter";
|
||||||
|
|
||||||
|
@ -41,20 +31,7 @@ pub struct ReplState {
|
||||||
cursor_rightward_position: usize,
|
cursor_rightward_position: usize,
|
||||||
//debug: Arc<RwLock<DebugState>>,
|
//debug: Arc<RwLock<DebugState>>,
|
||||||
list_rx: Receiver<DebugItem>,
|
list_rx: Receiver<DebugItem>,
|
||||||
pub controller_debug: std::sync::Arc<std::sync::RwLock<crate::debug_state::DebugState>>,
|
pub controller_debug: crate::debug_state::DebugState,
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct DebugState {
|
|
||||||
debug_flag: DebugFlag,
|
|
||||||
verbose: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
enum DebugFlag {
|
|
||||||
Skip,
|
|
||||||
List,
|
|
||||||
Normal,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReplState {
|
impl ReplState {
|
||||||
|
@ -80,20 +57,23 @@ impl ReplState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interpreter_event_callback<T: muss_interpreter::tokens::TokenReader>(
|
fn interpreter_event_callback<'a, T: muss_interpreter::tokens::TokenReader>(
|
||||||
_interpreter: &mut Interpreter<'_, T>,
|
debug_state: crate::debug_state::DebugState,
|
||||||
event: InterpreterEvent,
|
) -> impl Fn(
|
||||||
|
&mut Interpreter<'a, T>, InterpreterEvent,
|
||||||
) -> Result<(), InterpreterError> {
|
) -> Result<(), InterpreterError> {
|
||||||
|
move |_interpreter, event| {
|
||||||
match event {
|
match event {
|
||||||
InterpreterEvent::StatementComplete => {
|
InterpreterEvent::StatementComplete => {
|
||||||
if let Ok(mut d_state) = DEBUG_STATE.write() {
|
if let Ok(mut d_state) = debug_state.interpreter.write() {
|
||||||
d_state.debug_flag = DebugFlag::Normal;
|
d_state.debug_flag = crate::debug_state::InterpreterDebugFlag::Normal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn item_prompt(terminal: &mut Term, args: &CliArgs) {
|
fn item_prompt(terminal: &mut Term, args: &CliArgs) {
|
||||||
|
@ -148,7 +128,7 @@ fn pretty_print_item(item: &Item, terminal: &mut Term, args: &CliArgs, verbose:
|
||||||
|
|
||||||
fn handle_list_rx(state: &mut ReplState, args: &CliArgs) {
|
fn handle_list_rx(state: &mut ReplState, args: &CliArgs) {
|
||||||
//let items = state.list_rx.try_iter().collect::<Vec<_>>();
|
//let items = state.list_rx.try_iter().collect::<Vec<_>>();
|
||||||
let d_state = DEBUG_STATE
|
let d_state = state.controller_debug.interpreter
|
||||||
.read()
|
.read()
|
||||||
.expect("Failed to get read lock for debug state info")
|
.expect("Failed to get read lock for debug state info")
|
||||||
.clone();
|
.clone();
|
||||||
|
@ -162,12 +142,14 @@ fn handle_list_rx(state: &mut ReplState, args: &CliArgs) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let flag = d_state.debug_flag;
|
let flag = d_state.debug_flag;
|
||||||
|
drop(d_state);
|
||||||
match flag {
|
match flag {
|
||||||
DebugFlag::List => {
|
crate::debug_state::InterpreterDebugFlag::List => {
|
||||||
while let Ok(item) = state.list_rx.recv() {
|
while let Ok(item) = state.list_rx.recv() {
|
||||||
match item {
|
match item {
|
||||||
Ok(item) => {
|
Ok(item) => {
|
||||||
pretty_print_item(&item, &mut state.terminal, args, d_state.verbose)
|
let verbose = state.controller_debug.interpreter.read().map(|x| x.verbose).unwrap_or(false);
|
||||||
|
pretty_print_item(&item, &mut state.terminal, args, verbose)
|
||||||
}
|
}
|
||||||
Err(e) => error_prompt(
|
Err(e) => error_prompt(
|
||||||
muss_player::PlayerError::Playback(muss_player::PlaybackError::from_err(e)),
|
muss_player::PlayerError::Playback(muss_player::PlaybackError::from_err(e)),
|
||||||
|
@ -175,13 +157,13 @@ fn handle_list_rx(state: &mut ReplState, args: &CliArgs) {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
// stop listing if no longer in list mode
|
// stop listing if no longer in list mode
|
||||||
let flag = if let Ok(d_state) = DEBUG_STATE.read() {
|
let flag = if let Ok(d_state) = state.controller_debug.interpreter.read() {
|
||||||
d_state.debug_flag
|
d_state.debug_flag
|
||||||
} else {
|
} else {
|
||||||
DebugFlag::Normal
|
crate::debug_state::InterpreterDebugFlag::Normal
|
||||||
};
|
};
|
||||||
match flag {
|
match flag {
|
||||||
DebugFlag::List => {}
|
crate::debug_state::InterpreterDebugFlag::List => {}
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,23 +195,27 @@ pub fn repl(args: CliArgs) {
|
||||||
};
|
};
|
||||||
let (list_tx, list_rx) = mpsc::channel();
|
let (list_tx, list_rx) = mpsc::channel();
|
||||||
let mut state = ReplState::new(writer, term, list_rx);
|
let mut state = ReplState::new(writer, term, list_rx);
|
||||||
|
let controller_debug_clone = state.controller_debug.clone();
|
||||||
let player_builder = move || {
|
let player_builder = move || {
|
||||||
let runner = Interpreter::with_stream_and_callback(reader, &interpreter_event_callback);
|
let callback_handler = Box::new(interpreter_event_callback(controller_debug_clone.clone()));
|
||||||
|
// FIXME don't leak memory for callback handler
|
||||||
|
// (this is fine since it'll only get called once, it just looks bad)
|
||||||
|
let runner = Interpreter::with_stream_and_callback(reader, Box::leak(callback_handler));
|
||||||
let debugger = Debugger::new(runner, move |interpretor, item| {
|
let debugger = Debugger::new(runner, move |interpretor, item| {
|
||||||
let flag = if let Ok(d_state) = DEBUG_STATE.read() {
|
let flag = if let Ok(d_state) = controller_debug_clone.interpreter.read() {
|
||||||
d_state.debug_flag
|
d_state.debug_flag
|
||||||
} else {
|
} else {
|
||||||
DebugFlag::Normal
|
crate::debug_state::InterpreterDebugFlag::Normal
|
||||||
};
|
};
|
||||||
match flag {
|
match flag {
|
||||||
DebugFlag::Normal => item,
|
crate::debug_state::InterpreterDebugFlag::Normal => item,
|
||||||
DebugFlag::Skip => {
|
crate::debug_state::InterpreterDebugFlag::Skip => {
|
||||||
for _ in interpretor.by_ref() {
|
for _ in interpretor.by_ref() {
|
||||||
// NOTE: recursion occurs here
|
// NOTE: recursion occurs here
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
DebugFlag::List => {
|
crate::debug_state::InterpreterDebugFlag::List => {
|
||||||
if let Some(x) = item {
|
if let Some(x) = item {
|
||||||
list_tx.send(x.map_err(|e| e.to_string())).unwrap_or(());
|
list_tx.send(x.map_err(|e| e.to_string())).unwrap_or(());
|
||||||
for x in interpretor.by_ref() {
|
for x in interpretor.by_ref() {
|
||||||
|
@ -713,34 +699,34 @@ fn repl_commands(command_str: &str, state: &mut ReplState, args: &CliArgs) {
|
||||||
}
|
}
|
||||||
"?list" => {
|
"?list" => {
|
||||||
{
|
{
|
||||||
let mut debug_state = DEBUG_STATE
|
let mut debug_state = state.controller_debug.interpreter
|
||||||
.write()
|
.write()
|
||||||
.expect("Failed to get write lock for debug state");
|
.expect("Failed to get write lock for debug state");
|
||||||
debug_state.debug_flag = DebugFlag::List;
|
debug_state.debug_flag = crate::debug_state::InterpreterDebugFlag::List;
|
||||||
}
|
}
|
||||||
writeln!(state.terminal, "Listing upcoming items").expect(TERMINAL_WRITE_ERROR);
|
writeln!(state.terminal, "Listing upcoming items").expect(TERMINAL_WRITE_ERROR);
|
||||||
}
|
}
|
||||||
"?skip" => {
|
"?skip" => {
|
||||||
{
|
{
|
||||||
let mut debug_state = DEBUG_STATE
|
let mut debug_state = state.controller_debug.interpreter
|
||||||
.write()
|
.write()
|
||||||
.expect("Failed to get write lock for debug state");
|
.expect("Failed to get write lock for debug state");
|
||||||
debug_state.debug_flag = DebugFlag::Skip;
|
debug_state.debug_flag = crate::debug_state::InterpreterDebugFlag::Skip;
|
||||||
}
|
}
|
||||||
writeln!(state.terminal, "Skipping upcoming items").expect(TERMINAL_WRITE_ERROR);
|
writeln!(state.terminal, "Skipping upcoming items").expect(TERMINAL_WRITE_ERROR);
|
||||||
}
|
}
|
||||||
"?normal" => {
|
"?normal" => {
|
||||||
{
|
{
|
||||||
let mut debug_state = DEBUG_STATE
|
let mut debug_state = state.controller_debug.interpreter
|
||||||
.write()
|
.write()
|
||||||
.expect("Failed to get write lock for debug state");
|
.expect("Failed to get write lock for debug state");
|
||||||
debug_state.debug_flag = DebugFlag::Normal;
|
debug_state.debug_flag = crate::debug_state::InterpreterDebugFlag::Normal;
|
||||||
}
|
}
|
||||||
writeln!(state.terminal, "Resuming normal operation").expect(TERMINAL_WRITE_ERROR);
|
writeln!(state.terminal, "Resuming normal operation").expect(TERMINAL_WRITE_ERROR);
|
||||||
}
|
}
|
||||||
"?verbose" => {
|
"?verbose" => {
|
||||||
let verbose = {
|
let verbose = {
|
||||||
let mut debug_state = DEBUG_STATE
|
let mut debug_state = state.controller_debug.interpreter
|
||||||
.write()
|
.write()
|
||||||
.expect("Failed to get write lock for debug state");
|
.expect("Failed to get write lock for debug state");
|
||||||
debug_state.verbose = !debug_state.verbose;
|
debug_state.verbose = !debug_state.verbose;
|
||||||
|
@ -754,7 +740,7 @@ fn repl_commands(command_str: &str, state: &mut ReplState, args: &CliArgs) {
|
||||||
}
|
}
|
||||||
"?now" => {
|
"?now" => {
|
||||||
if let Some(item) = crate::playlists::get_current_item(state) {
|
if let Some(item) = crate::playlists::get_current_item(state) {
|
||||||
let verbose = DEBUG_STATE
|
let verbose = state.controller_debug.interpreter
|
||||||
.read()
|
.read()
|
||||||
.expect("Failed to get read lock for debug state")
|
.expect("Failed to get read lock for debug state")
|
||||||
.verbose;
|
.verbose;
|
||||||
|
@ -764,46 +750,38 @@ fn repl_commands(command_str: &str, state: &mut ReplState, args: &CliArgs) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"?next" => {
|
"?next" => {
|
||||||
state.controller_debug
|
state.controller_debug.control_tx
|
||||||
.read()
|
|
||||||
.expect("Failed to get read lock for debug player data")
|
|
||||||
.control_tx.as_ref()
|
|
||||||
.expect("Control action sender shouldn't be None")
|
|
||||||
.lock()
|
.lock()
|
||||||
.expect("Failed to get lock for control action sender")
|
.expect("Failed to get lock for control action sender")
|
||||||
|
.as_ref()
|
||||||
|
.expect("Control action sender shouldn't be None")
|
||||||
.send(muss_player::ControlAction::Next { ack: false })
|
.send(muss_player::ControlAction::Next { ack: false })
|
||||||
.expect("Failed to send control action");
|
.expect("Failed to send control action");
|
||||||
},
|
},
|
||||||
"?previous" => {
|
"?previous" => {
|
||||||
state.controller_debug
|
state.controller_debug.control_tx
|
||||||
.read()
|
|
||||||
.expect("Failed to get read lock for debug player data")
|
|
||||||
.control_tx.as_ref()
|
|
||||||
.expect("Control action sender shouldn't be None")
|
|
||||||
.lock()
|
.lock()
|
||||||
.expect("Failed to get lock for control action sender")
|
.expect("Failed to get lock for control action sender")
|
||||||
|
.as_ref()
|
||||||
|
.expect("Control action sender shouldn't be None")
|
||||||
.send(muss_player::ControlAction::Previous { ack: false })
|
.send(muss_player::ControlAction::Previous { ack: false })
|
||||||
.expect("Failed to send control action");
|
.expect("Failed to send control action");
|
||||||
},
|
},
|
||||||
"?pause" => {
|
"?pause" => {
|
||||||
state.controller_debug
|
state.controller_debug.control_tx
|
||||||
.read()
|
|
||||||
.expect("Failed to get read lock for debug player data")
|
|
||||||
.control_tx.as_ref()
|
|
||||||
.expect("Control action sender shouldn't be None")
|
|
||||||
.lock()
|
.lock()
|
||||||
.expect("Failed to get lock for control action sender")
|
.expect("Failed to get lock for control action sender")
|
||||||
|
.as_ref()
|
||||||
|
.expect("Control action sender shouldn't be None")
|
||||||
.send(muss_player::ControlAction::Pause { ack: false })
|
.send(muss_player::ControlAction::Pause { ack: false })
|
||||||
.expect("Failed to send control action");
|
.expect("Failed to send control action");
|
||||||
}
|
}
|
||||||
"?play" => {
|
"?play" => {
|
||||||
state.controller_debug
|
state.controller_debug.control_tx
|
||||||
.read()
|
|
||||||
.expect("Failed to get read lock for debug player data")
|
|
||||||
.control_tx.as_ref()
|
|
||||||
.expect("Control action sender shouldn't be None")
|
|
||||||
.lock()
|
.lock()
|
||||||
.expect("Failed to get lock for control action sender")
|
.expect("Failed to get lock for control action sender")
|
||||||
|
.as_ref()
|
||||||
|
.expect("Control action sender shouldn't be None")
|
||||||
.send(muss_player::ControlAction::Play { ack: false })
|
.send(muss_player::ControlAction::Play { ack: false })
|
||||||
.expect("Failed to send control action");
|
.expect("Failed to send control action");
|
||||||
}
|
}
|
||||||
|
@ -817,13 +795,11 @@ fn volume_cmd(cmd_args: &[&str], state: &mut ReplState) {
|
||||||
if let Some(volume_arg) = cmd_args.get(1) {
|
if let Some(volume_arg) = cmd_args.get(1) {
|
||||||
let volume_result: Result<f32, _> = volume_arg.parse();
|
let volume_result: Result<f32, _> = volume_arg.parse();
|
||||||
match volume_result {
|
match volume_result {
|
||||||
Ok(vol) => state.controller_debug
|
Ok(vol) => state.controller_debug.control_tx
|
||||||
.read()
|
|
||||||
.expect("Failed to get read lock for debug player data")
|
|
||||||
.control_tx.as_ref()
|
|
||||||
.expect("Control action sender shouldn't be None")
|
|
||||||
.lock()
|
.lock()
|
||||||
.expect("Failed to get lock for control action sender")
|
.expect("Failed to get lock for control action sender")
|
||||||
|
.as_ref()
|
||||||
|
.expect("Control action sender shouldn't be None")
|
||||||
.send(muss_player::ControlAction::SetVolume { ack: false, volume: (vol * 100.0).round() as _ })
|
.send(muss_player::ControlAction::SetVolume { ack: false, volume: (vol * 100.0).round() as _ })
|
||||||
.expect("Failed to send control action"),
|
.expect("Failed to send control action"),
|
||||||
Err(e) => writeln!(state.terminal, "Error parsing ?volume number parameter: {}", e).expect(TERMINAL_WRITE_ERROR)
|
Err(e) => writeln!(state.terminal, "Error parsing ?volume number parameter: {}", e).expect(TERMINAL_WRITE_ERROR)
|
||||||
|
|
Loading…
Reference in a new issue