feat(playlists): reorder tracks
This commit is contained in:
@@ -11,6 +11,7 @@ service Library {
|
|||||||
rpc DeletePlaylist(DeletePlaylistRequest) returns (google.protobuf.Empty);
|
rpc DeletePlaylist(DeletePlaylistRequest) returns (google.protobuf.Empty);
|
||||||
rpc AddTrackToPlaylist(AddTrackToPlaylistRequest) returns (google.protobuf.Empty);
|
rpc AddTrackToPlaylist(AddTrackToPlaylistRequest) returns (google.protobuf.Empty);
|
||||||
rpc RemoveTrackFromPlaylist(RemoveTrackFromPlaylistRequest) returns (google.protobuf.Empty);
|
rpc RemoveTrackFromPlaylist(RemoveTrackFromPlaylistRequest) returns (google.protobuf.Empty);
|
||||||
|
rpc SwapTracks(SwapTracksRequest) returns (TrackList);
|
||||||
}
|
}
|
||||||
|
|
||||||
message TrackList {
|
message TrackList {
|
||||||
@@ -56,3 +57,9 @@ message RemoveTrackFromPlaylistRequest {
|
|||||||
uint32 playlist_id = 1;
|
uint32 playlist_id = 1;
|
||||||
uint32 track_rank = 2;
|
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)
|
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::{
|
use crate::{
|
||||||
checksum::generate_hash,
|
checksum::generate_hash,
|
||||||
database::tracks::{
|
database::tracks::{
|
||||||
add_track_to_playlist, create_playlist, delete_playlist, get_playlists, get_tracks,
|
add_track_to_playlist, create_playlist, delete_playlist, get_playlist, get_playlists,
|
||||||
insert_tracks, remove_track_from_playlist,
|
get_tracks, insert_tracks, remove_track_from_playlist, swap_playlist_tracks,
|
||||||
},
|
},
|
||||||
music::metadata::{extract_track_data, TrackMetadata},
|
music::metadata::{extract_track_data, TrackMetadata},
|
||||||
proto::library::{
|
proto::library::{
|
||||||
library_server::Library, AddTrackToPlaylistRequest, CreatePlaylistRequest,
|
library_server::Library, AddTrackToPlaylistRequest, CreatePlaylistRequest,
|
||||||
CreatePlaylistResponse, DeletePlaylistRequest, ListPlaylistsResponse,
|
CreatePlaylistResponse, DeletePlaylistRequest, ListPlaylistsResponse,
|
||||||
RemoveTrackFromPlaylistRequest, Track, TrackList,
|
RemoveTrackFromPlaylistRequest, SwapTracksRequest, Track, TrackList,
|
||||||
},
|
},
|
||||||
state::GrooveState,
|
state::GrooveState,
|
||||||
};
|
};
|
||||||
@@ -139,6 +139,33 @@ impl Library for LibraryService {
|
|||||||
|
|
||||||
Ok(Response::new(()))
|
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> {
|
pub async fn index_path(path: PathBuf, db: &Pool, path_id: u64) -> Result<(), rusqlite::Error> {
|
||||||
|
|||||||
Reference in New Issue
Block a user