Handle cbd-tui results

This commit is contained in:
chmanie 2023-06-12 12:06:38 +02:00
parent 0c66165598
commit 1433ae9e7f
10 changed files with 76 additions and 39 deletions

1
Cargo.lock generated
View File

@ -384,6 +384,7 @@ dependencies = [
"tokio",
"tokio-stream",
"tonic",
"tracing",
]
[[package]]

View File

@ -1,11 +1,11 @@
use flume::Sender;
use std::path::Path;
use std::sync::atomic::AtomicU64;
use std::thread;
use std::time::Duration;
use std::{fs::File, sync::atomic::Ordering};
use symphonia::core::probe::Hint;
use tracing::{debug, warn};
use tracing::{warn};
use url::Url;
use crate::decoder::{MediaInfo, SymphoniaDecoder};

View File

@ -15,3 +15,4 @@ tokio-stream = "0.1"
tonic = "0.9"
notify-rust = "4.8.0"
serde = "1.0.164"
tracing = "0.1.37"

View File

@ -11,6 +11,7 @@ use ratatui::{
},
Frame,
};
use tracing::error;
use crabidy_core::proto::crabidy::LibraryNode;
@ -57,15 +58,21 @@ impl Library {
}
pub fn ascend(&mut self) {
if let Some(parent) = self.parent.as_ref() {
self.tx.send(MessageFromUi::GetLibraryNode(parent.clone()));
if let Err(err) = self.tx.send(MessageFromUi::GetLibraryNode(parent.clone())) {
error!("Send error: {}", err);
}
}
}
pub fn dive(&mut self) {
if let Some(idx) = self.list_state.selected() {
let item = &self.list[idx];
if let UiItemKind::Node = item.kind {
self.tx
.send(MessageFromUi::GetLibraryNode(item.uuid.clone()));
if let Err(err) = self
.tx
.send(MessageFromUi::GetLibraryNode(item.uuid.clone()))
{
error!("Send error: {}", err);
}
}
}
}
@ -73,7 +80,7 @@ impl Library {
if let Some(items) = self.get_selected() {
match self.tx.send(MessageFromUi::AppendTracks(items)) {
Ok(_) => self.remove_marks(),
Err(_) => { /* FIXME: warn */ }
Err(err) => error!("Send error: {}", err),
}
}
}
@ -81,7 +88,7 @@ impl Library {
if let Some(items) = self.get_selected() {
match self.tx.send(MessageFromUi::QueueTracks(items)) {
Ok(_) => self.remove_marks(),
Err(_) => { /* FIXME: warn */ }
Err(err) => error!("Send error: {}", err),
}
}
}
@ -89,7 +96,7 @@ impl Library {
if let Some(items) = self.get_selected() {
match self.tx.send(MessageFromUi::ReplaceQueue(items)) {
Ok(_) => self.remove_marks(),
Err(_) => { /* FIXME: warn */ }
Err(err) => error!("Send error: {}", err),
}
}
}
@ -97,7 +104,7 @@ impl Library {
if let Some(items) = self.get_selected() {
match self.tx.send(MessageFromUi::InsertTracks(items, pos)) {
Ok(_) => self.remove_marks(),
Err(_) => { /* FIXME: warn */ }
Err(err) => error!("Send error: {}", err),
}
}
}

View File

