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:
@@ -1,38 +1,88 @@
|
||||
// Player module - MPV integration placeholder
|
||||
// Full implementation in Phase 3
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{anyhow, Result};
|
||||
use libmpv::Mpv;
|
||||
use std::path::Path;
|
||||
|
||||
pub struct Player {
|
||||
// MPV instance will be added in Phase 3
|
||||
mpv: Mpv,
|
||||
}
|
||||
|
||||
impl Player {
|
||||
pub fn new() -> Result<Self> {
|
||||
Ok(Self {})
|
||||
let mpv = Mpv::new().map_err(|e| anyhow!("Failed to create MPV instance: {:?}", e))?;
|
||||
|
||||
// Configure MPV for audio/video playback
|
||||
mpv.set_property("vo", "null").ok(); // No video output for TUI mode
|
||||
mpv.set_property("video", "no").ok(); // Disable video decoding
|
||||
mpv.set_property("volume", 100).ok();
|
||||
mpv.set_property("pause", false).ok();
|
||||
|
||||
Ok(Self { mpv })
|
||||
}
|
||||
|
||||
pub fn play(&mut self, _path: &Path) -> Result<()> {
|
||||
// TODO: Implement MPV playback in Phase 3
|
||||
tracing::info!("Play called (not yet implemented)");
|
||||
pub fn play(&mut self, path: &Path) -> Result<()> {
|
||||
let path_str = path.to_string_lossy();
|
||||
self.mpv
|
||||
.command("loadfile", &[&path_str, "replace"])
|
||||
.map_err(|e| anyhow!("Failed to load file: {:?}", e))?;
|
||||
self.mpv.set_property("pause", false).ok();
|
||||
tracing::info!("Playing: {}", path_str);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn pause(&mut self) -> Result<()> {
|
||||
// TODO: Implement pause in Phase 3
|
||||
tracing::info!("Pause called (not yet implemented)");
|
||||
self.mpv
|
||||
.set_property("pause", true)
|
||||
.map_err(|e| anyhow!("Failed to pause: {:?}", e))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn resume(&mut self) -> Result<()> {
|
||||
self.mpv
|
||||
.set_property("pause", false)
|
||||
.map_err(|e| anyhow!("Failed to resume: {:?}", e))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn stop(&mut self) -> Result<()> {
|
||||
// TODO: Implement stop in Phase 3
|
||||
tracing::info!("Stop called (not yet implemented)");
|
||||
self.mpv
|
||||
.command("stop", &[])
|
||||
.map_err(|e| anyhow!("Failed to stop: {:?}", e))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_volume(&mut self, _volume: i64) -> Result<()> {
|
||||
// TODO: Implement volume control in Phase 3
|
||||
pub fn set_volume(&mut self, volume: i64) -> Result<()> {
|
||||
self.mpv
|
||||
.set_property("volume", volume)
|
||||
.map_err(|e| anyhow!("Failed to set volume: {:?}", e))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_position(&self) -> Option<f64> {
|
||||
self.mpv.get_property("time-pos").ok()
|
||||
}
|
||||
|
||||
pub fn get_duration(&self) -> Option<f64> {
|
||||
self.mpv.get_property("duration").ok()
|
||||
}
|
||||
|
||||
pub fn is_playing(&self) -> bool {
|
||||
self.mpv
|
||||
.get_property::<bool>("pause")
|
||||
.map(|paused| !paused)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn is_idle(&self) -> bool {
|
||||
self.mpv
|
||||
.get_property::<String>("idle-active")
|
||||
.map(|s| s == "yes")
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
pub fn seek(&mut self, seconds: f64) -> Result<()> {
|
||||
self.mpv
|
||||
.command("seek", &[&seconds.to_string(), "relative"])
|
||||
.map_err(|e| anyhow!("Failed to seek: {:?}", e))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user