From ee8ac99d9fa1f348065108b73297eebc8033e57e Mon Sep 17 00:00:00 2001 From: Ruben Beltran del Rio Date: Thu, 17 Jul 2025 15:31:38 +0200 Subject: Use objc2, rename dbus to mpris, add swinsian --- src/sources/apple_music.rs | 35 +++++++++++++------------- src/sources/dbus.rs | 43 -------------------------------- src/sources/mod.rs | 18 ++++++++++---- src/sources/mpris.rs | 43 ++++++++++++++++++++++++++++++++ src/sources/spotify.rs | 35 +++++++++++++------------- src/sources/swinsian.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 152 insertions(+), 84 deletions(-) delete mode 100644 src/sources/dbus.rs create mode 100644 src/sources/mpris.rs create mode 100644 src/sources/swinsian.rs (limited to 'src/sources') diff --git a/src/sources/apple_music.rs b/src/sources/apple_music.rs index 572fe6b..af61b61 100644 --- a/src/sources/apple_music.rs +++ b/src/sources/apple_music.rs @@ -1,10 +1,6 @@ use std::io::Result; -use objc2::{ - msg_send, - rc::{Retained, autoreleasepool}, - runtime::AnyObject, -}; +use objc2::{msg_send, rc::Retained, runtime::AnyObject}; use objc2_foundation::NSString; use objc2_scripting_bridge::SBApplication; @@ -28,19 +24,22 @@ impl LyricsSource for AppleMusic { fn current_track(&self) -> Option { unsafe { let bundle_identifier = NSString::from_str("com.apple.Music"); - let app = SBApplication::applicationWithBundleIdentifier(&bundle_identifier); - if let Some(app) = app - && app.isRunning() - { - let current_track: Option> = msg_send![&app, currentTrack]; - if let Some(current_track) = current_track { - let name_raw: Option> = msg_send![¤t_track, name]; - let artist_raw: Option> = msg_send![¤t_track, artist]; - - if let (Some(name_raw), Some(artist_raw)) = (name_raw, artist_raw) { - let name = autoreleasepool(|pool| name_raw.to_str(pool).to_string()); - let artist = autoreleasepool(|pool| artist_raw.to_str(pool).to_string()); - + if let Some(app) = SBApplication::applicationWithBundleIdentifier(&bundle_identifier) { + let key = NSString::from_str("currentTrack"); + let current_track: Option> = msg_send![&app, valueForKey:&*key]; + + if let Some(track) = current_track { + let name_key = NSString::from_str("name"); + let artist_key = NSString::from_str("artist"); + + let name: Option> = + msg_send![&track, valueForKey:&*name_key]; + let artist: Option> = + msg_send![&track, valueForKey:&*artist_key]; + + if let Some(name) = name.map(|s| s.to_string()) + && let Some(artist) = artist.map(|s| s.to_string()) + { return Some(Track { name, artist }); } } diff --git a/src/sources/dbus.rs b/src/sources/dbus.rs deleted file mode 100644 index 2f6bccd..0000000 --- a/src/sources/dbus.rs +++ /dev/null @@ -1,43 +0,0 @@ -use mpris::PlayerFinder; -use std::io::Result; - -use crate::Track; - -use super::LyricsSource; - -pub struct Dbus; - -impl Dbus { - pub fn new() -> Self { - Dbus - } -} - -impl LyricsSource for Dbus { - fn name(&self) -> String { - "dbus".to_string() - } - - fn current_track(&self) -> Option { - let player = PlayerFinder::new().ok()?.find_active().ok()?; - - let metadata = player.get_metadata().ok()?; - let name = metadata.title()?.to_string(); - let artists = metadata.artists()?; - let artist = artists.get(0)?.to_string(); - - Some(Track { name, artist }) - } - - fn disable(&self) -> Result<()> { - Ok(()) - } - - fn enable(&self) -> Result<()> { - Ok(()) - } - - fn reset(&self) -> Result<()> { - Ok(()) - } -} diff --git a/src/sources/mod.rs b/src/sources/mod.rs index bf68ec3..cac5833 100644 --- a/src/sources/mod.rs +++ b/src/sources/mod.rs @@ -1,20 +1,25 @@ +use crate::configuration::Configuration; use std::io::{Error, Result}; #[cfg(target_os = "macos")] mod apple_music; #[cfg(target_os = "macos")] mod spotify; +#[cfg(target_os = "macos")] +mod swinsian; #[cfg(target_os = "linux")] -mod dbus; +mod mpris; #[cfg(target_os = "macos")] use apple_music::AppleMusic; #[cfg(target_os = "macos")] use spotify::Spotify; +#[cfg(target_os = "macos")] +use swinsian::Swinsian; #[cfg(target_os = "linux")] -use dbus::Dbus; +use mpris::Mpris; use crate::Track; @@ -65,10 +70,12 @@ pub fn reset(source_name: &String) -> Result<()> { Err(Error::other("No such source was available.")) } -pub fn get_track() -> Option { +pub fn get_track(configuration: &Configuration) -> Option { let sources = available_sources(); for source in sources { - if let Some(track) = source.current_track() { + if configuration.is_enabled(&source.name()) + && let Some(track) = source.current_track() + { return Some(track); } } @@ -81,11 +88,12 @@ pub fn available_sources() -> Vec> { { sources.push(Box::new(AppleMusic::new())); sources.push(Box::new(Spotify::new())); + sources.push(Box::new(Swinsian::new())); } #[cfg(not(target_os = "macos"))] { - sources.push(Box::new(Dbus::new())); + sources.push(Box::new(Mpris::new())); } sources diff --git a/src/sources/mpris.rs b/src/sources/mpris.rs new file mode 100644 index 0000000..69eb862 --- /dev/null +++ b/src/sources/mpris.rs @@ -0,0 +1,43 @@ +use mpris::PlayerFinder; +use std::io::Result; + +use crate::Track; + +use super::LyricsSource; + +pub struct Mpris; + +impl Mpris { + pub fn new() -> Self { + Mpris + } +} + +impl LyricsSource for Mpris { + fn name(&self) -> String { + "mpris".to_string() + } + + fn current_track(&self) -> Option { + let player = PlayerFinder::new().ok()?.find_active().ok()?; + + let metadata = player.get_metadata().ok()?; + let name = metadata.title()?.to_string(); + let artists = metadata.artists()?; + let artist = artists.get(0)?.to_string(); + + Some(Track { name, artist }) + } + + fn disable(&self) -> Result<()> { + Ok(()) + } + + fn enable(&self) -> Result<()> { + Ok(()) + } + + fn reset(&self) -> Result<()> { + Ok(()) + } +} diff --git a/src/sources/spotify.rs b/src/sources/spotify.rs index cd37491..8010ad1 100644 --- a/src/sources/spotify.rs +++ b/src/sources/spotify.rs @@ -1,10 +1,6 @@ use std::io::Result; -use objc2::{ - msg_send, - rc::{Retained, autoreleasepool}, - runtime::AnyObject, -}; +use objc2::{msg_send, rc::Retained, runtime::AnyObject}; use objc2_foundation::NSString; use objc2_scripting_bridge::SBApplication; @@ -28,19 +24,22 @@ impl LyricsSource for Spotify { fn current_track(&self) -> Option { unsafe { let bundle_identifier = NSString::from_str("com.spotify.Client"); - let app = SBApplication::applicationWithBundleIdentifier(&bundle_identifier); - if let Some(app) = app - && app.isRunning() - { - let current_track: Option> = msg_send![&app, currentTrack]; - if let Some(current_track) = current_track { - let name_raw: Option> = msg_send![¤t_track, name]; - let artist_raw: Option> = msg_send![¤t_track, artist]; - - if let (Some(name_raw), Some(artist_raw)) = (name_raw, artist_raw) { - let name = autoreleasepool(|pool| name_raw.to_str(pool).to_string()); - let artist = autoreleasepool(|pool| artist_raw.to_str(pool).to_string()); - + if let Some(app) = SBApplication::applicationWithBundleIdentifier(&bundle_identifier) { + let key = NSString::from_str("currentTrack"); + let current_track: Option> = msg_send![&app, valueForKey:&*key]; + + if let Some(track) = current_track { + let name_key = NSString::from_str("name"); + let artist_key = NSString::from_str("artist"); + + let name: Option> = + msg_send![&track, valueForKey:&*name_key]; + let artist: Option> = + msg_send![&track, valueForKey:&*artist_key]; + + if let Some(name) = name.map(|s| s.to_string()) + && let Some(artist) = artist.map(|s| s.to_string()) + { return Some(Track { name, artist }); } } diff --git a/src/sources/swinsian.rs b/src/sources/swinsian.rs new file mode 100644 index 0000000..641af6f --- /dev/null +++ b/src/sources/swinsian.rs @@ -0,0 +1,62 @@ +use std::io::Result; + +use objc2::{msg_send, rc::Retained, runtime::AnyObject}; +use objc2_foundation::NSString; +use objc2_scripting_bridge::SBApplication; + +use crate::Track; + +use super::LyricsSource; + +pub struct Swinsian; + +impl Swinsian { + pub fn new() -> Self { + Swinsian + } +} + +impl LyricsSource for Swinsian { + fn name(&self) -> String { + "swinsian".to_string() + } + + fn current_track(&self) -> Option { + unsafe { + let bundle_identifier = NSString::from_str("com.swinsian.Swinsian"); + if let Some(app) = SBApplication::applicationWithBundleIdentifier(&bundle_identifier) { + let key = NSString::from_str("currentTrack"); + let current_track: Option> = msg_send![&app, valueForKey:&*key]; + + if let Some(track) = current_track { + let name_key = NSString::from_str("name"); + let artist_key = NSString::from_str("artist"); + + let name: Option> = + msg_send![&track, valueForKey:&*name_key]; + let artist: Option> = + msg_send![&track, valueForKey:&*artist_key]; + + if let Some(name) = name.map(|s| s.to_string()) + && let Some(artist) = artist.map(|s| s.to_string()) + { + return Some(Track { name, artist }); + } + } + } + } + None + } + + fn disable(&self) -> Result<()> { + Ok(()) + } + + fn enable(&self) -> Result<()> { + Ok(()) + } + + fn reset(&self) -> Result<()> { + Ok(()) + } +} -- cgit