feat!: playlists
This commit is contained in:
@@ -1,17 +1,21 @@
|
||||
use deadpool_sqlite::Pool;
|
||||
use std::{pin::Pin, time::Duration};
|
||||
use std::{path::PathBuf, pin::Pin, time::Duration};
|
||||
use tokio::sync::mpsc;
|
||||
use tokio_stream::{wrappers::ReceiverStream, Stream};
|
||||
|
||||
use crate::{
|
||||
database::tracks::{get_track, get_track_full_path},
|
||||
database::tracks::{
|
||||
get_playlist, get_specific_tracks, get_specific_tracks_full_path, get_track,
|
||||
get_track_full_path, Track,
|
||||
},
|
||||
music::queue::queue_to_track_vec,
|
||||
proto::{
|
||||
self,
|
||||
player::{
|
||||
player_server::Player, PauseState, PlayTrackResponse, PlayerStatus, Queue,
|
||||
SeekPositionRequest, SeekPositionResponse, SetVolumeRequest, SetVolumeResponse,
|
||||
SkipToQueueIndexRequest, SwapQueueIndicesRequest, TrackRequest,
|
||||
player_server::Player, PauseState, PlayPlaylistRequest, PlayTrackResponse,
|
||||
PlayerStatus, Queue, SeekPositionRequest, SeekPositionResponse, SetVolumeRequest,
|
||||
SetVolumeResponse, SkipToQueueIndexRequest, SwapQueueIndicesRequest, TrackRequest,
|
||||
TracksRequest,
|
||||
},
|
||||
},
|
||||
state::GrooveState,
|
||||
@@ -198,6 +202,75 @@ impl Player for PlayerService {
|
||||
Ok(tonic::Response::new(response))
|
||||
}
|
||||
|
||||
async fn add_tracks_to_queue(
|
||||
&self,
|
||||
request: tonic::Request<TracksRequest>,
|
||||
) -> Result<tonic::Response<Queue>, tonic::Status> {
|
||||
let input = request.get_ref();
|
||||
|
||||
let Ok(tracks) = get_specific_tracks(&self.pool, &input.tracks).await else {
|
||||
return Err(tonic::Status::not_found(""));
|
||||
};
|
||||
|
||||
let Ok(track_paths) = get_specific_tracks_full_path(&self.pool, &input.tracks).await else {
|
||||
return Err(tonic::Status::not_found(""));
|
||||
};
|
||||
|
||||
let state = self.state.lock().await;
|
||||
let mut player = state.player.lock().await;
|
||||
|
||||
let tracks_and_paths: Vec<(Track, PathBuf)> =
|
||||
tracks.into_iter().zip(track_paths.into_iter()).collect();
|
||||
|
||||
if let Err(_) = player.add_tracks_to_queue(tracks_and_paths, false).await {
|
||||
return Err(tonic::Status::internal(""));
|
||||
}
|
||||
|
||||
let queue = player.queue();
|
||||
|
||||
let response = Queue {
|
||||
tracks: queue_to_track_vec(queue),
|
||||
};
|
||||
|
||||
Ok(tonic::Response::new(response))
|
||||
}
|
||||
|
||||
async fn play_playlist(
|
||||
&self,
|
||||
request: tonic::Request<PlayPlaylistRequest>,
|
||||
) -> Result<tonic::Response<PlayerStatus>, tonic::Status> {
|
||||
let input = request.get_ref();
|
||||
|
||||
let Ok(playlist) = get_playlist(&self.pool, input.id).await else {
|
||||
return Err(tonic::Status::not_found(""));
|
||||
};
|
||||
|
||||
let Ok(track_paths) = get_specific_tracks_full_path(
|
||||
&self.pool,
|
||||
&playlist.tracks.iter().map(|t| t.hash.clone()).collect(),
|
||||
)
|
||||
.await
|
||||
else {
|
||||
return Err(tonic::Status::not_found(""));
|
||||
};
|
||||
|
||||
let state = self.state.lock().await;
|
||||
let mut player = state.player.lock().await;
|
||||
|
||||
let tracks = playlist.tracks.iter().map(|t| t.clone().into());
|
||||
|
||||
let tracks_and_paths: Vec<(Track, PathBuf)> =
|
||||
tracks.into_iter().zip(track_paths.into_iter()).collect();
|
||||
|
||||
if let Err(_) = player.add_tracks_to_queue(tracks_and_paths, true).await {
|
||||
return Err(tonic::Status::internal(""));
|
||||
}
|
||||
|
||||
let response = player.get_snapshot().into();
|
||||
|
||||
Ok(tonic::Response::new(response))
|
||||
}
|
||||
|
||||
async fn play_track_next(
|
||||
&self,
|
||||
request: tonic::Request<TrackRequest>,
|
||||
|
||||
Reference in New Issue
Block a user