From b9b0b613195572224f79c26f2cb1674e857fa5bc Mon Sep 17 00:00:00 2001 From: Elias Projahn Date: Fri, 5 Feb 2021 00:50:27 +0100 Subject: [PATCH] Add support for MPRIS --- crates/musicus/src/window.rs | 5 ++ crates/musicus_backend/Cargo.toml | 1 + crates/musicus_backend/src/player.rs | 98 ++++++++++++++++++++++++++-- de.johrpan.musicus.json | 2 + meson.build | 4 +- 5 files changed, 102 insertions(+), 8 deletions(-) diff --git a/crates/musicus/src/window.rs b/crates/musicus/src/window.rs index d5165e8..bdd3f85 100644 --- a/crates/musicus/src/window.rs +++ b/crates/musicus/src/window.rs @@ -158,6 +158,11 @@ impl Window { clone.navigator.reset(); 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_screen.clone().set_player(Some(player)); } diff --git a/crates/musicus_backend/Cargo.toml b/crates/musicus_backend/Cargo.toml index fb14f99..ad731ae 100644 --- a/crates/musicus_backend/Cargo.toml +++ b/crates/musicus_backend/Cargo.toml @@ -10,6 +10,7 @@ gio = "0.9.1" glib = "0.10.3" gstreamer = "0.16.4" gstreamer-player = "0.16.3" +mpris-player = "0.6.0" musicus_client = { version = "0.1.0", path = "../musicus_client" } musicus_database = { version = "0.1.0", path = "../musicus_database" } secret-service = "2.0.1" diff --git a/crates/musicus_backend/src/player.rs b/crates/musicus_backend/src/player.rs index cdb0da0..1e76370 100644 --- a/crates/musicus_backend/src/player.rs +++ b/crates/musicus_backend/src/player.rs @@ -1,9 +1,12 @@ use crate::{Error, Result}; +use mpris_player::{Metadata, MprisPlayer, PlaybackStatus}; use musicus_database::TrackSet; +use glib::clone; use gstreamer_player::prelude::*; use std::cell::{Cell, RefCell}; use std::path::PathBuf; use std::rc::Rc; +use std::sync::Arc; #[derive(Clone)] pub struct PlaylistItem { @@ -14,6 +17,7 @@ pub struct PlaylistItem { pub struct Player { music_library_path: PathBuf, player: gstreamer_player::Player, + mpris: Arc, playlist: RefCell>, current_item: Cell>, current_track: Cell>, @@ -23,6 +27,7 @@ pub struct Player { duration_cbs: RefCell>>, playing_cbs: RefCell>>, position_cbs: RefCell>>, + raise_cb: RefCell>>, } impl Player { @@ -34,9 +39,24 @@ impl Player { player.set_config(config).unwrap(); 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 { music_library_path, player: player.clone(), + mpris, playlist: RefCell::new(Vec::new()), current_item: Cell::new(None), current_track: Cell::new(None), @@ -46,6 +66,7 @@ impl Player { duration_cbs: RefCell::new(Vec::new()), playing_cbs: RefCell::new(Vec::new()), position_cbs: RefCell::new(Vec::new()), + raise_cb: RefCell::new(None), }); let clone = fragile::Fragile::new(result.clone()); @@ -56,9 +77,12 @@ impl Player { } else { clone.player.stop(); clone.playing.replace(false); + for cb in &*clone.playing_cbs.borrow() { 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 } @@ -99,6 +154,10 @@ impl Player { self.position_cbs.borrow_mut().push(Box::new(cb)); } + pub fn set_raise_cb(&self, cb: F) { + self.raise_cb.replace(Some(Box::new(cb))); + } + pub fn get_playlist(&self) -> Vec { self.playlist.borrow().clone() } @@ -144,6 +203,9 @@ impl Player { for cb in &*self.playing_cbs.borrow() { cb(true); } + + self.mpris.set_can_play(true); + self.mpris.set_playback_status(PlaybackStatus::Playing); } Ok(()) @@ -158,6 +220,8 @@ impl Player { for cb in &*self.playing_cbs.borrow() { cb(false); } + + self.mpris.set_playback_status(PlaybackStatus::Paused); } else { self.player.play(); self.playing.set(true); @@ -165,6 +229,8 @@ impl Player { for cb in &*self.playing_cbs.borrow() { 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<()> { + let item = &self.playlist.borrow()[current_item]; + let track = &item.track_set.tracks[current_track]; + let uri = format!( "file://{}", - self.music_library_path - .join( - self.playlist.borrow()[current_item].track_set.tracks[current_track].path.clone(), - ) - .to_str() - .unwrap(), + self.music_library_path.join(track.path.clone()).to_str().unwrap(), ); self.player.set_uri(&uri); @@ -266,6 +330,26 @@ impl Player { cb(current_item, current_track); } + let mut parts = Vec::::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(()) } @@ -283,5 +367,7 @@ impl Player { for cb in &*self.playlist_cbs.borrow() { cb(Vec::new()); } + + self.mpris.set_can_play(false); } } diff --git a/de.johrpan.musicus.json b/de.johrpan.musicus.json index a6da167..e3c68ef 100644 --- a/de.johrpan.musicus.json +++ b/de.johrpan.musicus.json @@ -15,6 +15,8 @@ "--socket=pulseaudio", "--filesystem=host", "--talk-name=org.freedesktop.secrets", + "--talk-name=org.mpris.MediaPlayer2.Player", + "--own-name=org.mpris.MediaPlayer2.de.johrpan.musicus", "--device=all" ], "build-options" : { diff --git a/meson.build b/meson.build index 6e4b6d0..e553bc7 100644 --- a/meson.build +++ b/meson.build @@ -8,8 +8,8 @@ dependency('dbus-1', version: '>= 1.3') dependency('glib-2.0', version: '>= 2.56') dependency('gio-2.0', version: '>= 2.56') dependency('gstreamer-1.0', version: '>= 1.12') -dependency('gtk+-3.0', version: '>= 3.24.7') -dependency('libcurl', version: '>= 7.24.0') +dependency('gtk4', version: '>= 4.0') +#dependency('libcurl', version: '>= 7.24.0') dependency('libdiscid', version: '>= 0.6.2') dependency('libadwaita-1', version: '>= 1.0') dependency('pango', version: '>= 1.0')