feat(playlists): reorder tracks
This commit is contained in:
@@ -11,6 +11,7 @@ service Library {
|
||||
rpc DeletePlaylist(DeletePlaylistRequest) returns (google.protobuf.Empty);
|
||||
rpc AddTrackToPlaylist(AddTrackToPlaylistRequest) returns (google.protobuf.Empty);
|
||||
rpc RemoveTrackFromPlaylist(RemoveTrackFromPlaylistRequest) returns (google.protobuf.Empty);
|
||||
rpc SwapTracks(SwapTracksRequest) returns (TrackList);
|
||||
}
|
||||
|
||||
message TrackList {
|
||||
@@ -56,3 +57,9 @@ message RemoveTrackFromPlaylistRequest {
|
||||
uint32 playlist_id = 1;
|
||||
uint32 track_rank = 2;
|
||||
}
|
||||
|
||||
message SwapTracksRequest {
|
||||
uint32 playlist_id = 1;
|
||||
uint32 a_rank = 2;
|
||||
uint32 b_rank = 3;
|
||||
}
|
||||
|
||||
@@ -340,3 +340,31 @@ pub async fn remove_track_from_playlist(
|
||||
|
||||
Ok(len == 1)
|
||||
}
|
||||
|
||||
pub async fn swap_playlist_tracks(
|
||||
pool: &Pool,
|
||||
playlist_id: u32,
|
||||
a_rank: u32,
|
||||
b_rank: u32,
|
||||
) -> Result<bool, rusqlite::Error> {
|
||||
let manager = pool.get().await.unwrap();
|
||||
let mut connection = manager.lock().unwrap();
|
||||
|
||||
let tx = connection.transaction()?;
|
||||
|
||||
tx.execute(
|
||||
"UPDATE playlist_tracks SET rank = CASE WHEN rank = ?2 THEN - ?3 - 1 ELSE - ?2 - 1 END WHERE playlist_id = ?1 AND rank IN (?2, ?3)",
|
||||
[playlist_id, a_rank, b_rank],
|
||||
)?;
|
||||
|
||||
let len = tx.execute("UPDATE playlist_tracks SET rank = - rank - 1 WHERE playlist_id = ?1 AND rank IN (- ?2 - 1, - ?3 - 1)", [playlist_id, a_rank, b_rank])?;
|
||||
|
||||
if len != 2 {
|
||||
tx.rollback()?;
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
tx.commit()?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@ use walkdir::{DirEntry, WalkDir};
|
||||
use crate::{
|
||||
checksum::generate_hash,
|
||||
database::tracks::{
|
||||
add_track_to_playlist, create_playlist, delete_playlist, get_playlists, get_tracks,
|
||||
insert_tracks, remove_track_from_playlist,
|
||||
add_track_to_playlist, create_playlist, delete_playlist, get_playlist, get_playlists,
|
||||
get_tracks, insert_tracks, remove_track_from_playlist, swap_playlist_tracks,
|
||||
},
|
||||
music::metadata::{extract_track_data, TrackMetadata},
|
||||
proto::library::{
|
||||
library_server::Library, AddTrackToPlaylistRequest, CreatePlaylistRequest,
|
||||
CreatePlaylistResponse, DeletePlaylistRequest, ListPlaylistsResponse,
|
||||
RemoveTrackFromPlaylistRequest, Track, TrackList,
|
||||
RemoveTrackFromPlaylistRequest, SwapTracksRequest, Track, TrackList,
|
||||
},
|
||||
state::GrooveState,
|
||||
};
|
||||
@@ -139,6 +139,33 @@ impl Library for LibraryService {
|
||||
|
||||
Ok(Response::new(()))
|
||||
}
|
||||
|
||||
async fn swap_tracks(
|
||||
&self,
|
||||
request: Request<SwapTracksRequest>,
|
||||
) -> Result<Response<TrackList>, Status> {
|
||||
let input = request.get_ref();
|
||||
|
||||
let Ok(success) =
|
||||
swap_playlist_tracks(&self.pool, input.playlist_id, input.a_rank, input.b_rank).await
|
||||
else {
|
||||
return Err(Status::internal(""));
|
||||
};
|
||||
|
||||
if !success {
|
||||
return Err(Status::internal(""));
|
||||
}
|
||||
|
||||
let Ok(playlist) = get_playlist(&self.pool, input.playlist_id).await else {
|
||||
return Err(Status::internal(""));
|
||||
};
|
||||
|
||||
let response = TrackList {
|
||||
tracks: playlist.tracks,
|
||||
};
|
||||
|
||||
Ok(Response::new(response))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn index_path(path: PathBuf, db: &Pool, path_id: u64) -> Result<(), rusqlite::Error> {
|
||||
|
||||
Reference in New Issue
Block a user