Merge branch 'KoffeinFlummi-mpris' into develop
This commit is contained in:
@@ -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"]
|
||||
|
||||
19
src/main.rs
19
src/main.rs
@@ -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),
|
||||
|
||||
175
src/mpris.rs
175
src/mpris.rs
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user