use std::ffi::CStr; use std::io::Result; use cocoa::{base::nil, foundation::NSString}; use objc::{class, msg_send, sel, sel_impl, runtime::Object}; use objc_id::Id; use crate::Track; use super::LyricsSource; pub struct Spotify; impl Spotify { pub fn new() -> Self { Spotify } } impl LyricsSource for Spotify { fn name(&self) -> String { "spotify".to_string() } fn current_track(&self) -> Option { unsafe { let app: Id = { let cls = class!(SBApplication); let bundle_identifier = NSString::alloc(nil).init_str("com.spotify.Client"); let app: *mut Object = msg_send![cls, applicationWithBundleIdentifier:bundle_identifier]; Id::from_ptr(app) }; if msg_send![app, isRunning] { let current_track: *mut Object = msg_send![app, currentTrack]; if !current_track.is_null() { let name_raw: *mut Object = msg_send![current_track, name]; let artist_raw: *mut Object = msg_send![current_track, artist]; let name_ptr: *const i8 = msg_send![name_raw, UTF8String]; let artist_ptr: *const i8 = msg_send![artist_raw, UTF8String]; let name = CStr::from_ptr(name_ptr).to_string_lossy().into_owned(); let artist = CStr::from_ptr(artist_ptr).to_string_lossy().into_owned(); return Some(Track { name, artist }) } } } None } fn disable(&self) -> Result<()> { Ok(()) } fn enable(&self) -> Result<()> { Ok(()) } fn reset(&self) -> Result<()> { Ok(()) } }