aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xsrc/app.rs38
-rwxr-xr-xsrc/connection.rs43
-rwxr-xr-xsrc/handler.rs44
-rwxr-xr-xsrc/list.rs6
-rwxr-xr-xsrc/main.rs2
-rwxr-xr-xsrc/ui.rs46
6 files changed, 146 insertions, 33 deletions
diff --git a/src/app.rs b/src/app.rs
index d57c0b6..cb7b520 100755
--- a/src/app.rs
+++ b/src/app.rs
@@ -1,5 +1,6 @@
-use crate::connection::Connection;
+use crate::connection::{self, Connection};
use crate::list::ContentList;
+use mpd::Client;
use std::collections::VecDeque;
// Application result type
@@ -12,20 +13,30 @@ pub struct App {
pub running: bool,
pub conn: Connection,
pub play_deque: VecDeque<String>,
- pub list: ContentList,
+ pub song_list: ContentList<String>,
+ pub queue_list: ContentList<String>,
+ pub pl_list: ContentList<String>,
}
impl App {
- pub fn new(addrs: &str) -> Self {
+ pub fn builder(addrs: &str) -> AppResult<Self> {
let mut conn = Connection::new(addrs).unwrap();
let mut vec: VecDeque<String> = VecDeque::new();
+ let mut pl_list = ContentList::new();
+ pl_list.list = Self::get_playlist(&mut conn.conn)?;
Self::get_queue(&mut conn, &mut vec);
- Self {
+
+ let mut song_list = ContentList::new();
+ song_list.list = conn.songs_filenames.clone();
+
+ Ok(Self {
running: true,
conn,
play_deque: vec,
- list: ContentList::new(),
- }
+ song_list,
+ queue_list: ContentList::new(),
+ pl_list,
+ })
}
pub fn tick(&self) {}
@@ -52,10 +63,15 @@ impl App {
self.play_deque.clear();
Self::get_queue(&mut self.conn, &mut self.play_deque);
}
-}
-fn to_vecdeque(filenames: &Vec<String>) -> VecDeque<String> {
- let mut v: VecDeque<String> = VecDeque::new();
- v = filenames.iter().map(|x| x.to_string()).collect();
- v
+ pub fn get_playlist(conn: &mut Client) -> AppResult<Vec<String>> {
+ let list: Vec<String> = conn.playlists()?.iter().map(|p| p.clone().name).collect();
+
+ Ok(list)
+ }
+
+ pub fn update_playlist(&mut self) -> AppResult<()> {
+ Self::get_playlist(&mut self.conn.conn)?;
+ Ok(())
+ }
}
diff --git a/src/connection.rs b/src/connection.rs
index f2499e6..4f98beb 100755
--- a/src/connection.rs
+++ b/src/connection.rs
@@ -10,6 +10,7 @@ pub type Error = Box<dyn std::error::Error>;
pub struct Connection {
pub conn: Client,
pub songs_filenames: Vec<String>,
+ // pub state: String,
}
impl Connection {
@@ -25,6 +26,7 @@ impl Connection {
Ok(Self {
conn,
songs_filenames,
+ // state: "Stopped".to_string(),
})
}
@@ -50,14 +52,22 @@ impl Connection {
Ok(())
}
+ // pub fn update_state(&mut self) {
+ // match self.conn.status().unwrap().state {
+ // State::Stop => self.state = "Stopped".to_string(),
+ // State::Play => self.state = "Playing".to_string(),
+ // State::Pause => self.state = "Paused".to_string(),
+ // }
+ // }
+
pub fn push(&mut self, song: &Song) -> Result<()> {
if self.conn.queue().unwrap().is_empty() {
self.conn.push(song).unwrap();
self.conn.play().unwrap();
} else {
- self.conn.push(song).unwrap();
- if self.conn.status().unwrap().state == State::Stop {
- self.conn.play().unwrap();
+ self.conn.push(song)?;
+ if self.conn.status()?.state == State::Stop {
+ self.conn.play()?;
}
self.conn.next().unwrap();
}
@@ -65,6 +75,19 @@ impl Connection {
Ok(())
}
+ pub fn push_playlist(&mut self, playlist: &str) -> Result<()> {
+ let songs: Vec<Song> = self.conn.playlist(playlist)?;
+
+ for song in songs {
+ if self.songs_filenames.contains(&song.file) {
+ let song = self.get_song_with_only_filename(&song.file);
+ self.conn.push(&song)?;
+ self.conn.play()?;
+ }
+ }
+ Ok(())
+ }
+
pub fn get_song_with_only_filename(&self, filename: &str) -> Song {
Song {
file: filename.to_string(),
@@ -81,7 +104,6 @@ impl Connection {
pub fn get_current_song(&mut self) -> Option<String> {
self.conn.currentsong().unwrap().unwrap_or_default().title
-
}
pub fn status(&mut self) {
let current_song = self.conn.currentsong();
@@ -99,6 +121,19 @@ impl Connection {
);
}
+ pub fn now_playing(&mut self) -> Option<String> {
+ let song = self.conn.currentsong().unwrap().unwrap_or_default();
+ if let Some(s) = song.title {
+ if let Some(a) = song.artist {
+ Some(format!("{} - {}", s, a))
+ } else {
+ Some(s)
+ }
+ } else {
+ None
+ }
+ }
+
// Playback controls
pub fn pause(&mut self) {
self.conn.pause(true).unwrap();
diff --git a/src/handler.rs b/src/handler.rs
index 32b4b6f..91b5f86 100755
--- a/src/handler.rs
+++ b/src/handler.rs
@@ -11,17 +11,17 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
}
KeyCode::Char('j') => {
- app.list.next();
+ app.song_list.next();
}
KeyCode::Char('k') => {
- app.list.prev();
+ app.song_list.prev();
}
KeyCode::Enter | KeyCode::Char('l') => {
- let song = app.conn.get_song_with_only_filename(app.conn.songs_filenames.get(app.list.index).unwrap());
- app.conn.push(&song).unwrap();
- app.update_queue();
+ let song = app.conn.get_song_with_only_filename(app.conn.songs_filenames.get(app.song_list.index).unwrap());
+ app.conn.push(&song)?;
+ // app.update_queue();
}
// Playback controls
@@ -35,10 +35,42 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App) -> AppResult<()> {
app.conn.pause();
}
+
// Clearn Queue
KeyCode::Char('x') => {
app.conn.conn.clear()?;
- app.update_queue();
+ // app.update_queue();
+ }
+
+ KeyCode::Char('d') => {
+ app.conn.play_dmenu()?;
+ }
+
+ KeyCode::Down=> {
+ app.pl_list.next();
+ }
+
+ KeyCode::Up=> {
+ app.pl_list.prev();
+ }
+
+
+ KeyCode::Right => {
+ app.conn.push_playlist(app.pl_list.list.get(app.pl_list.index).unwrap())?;
+ }
+
+ KeyCode::Char('f')=> {
+ // let place = app.conn.conn.status().unwrap().duration;
+ let (pos, _) = app.conn.conn.status().unwrap().time.unwrap();
+ let pos: i64 = (pos.as_secs() + 2).try_into().unwrap();
+ app.conn.conn.seek(2, pos )?;
+ }
+
+ KeyCode::Char('b')=> {
+ // let place = app.conn.conn.status().unwrap().duration;
+ let (pos, _) = app.conn.conn.status().unwrap().time.unwrap();
+ let pos: i64 = (pos.as_secs() - 2).try_into().unwrap();
+ app.conn.conn.seek(2, pos )?;
}
_ => {}
}
diff --git a/src/list.rs b/src/list.rs
index 669d1af..74790a1 100755
--- a/src/list.rs
+++ b/src/list.rs
@@ -1,11 +1,13 @@
#[derive(Debug)]
-pub struct ContentList {
+pub struct ContentList<T> {
+ pub list: Vec<T>,
pub index: usize
}
-impl ContentList {
+impl<T> ContentList<T> {
pub fn new() -> Self {
ContentList {
+ list: Vec::new(),
index: 0
}
}
diff --git a/src/main.rs b/src/main.rs
index 3fbfc14..4d849f1 100755
--- a/src/main.rs
+++ b/src/main.rs
@@ -42,7 +42,7 @@ fn main() -> AppResult<()> {
let backend = CrosstermBackend::new(io::stderr());
let terminal = Terminal::new(backend)?;
- let mut app = App::new("127.0.0.1:6600");
+ let mut app = App::builder("127.0.0.1:6600")?;
let events = EventHandler::new(250);
let mut tui = tui::Tui::new(terminal, events);
diff --git a/src/ui.rs b/src/ui.rs
index 3f2eec8..b605747 100755
--- a/src/ui.rs
+++ b/src/ui.rs
@@ -1,4 +1,4 @@
-use crate::{app::App, connection::Connection};
+use crate::app::App;
use ratatui::{prelude::*, widgets::*};
/// Renders the user interface widgets
@@ -9,7 +9,7 @@ pub fn render(app: &mut App, frame: &mut Frame) {
// - https://github.com/ratatui-org/ratatui/tree/master/examples
// List of songs
- let mut state = ListState::default();
+ let mut song_state = ListState::default();
let size = Rect::new(100, 0, frame.size().width, frame.size().height - 3);
let list = List::new(app.conn.songs_filenames.clone())
.block(Block::default().title("Song List").borders(Borders::ALL))
@@ -17,21 +17,49 @@ pub fn render(app: &mut App, frame: &mut Frame) {
.highlight_symbol(">>")
.repeat_highlight_symbol(true);
- state.select(Some(app.list.index));
- frame.render_stateful_widget(list, size, &mut state);
+ song_state.select(Some(app.song_list.index));
+ frame.render_stateful_widget(list, size, &mut song_state);
// Play Queue
+ let mut queue_state = ListState::default();
let size = Rect::new(0, 0, 100, frame.size().height - 25);
let list = List::new(app.play_deque.clone())
.block(Block::default().title("Play Queue").borders(Borders::ALL))
.highlight_style(Style::new().add_modifier(Modifier::REVERSED))
.highlight_symbol(">>")
.repeat_highlight_symbol(true);
- frame.render_widget(list, size);
+
+ app.update_queue();
+ frame.render_stateful_widget(list, size, &mut queue_state);
// Status
- let size = Rect::new(0, frame.size().height - 3, frame.size().width, 3);
- let status = Paragraph::new(app.conn.conn.status().unwrap().volume.to_string())
- .block(Block::default().title("Status").borders(Borders::ALL));
- frame.render_widget(status, size);
+ // let size = Rect::new(0, frame.size().height - 3, frame.size().width, 3);
+ // let song = app
+ // .conn
+ // .now_playing()
+ // .unwrap_or_else(|| "No Title Found".to_string());
+ //
+ // let (elapsed, total) = app.conn.conn.status().unwrap().time.unwrap();
+ //
+ // let mut lines = vec![];
+ // lines.push(Line::from(vec![
+ // Span::styled("Current: ", Style::default().fg(Color::Red)),
+ // Span::styled(song, Style::default().fg(Color::Yellow)),
+ // Span::styled(format!("[{}/{}]", elapsed.as_secs(), total.as_secs()), Style::default().fg(Color::Yellow)),
+ // ]));
+ // let status = Paragraph::new(Text::from(lines))
+ // .block(Block::default().title("Status").borders(Borders::ALL));
+ // frame.render_widget(status, size);
+
+ // Playlists
+ let mut state = ListState::default();
+ let size = Rect::new(0, 25, 100, frame.size().height - 25 - 3);
+ let list = List::new(app.pl_list.list.clone())
+ .block(Block::default().title("Playlists").borders(Borders::ALL))
+ .highlight_style(Style::new().add_modifier(Modifier::REVERSED))
+ .highlight_symbol(">>")
+ .repeat_highlight_symbol(true);
+
+ state.select(Some(app.pl_list.index));
+ frame.render_stateful_widget(list, size, &mut state);
}