feat(playlists): reorder tracks

This commit is contained in:
2024-12-03 00:22:20 +01:00
parent a652ae330f
commit e192bd5e23
3 changed files with 65 additions and 3 deletions

View File

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

View File

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

View File

@@ -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> {