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"
unicode-width = "0.1.5"
dbus = { version = "0.6.4", optional = true }
dbus-tokio = { version = "0.3.0", optional = true }
[dependencies.librespot]
git = "https://github.com/librespot-org/librespot.git"
@@ -42,5 +41,5 @@ features = ["pancurses-backend"]
[features]
pulseaudio_backend = ["librespot/pulseaudio-backend"]
portaudio_backend = ["librespot/portaudio-backend"]
mpris = ["dbus", "dbus-tokio"]
mpris = ["dbus"]
default = ["pulseaudio_backend", "mpris"]

View File

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

View File

@@ -1,26 +1,71 @@
use std::collections::HashMap;
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::tree::{Access};
use dbus_tokio::AConnection;
use dbus_tokio::tree::{AFactory, ATree, ATreeServer};
use tokio::reactor::Handle;
use tokio::runtime::current_thread::Runtime;
use futures::Stream;
use dbus::tree::{Access, Factory};
use dbus::stdintf::org_freedesktop_dbus::PropertiesPropertiesChanged;
use queue::Queue;
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)
.expect("Failed to connect to dbus"));
conn.register_name("org.mpris.MediaPlayer2.ncspot", dbus::NameFlag::ReplaceExisting as u32)
.expect("Failed to register dbus player name");
let f = AFactory::new_afn::<()>();
let f = Factory::new_fn::<()>();
let property_canquit = f.property::<bool, _>("CanQuit", ())
.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
let interface = f.interface("org.mpris.MediaPlayer", ())
let interface = f.interface("org.mpris.MediaPlayer2", ())
.add_p(property_canquit)
.add_p(property_canraise)
.add_p(property_cansetfullscreen)
@@ -86,11 +131,7 @@ pub fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Mutex<Queue>>) {
f.property::<String, _>("PlaybackStatus", ())
.access(Access::Read)
.on_get(move |iter, _| {
let status = match spotify.get_current_status() {
PlayerEvent::Playing => "Playing",
PlayerEvent::Paused => "Paused",
_ => "Stopped"
}.to_string();
let status = get_playbackstatus(spotify.clone());
iter.append(status);
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", ())
.access(Access::Read)
.on_get(move |iter, _| {
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.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())
)));
let hm = get_metadata(queue.clone());
iter.append(hm);
Ok(())
@@ -232,7 +238,7 @@ pub fn run_dbus_server(spotify: Arc<Spotify>, queue: Arc<Mutex<Queue>>) {
let method_playpause = {
let spotify = spotify.clone();
f.amethod("PlayPause", (), move |m| {
f.method("PlayPause", (), move |m| {
spotify.toggleplayback();
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 spotify = spotify.clone();
f.amethod("Play", (), move |m| {
f.method("Play", (), move |m| {
spotify.play();
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 spotify = spotify.clone();
f.amethod("Pause", (), move |m| {
f.method("Pause", (), move |m| {
spotify.pause();
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 spotify = spotify.clone();
f.amethod("Stop", (), move |m| {
f.method("Stop", (), move |m| {
spotify.stop();
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 queue = queue.clone();
f.amethod("Next", (), move |m| {
f.method("Next", (), move |m| {
queue.lock().expect("failed to lock queue").next();
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 queue = queue.clone();
f.amethod("Previous", (), move |m| {
f.method("Previous", (), move |m| {
queue.lock().expect("failed to lock queue").previous();
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_previous);
let tree = f.tree(ATree::new())
let tree = f.tree(())
.add(f.object_path("/org/mpris/MediaPlayer2", ()).introspectable()
.add(interface)
.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");
let mut rt = Runtime::new().unwrap();
let aconn = AConnection::new(conn.clone(), Handle::default(), &mut rt).unwrap();
let server = ATreeServer::new(conn.clone(), &tree, aconn.messages().unwrap());
conn.add_handler(tree);
loop {
if let Some(m) = conn.incoming(200).next() {
warn!("Unhandled dbus message: {:?}", m);
}
let server = server.for_each(|m| {
warn!("Unhandled dbus message: {:?}", m);
Ok(())
});
rt.block_on(server).unwrap();
rt.run().unwrap();
if let Ok(_) = rx.try_recv() {
let mut changed: PropertiesPropertiesChanged = Default::default();
changed.interface_name = "org.mpris.MediaPlayer2.Player".to_string();
changed.changed_properties.insert(
"Metadata".to_string(),
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();
}
}