mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 19:57:25 +01:00
player: Separate append and append + play
This commit is contained in:
parent
8ff56d2878
commit
13fed08ebf
2 changed files with 62 additions and 40 deletions
|
|
@ -3,6 +3,7 @@ use std::{
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Context, Result};
|
||||||
use fragile::Fragile;
|
use fragile::Fragile;
|
||||||
use gstreamer_play::gst;
|
use gstreamer_play::gst;
|
||||||
use gtk::{
|
use gtk::{
|
||||||
|
|
@ -33,7 +34,7 @@ mod imp {
|
||||||
pub active: Cell<bool>,
|
pub active: Cell<bool>,
|
||||||
#[property(get, set)]
|
#[property(get, set)]
|
||||||
pub playing: Cell<bool>,
|
pub playing: Cell<bool>,
|
||||||
#[property(get, set = Self::set_program)]
|
#[property(get, set)]
|
||||||
pub program: RefCell<Option<Program>>,
|
pub program: RefCell<Option<Program>>,
|
||||||
#[property(get, construct_only)]
|
#[property(get, construct_only)]
|
||||||
pub playlist: OnceCell<gio::ListStore>,
|
pub playlist: OnceCell<gio::ListStore>,
|
||||||
|
|
@ -50,17 +51,6 @@ mod imp {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Player {
|
impl Player {
|
||||||
pub fn set_program(&self, program: &Program) {
|
|
||||||
self.program.replace(Some(program.to_owned()));
|
|
||||||
|
|
||||||
if !self.obj().active() {
|
|
||||||
self.obj().set_active(true);
|
|
||||||
self.obj().generate_items(program);
|
|
||||||
self.obj().set_current_index(0);
|
|
||||||
self.obj().play();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_current_index(&self, index: u32) {
|
pub fn set_current_index(&self, index: u32) {
|
||||||
let playlist = self.playlist.get().unwrap();
|
let playlist = self.playlist.get().unwrap();
|
||||||
|
|
||||||
|
|
@ -275,32 +265,56 @@ impl Player {
|
||||||
items
|
items
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append(&self, items: Vec<PlaylistItem>) {
|
/// Append playlist items to the playlist and return the index of the first newly added item.
|
||||||
let playlist = self.playlist();
|
/// An error will be returned if `items` is empty.
|
||||||
|
pub fn append(&self, items: Vec<PlaylistItem>) -> Result<u32> {
|
||||||
|
if !items.is_empty() {
|
||||||
|
let playlist = self.playlist();
|
||||||
|
let first_index = playlist.n_items();
|
||||||
|
|
||||||
for item in items {
|
for item in items {
|
||||||
playlist.append(&item);
|
playlist.append(&item);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.active() && playlist.n_items() > 0 {
|
// If playlist was empty:
|
||||||
self.set_active(true);
|
if first_index == 0 {
|
||||||
self.set_current_index(0);
|
self.set_active(true);
|
||||||
self.play();
|
self.set_current_index(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(first_index)
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("At least one item has to be added to the playlist"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Append playlist items to the playlist and immediately start playing the first newly added
|
||||||
|
/// item. This will discard the error if `items` is empty.
|
||||||
pub fn append_and_play(&self, items: Vec<PlaylistItem>) {
|
pub fn append_and_play(&self, items: Vec<PlaylistItem>) {
|
||||||
let playlist = self.playlist();
|
match self.append(items) {
|
||||||
let first_index = playlist.n_items();
|
Ok(index) => {
|
||||||
|
self.set_current_index(index);
|
||||||
for item in items {
|
self.play();
|
||||||
playlist.append(&item);
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!("Failed to append and play items: {err}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if playlist.n_items() > first_index {
|
/// Generate new playlist items based on the current program and immediately start playing the
|
||||||
self.set_active(true);
|
/// first new item.
|
||||||
self.set_current_index(first_index);
|
pub fn play_from_program(&self) {
|
||||||
self.play();
|
if let Some(program) = self.program() {
|
||||||
|
match self.generate_items(&program) {
|
||||||
|
Ok(index) => {
|
||||||
|
self.set_current_index(index);
|
||||||
|
self.play();
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!("Failed to play from program: {err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -367,8 +381,10 @@ impl Player {
|
||||||
if self.current_index() < self.playlist().n_items() - 1 {
|
if self.current_index() < self.playlist().n_items() - 1 {
|
||||||
self.set_current_index(self.current_index() + 1);
|
self.set_current_index(self.current_index() + 1);
|
||||||
} else if let Some(program) = self.program() {
|
} else if let Some(program) = self.program() {
|
||||||
self.generate_items(&program);
|
match self.generate_items(&program) {
|
||||||
self.set_current_index(self.current_index() + 1);
|
Ok(index) => self.set_current_index(index),
|
||||||
|
Err(err) => log::warn!("Failed to continue playing from program: {err}"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -434,13 +450,17 @@ impl Player {
|
||||||
.expect("mpris should not be set");
|
.expect("mpris should not be set");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_items(&self, program: &Program) {
|
/// Generate new playlist items based on `program` and return the index of the first newly
|
||||||
if let Some(library) = self.library() {
|
/// added item if successful.
|
||||||
// TODO: if program.play_full_recordings() {
|
fn generate_items(&self, program: &Program) -> Result<u32> {
|
||||||
let recording = library.generate_recording(program).unwrap();
|
let recording = self
|
||||||
let playlist = self.recording_to_playlist(&recording);
|
.library()
|
||||||
self.append(playlist);
|
.unwrap()
|
||||||
}
|
.generate_recording(program)
|
||||||
|
.context("Failed to generate playlist items from program")?;
|
||||||
|
|
||||||
|
let playlist = self.recording_to_playlist(&recording);
|
||||||
|
self.append(playlist)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn library_path_to_file_path(&self, path: &str) -> String {
|
fn library_path_to_file_path(&self, path: &str) -> String {
|
||||||
|
|
|
||||||
|
|
@ -208,7 +208,7 @@ impl SearchPage {
|
||||||
fn play_button_clicked(&self) {
|
fn play_button_clicked(&self) {
|
||||||
let program = Program::from_query(self.imp().query.get().unwrap().clone());
|
let program = Program::from_query(self.imp().query.get().unwrap().clone());
|
||||||
self.player().set_program(program);
|
self.player().set_program(program);
|
||||||
self.player().play();
|
self.player().play_from_program();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
|
|
@ -218,6 +218,7 @@ impl SearchPage {
|
||||||
if imp.programs_flow_box.is_visible() {
|
if imp.programs_flow_box.is_visible() {
|
||||||
if let Some(program) = imp.programs.borrow().first().cloned() {
|
if let Some(program) = imp.programs.borrow().first().cloned() {
|
||||||
self.player().set_program(program);
|
self.player().set_program(program);
|
||||||
|
self.player().play_from_program();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut new_query = self.imp().query.get().unwrap().clone();
|
let mut new_query = self.imp().query.get().unwrap().clone();
|
||||||
|
|
@ -263,6 +264,7 @@ impl SearchPage {
|
||||||
fn program_selected(&self, tile: >k::FlowBoxChild) {
|
fn program_selected(&self, tile: >k::FlowBoxChild) {
|
||||||
self.player()
|
self.player()
|
||||||
.set_program(tile.downcast_ref::<ProgramTile>().unwrap().program());
|
.set_program(tile.downcast_ref::<ProgramTile>().unwrap().program());
|
||||||
|
self.player().play_from_program();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue