diff --git a/src/basic_listener.rs b/src/basic_listener.rs new file mode 100644 index 0000000..da8517f --- /dev/null +++ b/src/basic_listener.rs @@ -0,0 +1,51 @@ +use crate::mpv_event_handler::events::{MpvEvent, Listener, FileInfo}; + +pub struct MpvListener; + +impl MpvListener { + fn print_file_info(&self, file_info: FileInfo) { + let FileInfo {filename, metadata} = file_info; + + println!("[RPC] FILENAME: {filename}"); + + if let Some(artist) = metadata.artist { + println!("[RPC] ARTIST: {artist}"); + } + + if let Some(album) = metadata.album { + println!("[RPC] ALBUM: {album}"); + } + + if let Some(title) = metadata.title { + println!("[RPC] TITLE: {title}"); + } + + if let Some(track) = metadata.track { + println!("[RPC] TRACK: {track}"); + } + } + + fn print_seek_time(&self, time: i64) { + println!("[RPC] SEEKING: {time}"); + } + + fn print_play(&self) { + println!("[RPC] PLAY"); + } + + fn print_pause(&self) { + println!("[RPC] PAUSE"); + } +} + + +impl Listener for MpvListener { + fn handle_event(&self, event: MpvEvent) { + match event { + MpvEvent::FileLoaded(file_info) => self.print_file_info(file_info), + MpvEvent::Seek(time) => self.print_seek_time(time), + MpvEvent::Pause => self.print_pause(), + MpvEvent::Play => self.print_play(), + } + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 80c9f45..74b7d59 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,19 @@ use mpv_client::mpv_handle; mod mpv_event_handler; +mod basic_listener; // For testing purposes #[no_mangle] fn mpv_open_cplugin(handle: *mut mpv_handle) -> std::os::raw::c_int { - let client = mpv_event_handler::MpvHandler::from_ptr(handle); + let listener = Box::new(basic_listener::MpvListener); + let client = mpv_event_handler::MpvEventHandler::from_ptr(handle, listener); + + if let Err(e) = client.initialize() { + println!("[RPC] Error initializing mpv client: {e}") + } + while client.poll_events() { - + } return 0; } \ No newline at end of file diff --git a/src/mpv_event_handler.rs b/src/mpv_event_handler.rs index fd27066..fe09b0d 100644 --- a/src/mpv_event_handler.rs +++ b/src/mpv_event_handler.rs @@ -1,32 +1,44 @@ -use mpv_client::{Handle, Event, Property, mpv_handle}; +use mpv_client::{Handle, Event, Property, Format, mpv_handle}; -pub struct MpvHandler { - mpv: Handle +pub mod events; +use events::{MpvEvent, Listener, FileInfo, FileMetadata}; + + +const NAME_PAUSE_PROP: &str = "pause"; +const REPL_PAUSE_PROP: u64 = 1; + +pub struct MpvEventHandler { + mpv: Handle, + listener: Box } -impl MpvHandler { - pub fn new(mpv: Handle) -> Self { +impl MpvEventHandler { + pub fn new<'a>(mpv: Handle, listener: Box) -> Self { Self { - mpv + mpv, + listener } } - pub fn from_ptr(handle: *mut mpv_handle) -> Self { - MpvHandler::new(Handle::from_ptr(handle)) + pub fn from_ptr<'a>(handle: *mut mpv_handle, listener: Box) -> Self { + MpvEventHandler::new(Handle::from_ptr(handle), listener) + } + + pub fn initialize(&self) -> Result<(), String> { + self.observe_property(REPL_PAUSE_PROP, NAME_PAUSE_PROP, bool::MPV_FORMAT) } - #[allow(dead_code)] fn observe_property(&self, id: u64, name: &str, format: i32) -> Result<(), String>{ match self.mpv.observe_property(id, name, format) { Ok(_) => Ok(()), Err(_) => Err(format!("Couldn't observe property: {name} (id: {id})")) } } - - #[allow(dead_code)] - fn on_property_change(&self, prop_id: u64, _prop: Property) { + + fn on_property_change(&self, prop_id: u64, prop: Property) { println!("[RPC] Property changed: {prop_id}"); match prop_id { + REPL_PAUSE_PROP => self.handle_pause_change(prop.data().unwrap()), _ => () } } @@ -34,12 +46,62 @@ impl MpvHandler { fn handle_event(&self, event: Event) { println!("[RPC] Event: {event}"); match event { + Event::FileLoaded => self.handle_file_loaded(), + Event::PlaybackRestart => self.handle_playback_restart(), _ => () } } + // TODO + // Replace unwrap with error handling + fn handle_file_loaded(&self) { + let filename = self.mpv.get_property("filename").unwrap(); + let artist = self.mpv.get_property("metadata/by-key/artist").ok(); + let album = self.mpv.get_property("metadata/by-key/album").ok(); + let title = self.mpv.get_property("metadata/by-key/title").ok(); + let track = self.mpv.get_property("metadata/by-key/Artist").ok(); + + let metadata = FileMetadata { + artist, + album, + title, + track + }; + + let file_info = FileInfo { + filename, + metadata + }; + + let event = MpvEvent::FileLoaded(file_info); + self.listener.handle_event(event); + } + + fn handle_playback_restart(&self) { + let res = self.mpv.get_property("playback-time").ok(); + match res { + Some(time) => { + let event = MpvEvent::Seek(time); + self.listener.handle_event(event); + } + None => { + println!("[RPC] Failed retrieving playback-time."); + println!("[RPC] This usually happens seeking into file end. Possibly mpv bug?"); + }, + } + } + + fn handle_pause_change(&self, pause: bool) { + let event = match pause { + false => MpvEvent::Play, + true => MpvEvent::Pause + }; + self.listener.handle_event(event); + } + // TODO! - // Add logging + // Add logging and error handling, + // yes unwrap on property changes and events pub fn poll_events(&self) -> bool { match self.mpv.wait_event(0.0) { Event::None => (), @@ -49,4 +111,4 @@ impl MpvHandler { } true } -} \ No newline at end of file +} diff --git a/src/mpv_event_handler/events.rs b/src/mpv_event_handler/events.rs new file mode 100644 index 0000000..684ba5d --- /dev/null +++ b/src/mpv_event_handler/events.rs @@ -0,0 +1,22 @@ +pub struct FileInfo { + pub filename: String, + pub metadata: FileMetadata +} + +pub struct FileMetadata { + pub artist: Option, + pub album: Option, + pub title: Option, + pub track: Option +} + +pub enum MpvEvent { + FileLoaded(FileInfo), + Seek(i64), + Pause, + Play +} + +pub trait Listener { + fn handle_event(&self, event: MpvEvent); +} \ No newline at end of file