added mpv command
This commit is contained in:
+1
-1
@@ -8,7 +8,7 @@ async fn main() -> Result<()> {
|
||||
terminal.clear()?;
|
||||
let mut app = App::default();
|
||||
app.load_stations().await?;
|
||||
let app_result = app.run(&mut terminal);
|
||||
let app_result = app.run(&mut terminal).await;
|
||||
|
||||
if let Err(err) = tui::restore() {
|
||||
eprintln!(
|
||||
|
||||
+52
-12
@@ -1,9 +1,11 @@
|
||||
use crate::radio::station::StationInfo;
|
||||
use color_eyre::{
|
||||
Result,
|
||||
eyre::{WrapErr, eyre},
|
||||
};
|
||||
use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind};
|
||||
use radiobrowser::RadioBrowserAPI;
|
||||
use ratatui::widgets::{List, ListItem, ListState};
|
||||
use ratatui::{
|
||||
DefaultTerminal, Frame,
|
||||
layout::{Constraint, Layout},
|
||||
@@ -11,9 +13,7 @@ use ratatui::{
|
||||
widgets::{Block, Paragraph},
|
||||
};
|
||||
use std::io::{self};
|
||||
|
||||
use crate::radio::station::StationInfo;
|
||||
use ratatui::widgets::{List, ListItem, ListState};
|
||||
use tokio::process::Child;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum InputMode {
|
||||
@@ -29,6 +29,7 @@ pub struct App {
|
||||
filtered_stations: Vec<StationInfo>,
|
||||
search_query: String,
|
||||
input_mode: InputMode,
|
||||
player: Option<Child>,
|
||||
}
|
||||
|
||||
impl Default for App {
|
||||
@@ -44,15 +45,18 @@ impl Default for App {
|
||||
filtered_stations: Vec::new(),
|
||||
input_mode: InputMode::Normal,
|
||||
search_query: String::new(),
|
||||
player: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn run(&mut self, terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
pub async fn run(&mut self, terminal: &mut DefaultTerminal) -> Result<()> {
|
||||
while !self.exit {
|
||||
terminal.draw(|frame| self.draw(frame))?;
|
||||
self.handle_events().wrap_err("handle events failed")?;
|
||||
self.handle_events()
|
||||
.await
|
||||
.wrap_err("handle events failed")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -108,30 +112,34 @@ impl App {
|
||||
.block(Block::bordered().title("Info"));
|
||||
frame.render_widget(paragraph, bottom_left);
|
||||
|
||||
let search = Paragraph::new(format!("{}", self.search_query))
|
||||
.block(Block::bordered().title("Search"));
|
||||
let mut search_string = self.search_query.clone();
|
||||
if self.input_mode == InputMode::Search {
|
||||
search_string.push('█');
|
||||
}
|
||||
let search = Paragraph::new(search_string).block(Block::bordered().title("Search"));
|
||||
|
||||
frame.render_widget(search, top_right);
|
||||
frame.render_widget(Block::bordered().title("Played Songs"), bottom_right);
|
||||
}
|
||||
|
||||
fn handle_events(&mut self) -> io::Result<()> {
|
||||
async fn handle_events(&mut self) -> io::Result<()> {
|
||||
match event::read()? {
|
||||
Event::Key(key_event) if key_event.kind == KeyEventKind::Press => {
|
||||
self.handle_key_event(key_event)
|
||||
self.handle_key_event(key_event).await
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_key_event(&mut self, key_event: KeyEvent) {
|
||||
pub async fn handle_key_event(&mut self, key_event: KeyEvent) {
|
||||
match self.input_mode {
|
||||
InputMode::Normal => match key_event.code {
|
||||
KeyCode::Char('/') => {
|
||||
self.input_mode = InputMode::Search;
|
||||
self.search_query.clear();
|
||||
}
|
||||
KeyCode::Char('q') => self.exit(),
|
||||
KeyCode::Char('q') => self.exit().await,
|
||||
KeyCode::Down | KeyCode::Char('j') => {
|
||||
if let Some(i) = self.station_list_state.selected() {
|
||||
let next = (i + 1).min(self.stations.len().saturating_sub(1));
|
||||
@@ -144,6 +152,13 @@ impl App {
|
||||
self.station_list_state.select(Some(prev));
|
||||
}
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
if let Some(i) = self.station_list_state.selected() {
|
||||
if let Some(station) = self.stations.get(i) {
|
||||
self.play_station(station.url.clone()).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
InputMode::Search => match key_event.code {
|
||||
@@ -163,7 +178,10 @@ impl App {
|
||||
}
|
||||
}
|
||||
|
||||
fn exit(&mut self) {
|
||||
async fn exit(&mut self) {
|
||||
if let Some(mut child) = self.player.take() {
|
||||
let _ = child.kill().await;
|
||||
}
|
||||
self.exit = true;
|
||||
}
|
||||
|
||||
@@ -218,4 +236,26 @@ impl App {
|
||||
self.station_list_state.select(Some(0));
|
||||
}
|
||||
}
|
||||
|
||||
async fn play_station(&mut self, url: String) {
|
||||
if let Some(mut child) = self.player.take() {
|
||||
let _ = child.kill().await;
|
||||
}
|
||||
|
||||
let child = tokio::process::Command::new("mpv")
|
||||
.arg(&url)
|
||||
.arg("--no-video")
|
||||
.stdout(std::process::Stdio::null())
|
||||
.stderr(std::process::Stdio::null())
|
||||
.spawn();
|
||||
|
||||
match child {
|
||||
Ok(child) => {
|
||||
self.player = Some(child);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Failed to play station: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user