diff --git a/Cargo.lock b/Cargo.lock index 5501070f..6b177e3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -152,7 +152,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -262,7 +262,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.92", + "syn 2.0.93", "which", ] @@ -281,7 +281,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -331,9 +331,9 @@ checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cc" -version = "1.2.5" +version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" +checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333" dependencies = [ "jobserver", "libc", @@ -598,7 +598,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -609,7 +609,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -708,7 +708,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -718,7 +718,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -762,7 +762,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -943,7 +943,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -1023,9 +1023,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "governor" @@ -1526,7 +1526,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -2260,7 +2260,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -2322,7 +2322,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -2574,7 +2574,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -3096,22 +3096,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -3144,7 +3144,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -3325,6 +3325,7 @@ dependencies = [ "librespot-discovery", "librespot-metadata", "librespot-playback", + "librespot-protocol", "log", "pledge", "serde", @@ -3485,9 +3486,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.92" +version = "2.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ae51629bf965c5c098cc9e87908a3df5301051a9e087d6f9bef5c9771ed126" +checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058" dependencies = [ "proc-macro2", "quote", @@ -3508,7 +3509,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -3606,7 +3607,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -3617,7 +3618,7 @@ checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -3709,7 +3710,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -4074,7 +4075,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", "wasm-bindgen-shared", ] @@ -4109,7 +4110,7 @@ checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4269,7 +4270,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -4280,7 +4281,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -4557,7 +4558,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", "synstructure", ] @@ -4579,7 +4580,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] [[package]] @@ -4599,7 +4600,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", "synstructure", ] @@ -4628,5 +4629,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.93", ] diff --git a/Cargo.toml b/Cargo.toml index 87330619..66d3e156 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ librespot-core = "0.6" librespot-discovery = "0.6" librespot-connect = "0.6" librespot-metadata = "0.6" +librespot-protocol = "0.6" toml = "0.8.19" color-eyre = "0.6" directories = "5.0.1" diff --git a/src/dbus_mpris.rs b/src/dbus_mpris.rs index 342e57d8..84ac7c6c 100644 --- a/src/dbus_mpris.rs +++ b/src/dbus_mpris.rs @@ -13,9 +13,11 @@ use futures::{ task::{Context, Poll}, Future, }; -use librespot_connect::spirc::Spirc; +use librespot_connect::spirc::{Spirc, SpircLoadCommand}; +use librespot_core::{spotify_id::SpotifyItemType, Session, SpotifyId}; use librespot_metadata::audio::AudioItem; use librespot_playback::player::PlayerEvent; +use librespot_protocol::spirc::TrackRef; use log::{error, warn}; use std::convert::TryFrom; use std::{ @@ -25,9 +27,12 @@ use std::{ }; use thiserror::Error; use time::format_description::well_known::Iso8601; -use tokio::sync::{ - mpsc::{UnboundedReceiver, UnboundedSender}, - Mutex, +use tokio::{ + runtime::Handle, + sync::{ + mpsc::{UnboundedReceiver, UnboundedSender}, + Mutex, + }, }; type DbusMap = HashMap>>; @@ -47,9 +52,13 @@ pub(crate) struct DbusServer { } impl DbusServer { - pub fn new(event_rx: UnboundedReceiver, dbus_type: DBusType) -> DbusServer { + pub fn new( + event_rx: UnboundedReceiver, + dbus_type: DBusType, + session: Session, + ) -> DbusServer { let (control_tx, control_rx) = tokio::sync::mpsc::unbounded_channel(); - let dbus_future = Box::pin(create_dbus_server(event_rx, control_rx, dbus_type)); + let dbus_future = Box::pin(create_dbus_server(event_rx, control_rx, dbus_type, session)); DbusServer { dbus_future, control_tx, @@ -149,6 +158,25 @@ impl RepeatState { } } +impl From for bool { + fn from(repeat: RepeatState) -> Self { + match repeat { + RepeatState::None => false, + RepeatState::All => true, + } + } +} + +impl From for RepeatState { + fn from(repeat: bool) -> Self { + if repeat { + RepeatState::All + } else { + RepeatState::None + } + } +} + #[derive(Debug)] struct CurrentStateInner { status: PlaybackStatus, @@ -258,11 +286,7 @@ impl CurrentStateInner { insert_attr(&mut changed, "Shuffle", self.shuffle); } PlayerEvent::RepeatChanged { repeat } => { - self.repeat = if repeat { - RepeatState::All - } else { - RepeatState::None - }; + self.repeat = repeat.into(); insert_attr( &mut changed, "LoopStatus", @@ -392,6 +416,7 @@ async fn create_dbus_server( mut event_rx: UnboundedReceiver, mut control_rx: UnboundedReceiver, dbus_type: DBusType, + session: Session, ) -> Result<(), DbusError> { let (resource, conn) = match dbus_type { DBusType::Session => connection::new_session_sync(), @@ -468,6 +493,7 @@ async fn create_dbus_server( let seeked_fn = register_player_interface( &mut cr, spirc, + session.clone(), current_state.clone(), quit_tx.clone(), ); @@ -551,6 +577,7 @@ type SeekedSignal = Box dbus::Message + Send + S fn register_player_interface( cr: &mut Crossroads, spirc: Arc, + session: Session, current_state: Arc, quit_tx: tokio::sync::mpsc::UnboundedSender<()>, ) -> SeekedSignal { @@ -688,11 +715,83 @@ fn register_player_interface( }, ); - b.method("OpenUri", ("uri",), (), move |_, _, (_,): (String,)| { - warn!("OpenUri is currently not implemented"); - Err::<(), _>(dbus::MethodErr::no_method( - "this method is currently not implemented", - )) + let local_spirc = spirc.clone(); + let local_state = current_state.clone(); + b.method("OpenUri", ("uri",), (), move |_, _, (uri,): (String,)| { + let id = SpotifyId::from_uri(&uri).map_err(|e| MethodErr::invalid_arg(&e))?; + let CurrentStateInner { + shuffle, repeat, .. + } = *local_state.read()?; + + fn id_to_trackref(id: &SpotifyId) -> TrackRef { + let mut trackref = TrackRef::new(); + if let Ok(uri) = id.to_uri() { + trackref.set_uri(uri); + } else { + trackref.set_gid(id.to_raw().to_vec()); + } + trackref + } + + let session = session.clone(); + + let (playing_track_index, context_uri, tracks) = Handle::current() + .block_on(async move { + use librespot_metadata::*; + Ok::<_, librespot_core::Error>(match id.item_type { + SpotifyItemType::Album => { + let album = Album::get(&session, &id).await?; + (0, uri, album.tracks().map(id_to_trackref).collect()) + } + SpotifyItemType::Artist => { + let artist = Artist::get(&session, &id).await?; + ( + 0, + uri, + artist + .top_tracks + .for_country(&session.country()) + .iter() + .map(id_to_trackref) + .collect(), + ) + } + SpotifyItemType::Playlist => { + let playlist = Playlist::get(&session, &id).await?; + (0, uri, playlist.tracks().map(id_to_trackref).collect()) + } + SpotifyItemType::Track => { + let track = Track::get(&session, &id).await?; + ( + track.number as u32, + track.album.id.to_uri()?, + vec![id_to_trackref(&track.id)], + ) + } + SpotifyItemType::Episode => (0, uri, vec![id_to_trackref(&id)]), + SpotifyItemType::Show => { + let show = Show::get(&session, &id).await?; + (0, uri, show.episodes.iter().map(id_to_trackref).collect()) + } + SpotifyItemType::Local | SpotifyItemType::Unknown => { + return Err(librespot_core::Error::unimplemented( + "this type of uri is not supported", + )); + } + }) + }) + .map_err(|e| MethodErr::failed(&e))?; + + local_spirc + .load(SpircLoadCommand { + context_uri, + start_playing: true, + shuffle, + repeat: repeat.into(), + playing_track_index, + tracks, + }) + .map_err(|e| MethodErr::failed(&e)) }); let local_state = current_state.clone(); diff --git a/src/main_loop.rs b/src/main_loop.rs index 073fc0e6..26aa5686 100644 --- a/src/main_loop.rs +++ b/src/main_loop.rs @@ -107,7 +107,8 @@ impl MainLoop { #[cfg(feature = "dbus_mpris")] let mpris_event_tx = if self.use_mpris { let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); - *dbus_server.as_mut() = Either::Left(DbusServer::new(rx, self.dbus_type)); + *dbus_server.as_mut() = + Either::Left(DbusServer::new(rx, self.dbus_type, self.session.clone())); Some(tx) } else { None