From a8861fc1aa952a2a54da7505570be1607098e319 Mon Sep 17 00:00:00 2001 From: Bettehem Date: Tue, 10 Nov 2020 21:18:22 +0200 Subject: [PATCH] Spotify URL support for MPRIS OpenUri function (#314) * Added OpenUri D-BUS MPRIS support. Removed "user:" from URIType check because Spotify doesn't always provide it. * Added tags to .gitignore * Changed mpris metadata to actually return the track's url instead of the Spotify URI so that it matches the functionality of the official Spotify client. * Changed mpris:trackid and xesam:url to not use static naming so it can support podcasts. * Changed xesam:url to default to an empty string instead of "0" * Added possibility to start playing Shows and Episodes via MPRIS. Added possibility to search for Podcast Episodes. * Fixed mpris:trackid not returning the id in the correct format. MPRIS OpenUri function now supports Spotify url links. * return result directly instead of mut string * handle artist URLs/URIs Co-authored-by: Henrik Friedrichsen --- src/mpris.rs | 33 +++++++++++++++++++++++---------- src/spotify.rs | 4 ++-- src/ui/artist.rs | 2 +- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/mpris.rs b/src/mpris.rs index 34742bf..576a13b 100644 --- a/src/mpris.rs +++ b/src/mpris.rs @@ -21,6 +21,7 @@ use crate::show::Show; use crate::spotify::{PlayerEvent, Spotify, URIType}; use crate::track::Track; use crate::traits::ListItem; +use regex::Regex; type Metadata = HashMap>>; @@ -41,12 +42,7 @@ fn get_metadata(playable: Option) -> Metadata { hm.insert( "mpris:trackid".to_string(), - Variant(Box::new(Path::from(format!( - "/org/ncspot/{}", - playable - .map(|t| t.uri().replace(':', "/")) - .unwrap_or_else(|| "0".to_string()) - )))), + Variant(Box::new(playable.map(|t| t.uri()).unwrap_or_default())), ); hm.insert( "mpris:length".to_string(), @@ -481,11 +477,22 @@ fn run_dbus_server(spotify: Arc, queue: Arc, rx: mpsc::Receiver< f.method("OpenUri", (), move |m| { let uri_data: Option<&str> = m.msg.get1(); let uri = match uri_data { - Some(s) => s, - None => "", + Some(s) => { + let spotify_uri = if s.contains("open.spotify.com") { + let regex = Regex::new(r"https?://open\.spotify\.com(/user)?/(album|track|playlist|show|episode)/(.+)(\?si=\S+)?").unwrap(); + let captures = regex.captures(s).unwrap(); + let uri_type = &captures[2]; + let id = &captures[3]; + format!("spotify:{}:{}", uri_type, id) + }else { + s.to_string() + }; + spotify_uri + } + None => "".to_string(), }; let id = &uri[uri.rfind(':').unwrap_or(0) + 1..uri.len()]; - let uri_type = URIType::from_uri(uri); + let uri_type = URIType::from_uri(&uri); match uri_type { Some(URIType::Album) => { if let Some(a) = spotify.album(&id) { @@ -548,7 +555,13 @@ fn run_dbus_server(spotify: Arc, queue: Arc, rx: mpsc::Receiver< queue.play(0, false, false) } } - Some(URIType::Artist) => {} + Some(URIType::Artist) => { + if let Some(a) = spotify.artist_top_tracks(&id) { + queue.clear(); + queue.append_next(a.iter().map(|track| Playable::Track(track.clone())).collect()); + queue.play(0, false, false) + } + } None => {} } Ok(vec![m.msg.method_return()]) diff --git a/src/spotify.rs b/src/spotify.rs index 3f89da3..419322b 100644 --- a/src/spotify.rs +++ b/src/spotify.rs @@ -822,8 +822,8 @@ impl Spotify { self.api_with_retry(|api| api.user_playlist_follow_playlist(&owner_id, &id, true)) } - pub fn artist_top_tracks(&self, id: String) -> Option> { - self.api_with_retry(|api| api.artist_top_tracks(&id, None)) + pub fn artist_top_tracks(&self, id: &str) -> Option> { + self.api_with_retry(|api| api.artist_top_tracks(id, None)) .map(|ft| ft.tracks.iter().map(|t| t.into()).collect()) } diff --git a/src/ui/artist.rs b/src/ui/artist.rs index a47ddc8..652e887 100644 --- a/src/ui/artist.rs +++ b/src/ui/artist.rs @@ -40,7 +40,7 @@ impl ArtistView { let library = library.clone(); thread::spawn(move || { if let Some(id) = id { - if let Some(tracks) = spotify.artist_top_tracks(id) { + if let Some(tracks) = spotify.artist_top_tracks(&id) { top_tracks.write().unwrap().extend(tracks); library.trigger_redraw(); }