Merge branch 'KoffeinFlummi-mpris' into develop

This commit is contained in:
Henrik Friedrichsen
2019-03-12 18:04:41 +01:00
3 changed files with 115 additions and 82 deletions

View File

@@ -27,7 +27,6 @@ tokio-core = "0.1"
tokio-timer = "0.2" tokio-timer = "0.2"
unicode-width = "0.1.5" unicode-width = "0.1.5"
dbus = { version = "0.6.4", optional = true } dbus = { version = "0.6.4", optional = true }
dbus-tokio = { version = "0.3.0", optional = true }
[dependencies.librespot] [dependencies.librespot]
git = "https://github.com/librespot-org/librespot.git" git = "https://github.com/librespot-org/librespot.git"
@@ -42,5 +41,5 @@ features = ["pancurses-backend"]
[features] [features]
pulseaudio_backend = ["librespot/pulseaudio-backend"] pulseaudio_backend = ["librespot/pulseaudio-backend"]
portaudio_backend = ["librespot/portaudio-backend"] portaudio_backend = ["librespot/portaudio-backend"]
mpris = ["dbus", "dbus-tokio"] mpris = ["dbus"]
default = ["pulseaudio_backend", "mpris"] default = ["pulseaudio_backend", "mpris"]

View File

@@ -11,8 +11,6 @@ extern crate unicode_width;
#[cfg(feature = "mpris")] #[cfg(feature = "mpris")]
extern crate dbus; extern crate dbus;
#[cfg(feature = "mpris")]
extern crate dbus_tokio;
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;
@@ -53,9 +51,6 @@ use commands::CommandManager;
use events::{Event, EventManager}; use events::{Event, EventManager};
use spotify::PlayerEvent; use spotify::PlayerEvent;
#[cfg(feature = "mpris")]
use mpris::run_dbus_server;
fn init_logger(content: TextContent, write_to_file: bool) { fn init_logger(content: TextContent, write_to_file: bool) {
let mut builder = env_logger::Builder::from_default_env(); let mut builder = env_logger::Builder::from_default_env();
{ {
@@ -147,13 +142,7 @@ fn main() {
))); )));
#[cfg(feature = "mpris")] #[cfg(feature = "mpris")]
{ let mpris_manager = mpris::MprisManager::new(spotify.clone(), queue.clone());
let spotify = spotify.clone();
let queue = queue.clone();
std::thread::spawn(move || {
run_dbus_server(spotify, queue);
});
}
let search = ui::search::SearchView::new(spotify.clone(), queue.clone()); let search = ui::search::SearchView::new(spotify.clone(), queue.clone());
@@ -347,6 +336,9 @@ fn main() {
queue.lock().expect("could not lock queue").next(); queue.lock().expect("could not lock queue").next();
} }
spotify.update_status(state); spotify.update_status(state);
#[cfg(feature = "mpris")]
mpris_manager.update();
} }
Event::Playlist(event) => playlists.handle_ev(&mut cursive, event), Event::Playlist(event) => playlists.handle_ev(&mut cursive, event),
Event::Command(cmd) => { Event::Command(cmd) => {
@@ -356,6 +348,9 @@ fn main() {
v.set_error(e); v.set_error(e);
}); });
} }
#[cfg(feature = "mpris")]
mpris_manager.update();
} }
Event::ScreenChange(name) => match name.as_ref() { Event::ScreenChange(name) => match name.as_ref() {
"playlists" => playlists.repopulate(&mut cursive), "playlists" => playlists.repopulate(&mut cursive),

View File

@@ -1,26 +1,71 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex, mpsc};
use dbus::{Path, SignalArgs};
use dbus::arg::{Variant, RefArg}; use dbus::arg::{Variant, RefArg};
use dbus::tree::{Access}; use dbus::tree::{Access, Factory};
use dbus_tokio::AConnection; use dbus::stdintf::org_freedesktop_dbus::PropertiesPropertiesChanged;
use dbus_tokio::tree::{AFactory, ATree, ATreeServer};
use tokio::reactor::Handle;
use tokio::runtime::current_thread::Runtime;
use futures::Stream;
use queue::Queue; use queue::Queue;
use spotify::{PlayerEvent, Spotify}; use spotify::{PlayerEvent, Spotify};
pub fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Mutex<Queue>>) { fn get_playbackstatus(spotify: Arc<Spotify>) -> String {
match spotify.get_current_status() {
PlayerEvent::Playing => "Playing",
PlayerEvent::Paused => "Paused",
_ => "Stopped"
}.to_string()
}
fn get_metadata(queue: Arc<Mutex<Queue>>) -> HashMap<String, Variant<Box<RefArg>>> {
let mut hm: HashMap<String, Variant<Box<RefArg>>> = HashMap::new();
let queue = queue.lock().expect("could not lock queue");
let track = queue.get_current();
hm.insert("mpris:trackid".to_string(), Variant(Box::new(
track.map(|t| format!("spotify:track:{}", t.id.to_base62())).unwrap_or("".to_string())
)));
hm.insert("mpris:length".to_string(), Variant(Box::new(
track.map(|t| t.duration * 1_000_000).unwrap_or(0)
)));
hm.insert("mpris:artUrl".to_string(), Variant(Box::new(
track.map(|t| t.cover_url.clone()).unwrap_or("".to_string())
)));
hm.insert("xesam:album".to_string(), Variant(Box::new(
track.map(|t| t.album.clone()).unwrap_or("".to_string())
)));
hm.insert("xesam:albumArtist".to_string(), Variant(Box::new(
track.map(|t| t.album_artists.clone()).unwrap_or(Vec::new())
)));
hm.insert("xesam:artist".to_string(), Variant(Box::new(
track.map(|t| t.artists.clone()).unwrap_or(Vec::new())
)));
hm.insert("xesam:discNumber".to_string(), Variant(Box::new(
track.map(|t| t.disc_number).unwrap_or(0)
)));
hm.insert("xesam:title".to_string(), Variant(Box::new(
track.map(|t| t.title.clone()).unwrap_or("".to_string())
)));
hm.insert("xesam:trackNumber".to_string(), Variant(Box::new(
track.map(|t| t.track_number).unwrap_or(0)
)));
hm.insert("xesam:url".to_string(), Variant(Box::new(
track.map(|t| t.url.clone()).unwrap_or("".to_string())
)));
hm
}
fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Mutex<Queue>>, rx: mpsc::Receiver<()>) {
let conn = Rc::new(dbus::Connection::get_private(dbus::BusType::Session) let conn = Rc::new(dbus::Connection::get_private(dbus::BusType::Session)
.expect("Failed to connect to dbus")); .expect("Failed to connect to dbus"));
conn.register_name("org.mpris.MediaPlayer2.ncspot", dbus::NameFlag::ReplaceExisting as u32) conn.register_name("org.mpris.MediaPlayer2.ncspot", dbus::NameFlag::ReplaceExisting as u32)
.expect("Failed to register dbus player name"); .expect("Failed to register dbus player name");
let f = AFactory::new_afn::<()>(); let f = Factory::new_fn::<()>();
let property_canquit = f.property::<bool, _>("CanQuit", ()) let property_canquit = f.property::<bool, _>("CanQuit", ())
.access(Access::Read) .access(Access::Read)
@@ -72,7 +117,7 @@ pub fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Mutex<Queue>>) {
}); });
// https://specifications.freedesktop.org/mpris-spec/latest/Media_Player.html // https://specifications.freedesktop.org/mpris-spec/latest/Media_Player.html
let interface = f.interface("org.mpris.MediaPlayer", ()) let interface = f.interface("org.mpris.MediaPlayer2", ())
.add_p(property_canquit) .add_p(property_canquit)
.add_p(property_canraise) .add_p(property_canraise)
.add_p(property_cansetfullscreen) .add_p(property_cansetfullscreen)
@@ -86,11 +131,7 @@ pub fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Mutex<Queue>>) {
f.property::<String, _>("PlaybackStatus", ()) f.property::<String, _>("PlaybackStatus", ())
.access(Access::Read) .access(Access::Read)
.on_get(move |iter, _| { .on_get(move |iter, _| {
let status = match spotify.get_current_status() { let status = get_playbackstatus(spotify.clone());
PlayerEvent::Playing => "Playing",
PlayerEvent::Paused => "Paused",
_ => "Stopped"
}.to_string();
iter.append(status); iter.append(status);
Ok(()) Ok(())
}) })
@@ -108,42 +149,7 @@ pub fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Mutex<Queue>>) {
f.property::<HashMap<String, Variant<Box<RefArg>>>, _>("Metadata", ()) f.property::<HashMap<String, Variant<Box<RefArg>>>, _>("Metadata", ())
.access(Access::Read) .access(Access::Read)
.on_get(move |iter, _| { .on_get(move |iter, _| {
let mut hm: HashMap<String, Variant<Box<RefArg>>> = HashMap::new(); let hm = get_metadata(queue.clone());
let queue = queue.lock().expect("could not lock queue");
let track = queue.get_current();
hm.insert("mpris:trackid".to_string(), Variant(Box::new(
track.map(|t| format!("spotify:track:{}", t.id.to_base62())).unwrap_or("".to_string())
)));
hm.insert("mpris:length".to_string(), Variant(Box::new(
track.map(|t| t.duration * 1_000_000).unwrap_or(0)
)));
hm.insert("mpris:artUrl".to_string(), Variant(Box::new(
track.map(|t| t.cover_url.clone()).unwrap_or("".to_string())
)));
hm.insert("xesam:album".to_string(), Variant(Box::new(
track.map(|t| t.album.clone()).unwrap_or("".to_string())
)));
hm.insert("xesam:albumArtist".to_string(), Variant(Box::new(
track.map(|t| t.album_artists.join(", ")).unwrap_or("".to_string())
)));
hm.insert("xesam:artist".to_string(), Variant(Box::new(
track.map(|t| t.artists.join(", ")).unwrap_or("".to_string())
)));
hm.insert("xesam:discNumber".to_string(), Variant(Box::new(
track.map(|t| t.disc_number).unwrap_or(0)
)));
hm.insert("xesam:title".to_string(), Variant(Box::new(
track.map(|t| t.title.clone()).unwrap_or("".to_string())
)));
hm.insert("xesam:trackNumber".to_string(), Variant(Box::new(
track.map(|t| t.track_number).unwrap_or(0)
)));
hm.insert("xesam:url".to_string(), Variant(Box::new(
track.map(|t| t.url.clone()).unwrap_or("".to_string())
)));
iter.append(hm); iter.append(hm);
Ok(()) Ok(())
@@ -232,7 +238,7 @@ pub fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Mutex<Queue>>) {
let method_playpause = { let method_playpause = {
let spotify = spotify.clone(); let spotify = spotify.clone();
f.amethod("PlayPause", (), move |m| { f.method("PlayPause", (), move |m| {
spotify.toggleplayback(); spotify.toggleplayback();
Ok(vec![m.msg.method_return()]) Ok(vec![m.msg.method_return()])
}) })
@@ -240,7 +246,7 @@ pub fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Mutex<Queue>>) {
let method_play = { let method_play = {
let spotify = spotify.clone(); let spotify = spotify.clone();
f.amethod("Play", (), move |m| { f.method("Play", (), move |m| {
spotify.play(); spotify.play();
Ok(vec![m.msg.method_return()]) Ok(vec![m.msg.method_return()])
}) })
@@ -248,7 +254,7 @@ pub fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Mutex<Queue>>) {
let method_pause = { let method_pause = {
let spotify = spotify.clone(); let spotify = spotify.clone();
f.amethod("Pause", (), move |m| { f.method("Pause", (), move |m| {
spotify.pause(); spotify.pause();
Ok(vec![m.msg.method_return()]) Ok(vec![m.msg.method_return()])
}) })
@@ -256,7 +262,7 @@ pub fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Mutex<Queue>>) {
let method_stop = { let method_stop = {
let spotify = spotify.clone(); let spotify = spotify.clone();
f.amethod("Stop", (), move |m| { f.method("Stop", (), move |m| {
spotify.stop(); spotify.stop();
Ok(vec![m.msg.method_return()]) Ok(vec![m.msg.method_return()])
}) })
@@ -264,7 +270,7 @@ pub fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Mutex<Queue>>) {
let method_next = { let method_next = {
let queue = queue.clone(); let queue = queue.clone();
f.amethod("Next", (), move |m| { f.method("Next", (), move |m| {
queue.lock().expect("failed to lock queue").next(); queue.lock().expect("failed to lock queue").next();
Ok(vec![m.msg.method_return()]) Ok(vec![m.msg.method_return()])
}) })
@@ -272,7 +278,7 @@ pub fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Mutex<Queue>>) {
let method_previous = { let method_previous = {
let queue = queue.clone(); let queue = queue.clone();
f.amethod("Previous", (), move |m| { f.method("Previous", (), move |m| {
queue.lock().expect("failed to lock queue").previous(); queue.lock().expect("failed to lock queue").previous();
Ok(vec![m.msg.method_return()]) Ok(vec![m.msg.method_return()])
}) })
@@ -303,7 +309,7 @@ pub fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Mutex<Queue>>) {
.add_m(method_next) .add_m(method_next)
.add_m(method_previous); .add_m(method_previous);
let tree = f.tree(ATree::new()) let tree = f.tree(())
.add(f.object_path("/org/mpris/MediaPlayer2", ()).introspectable() .add(f.object_path("/org/mpris/MediaPlayer2", ()).introspectable()
.add(interface) .add(interface)
.add(interface_player) .add(interface_player)
@@ -311,14 +317,47 @@ pub fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Mutex<Queue>>) {
tree.set_registered(&conn, true).expect("failed to register tree"); tree.set_registered(&conn, true).expect("failed to register tree");
let mut rt = Runtime::new().unwrap(); conn.add_handler(tree);
let aconn = AConnection::new(conn.clone(), Handle::default(), &mut rt).unwrap(); loop {
let server = ATreeServer::new(conn.clone(), &tree, aconn.messages().unwrap()); if let Some(m) = conn.incoming(200).next() {
warn!("Unhandled dbus message: {:?}", m);
}
let server = server.for_each(|m| { if let Ok(_) = rx.try_recv() {
warn!("Unhandled dbus message: {:?}", m); let mut changed: PropertiesPropertiesChanged = Default::default();
Ok(()) changed.interface_name = "org.mpris.MediaPlayer2.Player".to_string();
}); changed.changed_properties.insert(
rt.block_on(server).unwrap(); "Metadata".to_string(),
rt.run().unwrap(); Variant(Box::new(get_metadata(queue.clone())))
);
changed.changed_properties.insert(
"PlaybackStatus".to_string(),
Variant(Box::new(get_playbackstatus(spotify.clone())))
);
conn.send(changed.to_emit_message(&Path::new("/org/mpris/MediaPlayer2".to_string()).unwrap())).unwrap();
}
}
}
pub struct MprisManager {
tx: mpsc::Sender<()>
}
impl MprisManager {
pub fn new(spotify: Arc<Spotify>, queue: Arc<Mutex<Queue>>) -> Self {
let (tx, rx) = mpsc::channel::<()>();
std::thread::spawn(move || {
run_dbus_server(spotify, queue, rx);
});
MprisManager {
tx: tx
}
}
pub fn update(&self) {
self.tx.send(()).unwrap();
}
} }