mirror of
https://github.com/Dangoware/dango-music-player.git
synced 2025-04-19 01:52:53 -05:00
Added Error Handling for Queue and abstractions over the ControllerHandle
This commit is contained in:
parent
f51650f4d2
commit
d18f980fa0
6 changed files with 344 additions and 162 deletions
|
@ -37,4 +37,4 @@ futures = "0.3.30"
|
||||||
async-channel = "2.3.1"
|
async-channel = "2.3.1"
|
||||||
ciborium = "0.2.2"
|
ciborium = "0.2.2"
|
||||||
itertools = "0.13.0"
|
itertools = "0.13.0"
|
||||||
prismriver = { git = "https://github.com/Dangoware/prismriver.git" }
|
prismriver = { git = "https://github.com/Dangoware/prismriver.git", features = ["ffmpeg"]}
|
||||||
|
|
|
@ -11,6 +11,7 @@ pub mod music_storage {
|
||||||
pub mod music_controller {
|
pub mod music_controller {
|
||||||
pub mod connections;
|
pub mod connections;
|
||||||
pub mod controller;
|
pub mod controller;
|
||||||
|
pub mod controller_handle;
|
||||||
pub mod queue;
|
pub mod queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
use kushi::{Queue, QueueItemType};
|
use kushi::{Queue, QueueItemType};
|
||||||
use kushi::{QueueError, QueueItem};
|
use kushi::{QueueError, QueueItem};
|
||||||
use prismriver::{Prismriver, Volume};
|
use prismriver::{Prismriver, Volume, Error as PrismError};
|
||||||
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::to_string_pretty;
|
use serde_json::to_string_pretty;
|
||||||
|
@ -26,6 +26,8 @@ use super::queue::{QueueAlbum, QueueSong};
|
||||||
|
|
||||||
pub struct Controller();
|
pub struct Controller();
|
||||||
|
|
||||||
|
type QueueItem_ = QueueItem<QueueSong, QueueAlbum>;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum ControllerError {
|
pub enum ControllerError {
|
||||||
#[error("{0:?}")]
|
#[error("{0:?}")]
|
||||||
|
@ -83,8 +85,16 @@ pub enum PlayerCommand {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum PlayerResponse {
|
pub enum PlayerResponse {
|
||||||
Empty,
|
Empty(Result<(), PlayerError>),
|
||||||
NowPlaying(Song)
|
NowPlaying(Result<Song, QueueError>)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug, PartialEq, Clone)]
|
||||||
|
pub enum PlayerError {
|
||||||
|
#[error("{0}")]
|
||||||
|
QueueError(#[from] QueueError),
|
||||||
|
#[error("{0}")]
|
||||||
|
Prismriver(#[from] PrismError),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, PartialOrd, Clone)]
|
#[derive(Debug, PartialEq, PartialOrd, Clone)]
|
||||||
|
@ -113,21 +123,21 @@ pub enum LibraryResponse {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum QueueCommand {
|
pub enum QueueCommand {
|
||||||
Append(QueueItem<QueueSong, QueueAlbum>, bool),
|
Append(QueueItem_, bool),
|
||||||
Next,
|
Next,
|
||||||
Prev,
|
Prev,
|
||||||
GetIndex(usize),
|
GetIndex(usize),
|
||||||
NowPlaying,
|
NowPlaying,
|
||||||
Get,
|
Get,
|
||||||
Clear
|
Clear,
|
||||||
|
Remove(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum QueueResponse {
|
pub enum QueueResponse {
|
||||||
Ok,
|
Empty(Result<(), QueueError>),
|
||||||
Item(QueueItem<QueueSong, QueueAlbum>),
|
Item(Result<QueueItem_, QueueError>),
|
||||||
GetAll(Vec<QueueItem<QueueSong, QueueAlbum>>),
|
GetAll(Vec<QueueItem_>),
|
||||||
Err(QueueError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -302,116 +312,136 @@ impl Controller {
|
||||||
lib_mail: MailMan<LibraryCommand, LibraryResponse>,
|
lib_mail: MailMan<LibraryCommand, LibraryResponse>,
|
||||||
mut state: ControllerState,
|
mut state: ControllerState,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
let mut first = true;
|
player.write().unwrap().set_volume(Volume::new(state.volume));
|
||||||
{
|
println!("volume set to {}", state.volume);
|
||||||
player.write().unwrap().set_volume(Volume::new(state.volume));
|
'outer: while true {
|
||||||
println!("volume set to {}", state.volume);
|
|
||||||
}
|
|
||||||
while true {
|
|
||||||
let _mail = player_mail.recv().await;
|
let _mail = player_mail.recv().await;
|
||||||
if let Ok(mail) = _mail {
|
if let Ok(mail) = _mail {
|
||||||
match mail {
|
match mail {
|
||||||
PlayerCommand::Play => {
|
PlayerCommand::Play => {
|
||||||
player.write().unwrap().play();
|
player.write().unwrap().play();
|
||||||
player_mail.send(PlayerResponse::Empty).await.unwrap();
|
player_mail.send(PlayerResponse::Empty(Ok(()))).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerCommand::Pause => {
|
PlayerCommand::Pause => {
|
||||||
player.write().unwrap().pause();
|
player.write().unwrap().pause();
|
||||||
player_mail.send(PlayerResponse::Empty).await.unwrap();
|
player_mail.send(PlayerResponse::Empty(Ok(()))).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerCommand::SetVolume(volume) => {
|
PlayerCommand::SetVolume(volume) => {
|
||||||
player.write().unwrap().set_volume(Volume::new(volume));
|
player.write().unwrap().set_volume(Volume::new(volume));
|
||||||
println!("volume set to {volume}");
|
println!("volume set to {volume}");
|
||||||
player_mail.send(PlayerResponse::Empty).await.unwrap();
|
player_mail.send(PlayerResponse::Empty(Ok(()))).await.unwrap();
|
||||||
|
|
||||||
state.volume = volume;
|
state.volume = volume;
|
||||||
_ = state.write_file()
|
_ = state.write_file()
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerCommand::NextSong => {
|
PlayerCommand::NextSong => {
|
||||||
queue_mail.send(QueueCommand::Next).await.unwrap();
|
queue_mail.send(QueueCommand::Next).await.unwrap();
|
||||||
|
|
||||||
if let QueueResponse::Item(item) = queue_mail.recv().await.unwrap() {
|
match queue_mail.recv().await.unwrap() {
|
||||||
let uri = match &item.item {
|
QueueResponse::Item(Ok(item)) => {
|
||||||
QueueItemType::Single(song) => song.song.primary_uri().unwrap().0,
|
let uri = match &item.item {
|
||||||
_ => unimplemented!(),
|
QueueItemType::Single(song) => song.song.primary_uri().unwrap().0,
|
||||||
};
|
_ => unimplemented!(),
|
||||||
|
};
|
||||||
|
|
||||||
let prism_uri = prismriver::utils::path_to_uri(&uri.as_path().unwrap()).unwrap();
|
let prism_uri = prismriver::utils::path_to_uri(&uri.as_path().unwrap()).unwrap();
|
||||||
println!("Playing song at path: {:?}", prism_uri);
|
println!("Playing song at path: {:?}", prism_uri);
|
||||||
player.write().unwrap().load_new(&prism_uri).unwrap();
|
|
||||||
player.write().unwrap().play();
|
|
||||||
|
|
||||||
let QueueItemType::Single(np_song) = item.item else { panic!("This is temporary, handle queueItemTypes at some point")};
|
// handle error here for unknown formats
|
||||||
|
player.write().unwrap().load_new(&prism_uri).unwrap();
|
||||||
|
player.write().unwrap().play();
|
||||||
|
|
||||||
// Append next song in library
|
let QueueItemType::Single(np_song) = item.item else { panic!("This is temporary, handle queueItemTypes at some point")};
|
||||||
lib_mail.send(LibraryCommand::AllSongs).await.unwrap();
|
|
||||||
|
|
||||||
let LibraryResponse::AllSongs(songs) = lib_mail.recv().await.unwrap() else {
|
// Append next song in library
|
||||||
continue;
|
lib_mail.send(LibraryCommand::AllSongs).await.unwrap();
|
||||||
};
|
let LibraryResponse::AllSongs(songs) = lib_mail.recv().await.unwrap() else {
|
||||||
lib_mail.send(LibraryCommand::Song(np_song.song.uuid)).await.unwrap();
|
continue;
|
||||||
let LibraryResponse::Song(_, i) = lib_mail.recv().await.unwrap() else {
|
};
|
||||||
unreachable!()
|
lib_mail.send(LibraryCommand::Song(np_song.song.uuid)).await.unwrap();
|
||||||
};
|
let LibraryResponse::Song(_, i) = lib_mail.recv().await.unwrap() else {
|
||||||
if let Some(song) = songs.get(i + 49) {
|
|
||||||
queue_mail.send(
|
|
||||||
QueueCommand::Append(
|
|
||||||
QueueItem::from_item_type(
|
|
||||||
QueueItemType::Single(
|
|
||||||
QueueSong {
|
|
||||||
song: song.clone(),
|
|
||||||
location: np_song.location
|
|
||||||
}
|
|
||||||
)
|
|
||||||
),
|
|
||||||
false
|
|
||||||
)
|
|
||||||
).await
|
|
||||||
.unwrap();
|
|
||||||
let QueueResponse::Ok = queue_mail.recv().await.unwrap() else {
|
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
} else {
|
if let Some(song) = songs.get(i + 49) {
|
||||||
println!("Library Empty");
|
queue_mail.send(
|
||||||
}
|
QueueCommand::Append(
|
||||||
|
QueueItem::from_item_type(
|
||||||
|
QueueItemType::Single(
|
||||||
|
QueueSong {
|
||||||
|
song: song.clone(),
|
||||||
|
location: np_song.location
|
||||||
|
}
|
||||||
|
)
|
||||||
|
),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
).await
|
||||||
|
.unwrap();
|
||||||
|
let QueueResponse::Empty(Ok(())) = queue_mail.recv().await.unwrap() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
println!("Library Empty");
|
||||||
|
}
|
||||||
|
|
||||||
player_mail.send(PlayerResponse::NowPlaying(np_song.song.clone())).await.unwrap();
|
player_mail.send(PlayerResponse::NowPlaying(Ok(np_song.song.clone()))).await.unwrap();
|
||||||
|
} QueueResponse::Item(Err(e)) => {
|
||||||
|
player_mail.send(PlayerResponse::NowPlaying(Err(e.into()))).await.unwrap();
|
||||||
|
}
|
||||||
|
_ => continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerCommand::PrevSong => {
|
PlayerCommand::PrevSong => {
|
||||||
queue_mail.send(QueueCommand::Prev).await.unwrap();
|
queue_mail.send(QueueCommand::Prev).await.unwrap();
|
||||||
|
match queue_mail.recv().await.unwrap() {
|
||||||
|
QueueResponse::Item(Ok(item)) => {
|
||||||
|
let uri = match &item.item {
|
||||||
|
QueueItemType::Single(song) => song.song.primary_uri().unwrap().0,
|
||||||
|
_ => unimplemented!(),
|
||||||
|
};
|
||||||
|
|
||||||
if let QueueResponse::Item(item) = queue_mail.recv().await.unwrap() {
|
let prism_uri = prismriver::utils::path_to_uri(&uri.as_path().unwrap()).unwrap();
|
||||||
let uri = match &item.item {
|
player.write().unwrap().load_new(&prism_uri).unwrap();
|
||||||
QueueItemType::Single(song) => song.song.primary_uri().unwrap().0,
|
player.write().unwrap().play();
|
||||||
_ => unimplemented!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let prism_uri = prismriver::utils::path_to_uri(&uri.as_path().unwrap()).unwrap();
|
let QueueItemType::Single(np_song) = item.item else { panic!("This is temporary, handle queueItemTypes at some point")};
|
||||||
player.write().unwrap().load_new(&prism_uri).unwrap();
|
player_mail.send(PlayerResponse::NowPlaying(Ok(np_song.song.clone()))).await.unwrap();
|
||||||
player.write().unwrap().play();
|
}
|
||||||
|
QueueResponse::Item(Err(e)) => {
|
||||||
let QueueItemType::Single(np_song) = item.item else { panic!("This is temporary, handle queueItemTypes at some point")};
|
player_mail.send(PlayerResponse::NowPlaying(Err(e.into()))).await.unwrap();
|
||||||
player_mail.send(PlayerResponse::NowPlaying(np_song.song.clone())).await.unwrap();
|
}
|
||||||
|
_ => continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerCommand::Enqueue(index) => {
|
PlayerCommand::Enqueue(index) => {
|
||||||
queue_mail
|
queue_mail
|
||||||
.send(QueueCommand::GetIndex(index))
|
.send(QueueCommand::GetIndex(index))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
if let QueueResponse::Item(item) = queue_mail.recv().await.unwrap() {
|
match queue_mail.recv().await.unwrap() {
|
||||||
match item.item {
|
QueueResponse::Item(Ok(item)) => {
|
||||||
QueueItemType::Single(song) => {
|
match item.item {
|
||||||
let prism_uri = prismriver::utils::path_to_uri(&song.song.primary_uri().unwrap().0.as_path().unwrap()).unwrap();
|
QueueItemType::Single(song) => {
|
||||||
player.write().unwrap().load_new(&prism_uri).unwrap();
|
let prism_uri = prismriver::utils::path_to_uri(&song.song.primary_uri().unwrap().0.as_path().unwrap()).unwrap();
|
||||||
player.write().unwrap().play();
|
player.write().unwrap().load_new(&prism_uri).unwrap();
|
||||||
|
player.write().unwrap().play();
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
player_mail.send(PlayerResponse::Empty(Ok(()))).await.unwrap();
|
||||||
}
|
}
|
||||||
player_mail.send(PlayerResponse::Empty).await.unwrap();
|
QueueResponse::Item(Err(e)) => {
|
||||||
|
player_mail.send(PlayerResponse::Empty(Err(e.into()))).await.unwrap();
|
||||||
|
}
|
||||||
|
_ => continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerCommand::PlayNow(uuid, location) => {
|
PlayerCommand::PlayNow(uuid, location) => {
|
||||||
// TODO: This assumes the uuid doesn't point to an album. we've been over this.
|
// TODO: This assumes the uuid doesn't point to an album. we've been over this.
|
||||||
lib_mail.send(LibraryCommand::Song(uuid)).await.unwrap();
|
lib_mail.send(LibraryCommand::Song(uuid)).await.unwrap();
|
||||||
|
@ -419,13 +449,23 @@ impl Controller {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
queue_mail.send(QueueCommand::Clear).await.unwrap();
|
queue_mail.send(QueueCommand::Clear).await.unwrap();
|
||||||
let QueueResponse::Ok = queue_mail.recv().await.unwrap() else {
|
match queue_mail.recv().await.unwrap() {
|
||||||
unreachable!()
|
QueueResponse::Empty(Ok(())) => (),
|
||||||
};
|
QueueResponse::Empty(Err(e)) => {
|
||||||
|
player_mail.send(PlayerResponse::NowPlaying(Err(e.into()))).await.unwrap();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
queue_mail.send(QueueCommand::Append(QueueItem::from_item_type(QueueItemType::Single(QueueSong { song: song.clone(), location })), true)).await.unwrap();
|
queue_mail.send(QueueCommand::Append(QueueItem::from_item_type(QueueItemType::Single(QueueSong { song: song.clone(), location })), true)).await.unwrap();
|
||||||
let QueueResponse::Ok = queue_mail.recv().await.unwrap() else {
|
match queue_mail.recv().await.unwrap() {
|
||||||
unreachable!()
|
QueueResponse::Empty(Ok(())) => (),
|
||||||
};
|
QueueResponse::Empty(Err(e)) => {
|
||||||
|
player_mail.send(PlayerResponse::NowPlaying(Err(e.into()))).await.unwrap();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Handle non Local URIs here, and whenever `load_new()` or `load_gapless()` is called
|
// TODO: Handle non Local URIs here, and whenever `load_new()` or `load_gapless()` is called
|
||||||
let prism_uri = prismriver::utils::path_to_uri(&song.primary_uri().unwrap().0.as_path().unwrap()).unwrap();
|
let prism_uri = prismriver::utils::path_to_uri(&song.primary_uri().unwrap().0.as_path().unwrap()).unwrap();
|
||||||
|
@ -459,16 +499,21 @@ impl Controller {
|
||||||
for i in index+1..(index+50) {
|
for i in index+1..(index+50) {
|
||||||
if let Some(song) = songs.get(i) {
|
if let Some(song) = songs.get(i) {
|
||||||
queue_mail.send(QueueCommand::Append(QueueItem::from_item_type(QueueItemType::Single(QueueSong { song: song.clone(), location })), false)).await.unwrap();
|
queue_mail.send(QueueCommand::Append(QueueItem::from_item_type(QueueItemType::Single(QueueSong { song: song.clone(), location })), false)).await.unwrap();
|
||||||
let QueueResponse::Ok = queue_mail.recv().await.unwrap() else {
|
match queue_mail.recv().await.unwrap() {
|
||||||
unreachable!()
|
QueueResponse::Empty(Ok(())) => (),
|
||||||
};
|
QueueResponse::Empty(Err(e)) => {
|
||||||
|
player_mail.send(PlayerResponse::NowPlaying(Err(e.into()))).await.unwrap();
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("End of Library / Playlist");
|
println!("End of Library / Playlist");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ^ This be my solution for now ^
|
// ^ This be my solution for now ^
|
||||||
player_mail.send(PlayerResponse::NowPlaying(song.clone())).await.unwrap();
|
player_mail.send(PlayerResponse::NowPlaying(Ok(song.clone()))).await.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -540,32 +585,32 @@ impl Controller {
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
queue_mail
|
queue_mail
|
||||||
.send(QueueResponse::Ok)
|
.send(QueueResponse::Empty(Ok(())))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
},
|
},
|
||||||
QueueCommand::Next => {
|
QueueCommand::Next => {
|
||||||
let next = queue.next().unwrap();
|
let next = queue.next().map_or( Err(QueueError::NoNext), |s| Ok(s.clone()));
|
||||||
queue_mail
|
queue_mail
|
||||||
.send(QueueResponse::Item(next.clone()))
|
.send(QueueResponse::Item(next.clone()))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
QueueCommand::Prev => {
|
QueueCommand::Prev => {
|
||||||
let next = queue.prev().unwrap();
|
let prev = queue.prev().map_or( Err(QueueError::EmptyPlayed), |s| Ok(s.clone()));
|
||||||
queue_mail
|
queue_mail
|
||||||
.send(QueueResponse::Item(next.clone()))
|
.send(QueueResponse::Item(prev.clone()))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
QueueCommand::GetIndex(index) => {
|
QueueCommand::GetIndex(index) => {
|
||||||
let item = queue.items.get(index).expect("No item in the queue at index {index}").clone();
|
let item = queue.items.get(index).map_or( Err(QueueError::OutOfBounds { index, len: queue.items.len() }), |s| Ok(s.clone()));
|
||||||
queue_mail.send(QueueResponse::Item(item)).await.unwrap();
|
queue_mail.send(QueueResponse::Item(item)).await.unwrap();
|
||||||
}
|
}
|
||||||
QueueCommand::NowPlaying => {
|
QueueCommand::NowPlaying => {
|
||||||
let item = queue.current().unwrap();
|
let item = queue.current().map(|t| t.clone());
|
||||||
queue_mail
|
queue_mail
|
||||||
.send(QueueResponse::Item(item.clone()))
|
.send(QueueResponse::Item(item))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -574,7 +619,10 @@ impl Controller {
|
||||||
}
|
}
|
||||||
QueueCommand::Clear => {
|
QueueCommand::Clear => {
|
||||||
queue.clear();
|
queue.clear();
|
||||||
queue_mail.send(QueueResponse::Ok).await.unwrap();
|
queue_mail.send(QueueResponse::Empty(Ok(()))).await.unwrap();
|
||||||
|
}
|
||||||
|
QueueCommand::Remove(index) => {
|
||||||
|
queue_mail.send(QueueResponse::Item(queue.remove_item(index))).await.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
131
dmp-core/src/music_controller/controller_handle.rs
Normal file
131
dmp-core/src/music_controller/controller_handle.rs
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use kushi::{QueueError, QueueItem};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::music_storage::{library::Song, playlist::ExternalPlaylist};
|
||||||
|
|
||||||
|
use super::{controller::{ControllerHandle, LibraryCommand, LibraryResponse, PlayerCommand, PlayerError, PlayerLocation, PlayerResponse, QueueCommand, QueueResponse}, queue::{QueueAlbum, QueueSong}};
|
||||||
|
|
||||||
|
impl ControllerHandle {
|
||||||
|
// The Library Section
|
||||||
|
pub async fn lib_get_song(&self, uuid: Uuid) -> (Song, usize) {
|
||||||
|
self.lib_mail.send(LibraryCommand::Song(uuid)).await.unwrap();
|
||||||
|
let LibraryResponse::Song(song, index) = self.lib_mail.recv().await.unwrap() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
(song, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn lib_get_all(&self) -> Vec<Song> {
|
||||||
|
self.lib_mail.send(LibraryCommand::AllSongs).await.unwrap();
|
||||||
|
let LibraryResponse::AllSongs(songs) = self.lib_mail.recv().await.unwrap() else {
|
||||||
|
unreachable!("It has been reached")
|
||||||
|
};
|
||||||
|
songs
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn lib_save(&self) {
|
||||||
|
self.lib_mail.send(LibraryCommand::Save).await.unwrap();
|
||||||
|
let LibraryResponse::Ok = self.lib_mail.recv().await.unwrap() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Playlist Section
|
||||||
|
pub async fn playlist_get(&self, uuid: Uuid) -> Result<ExternalPlaylist, ()> {
|
||||||
|
self.lib_mail.send(LibraryCommand::ExternalPlaylist(uuid)).await.unwrap();
|
||||||
|
let LibraryResponse::ExternalPlaylist(playlist) = self.lib_mail.recv().await.unwrap() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
Ok(playlist)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a `Vec<(Uuid, String)>` containing the Uuid of the playlist and the name after
|
||||||
|
pub async fn playlist_get_all(&self) -> Vec<(Uuid, String)> {
|
||||||
|
self.lib_mail.send(LibraryCommand::Playlists).await.unwrap();
|
||||||
|
let LibraryResponse::Playlists(lists) = self.lib_mail.recv().await.unwrap() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
lists
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn playlist_import_m3u(&self, path: PathBuf) -> Result<(Uuid, String), ()> {
|
||||||
|
self.lib_mail.send(LibraryCommand::ImportM3UPlayList(path)).await.unwrap();
|
||||||
|
let LibraryResponse::ImportM3UPlayList(uuid, name) = self.lib_mail.recv().await.unwrap() else { unreachable!("It has been reached") };
|
||||||
|
Ok((uuid, name))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Queue Section
|
||||||
|
pub async fn queue_append(&self, item: QueueItem<QueueSong, QueueAlbum>) -> Result<(), QueueError> {
|
||||||
|
self.queue_mail.send(QueueCommand::Append(item, true)).await.unwrap();
|
||||||
|
let QueueResponse::Empty(res) = self.queue_mail.recv().await.unwrap() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn queue_remove(&self, index: usize) -> Result<QueueItem<QueueSong, QueueAlbum>, QueueError> {
|
||||||
|
self.queue_mail.send(QueueCommand::Remove(index)).await.unwrap();
|
||||||
|
let QueueResponse::Item(res) = self.queue_mail.recv().await.unwrap() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn queue_get_all(&self) -> Vec<QueueItem<QueueSong, QueueAlbum>> {
|
||||||
|
self.queue_mail.send(QueueCommand::Get).await.unwrap();
|
||||||
|
let QueueResponse::GetAll(queue) = self.queue_mail.recv().await.unwrap() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
queue
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Player Section
|
||||||
|
pub async fn play_now(&self, uuid: Uuid, location: PlayerLocation) -> Result<Song, QueueError> {
|
||||||
|
self.player_mail.send(PlayerCommand::PlayNow(uuid, location)).await.unwrap();
|
||||||
|
let PlayerResponse::NowPlaying(res) = self.player_mail.recv().await.unwrap() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn play(&self) -> Result<(), PlayerError> {
|
||||||
|
self.player_mail.send(PlayerCommand::Play).await.unwrap();
|
||||||
|
let PlayerResponse::Empty(res) = self.player_mail.recv().await.unwrap() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn pause(&self) -> Result<(), PlayerError> {
|
||||||
|
self.player_mail.send(PlayerCommand::Pause).await.unwrap();
|
||||||
|
let PlayerResponse::Empty(res) = self.player_mail.recv().await.unwrap() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_volume(&self, volume: f32) -> () {
|
||||||
|
self.player_mail.send(PlayerCommand::SetVolume(volume)).await.unwrap();
|
||||||
|
let PlayerResponse::Empty(Ok(())) = self.player_mail.recv().await.unwrap() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn next(&self) -> Result<Song, QueueError> {
|
||||||
|
self.player_mail.send(PlayerCommand::NextSong).await.unwrap();
|
||||||
|
let PlayerResponse::NowPlaying(res) = self.player_mail.recv().await.unwrap() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn prev(&self) -> Result<Song, QueueError> {
|
||||||
|
self.player_mail.send(PlayerCommand::PrevSong).await.unwrap();
|
||||||
|
let PlayerResponse::NowPlaying(res) = self.player_mail.recv().await.unwrap() else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,23 +10,20 @@ use crate::wrappers::_Song;
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn add_song_to_queue(app: AppHandle<Wry>, ctrl_handle: State<'_, ControllerHandle>, uuid: Uuid, location: PlayerLocation) -> Result<(), String> {
|
pub async fn add_song_to_queue(app: AppHandle<Wry>, ctrl_handle: State<'_, ControllerHandle>, uuid: Uuid, location: PlayerLocation) -> Result<(), String> {
|
||||||
dbg!(&location);
|
dbg!(&location);
|
||||||
ctrl_handle.lib_mail.send(dmp_core::music_controller::controller::LibraryCommand::Song(uuid)).await.unwrap();
|
let (song, _) = ctrl_handle.lib_get_song(uuid).await;
|
||||||
let LibraryResponse::Song(song, _) = ctrl_handle.lib_mail.recv().await.unwrap() else {
|
match ctrl_handle.queue_append(QueueItem::from_item_type(kushi::QueueItemType::Single(QueueSong { song, location }))).await {
|
||||||
unreachable!()
|
Ok(()) => (),
|
||||||
};
|
Err(e) => return Err(e.to_string())
|
||||||
ctrl_handle.queue_mail.send(dmp_core::music_controller::controller::QueueCommand::Append(QueueItem::from_item_type(kushi::QueueItemType::Single(QueueSong { song, location })), true)).await.unwrap();
|
}
|
||||||
let QueueResponse::Ok = ctrl_handle.queue_mail.recv().await.unwrap() else {
|
|
||||||
panic!()
|
|
||||||
};
|
|
||||||
app.emit("queue_updated", ()).unwrap();
|
app.emit("queue_updated", ()).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn play_now(app: AppHandle<Wry>, ctrl_handle: State<'_, ControllerHandle>, uuid: Uuid, location: PlayerLocation) -> Result<(), String> {
|
pub async fn play_now(app: AppHandle<Wry>, ctrl_handle: State<'_, ControllerHandle>, uuid: Uuid, location: PlayerLocation) -> Result<(), String> {
|
||||||
ctrl_handle.player_mail.send(PlayerCommand::PlayNow(uuid, location)).await.unwrap();
|
let song = match ctrl_handle.play_now(uuid, location).await {
|
||||||
let PlayerResponse::NowPlaying(song) = ctrl_handle.player_mail.recv().await.unwrap() else {
|
Ok(song) => song,
|
||||||
unreachable!()
|
Err(e) => return Err(e.to_string())
|
||||||
};
|
};
|
||||||
app.emit("queue_updated", ()).unwrap();
|
app.emit("queue_updated", ()).unwrap();
|
||||||
app.emit("now_playing_change", _Song::from(&song)).unwrap();
|
app.emit("now_playing_change", _Song::from(&song)).unwrap();
|
||||||
|
|
|
@ -13,35 +13,31 @@ pub struct ArtworkRx(pub Sender<Vec<u8>>);
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn play(app: AppHandle<Wry>, ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
|
pub async fn play(app: AppHandle<Wry>, ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
|
||||||
ctrl_handle.player_mail.send(dmp_core::music_controller::controller::PlayerCommand::Play).await.unwrap();
|
match ctrl_handle.play().await {
|
||||||
let res = ctrl_handle.player_mail.recv().await.unwrap();
|
Ok(()) => {
|
||||||
if let PlayerResponse::Empty = res {}
|
app.emit("playing", ()).unwrap();
|
||||||
else if let PlayerResponse::NowPlaying(song) = res {
|
Ok(())
|
||||||
app.emit("now_playing_change", _Song::from(&song)).unwrap();
|
},
|
||||||
} else {
|
Err(e) => Err(e.to_string())
|
||||||
unreachable!()
|
}
|
||||||
};
|
|
||||||
app.emit("playing", ()).unwrap();
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn pause(app: AppHandle<Wry>, ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
|
pub async fn pause(app: AppHandle<Wry>, ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
|
||||||
ctrl_handle.player_mail.send(dmp_core::music_controller::controller::PlayerCommand::Pause).await.unwrap();
|
match ctrl_handle.pause().await {
|
||||||
let PlayerResponse::Empty = ctrl_handle.player_mail.recv().await.unwrap() else {
|
Ok(()) => {
|
||||||
unreachable!()
|
app.emit("paused", ()).unwrap();
|
||||||
};
|
Ok(())
|
||||||
app.emit("paused", ()).unwrap();
|
}
|
||||||
Ok(())
|
Err(e) => Err(e.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn set_volume(ctrl_handle: State<'_, ControllerHandle>, volume: String) -> Result<(), String> {
|
pub async fn set_volume(ctrl_handle: State<'_, ControllerHandle>, volume: String) -> Result<(), String> {
|
||||||
let volume = volume.parse::<f32>().unwrap() / 100.0;
|
let volume = volume.parse::<f32>().unwrap() / 100.0;
|
||||||
ctrl_handle.player_mail.send(dmp_core::music_controller::controller::PlayerCommand::SetVolume(volume)).await.unwrap();
|
ctrl_handle.set_volume(volume).await;
|
||||||
let PlayerResponse::Empty = ctrl_handle.player_mail.recv().await.unwrap() else {
|
|
||||||
unreachable!()
|
|
||||||
};
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,11 +49,10 @@ pub async fn get_volume(ctrl_handle: State<'_, ControllerHandle>) -> Result<(),
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn next(app: AppHandle<Wry>, ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
|
pub async fn next(app: AppHandle<Wry>, ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
|
||||||
ctrl_handle.player_mail.send(dmp_core::music_controller::controller::PlayerCommand::NextSong).await.unwrap();
|
let song = match ctrl_handle.next().await {
|
||||||
let PlayerResponse::NowPlaying(song) = ctrl_handle.player_mail.recv().await.unwrap() else {
|
Ok(s) => s,
|
||||||
return Ok(())
|
Err(e) => return Err(e.to_string())
|
||||||
};
|
};
|
||||||
println!("next");
|
|
||||||
app.emit("now_playing_change", _Song::from(&song)).unwrap();
|
app.emit("now_playing_change", _Song::from(&song)).unwrap();
|
||||||
app.emit("queue_updated", ()).unwrap();
|
app.emit("queue_updated", ()).unwrap();
|
||||||
app.emit("playing", ()).unwrap();
|
app.emit("playing", ()).unwrap();
|
||||||
|
@ -66,9 +61,9 @@ pub async fn next(app: AppHandle<Wry>, ctrl_handle: State<'_, ControllerHandle>)
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn prev(app: AppHandle<Wry>, ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
|
pub async fn prev(app: AppHandle<Wry>, ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
|
||||||
ctrl_handle.player_mail.send(dmp_core::music_controller::controller::PlayerCommand::PrevSong).await.unwrap();
|
let song = match ctrl_handle.prev().await {
|
||||||
let PlayerResponse::NowPlaying(song) = ctrl_handle.player_mail.recv().await.unwrap() else {
|
Ok(s) => s,
|
||||||
unreachable!()
|
Err(e) => return Err(e.to_string())
|
||||||
};
|
};
|
||||||
println!("prev");
|
println!("prev");
|
||||||
app.emit("now_playing_change", _Song::from(&song)).unwrap();
|
app.emit("now_playing_change", _Song::from(&song)).unwrap();
|
||||||
|
@ -84,14 +79,28 @@ pub async fn now_playing(ctrl_handle: State<'_, ControllerHandle>) -> Result<(),
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_queue(ctrl_handle: State<'_, ControllerHandle>) -> Result<Vec<_Song>, String> {
|
pub async fn get_queue(ctrl_handle: State<'_, ControllerHandle>) -> Result<Vec<_Song>, String> {
|
||||||
ctrl_handle.queue_mail.send(QueueCommand::Get).await.unwrap();
|
Ok(
|
||||||
let QueueResponse::GetAll(queue) = ctrl_handle.queue_mail.recv().await.unwrap() else {
|
ctrl_handle
|
||||||
unreachable!()
|
.queue_get_all()
|
||||||
};
|
.await
|
||||||
Ok(queue.into_iter().map(|item| {
|
.into_iter()
|
||||||
let QueueItemType::Single(song) = item.item else { unreachable!("There should be no albums in the queue right now") };
|
.map(|item| {
|
||||||
_Song::from(&song.song)
|
let QueueItemType::Single(song) = item.item else { unreachable!("There should be no albums in the queue right now") };
|
||||||
}).collect_vec())
|
_Song::from(&song.song)
|
||||||
|
}
|
||||||
|
).collect_vec()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn remove_from_queue(app: AppHandle<Wry>, ctrl_handle: ControllerHandle, index: usize) -> Result<(), String> {
|
||||||
|
match ctrl_handle.queue_remove(index).await {
|
||||||
|
Ok(_) => {
|
||||||
|
app.emit("queue_updated", ()).unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => Err(e.to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Grab Album art from custom protocol
|
//Grab Album art from custom protocol
|
||||||
|
@ -129,19 +138,21 @@ impl From<&Song> for _Song {
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_library(ctrl_handle: State<'_, ControllerHandle>) -> Result<Vec<_Song>, String> {
|
pub async fn get_library(ctrl_handle: State<'_, ControllerHandle>) -> Result<Vec<_Song>, String> {
|
||||||
ctrl_handle.lib_mail.send(LibraryCommand::AllSongs).await.unwrap();
|
let songs = ctrl_handle
|
||||||
println!("getting library");
|
.lib_get_all()
|
||||||
let LibraryResponse::AllSongs(songs) = ctrl_handle.lib_mail.recv().await.unwrap() else { unreachable!("It has been reached") };
|
.await
|
||||||
|
.iter()
|
||||||
let _songs = songs.iter().map(|song| _Song::from(song)).collect::<Vec<_>>();
|
.map(|song| _Song::from(song))
|
||||||
|
.collect_vec();
|
||||||
Ok(_songs)
|
Ok(songs)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_playlist(ctrl_handle: State<'_, ControllerHandle>, uuid: Uuid) -> Result<Vec<_Song>, String> {
|
pub async fn get_playlist(ctrl_handle: State<'_, ControllerHandle>, uuid: Uuid) -> Result<Vec<_Song>, String> {
|
||||||
ctrl_handle.lib_mail.send(LibraryCommand::ExternalPlaylist(uuid)).await.unwrap();
|
let playlist = match ctrl_handle.playlist_get(uuid).await {
|
||||||
let LibraryResponse::ExternalPlaylist(playlist) = ctrl_handle.lib_mail.recv().await.unwrap() else { unreachable!("It has been reached") };
|
Ok(list) => list,
|
||||||
|
Err(_) => todo!()
|
||||||
|
};
|
||||||
|
|
||||||
let songs = playlist.tracks.iter().map(|song| _Song::from(song)).collect::<Vec<_>>();
|
let songs = playlist.tracks.iter().map(|song| _Song::from(song)).collect::<Vec<_>>();
|
||||||
println!("Got Playlist {}, len {}", playlist.title, playlist.tracks.len());
|
println!("Got Playlist {}, len {}", playlist.title, playlist.tracks.len());
|
||||||
|
@ -150,11 +161,7 @@ pub async fn get_playlist(ctrl_handle: State<'_, ControllerHandle>, uuid: Uuid)
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_playlists(app: AppHandle<Wry>, ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
|
pub async fn get_playlists(app: AppHandle<Wry>, ctrl_handle: State<'_, ControllerHandle>) -> Result<(), String> {
|
||||||
println!("getting Playlists");
|
let lists = ctrl_handle.playlist_get_all().await;
|
||||||
ctrl_handle.lib_mail.send(LibraryCommand::Playlists).await.unwrap();
|
|
||||||
let LibraryResponse::Playlists(lists) = ctrl_handle.lib_mail.recv().await.unwrap() else { unreachable!() };
|
|
||||||
println!("gotten playlists");
|
|
||||||
|
|
||||||
app.emit("playlists_gotten", lists.into_iter().map(|(uuid, name)| PlaylistPayload { uuid, name }).collect_vec()).unwrap();
|
app.emit("playlists_gotten", lists.into_iter().map(|(uuid, name)| PlaylistPayload { uuid, name }).collect_vec()).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -168,10 +175,9 @@ pub async fn import_playlist(ctrl_handle: State<'_, ControllerHandle>) -> Result
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
ctrl_handle.lib_mail.send(LibraryCommand::ImportM3UPlayList(PathBuf::from(file.path()))).await.unwrap();
|
let (uuid, name) = ctrl_handle.playlist_import_m3u(PathBuf::from(file.path())).await.unwrap();
|
||||||
let LibraryResponse::ImportM3UPlayList(uuid, name) = ctrl_handle.lib_mail.recv().await.unwrap() else { unreachable!("It has been reached") };
|
ctrl_handle.lib_save().await;
|
||||||
ctrl_handle.lib_mail.send(LibraryCommand::Save).await.unwrap();
|
|
||||||
let LibraryResponse::Ok = ctrl_handle.lib_mail.recv().await.unwrap() else { unreachable!() };
|
|
||||||
println!("Imported Playlist {name}");
|
println!("Imported Playlist {name}");
|
||||||
Ok(PlaylistPayload {uuid, name})
|
Ok(PlaylistPayload {uuid, name})
|
||||||
}
|
}
|
||||||
|
@ -183,9 +189,8 @@ pub struct PlaylistPayload {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_song(ctrl_handle: State<'_, ControllerHandle>) -> Result<_Song, String> {
|
pub async fn get_song(ctrl_handle: State<'_, ControllerHandle>, uuid: Uuid) -> Result<_Song, String> {
|
||||||
ctrl_handle.lib_mail.send(LibraryCommand::Song(Uuid::default())).await.unwrap();
|
let song = ctrl_handle.lib_get_song(uuid).await.0;
|
||||||
let LibraryResponse::Song(song, _) = ctrl_handle.lib_mail.recv().await.unwrap() else { unreachable!("It has been reached") };
|
|
||||||
println!("got song {}", &song.tags.get(&Tag::Title).unwrap_or(&String::new()));
|
println!("got song {}", &song.tags.get(&Tag::Title).unwrap_or(&String::new()));
|
||||||
Ok(_Song::from(&song))
|
Ok(_Song::from(&song))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue