Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New DBUS method: TransferPlayback #1162

Merged
merged 12 commits into from
Mar 3, 2023
85 changes: 71 additions & 14 deletions src/dbus_mpris.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use librespot_core::{
spotify_id::SpotifyAudioType,
eladyn marked this conversation as resolved.
Show resolved Hide resolved
};
use librespot_playback::player::PlayerEvent;
use log::{error, info};
use log::{error, info, warn};
use rspotify::{
model::{
offset::Offset, AlbumId, ArtistId, EpisodeId, IdError, PlayableItem, PlaylistId,
Expand Down Expand Up @@ -234,12 +234,14 @@ async fn create_dbus_server(
b.method("VolumeUp", (), (), move |_, _, (): ()| {
local_spirc.volume_up();
Ok(())
});
})
.deprecated();
let local_spirc = spirc.clone();
b.method("VolumeDown", (), (), move |_, _, (): ()| {
local_spirc.volume_down();
Ok(())
});
})
.deprecated();
let local_spirc = spirc.clone();
b.method("Next", (), (), move |_, _, (): ()| {
local_spirc.next();
Expand Down Expand Up @@ -413,30 +415,22 @@ async fn create_dbus_server(

let uri = Uri::from_id(id_type, id).map_err(|_| MethodErr::invalid_arg(&uri))?;

let device_id = sp_client.device().ok().and_then(|devices| {
devices.into_iter().find_map(|d| {
if d.is_active && d.name == mv_device_name {
Some(d.id)
} else {
None
}
})
});
let device_id = get_device_id(&sp_client, &mv_device_name, true);

if let Some(device_id) = device_id {
match uri {
Uri::Playable(id) => {
let _ = sp_client.start_uris_playback(
Some(id.as_ref()),
device_id.as_deref(),
Some(&device_id),
Some(Offset::for_position(0)),
None,
);
}
Uri::Context(id) => {
let _ = sp_client.start_context_playback(
&id,
device_id.as_deref(),
Some(&device_id),
Some(Offset::for_position(0)),
None,
);
Expand Down Expand Up @@ -562,12 +556,53 @@ async fn create_dbus_server(
}
});

let spotifyd_ctrls_interface: IfaceToken<()> =
cr.register("io.github.spotifyd.Controls", |b| {
let local_spirc = spirc.clone();
b.method("VolumeUp", (), (), move |_, _, (): ()| {
local_spirc.volume_up();
Ok(())
});
let local_spirc = spirc.clone();
b.method("VolumeDown", (), (), move |_, _, (): ()| {
local_spirc.volume_down();
Ok(())
});

let mv_device_name = device_name.clone();
let sp_client = Arc::clone(&spotify_api_client);
b.method("TransferPlayback", (), (), move |_, _, (): ()| {
let device_id = get_device_id(&sp_client, &mv_device_name, false);
if let Some(device_id) = device_id {
info!("Transferring playback to device {}", device_id);
match sp_client.transfer_playback(&device_id, Some(true)) {
Ok(_) => Ok(()),
Err(err) => {
let e = format!("TransferPlayback failed: {}", err);
error!("{}", e);
Err(MethodErr::failed(&e))
}
}
} else {
let msg = format!("Could not find device with name {}", mv_device_name);
warn!("TransferPlayback: {}", msg);
Err(MethodErr::failed(&msg))
}
});
});

cr.insert(
"/org/mpris/MediaPlayer2",
&[media_player2_interface, player_interface],
(),
);

cr.insert(
"/io/github/spotifyd/Controls",
&[spotifyd_ctrls_interface],
(),
);

conn.start_receive(
MatchRule::new_method_call(),
Box::new(move |msg, conn| {
Expand Down Expand Up @@ -698,6 +733,28 @@ async fn create_dbus_server(
}
}

fn get_device_id(
sp_client: &AuthCodeSpotify,
device_name: &str,
only_active: bool,
) -> Option<String> {
let device_result = sp_client.device();
match device_result {
Ok(devices) => devices.into_iter().find_map(|d| {
if d.name == device_name && (d.is_active || !only_active) {
info!("Found device: {}, active: {}", d.name, d.is_active);
d.id
} else {
None
}
}),
Err(err) => {
error!("Get devices error: {}", err);
None
}
}
}

fn uri_to_object_path(uri: String) -> dbus::Path<'static> {
let mut path = String::with_capacity(uri.len() + 1);
for element in uri.split(':') {
Expand Down