@ -117,7 +117,7 @@ impl App {
let main = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
.split(f.size());
.split(full_screen);
self.library.render(f, main[0], library_focused);

View File

@ -47,10 +47,14 @@ impl NowPlaying {
}
pub fn update_track(&mut self, active: Option<Track>) {
if let Some(track) = &active {
let body = if let Some(ref album) = track.album {
format!("{} by {} ({})", track.title, track.artist, album.title)
} else {
format!("{} by {}", track.title, track.artist)
};
Notification::new()
.summary("Crabidy playing")
// FIXME: album
.body(&format!("{} by {}", track.title, track.artist))
.summary("Playing")
.body(&body)
.show()
.unwrap();
}
@ -118,7 +122,7 @@ impl NowPlaying {
f.render_widget(media_info_p, now_playing_layout[0]);
if let (Some(position), Some(duration), Some(track)) =
if let (Some(position), Some(duration), Some(_track)) =
(self.position, self.duration, &self.track)
{
let pos = position.as_secs();

View File

@ -9,6 +9,7 @@ use ratatui::{
},
Frame,
};
use tracing::error;
use crabidy_core::proto::crabidy::Queue as QueueData;
@ -33,20 +34,28 @@ impl Queue {
}
}
pub fn play_next(&self) {
self.tx.send(MessageFromUi::NextTrack);
if let Err(err) = self.tx.send(MessageFromUi::NextTrack) {
error!("Send error: {}", err);
}
}
pub fn play_prev(&self) {
self.tx.send(MessageFromUi::PrevTrack);
if let Err(err) = self.tx.send(MessageFromUi::PrevTrack) {
error!("Send error: {}", err);
}
}
pub fn play_selected(&self) {
if let Some(pos) = self.selected() {
self.tx.send(MessageFromUi::SetCurrentTrack(pos));
if let Err(err) = self.tx.send(MessageFromUi::SetCurrentTrack(pos)) {
error!("Send error: {}", err);
}
}
}
pub fn remove_track(&mut self) {
if let Some(pos) = self.selected() {
// FIXME: mark multiple tracks on queue and remove them
self.tx.send(MessageFromUi::RemoveTracks(vec![pos]));
if let Err(err) = self.tx.send(MessageFromUi::RemoveTracks(vec![pos])) {
error!("Send error: {}", err);
}
}
}
pub fn update_position(&mut self, pos: usize) {
@ -57,10 +66,9 @@ impl Queue {
self.list = queue
.tracks
.iter()
.enumerate()
.map(|(i, t)| UiItem {
uuid: t.uuid.clone(),
title: format!("{} - {}", t.artist, t.title),
.map(|track| UiItem {
uuid: track.uuid.clone(),
title: format!("{} - {}", track.artist, track.title),
kind: UiItemKind::Track,
marked: false,
is_queable: false,

View File

@ -36,6 +36,7 @@ use ratatui::{backend::CrosstermBackend, Terminal};
use tokio::{fs, select, signal, task};
use tokio_stream::StreamExt;
use tonic::{transport::Channel, Request, Status, Streaming};
use tracing::error;
use app::{App, MessageFromUi, MessageToUi, StatefulList, UiFocus};
use config::Config;
@ -44,6 +45,7 @@ use rpc::RpcClient;
static CONFIG: OnceLock<Config> = OnceLock::new();
#[tokio::main]
// FIXME: use anyhow, thiserror
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = CONFIG.get_or_init(|| crabidy_core::init_config("cbd-tui.toml"));
@ -51,12 +53,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let (tx, ui_rx): (Sender<MessageToUi>, Receiver<MessageToUi>) = flume::unbounded();
// FIXME: unwrap
tokio::spawn(async move { orchestrate(config, (tx, rx)).await.unwrap() });
tokio::spawn(async move { orchestrate(config, (tx, rx)).await.unwrap() }).await?;
tokio::task::spawn_blocking(|| {
run_ui(ui_tx, ui_rx);
})
.await;
.await?;
Ok(())
}
@ -68,14 +70,16 @@ async fn orchestrate<'a>(
let mut rpc_client = rpc::RpcClient::connect(&config.server.address).await?;
if let Some(root_node) = rpc_client.get_library_node("node:/").await? {
tx.send(MessageToUi::ReplaceLibraryNode(root_node.clone()));
tx.send(MessageToUi::ReplaceLibraryNode(root_node.clone()))?;
}
let init_data = rpc_client.init().await?;
tx.send_async(MessageToUi::Init(init_data)).await?;
loop {
poll(&mut rpc_client, &rx, &tx).await.ok();
if let Err(err) = poll(&mut rpc_client, &rx, &tx).await {
error!("Poll error: {}", err);
}
}
}
@ -89,7 +93,7 @@ async fn poll(
match msg {
MessageFromUi::GetLibraryNode(uuid) => {
if let Some(node) = rpc_client.get_library_node(&uuid).await? {
tx.send(MessageToUi::ReplaceLibraryNode(node.clone()));
tx.send(MessageToUi::ReplaceLibraryNode(node.clone()))?;
}
},
MessageFromUi::AppendTracks(uuids) => {
@ -211,7 +215,7 @@ fn run_ui(tx: Sender<MessageFromUi>, rx: Receiver<MessageToUi>) {
}
}
terminal.draw(|f| app.render(f));
terminal.draw(|f| app.render(f)).unwrap();
let timeout = tick_rate
.checked_sub(last_tick.elapsed())
@ -226,25 +230,39 @@ fn run_ui(tx: Sender<MessageFromUi>, rx: Receiver<MessageToUi>) {
}
(_, KeyModifiers::NONE, KeyCode::Tab) => app.cycle_active(),
(_, KeyModifiers::NONE, KeyCode::Char(' ')) => {
tx.send(MessageFromUi::TogglePlay);
if let Err(err) = tx.send(MessageFromUi::TogglePlay) {
error!("Send error: {}", err);
}
}
(_, KeyModifiers::NONE, KeyCode::Char('r')) => {
tx.send(MessageFromUi::RestartTrack);
if let Err(err) = tx.send(MessageFromUi::RestartTrack) {
error!("Send error: {}", err);
}
}
(_, KeyModifiers::SHIFT, KeyCode::Char('J')) => {
tx.send(MessageFromUi::ChangeVolume(-0.1));
if let Err(err) = tx.send(MessageFromUi::ChangeVolume(-0.1)) {
error!("Send error: {}", err);
}
}
(_, KeyModifiers::SHIFT, KeyCode::Char('K')) => {
tx.send(MessageFromUi::ChangeVolume(0.1));
if let Err(err) = tx.send(MessageFromUi::ChangeVolume(0.1)) {
error!("Send error: {}", err);
}
}
(_, KeyModifiers::NONE, KeyCode::Char('m')) => {
tx.send(MessageFromUi::ToggleMute);
if let Err(err) = tx.send(MessageFromUi::ToggleMute) {
error!("Send error: {}", err);
}
}
(_, KeyModifiers::NONE, KeyCode::Char('z')) => {
tx.send(MessageFromUi::ToggleShuffle);
if let Err(err) = tx.send(MessageFromUi::ToggleShuffle) {
error!("Send error: {}", err);
}
}
(_, KeyModifiers::NONE, KeyCode::Char('x')) => {
tx.send(MessageFromUi::ToggleRepeat);
if let Err(err) = tx.send(MessageFromUi::ToggleRepeat) {
error!("Send error: {}", err);
}
}
(_, KeyModifiers::CONTROL, KeyCode::Char('n')) => {
app.queue.play_next();

View File

@ -72,9 +72,7 @@ impl RpcClient {
}
pub async fn reconnect_update_stream(&mut self) {
let update_stream = Self::get_update_stream(&mut self.client).await;
// FIXME: apparently mem::replace doesn't do anything here
mem::replace(&mut self.update_stream, update_stream);
self.update_stream = Self::get_update_stream(&mut self.client).await;
}
pub async fn init(&mut self) -> Result<InitResponse, Box<dyn Error>> {

View File

@ -73,7 +73,7 @@ where
if let Some(config_dir) = dirs::config_dir() {
let dir = Path::new(&config_dir).join("crabidy");
if !dir.is_dir() {
create_dir_all(&dir);
create_dir_all(&dir).expect("Could not create crabidy directory in config dir");
}
let config_file_path = dir.join(config_file_name);
if !config_file_path.is_file() {