Implement MPV integration for audio/video playback

- Initialize libmpv with audio-only configuration
- Implement play, pause, resume, stop, seek controls
- Add position and duration tracking from MPV
- Auto-advance to next track when current ends
- Update keybindings to use actual player
- Add shell.nix for development environment with libmpv
- Real playback now working with Enter/Space/n/p keys
This commit is contained in:
2025-12-06 12:49:46 +01:00
parent 0093db98c2
commit e840aa9b26
3 changed files with 106 additions and 19 deletions

View File

@@ -46,7 +46,7 @@ async fn main() -> Result<()> {
}
// Initialize player
let _player = player::Player::new()?;
let mut player = player::Player::new()?;
// Initialize app state
let mut state = AppState::new(cache, config);
@@ -59,7 +59,7 @@ async fn main() -> Result<()> {
let mut terminal = Terminal::new(backend)?;
// Run app
let result = run_app(&mut terminal, &mut state).await;
let result = run_app(&mut terminal, &mut state, &mut player).await;
// Restore terminal
disable_raw_mode()?;
@@ -76,14 +76,31 @@ async fn main() -> Result<()> {
async fn run_app<B: ratatui::backend::Backend>(
terminal: &mut Terminal<B>,
state: &mut AppState,
player: &mut player::Player,
) -> Result<()> {
loop {
// Update position and duration from player
state.current_position = player.get_position().unwrap_or(0.0);
state.current_duration = player.get_duration().unwrap_or(0.0);
// Check if track ended and play next
if player.is_idle() && state.player_state == PlayerState::Playing {
if state.playlist_index + 1 < state.playlist.len() {
state.play_next();
if let Some(ref path) = state.current_file {
player.play(path)?;
}
} else {
state.player_state = PlayerState::Stopped;
}
}
terminal.draw(|f| ui::render(f, state))?;
if event::poll(std::time::Duration::from_millis(100))? {
if let Event::Key(key) = event::read()? {
if key.kind == KeyEventKind::Press {
handle_key_event(state, key.code).await?;
handle_key_event(state, player, key.code).await?;
}
}
}
@@ -96,7 +113,7 @@ async fn run_app<B: ratatui::backend::Backend>(
Ok(())
}
async fn handle_key_event(state: &mut AppState, key_code: KeyCode) -> Result<()> {
async fn handle_key_event(state: &mut AppState, player: &mut player::Player, key_code: KeyCode) -> Result<()> {
match key_code {
KeyCode::Char('q') => {
state.should_quit = true;
@@ -122,28 +139,33 @@ async fn handle_key_event(state: &mut AppState, key_code: KeyCode) -> Result<()>
KeyCode::Char('n') => {
state.play_next();
if let Some(ref path) = state.current_file {
player.play(path)?;
tracing::info!("Next track: {:?}", path);
}
}
KeyCode::Char('p') => {
state.play_previous();
if let Some(ref path) = state.current_file {
player.play(path)?;
tracing::info!("Previous track: {:?}", path);
}
}
KeyCode::Enter => {
state.play_selection();
if let Some(ref path) = state.current_file {
player.play(path)?;
tracing::info!("Playing: {:?} (playlist: {} tracks)", path, state.playlist.len());
}
}
KeyCode::Char(' ') => {
match state.player_state {
PlayerState::Playing => {
player.pause()?;
state.player_state = PlayerState::Paused;
tracing::info!("Paused");
}
PlayerState::Paused => {
player.resume()?;
state.player_state = PlayerState::Playing;
tracing::info!("Resumed");
}