musicus/crates/musicus_backend/src/player.rs

374 lines
11 KiB
Rust
Raw Normal View History

2021-02-04 21:47:22 +01:00
use crate::{Error, Result};
2021-02-05 00:50:27 +01:00
use mpris_player::{Metadata, MprisPlayer, PlaybackStatus};
2021-02-04 21:47:22 +01:00
use musicus_database::TrackSet;
2021-02-05 00:50:27 +01:00
use glib::clone;
2020-11-07 16:11:08 +01:00
use gstreamer_player::prelude::*;
use std::cell::{Cell, RefCell};
use std::path::PathBuf;
use std::rc::Rc;
2021-02-05 00:50:27 +01:00
use std::sync::Arc;
2020-11-07 16:11:08 +01:00
#[derive(Clone)]
pub struct PlaylistItem {
2021-01-16 15:08:12 +01:00
pub track_set: TrackSet,
2020-12-20 11:47:27 +01:00
pub indices: Vec<usize>,
2020-11-07 16:11:08 +01:00
}
pub struct Player {
music_library_path: PathBuf,
player: gstreamer_player::Player,
2021-02-05 00:50:27 +01:00
mpris: Arc<MprisPlayer>,
2020-11-07 16:11:08 +01:00
playlist: RefCell<Vec<PlaylistItem>>,
current_item: Cell<Option<usize>>,
current_track: Cell<Option<usize>>,
playing: Cell<bool>,
2020-12-20 11:47:27 +01:00
playlist_cbs: RefCell<Vec<Box<dyn Fn(Vec<PlaylistItem>)>>>,
track_cbs: RefCell<Vec<Box<dyn Fn(usize, usize)>>>,
duration_cbs: RefCell<Vec<Box<dyn Fn(u64)>>>,
playing_cbs: RefCell<Vec<Box<dyn Fn(bool)>>>,
position_cbs: RefCell<Vec<Box<dyn Fn(u64)>>>,
2021-02-05 00:50:27 +01:00
raise_cb: RefCell<Option<Box<dyn Fn()>>>,
2020-11-07 16:11:08 +01:00
}
impl Player {
pub fn new(music_library_path: PathBuf) -> Rc<Self> {
let dispatcher = gstreamer_player::PlayerGMainContextSignalDispatcher::new(None);
let player = gstreamer_player::Player::new(None, Some(&dispatcher.upcast()));
let mut config = player.get_config();
config.set_position_update_interval(250);
player.set_config(config).unwrap();
player.set_video_track_enabled(false);
2021-02-05 00:50:27 +01:00
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);
2020-11-07 16:11:08 +01:00
let result = Rc::new(Self {
music_library_path,
player: player.clone(),
2021-02-05 00:50:27 +01:00
mpris,
2020-11-07 16:11:08 +01:00
playlist: RefCell::new(Vec::new()),
current_item: Cell::new(None),
current_track: Cell::new(None),
playing: Cell::new(false),
2020-11-07 20:07:26 +01:00
playlist_cbs: RefCell::new(Vec::new()),
track_cbs: RefCell::new(Vec::new()),
duration_cbs: RefCell::new(Vec::new()),
playing_cbs: RefCell::new(Vec::new()),
position_cbs: RefCell::new(Vec::new()),
2021-02-05 00:50:27 +01:00
raise_cb: RefCell::new(None),
2020-11-07 16:11:08 +01:00
});
let clone = fragile::Fragile::new(result.clone());
player.connect_end_of_stream(move |_| {
let clone = clone.get();
if clone.has_next() {
clone.next().unwrap();
} else {
clone.player.stop();
2020-11-07 20:07:26 +01:00
clone.playing.replace(false);
2021-02-05 00:50:27 +01:00
2020-11-07 20:07:26 +01:00
for cb in &*clone.playing_cbs.borrow() {
2020-11-07 16:11:08 +01:00
cb(false);
}
2021-02-05 00:50:27 +01:00
clone.mpris.set_playback_status(PlaybackStatus::Paused);
2020-11-07 16:11:08 +01:00
}
});
let clone = fragile::Fragile::new(result.clone());
player.connect_position_updated(move |_, position| {
2020-11-07 20:07:26 +01:00
for cb in &*clone.get().position_cbs.borrow() {
2020-11-07 16:11:08 +01:00
cb(position.mseconds().unwrap());
}
});
let clone = fragile::Fragile::new(result.clone());
player.connect_duration_changed(move |_, duration| {
2020-11-07 20:07:26 +01:00
for cb in &*clone.get().duration_cbs.borrow() {
2020-11-07 16:11:08 +01:00
cb(duration.mseconds().unwrap());
}
});
2021-02-05 00:50:27 +01:00
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()
}
}));
2020-11-07 16:11:08 +01:00
result
}
2020-12-20 11:47:27 +01:00
pub fn add_playlist_cb<F: Fn(Vec<PlaylistItem>) + 'static>(&self, cb: F) {
2020-11-07 20:07:26 +01:00
self.playlist_cbs.borrow_mut().push(Box::new(cb));
2020-11-07 16:11:08 +01:00
}
2020-12-20 11:47:27 +01:00
pub fn add_track_cb<F: Fn(usize, usize) + 'static>(&self, cb: F) {
2020-11-07 20:07:26 +01:00
self.track_cbs.borrow_mut().push(Box::new(cb));
2020-11-07 16:11:08 +01:00
}
2020-12-20 11:47:27 +01:00
pub fn add_duration_cb<F: Fn(u64) + 'static>(&self, cb: F) {
2020-11-07 20:07:26 +01:00
self.duration_cbs.borrow_mut().push(Box::new(cb));
2020-11-07 16:11:08 +01:00
}
2020-12-20 11:47:27 +01:00
pub fn add_playing_cb<F: Fn(bool) + 'static>(&self, cb: F) {
2020-11-07 20:07:26 +01:00
self.playing_cbs.borrow_mut().push(Box::new(cb));
2020-11-07 16:11:08 +01:00
}
2020-12-20 11:47:27 +01:00
pub fn add_position_cb<F: Fn(u64) + 'static>(&self, cb: F) {
2020-11-07 20:07:26 +01:00
self.position_cbs.borrow_mut().push(Box::new(cb));
2020-11-07 16:11:08 +01:00
}
2021-02-05 00:50:27 +01:00
pub fn set_raise_cb<F: Fn() + 'static>(&self, cb: F) {
self.raise_cb.replace(Some(Box::new(cb)));
}
2020-11-07 16:11:08 +01:00
pub fn get_playlist(&self) -> Vec<PlaylistItem> {
self.playlist.borrow().clone()
}
pub fn get_current_item(&self) -> Option<usize> {
self.current_item.get()
}
pub fn get_current_track(&self) -> Option<usize> {
self.current_track.get()
}
pub fn get_duration(&self) -> gstreamer::ClockTime {
self.player.get_duration()
}
pub fn is_playing(&self) -> bool {
self.playing.get()
}
pub fn add_item(&self, item: PlaylistItem) -> Result<()> {
2020-12-20 11:47:27 +01:00
if item.indices.is_empty() {
2021-02-04 16:31:37 +01:00
Err(Error::Other("Tried to add an empty playlist item!"))
2020-11-07 16:11:08 +01:00
} else {
let was_empty = {
let mut playlist = self.playlist.borrow_mut();
let was_empty = playlist.is_empty();
playlist.push(item);
was_empty
};
2020-11-07 20:07:26 +01:00
for cb in &*self.playlist_cbs.borrow() {
2020-11-07 16:11:08 +01:00
cb(self.playlist.borrow().clone());
}
if was_empty {
self.set_track(0, 0)?;
self.player.play();
self.playing.set(true);
2020-11-07 20:07:26 +01:00
for cb in &*self.playing_cbs.borrow() {
2020-11-07 16:11:08 +01:00
cb(true);
}
2021-02-05 00:50:27 +01:00
self.mpris.set_can_play(true);
self.mpris.set_playback_status(PlaybackStatus::Playing);
2020-11-07 16:11:08 +01:00
}
Ok(())
}
}
pub fn play_pause(&self) {
if self.is_playing() {
self.player.pause();
self.playing.set(false);
2020-11-07 20:07:26 +01:00
for cb in &*self.playing_cbs.borrow() {
2020-11-07 16:11:08 +01:00
cb(false);
}
2021-02-05 00:50:27 +01:00
self.mpris.set_playback_status(PlaybackStatus::Paused);
2020-11-07 16:11:08 +01:00
} else {
self.player.play();
self.playing.set(true);
2020-11-07 20:07:26 +01:00
for cb in &*self.playing_cbs.borrow() {
2020-11-07 16:11:08 +01:00
cb(true);
}
2021-02-05 00:50:27 +01:00
self.mpris.set_playback_status(PlaybackStatus::Playing);
2020-11-07 16:11:08 +01:00
}
}
2020-11-07 20:07:26 +01:00
pub fn seek(&self, ms: u64) {
self.player.seek(gstreamer::ClockTime::from_mseconds(ms));
}
2020-11-07 16:11:08 +01:00
pub fn has_previous(&self) -> bool {
if let Some(current_item) = self.current_item.get() {
if let Some(current_track) = self.current_track.get() {
current_track > 0 || current_item > 0
} else {
false
}
} else {
false
}
}
pub fn previous(&self) -> Result<()> {
2021-02-04 16:31:37 +01:00
let mut current_item = self.current_item.get()
.ok_or(Error::Other("Player tried to access non existant current item."))?;
2020-11-07 16:11:08 +01:00
let mut current_track = self
.current_track
.get()
2021-02-04 16:31:37 +01:00
.ok_or(Error::Other("Player tried to access non existant current track."))?;
2020-11-07 16:11:08 +01:00
let playlist = self.playlist.borrow();
if current_track > 0 {
current_track -= 1;
} else if current_item > 0 {
current_item -= 1;
2020-12-20 11:47:27 +01:00
current_track = playlist[current_item].indices.len() - 1;
2020-11-07 16:11:08 +01:00
} else {
2021-02-04 16:31:37 +01:00
return Err(Error::Other("No existing previous track."));
2020-11-07 16:11:08 +01:00
}
self.set_track(current_item, current_track)
}
pub fn has_next(&self) -> bool {
if let Some(current_item) = self.current_item.get() {
if let Some(current_track) = self.current_track.get() {
let playlist = self.playlist.borrow();
let item = &playlist[current_item];
2020-12-20 11:47:27 +01:00
current_track + 1 < item.indices.len() || current_item + 1 < playlist.len()
2020-11-07 16:11:08 +01:00
} else {
false
}
} else {
false
}
}
pub fn next(&self) -> Result<()> {
2021-02-04 16:31:37 +01:00
let mut current_item = self.current_item.get()
.ok_or(Error::Other("Player tried to access non existant current item."))?;
2020-11-07 16:11:08 +01:00
let mut current_track = self
.current_track
.get()
2021-02-04 16:31:37 +01:00
.ok_or(Error::Other("Player tried to access non existant current track."))?;
2020-11-07 16:11:08 +01:00
let playlist = self.playlist.borrow();
let item = &playlist[current_item];
2020-12-20 11:47:27 +01:00
if current_track + 1 < item.indices.len() {
2020-11-07 16:11:08 +01:00
current_track += 1;
} else if current_item + 1 < playlist.len() {
current_item += 1;
current_track = 0;
} else {
2021-02-04 16:31:37 +01:00
return Err(Error::Other("No existing previous track."));
2020-11-07 16:11:08 +01:00
}
self.set_track(current_item, current_track)
}
pub fn set_track(&self, current_item: usize, current_track: usize) -> Result<()> {
2021-02-05 00:50:27 +01:00
let item = &self.playlist.borrow()[current_item];
let track = &item.track_set.tracks[current_track];
2020-11-07 16:11:08 +01:00
let uri = format!(
"file://{}",
2021-02-05 00:50:27 +01:00
self.music_library_path.join(track.path.clone()).to_str().unwrap(),
2020-11-07 16:11:08 +01:00
);
self.player.set_uri(&uri);
if self.is_playing() {
self.player.play();
}
self.current_item.set(Some(current_item));
self.current_track.set(Some(current_track));
2020-11-07 20:07:26 +01:00
for cb in &*self.track_cbs.borrow() {
2020-11-07 16:11:08 +01:00
cb(current_item, current_track);
}
2021-02-05 00:50:27 +01:00
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());
2020-11-07 16:11:08 +01:00
Ok(())
}
pub fn clear(&self) {
self.player.stop();
self.playing.set(false);
self.current_item.set(None);
self.current_track.set(None);
self.playlist.replace(Vec::new());
2020-11-07 20:07:26 +01:00
for cb in &*self.playing_cbs.borrow() {
2020-11-07 16:11:08 +01:00
cb(false);
}
2020-11-07 20:07:26 +01:00
for cb in &*self.playlist_cbs.borrow() {
2020-11-07 16:11:08 +01:00
cb(Vec::new());
}
2021-02-05 00:50:27 +01:00
self.mpris.set_can_play(false);
2020-11-07 16:11:08 +01:00
}
}