Add support for MPRIS

This commit is contained in:
Elias Projahn 2021-02-05 00:50:27 +01:00
parent 9256e60122
commit b9b0b61319
5 changed files with 102 additions and 8 deletions

View file

@ -158,6 +158,11 @@ impl Window {
clone.navigator.reset(); clone.navigator.reset();
let player = clone.backend.get_player().unwrap(); let player = clone.backend.get_player().unwrap();
player.set_raise_cb(clone!(@weak clone => move || {
clone.window.present();
}));
clone.player_bar.set_player(Some(player.clone())); clone.player_bar.set_player(Some(player.clone()));
clone.player_screen.clone().set_player(Some(player)); clone.player_screen.clone().set_player(Some(player));
} }

View file

@ -10,6 +10,7 @@ gio = "0.9.1"
glib = "0.10.3" glib = "0.10.3"
gstreamer = "0.16.4" gstreamer = "0.16.4"
gstreamer-player = "0.16.3" gstreamer-player = "0.16.3"
mpris-player = "0.6.0"
musicus_client = { version = "0.1.0", path = "../musicus_client" } musicus_client = { version = "0.1.0", path = "../musicus_client" }
musicus_database = { version = "0.1.0", path = "../musicus_database" } musicus_database = { version = "0.1.0", path = "../musicus_database" }
secret-service = "2.0.1" secret-service = "2.0.1"

View file

@ -1,9 +1,12 @@
use crate::{Error, Result}; use crate::{Error, Result};
use mpris_player::{Metadata, MprisPlayer, PlaybackStatus};
use musicus_database::TrackSet; use musicus_database::TrackSet;
use glib::clone;
use gstreamer_player::prelude::*; use gstreamer_player::prelude::*;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc;
#[derive(Clone)] #[derive(Clone)]
pub struct PlaylistItem { pub struct PlaylistItem {
@ -14,6 +17,7 @@ pub struct PlaylistItem {
pub struct Player { pub struct Player {
music_library_path: PathBuf, music_library_path: PathBuf,
player: gstreamer_player::Player, player: gstreamer_player::Player,
mpris: Arc<MprisPlayer>,
playlist: RefCell<Vec<PlaylistItem>>, playlist: RefCell<Vec<PlaylistItem>>,
current_item: Cell<Option<usize>>, current_item: Cell<Option<usize>>,
current_track: Cell<Option<usize>>, current_track: Cell<Option<usize>>,
@ -23,6 +27,7 @@ pub struct Player {
duration_cbs: RefCell<Vec<Box<dyn Fn(u64)>>>, duration_cbs: RefCell<Vec<Box<dyn Fn(u64)>>>,
playing_cbs: RefCell<Vec<Box<dyn Fn(bool)>>>, playing_cbs: RefCell<Vec<Box<dyn Fn(bool)>>>,
position_cbs: RefCell<Vec<Box<dyn Fn(u64)>>>, position_cbs: RefCell<Vec<Box<dyn Fn(u64)>>>,
raise_cb: RefCell<Option<Box<dyn Fn()>>>,
} }
impl Player { impl Player {
@ -34,9 +39,24 @@ impl Player {
player.set_config(config).unwrap(); player.set_config(config).unwrap();
player.set_video_track_enabled(false); player.set_video_track_enabled(false);
let mpris = MprisPlayer::new(
"de.johrpan.musicus".to_string(),
"Musicus".to_string(),
"de.johrpan.musicus.desktop".to_string(),
);
mpris.set_can_raise(true);
mpris.set_can_play(false);
mpris.set_can_go_previous(false);
mpris.set_can_go_next(false);
mpris.set_can_seek(false);
mpris.set_can_set_fullscreen(false);
let result = Rc::new(Self { let result = Rc::new(Self {
music_library_path, music_library_path,
player: player.clone(), player: player.clone(),
mpris,
playlist: RefCell::new(Vec::new()), playlist: RefCell::new(Vec::new()),
current_item: Cell::new(None), current_item: Cell::new(None),
current_track: Cell::new(None), current_track: Cell::new(None),
@ -46,6 +66,7 @@ impl Player {
duration_cbs: RefCell::new(Vec::new()), duration_cbs: RefCell::new(Vec::new()),
playing_cbs: RefCell::new(Vec::new()), playing_cbs: RefCell::new(Vec::new()),
position_cbs: RefCell::new(Vec::new()), position_cbs: RefCell::new(Vec::new()),
raise_cb: RefCell::new(None),
}); });
let clone = fragile::Fragile::new(result.clone()); let clone = fragile::Fragile::new(result.clone());
@ -56,9 +77,12 @@ impl Player {
} else { } else {
clone.player.stop(); clone.player.stop();
clone.playing.replace(false); clone.playing.replace(false);
for cb in &*clone.playing_cbs.borrow() { for cb in &*clone.playing_cbs.borrow() {
cb(false); cb(false);
} }
clone.mpris.set_playback_status(PlaybackStatus::Paused);
} }
}); });
@ -76,6 +100,37 @@ impl Player {
} }
}); });
result.mpris.connect_play_pause(clone!(@weak result => move || {
result.play_pause();
}));
result.mpris.connect_play(clone!(@weak result => move || {
if !result.is_playing() {
result.play_pause();
}
}));
result.mpris.connect_pause(clone!(@weak result => move || {
if result.is_playing() {
result.play_pause();
}
}));
result.mpris.connect_previous(clone!(@weak result => move || {
let _ = result.previous();
}));
result.mpris.connect_next(clone!(@weak result => move || {
let _ = result.next();
}));
result.mpris.connect_raise(clone!(@weak result => move || {
let cb = result.raise_cb.borrow();
if let Some(cb) = &*cb {
cb()
}
}));
result result
} }
@ -99,6 +154,10 @@ impl Player {
self.position_cbs.borrow_mut().push(Box::new(cb)); self.position_cbs.borrow_mut().push(Box::new(cb));
} }
pub fn set_raise_cb<F: Fn() + 'static>(&self, cb: F) {
self.raise_cb.replace(Some(Box::new(cb)));
}
pub fn get_playlist(&self) -> Vec<PlaylistItem> { pub fn get_playlist(&self) -> Vec<PlaylistItem> {
self.playlist.borrow().clone() self.playlist.borrow().clone()
} }
@ -144,6 +203,9 @@ impl Player {
for cb in &*self.playing_cbs.borrow() { for cb in &*self.playing_cbs.borrow() {
cb(true); cb(true);
} }
self.mpris.set_can_play(true);
self.mpris.set_playback_status(PlaybackStatus::Playing);
} }
Ok(()) Ok(())
@ -158,6 +220,8 @@ impl Player {
for cb in &*self.playing_cbs.borrow() { for cb in &*self.playing_cbs.borrow() {
cb(false); cb(false);
} }
self.mpris.set_playback_status(PlaybackStatus::Paused);
} else { } else {
self.player.play(); self.player.play();
self.playing.set(true); self.playing.set(true);
@ -165,6 +229,8 @@ impl Player {
for cb in &*self.playing_cbs.borrow() { for cb in &*self.playing_cbs.borrow() {
cb(true); cb(true);
} }
self.mpris.set_playback_status(PlaybackStatus::Playing);
} }
} }
@ -244,14 +310,12 @@ impl Player {
} }
pub fn set_track(&self, current_item: usize, current_track: usize) -> Result<()> { pub fn set_track(&self, current_item: usize, current_track: usize) -> Result<()> {
let item = &self.playlist.borrow()[current_item];
let track = &item.track_set.tracks[current_track];
let uri = format!( let uri = format!(
"file://{}", "file://{}",
self.music_library_path self.music_library_path.join(track.path.clone()).to_str().unwrap(),
.join(
self.playlist.borrow()[current_item].track_set.tracks[current_track].path.clone(),
)
.to_str()
.unwrap(),
); );
self.player.set_uri(&uri); self.player.set_uri(&uri);
@ -266,6 +330,26 @@ impl Player {
cb(current_item, current_track); cb(current_item, current_track);
} }
let mut parts = Vec::<String>::new();
for part in &track.work_parts {
parts.push(item.track_set.recording.work.parts[*part].title.clone());
}
let mut title = item.track_set.recording.work.get_title();
if !parts.is_empty() {
title = format!("{}: {}", title, parts.join(", "));
}
let subtitle = item.track_set.recording.get_performers();
let mut metadata = Metadata::new();
metadata.artist = Some(vec![title]);
metadata.title = Some(subtitle);
self.mpris.set_metadata(metadata);
self.mpris.set_can_go_previous(self.has_previous());
self.mpris.set_can_go_next(self.has_next());
Ok(()) Ok(())
} }
@ -283,5 +367,7 @@ impl Player {
for cb in &*self.playlist_cbs.borrow() { for cb in &*self.playlist_cbs.borrow() {
cb(Vec::new()); cb(Vec::new());
} }
self.mpris.set_can_play(false);
} }
} }

