use souvlaki::{MediaControlEvent, MediaControls, MediaMetadata, MediaPlayback, PlatformConfig}; use std::sync::Mutex; use tauri::{AppHandle, Emitter, WebviewWindow}; pub struct Media { controls: Mutex>, } impl Media { pub fn new() -> Self { Self { controls: Mutex::new(None) } } pub fn attach(&self, app: AppHandle, window: &WebviewWindow) -> Result<(), String> { #[cfg(target_os = "windows")] let hwnd = window.hwnd().ok().map(|h| h.0 as *mut std::ffi::c_void); #[cfg(not(target_os = "windows"))] let hwnd = { let _ = window; None }; let mut controls = MediaControls::new(PlatformConfig { dbus_name: "app.pipu.music.desktop", display_name: "Pipu Music", hwnd, }) .map_err(|e| format!("{e:?}"))?; let handle = app.clone(); controls .attach(move |event| { let name = match event { MediaControlEvent::Play => "play", MediaControlEvent::Pause => "pause", MediaControlEvent::Toggle => "toggle", MediaControlEvent::Next => "next", MediaControlEvent::Previous => "previous", MediaControlEvent::Stop => "stop", _ => return, }; let _ = handle.emit("media", name); }) .map_err(|e| format!("{e:?}"))?; *self.controls.lock().map_err(|e| e.to_string())? = Some(controls); Ok(()) } pub fn set(&self, title: &str, artist: &str, album: &str, cover_url: Option<&str>, playing: bool) -> Result<(), String> { let mut slot = self.controls.lock().map_err(|e| e.to_string())?; let Some(controls) = slot.as_mut() else { return Ok(()); }; controls .set_metadata(MediaMetadata { title: Some(title), artist: Some(artist), album: Some(album), cover_url, duration: None, }) .map_err(|e| format!("{e:?}"))?; let playback = if playing { MediaPlayback::Playing { progress: None } } else { MediaPlayback::Paused { progress: None } }; controls.set_playback(playback).map_err(|e| format!("{e:?}")) } }