Added Error Handling for Queue and abstractions over the ControllerHandle

This commit is contained in:
MrDulfin 2024-12-27 22:45:59 -05:00
parent f51650f4d2
commit d18f980fa0
6 changed files with 344 additions and 162 deletions

View file

@ -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"]}

View file

@ -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;
} }

View file

@ -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();
} }
} }
} }

View 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
}
}

View file

@ -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();

View file

@ -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))
} }