View file

@ -15,6 +15,8 @@
"--socket=pulseaudio", "--socket=pulseaudio",
"--filesystem=host", "--filesystem=host",
"--talk-name=org.freedesktop.secrets", "--talk-name=org.freedesktop.secrets",
"--talk-name=org.mpris.MediaPlayer2.Player",
"--own-name=org.mpris.MediaPlayer2.de.johrpan.musicus",
"--device=all" "--device=all"
], ],
"build-options" : { "build-options" : {

View file

@ -8,8 +8,8 @@ dependency('dbus-1', version: '>= 1.3')
dependency('glib-2.0', version: '>= 2.56') dependency('glib-2.0', version: '>= 2.56')
dependency('gio-2.0', version: '>= 2.56') dependency('gio-2.0', version: '>= 2.56')
dependency('gstreamer-1.0', version: '>= 1.12') dependency('gstreamer-1.0', version: '>= 1.12')
dependency('gtk+-3.0', version: '>= 3.24.7') dependency('gtk4', version: '>= 4.0')
dependency('libcurl', version: '>= 7.24.0') #dependency('libcurl', version: '>= 7.24.0')
dependency('libdiscid', version: '>= 0.6.2') dependency('libdiscid', version: '>= 0.6.2')
dependency('libadwaita-1', version: '>= 1.0') dependency('libadwaita-1', version: '>= 1.0')
dependency('pango', version: '>= 1.0') dependency('pango', version: '>= 1.0')