player: Implement MPRIS

This commit is contained in:
Elias Projahn 2023-11-03 18:20:41 +01:00
parent c378305465
commit 31144dff46
6 changed files with 213 additions and 67 deletions

180
Cargo.lock generated
View file

@ -61,6 +61,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.0"
@ -85,9 +91,9 @@ version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c0466dfa8c0ee78deef390c274ad756801e0a6dbb86c5ef0924a298c5761c4d"
dependencies = [
"bitflags",
"bitflags 2.4.0",
"cairo-sys-rs",
"glib",
"glib 0.18.2",
"libc",
"once_cell",
"thiserror",
@ -99,7 +105,7 @@ version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51"
dependencies = [
"glib-sys",
"glib-sys 0.18.1",
"libc",
"system-deps",
]
@ -146,6 +152,16 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
[[package]]
name = "dbus"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48b5f0f36f1eebe901b0e6bee369a77ed3396334bf3f09abd46454a576f71819"
dependencies = [
"libc",
"libdbus-sys",
]
[[package]]
name = "either"
version = "1.9.0"
@ -251,7 +267,7 @@ checksum = "bbc9c2ed73a81d556b65d08879ba4ee58808a6b1927ce915262185d6d547c6f3"
dependencies = [
"gdk-pixbuf-sys",
"gio",
"glib",
"glib 0.18.2",
"libc",
"once_cell",
]
@ -263,8 +279,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7"
dependencies = [
"gio-sys",
"glib-sys",
"gobject-sys",
"glib-sys 0.18.1",
"gobject-sys 0.18.0",
"libc",
"system-deps",
]
@ -279,7 +295,7 @@ dependencies = [
"gdk-pixbuf",
"gdk4-sys",
"gio",
"glib",
"glib 0.18.2",
"libc",
"pango",
]
@ -293,8 +309,8 @@ dependencies = [
"cairo-sys-rs",
"gdk-pixbuf-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"glib-sys 0.18.1",
"gobject-sys 0.18.0",
"libc",
"pango-sys",
"pkg-config",
@ -343,7 +359,7 @@ dependencies = [
"futures-io",
"futures-util",
"gio-sys",
"glib",
"glib 0.18.2",
"libc",
"once_cell",
"pin-project-lite",
@ -357,29 +373,49 @@ version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2"
dependencies = [
"glib-sys",
"gobject-sys",
"glib-sys 0.18.1",
"gobject-sys 0.18.0",
"libc",
"system-deps",
"winapi",
]
[[package]]
name = "glib"
version = "0.15.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edb0306fbad0ab5428b0ca674a23893db909a98582969c9b537be4ced78c505d"
dependencies = [
"bitflags 1.3.2",
"futures-channel",
"futures-core",
"futures-executor",
"futures-task",
"glib-macros 0.15.13",
"glib-sys 0.15.10",
"gobject-sys 0.15.10",
"libc",
"once_cell",
"smallvec",
"thiserror",
]
[[package]]
name = "glib"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c316afb01ce8067c5eaab1fc4f2cd47dc21ce7b6296358605e2ffab23ccbd19"
dependencies = [
"bitflags",
"bitflags 2.4.0",
"futures-channel",
"futures-core",
"futures-executor",
"futures-task",
"futures-util",
"gio-sys",
"glib-macros",
"glib-sys",
"gobject-sys",
"glib-macros 0.18.2",
"glib-sys 0.18.1",
"gobject-sys 0.18.0",
"libc",
"memchr",
"once_cell",
@ -387,6 +423,21 @@ dependencies = [
"thiserror",
]
[[package]]
name = "glib-macros"
version = "0.15.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10c6ae9f6fa26f4fb2ac16b528d138d971ead56141de489f8111e259b9df3c4a"
dependencies = [
"anyhow",
"heck",
"proc-macro-crate",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "glib-macros"
version = "0.18.2"
@ -401,6 +452,16 @@ dependencies = [
"syn 2.0.37",
]
[[package]]
name = "glib-sys"
version = "0.15.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4"
dependencies = [
"libc",
"system-deps",
]
[[package]]
name = "glib-sys"
version = "0.18.1"
@ -411,13 +472,24 @@ dependencies = [
"system-deps",
]
[[package]]
name = "gobject-sys"
version = "0.15.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a"
dependencies = [
"glib-sys 0.15.10",
"libc",
"system-deps",
]
[[package]]
name = "gobject-sys"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44"
dependencies = [
"glib-sys",
"glib-sys 0.18.1",
"libc",
"system-deps",
]
@ -428,7 +500,7 @@ version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2228cda1505613a7a956cca69076892cfbda84fc2b7a62b94a41a272c0c401"
dependencies = [
"glib",
"glib 0.18.2",
"graphene-sys",
"libc",
]
@ -439,7 +511,7 @@ version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc4144cee8fc8788f2a9b73dc5f1d4e1189d1f95305c4cb7bd9c1af1cfa31f59"
dependencies = [
"glib-sys",
"glib-sys 0.18.1",
"libc",
"pkg-config",
"system-deps",
@ -453,7 +525,7 @@ checksum = "0d958e351d2f210309b32d081c832d7de0aca0b077aa10d88336c6379bd01f7e"
dependencies = [
"cairo-rs",
"gdk4",
"glib",
"glib 0.18.2",
"graphene-rs",
"gsk4-sys",
"libc",
@ -468,8 +540,8 @@ checksum = "12bd9e3effea989f020e8f1ff3fa3b8c63ba93d43b899c11a118868853a56d55"
dependencies = [
"cairo-sys-rs",
"gdk4-sys",
"glib-sys",
"gobject-sys",
"glib-sys 0.18.1",
"gobject-sys 0.18.0",
"graphene-sys",
"libc",
"pango-sys",
@ -486,7 +558,7 @@ dependencies = [
"futures-channel",
"futures-core",
"futures-util",
"glib",
"glib 0.18.2",
"gstreamer-sys",
"itertools",
"libc",
@ -508,7 +580,7 @@ checksum = "0fe38a6d5c1e516ce3fd6069e972a540d315448ed69fdadad739e6c6c6eb2a01"
dependencies = [
"atomic_refcell",
"cfg-if",
"glib",
"glib 0.18.2",
"gstreamer",
"gstreamer-base-sys",
"libc",
@ -520,8 +592,8 @@ version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4ca701f9078fe115b29b24c80910b577f9cb5b039182f050dbadf5933594b64"
dependencies = [
"glib-sys",
"gobject-sys",
"glib-sys 0.18.1",
"gobject-sys 0.18.0",
"gstreamer-sys",
"libc",
"system-deps",
@ -533,7 +605,7 @@ version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e68dc9772932f6133a9517742918b13ab5414db1f47e19daebc3027a1c3d20d2"
dependencies = [
"glib",
"glib 0.18.2",
"gstreamer",
"gstreamer-player-sys",
"gstreamer-video",
@ -546,8 +618,8 @@ version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5ef4d00b43d0aa94e9a518e6ef4a4c504b4b855304a0a5f4ed1493d5e5ca66c"
dependencies = [
"glib-sys",
"gobject-sys",
"glib-sys 0.18.1",
"gobject-sys 0.18.0",
"gstreamer-sys",
"gstreamer-video-sys",
"libc",
@ -560,8 +632,8 @@ version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f86bf9de67a6ab7af67ac11588f4939e984a936030437219f269fe969d79ad8c"
dependencies = [
"glib-sys",
"gobject-sys",
"glib-sys 0.18.1",
"gobject-sys 0.18.0",
"libc",
"system-deps",
]
@ -574,7 +646,7 @@ checksum = "01b4d3141362b3d44a684e697d2bc55fea73d023315449cda83f0f4324531d64"
dependencies = [
"cfg-if",
"futures-channel",
"glib",
"glib 0.18.2",
"gstreamer",
"gstreamer-base",
"gstreamer-video-sys",
@ -587,8 +659,8 @@ version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cdc36baab839921b05d2468524da649f373dccc5f966c75e564029dc135b1c"
dependencies = [
"glib-sys",
"gobject-sys",
"glib-sys 0.18.1",
"gobject-sys 0.18.0",
"gstreamer-base-sys",
"gstreamer-sys",
"libc",
@ -607,7 +679,7 @@ dependencies = [
"gdk-pixbuf",
"gdk4",
"gio",
"glib",
"glib 0.18.2",
"graphene-rs",
"gsk4",
"gtk4-macros",
@ -640,8 +712,8 @@ dependencies = [
"gdk-pixbuf-sys",
"gdk4-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"glib-sys 0.18.1",
"gobject-sys 0.18.0",
"graphene-sys",
"gsk4-sys",
"libc",
@ -746,7 +818,7 @@ dependencies = [
"gdk-pixbuf",
"gdk4",
"gio",
"glib",
"glib 0.18.2",
"gtk4",
"libadwaita-sys",
"libc",
@ -761,8 +833,8 @@ checksum = "5e10aaa38de1d53374f90deeb4535209adc40cc5dba37f9704724169bceec69a"
dependencies = [
"gdk4-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"glib-sys 0.18.1",
"gobject-sys 0.18.0",
"gtk4-sys",
"libc",
"pango-sys",
@ -775,6 +847,15 @@ version = "0.2.146"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
[[package]]
name = "libdbus-sys"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72"
dependencies = [
"pkg-config",
]
[[package]]
name = "libsqlite3-sys"
version = "0.26.0"
@ -829,6 +910,16 @@ dependencies = [
"autocfg",
]
[[package]]
name = "mpris-player"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be832ec9171fdaf43609d02bb552f4129ba6eacd184bb25186e2906dbd3cf098"
dependencies = [
"dbus",
"glib 0.15.12",
]
[[package]]
name = "muldiv"
version = "1.0.1"
@ -846,6 +937,7 @@ dependencies = [
"gtk4",
"libadwaita",
"log",
"mpris-player",
"once_cell",
"rand",
"rusqlite",
@ -951,7 +1043,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06a9e54b831d033206160096b825f2070cf5fda7e35167b1c01e9e774f9202d1"
dependencies = [
"gio",
"glib",
"glib 0.18.2",
"libc",
"once_cell",
"pango-sys",
@ -963,8 +1055,8 @@ version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5"
dependencies = [
"glib-sys",
"gobject-sys",
"glib-sys 0.18.1",
"gobject-sys 0.18.0",
"libc",
"system-deps",
]
@ -1110,7 +1202,7 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2"
dependencies = [
"bitflags",
"bitflags 2.4.0",
"fallible-iterator",
"fallible-streaming-iterator",
"hashlink",

View file

@ -11,6 +11,7 @@ gettext-rs = { version = "0.7", features = ["gettext-system"] }
gstreamer-player = "0.21"
gtk = { package = "gtk4", version = "0.7", features = ["v4_12", "blueprint"] }
log = "0.4"
mpris-player = "0.6"
once_cell = "1"
rand = "0.8"
rusqlite = { version = "0.29", features = ["bundled"] }

View file

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

View file

@ -3,13 +3,19 @@ use fragile::Fragile;
use gstreamer_player::gst;
use gtk::{
gio,
glib::{self, Properties},
glib::{self, clone, Properties},
prelude::*,
subclass::prelude::*,
};
use std::cell::{Cell, OnceCell};
use mpris_player::{MprisPlayer, PlaybackStatus};
use std::{
cell::{Cell, OnceCell},
sync::Arc,
};
mod imp {
use mpris_player::Metadata;
use super::*;
#[derive(Properties, Debug, Default)]
@ -31,6 +37,8 @@ mod imp {
pub position: Cell<f64>,
#[property(get, construct_only)]
pub player: OnceCell<gstreamer_player::Player>,
pub mpris: OnceCell<Arc<MprisPlayer>>,
}
impl MusicusPlayer {
@ -39,21 +47,28 @@ mod imp {
if let Some(item) = playlist.item(index) {
if let Some(old_item) = playlist.item(self.current_index.get()) {
old_item.downcast::<PlaylistItem>()
old_item
.downcast::<PlaylistItem>()
.unwrap()
.set_is_playing(false);
}
let item = item.downcast::<PlaylistItem>().unwrap();
self.mpris.get().unwrap().set_metadata(Metadata {
artist: Some(vec![item.make_title()]),
title: item.make_subtitle(),
..Default::default()
});
let uri = glib::filename_to_uri(&item.path(), None)
.expect("track path should be parsable as an URI");
.expect("track path should be parsable as an URI");
let player = self.player.get().unwrap();
player.set_uri(Some(&uri));
if self.playing.get() {
player.play();
}
self.current_index.set(index);
item.set_is_playing(true);
}
@ -80,6 +95,29 @@ mod imp {
fn constructed(&self) {
self.parent_constructed();
let mpris = MprisPlayer::new(
"de.johrpan.musicus".to_string(),
"Musicus".to_string(),
"de.johrpan.musicus.desktop".to_string(),
);
mpris.set_can_play(true);
mpris.set_can_pause(true);
mpris.set_can_go_previous(true);
mpris.set_can_go_next(true);
mpris.set_can_seek(false);
mpris.set_can_raise(false);
mpris.set_can_set_fullscreen(false);
let obj = self.obj();
mpris.connect_play(clone!(@weak obj => move || obj.play()));
mpris.connect_pause(clone!(@weak obj => move || obj.pause()));
mpris.connect_play_pause(clone!(@weak obj => move || obj.play_pause()));
mpris.connect_previous(clone!(@weak obj => move || obj.previous()));
mpris.connect_next(clone!(@weak obj => move || obj.next()));
self.mpris.set(mpris).expect("mpris should not be set");
let player = self.player.get().unwrap();
let mut config = player.config();
@ -174,14 +212,24 @@ impl MusicusPlayer {
}
}
pub fn play_pause(&self) {
if self.playing() {
self.pause();
} else {
self.play();
}
}
pub fn play(&self) {
self.player().play();
self.set_playing(true);
self.imp().mpris.get().unwrap().set_playback_status(PlaybackStatus::Playing);
}
pub fn pause(&self) {
self.player().pause();
self.set_playing(false);
self.imp().mpris.get().unwrap().set_playback_status(PlaybackStatus::Paused);
}
pub fn current_item(&self) -> Option<PlaylistItem> {

View file

@ -40,17 +40,10 @@ mod imp {
impl PlayerBar {
fn update(&self) {
if let Some(item) = self.player.borrow().current_item() {
let mut title = item.title();
self.title_label.set_label(&item.make_title());
if let Some(part_title) = item.part_title() {
title.push_str(": ");
title.push_str(&part_title);
}
self.title_label.set_label(&title);
if let Some(performances) = item.performers() {
self.subtitle_label.set_label(&performances);
if let Some(subtitle) = item.make_subtitle() {
self.subtitle_label.set_label(&subtitle);
self.subtitle_label.set_visible(true);
} else {
self.subtitle_label.set_visible(false);
@ -179,12 +172,7 @@ impl PlayerBar {
#[template_callback]
fn play_pause(&self, _: &gtk::Button) {
let player = self.player();
if player.playing() {
player.pause();
} else {
player.play();
}
self.player().play_pause();
}
}

View file

@ -59,4 +59,19 @@ impl PlaylistItem {
.property("path", path.as_ref())
.build()
}
pub fn make_title(&self) -> String {
let mut title = self.title();
if let Some(part_title) = self.part_title() {
title.push_str(": ");
title.push_str(&part_title);
}
title
}
pub fn make_subtitle(&self) -> Option<String> {
self.performers()
}
}