From 4eb52879a613be7d9b99e888679cd1c296e5b06d Mon Sep 17 00:00:00 2001 From: Tsiry Sandratraina Date: Thu, 26 Dec 2024 02:35:08 +0100 Subject: [PATCH 01/26] playlist: add db queries for playlist --- crates/library/src/entity/playlist_tracks.rs | 4 + crates/library/src/repo/folder.rs | 73 ++++++++++++++++++- crates/library/src/repo/playlist.rs | 77 +++++++++++++++++++- crates/library/src/repo/playlist_tracks.rs | 55 +++++++++++++- 4 files changed, 199 insertions(+), 10 deletions(-) diff --git a/crates/library/src/entity/playlist_tracks.rs b/crates/library/src/entity/playlist_tracks.rs index 201e28cb9e2..3a66c9aad41 100644 --- a/crates/library/src/entity/playlist_tracks.rs +++ b/crates/library/src/entity/playlist_tracks.rs @@ -1,6 +1,10 @@ +use chrono::{DateTime, Utc}; + #[derive(sqlx::FromRow, Default)] pub struct PlaylistTracks { pub id: String, pub playlist_id: String, pub track_id: String, + #[serde(with = "chrono::serde::ts_seconds")] + pub created_at: DateTime, } diff --git a/crates/library/src/repo/folder.rs b/crates/library/src/repo/folder.rs index 9a7b59ae0e8..e31f5968941 100644 --- a/crates/library/src/repo/folder.rs +++ b/crates/library/src/repo/folder.rs @@ -1,8 +1,73 @@ use crate::entity::folder::Folder; -use sqlx::{Pool, Sqlite}; +use sqlx::{types::chrono, Pool, Sqlite}; -pub async fn save(pool: Pool, folder: Folder) {} +pub async fn save(pool: Pool, folder: Folder) -> Result<(), sqlx::Error> { + sqlx::query( + r#" + INSERT INTO folder ( + id, + name, + created_at, + updated_at + ) + VALUES ($1, $2, $3, $4) + "#, + ) + .bind(folder.id) + .bind(&folder.name) + .bind(folder.created_at) + .bind(folder.updated_at) + .execute(&pool) + .await?; + Ok(()) +} -pub async fn find(pool: Pool) {} +pub async fn find(pool: Pool, id: &str) -> Result, sqlx::Error> { + sqlx::query_as::<_, Folder>(r#"SELECT * FROM folder WHERE id = $1"#) + .bind(id) + .fetch_optional(&pool) + .await +} -pub async fn all(pool: Pool) {} +pub async fn find_by_parent( + pool: Pool, + parent_id: &str, +) -> Result, sqlx::Error> { + sqlx::query_as::<_, Folder>(r#"SELECT * FROM folder WHERE parent_id = $1"#) + .bind(parent_id) + .fetch_all(&pool) + .await +} + +pub async fn all(pool: Pool) -> Result, sqlx::Error> { + sqlx::query_as::<_, Folder>(r#"SELECT * FROM folder ORDER BY name ASC"#) + .fetch_all(&pool) + .await +} + +pub async fn delete(pool: Pool, id: &str) -> Result<(), sqlx::Error> { + sqlx::query(r#"DELETE FROM folder WHERE id = $1"#) + .bind(id) + .execute(&pool) + .await?; + Ok(()) +} + +pub async fn update(pool: Pool, folder: Folder) -> Result<(), sqlx::Error> { + sqlx::query( + r#" + UPDATE folder SET + name = $2, + updated_at = $3, + parent_id = $4 + WHERE id = $1 + "#, + ) + .bind(&folder.id) + .bind(&folder.name) + .bind(chrono::Utc::now()) + .bind(&folder.parent_id) + .execute(&pool) + .await?; + Ok(()) +} diff --git a/crates/library/src/repo/playlist.rs b/crates/library/src/repo/playlist.rs index 46aa76dcbf1..10fd230f8fb 100644 --- a/crates/library/src/repo/playlist.rs +++ b/crates/library/src/repo/playlist.rs @@ -1,8 +1,79 @@ use crate::entity::playlist::Playlist; use sqlx::{Pool, Sqlite}; -pub async fn save(pool: Pool, playlist: Playlist) {} +pub async fn save(pool: Pool, playlist: Playlist) -> Result<(), sqlx::Error> { + sqlx::query( + r#" + INSERT INTO playlist ( + id, + name, + folder_id, + created_at, + updated_at + ) + VALUES ($1, $2, $3, $4, $5) + "#, + ) + .bind(&playlist.id) + .bind(&playlist.name) + .bind(&playlist.folder_id) + .bind(playlist.created_at) + .bind(playlist.updated_at) + .execute(&pool) + .await?; + Ok(()) +} -pub async fn find(pool: Pool) {} +pub async fn find(pool: Pool, id: &str) -> Result, sqlx::Error> { + sqlx::query_as::<_, Playlist>(r#"SELECT * FROM playlist WHERE id = $1"#) + .bind(id) + .fetch_optional(&pool) + .await +} -pub async fn all(pool: Pool) {} +pub async fn find_by_folder( + pool: Pool, + folder_id: &str, +) -> Result, sqlx::Error> { + sqlx::query_as::<_, Playlist>( + r#" + SELECT * FROM playlist WHERE folder_id = $1 ORDER BY name ASC + "#, + ) + .bind(folder_id) + .fetch_all(&pool) + .await +} + +pub async fn all(pool: Pool) -> Result, sqlx::Error> { + sqlx::query_as::<_, Playlist>(r#"SELECT * FROM playlist ORDER BY name ASC"#) + .fetch_all(&pool) + .await +} + +pub async fn delete(pool: Pool, id: &str) -> Result<(), sqlx::Error> { + sqlx::query(r#"DELETE FROM playlist WHERE id = $1"#) + .bind(id) + .execute(&pool) + .await?; + Ok(()) +} + +pub async fn update(pool: Pool, playlist: Playlist) -> Result<(), sqlx::Error> { + sqlx::query( + r#" + UPDATE playlist SET + name = $2, + updated_at = $3, + folder_id = $4 + WHERE id = $1 + "#, + ) + .bind(&playlist.id) + .bind(&playlist.name) + .bind(chrono::Utc::now()) + .bind(&playlist.folder_id) + .execute(&pool) + .await?; + Ok(()) +} diff --git a/crates/library/src/repo/playlist_tracks.rs b/crates/library/src/repo/playlist_tracks.rs index 877972430eb..eaf18da152c 100644 --- a/crates/library/src/repo/playlist_tracks.rs +++ b/crates/library/src/repo/playlist_tracks.rs @@ -1,6 +1,55 @@ -use crate::entity::playlist_tracks::PlaylistTracks; +use crate::entity::{playlist_tracks::PlaylistTracks, track::Track}; use sqlx::{Pool, Sqlite}; -pub async fn save(pool: Pool, playlist_track: PlaylistTracks) {} +pub async fn save(pool: Pool, playlist_track: PlaylistTracks) -> Result<(), sqlx::Error> { + sqlx::query( + r#" + INSERT INTO playlist_tracks ( + id, + playlist_id, + track_id, + created_at + ) + VALUES ($1, $2, $3, $4) + "#, + ) + .bind(&playlist_track.id) + .bind(&playlist_track.playlist_id) + .bind(&playlist_track.track_id) + .bind(playlist_track.created_at) + .execute(&pool) + .await?; + Ok(()) +} -pub async fn find(pool: Pool) {} +pub async fn find_by_playlist( + pool: Pool, + playlist_id: &str, +) -> Result, sqlx::Error> { + match sqlx::query_as::<_, Track>( + r#" + SELECT * FROM playlist_tracks + LEFT JOIN track ON playlist_tracks.track_id = track.id + WHERE playlist_tracks.playlist_id = $1 + ORDER BY playlist_tracks.created_at ASC + "#, + ) + .bind(playlist_id) + .fetch_all(&pool) + .await + { + Ok(playlist_tracks) => Ok(playlist_tracks), + Err(e) => { + eprintln!("Error finding playlist tracks: {:?}", e); + Err(e) + } + } +} + +pub async fn delete(pool: Pool, id: &str) -> Result<(), sqlx::Error> { + sqlx::query(r#"DELTE FROM playlist_tracks WHERE id = $1"#) + .bind(id) + .execute(&pool) + .await?; + Ok(()) +} From 2b9def58af50a41cf7d25cc1a178360f745d8af4 Mon Sep 17 00:00:00 2001 From: Tsiry Sandratraina Date: Thu, 26 Dec 2024 02:37:42 +0100 Subject: [PATCH 02/26] playlist: fix typo --- crates/library/src/repo/playlist_tracks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/library/src/repo/playlist_tracks.rs b/crates/library/src/repo/playlist_tracks.rs index eaf18da152c..0ab04890026 100644 --- a/crates/library/src/repo/playlist_tracks.rs +++ b/crates/library/src/repo/playlist_tracks.rs @@ -47,7 +47,7 @@ pub async fn find_by_playlist( } pub async fn delete(pool: Pool, id: &str) -> Result<(), sqlx::Error> { - sqlx::query(r#"DELTE FROM playlist_tracks WHERE id = $1"#) + sqlx::query(r#"DELETE FROM playlist_tracks WHERE id = $1"#) .bind(id) .execute(&pool) .await?; From 6b32aaf8651838dcbb6e9d334b0dab2054eb8795 Mon Sep 17 00:00:00 2001 From: Tsiry Sandratraina Date: Fri, 27 Dec 2024 05:34:28 +0100 Subject: [PATCH 03/26] playlist: update db queries for playlist --- crates/library/src/repo/playlist.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/library/src/repo/playlist.rs b/crates/library/src/repo/playlist.rs index 10fd230f8fb..b6c5a0c8d4c 100644 --- a/crates/library/src/repo/playlist.rs +++ b/crates/library/src/repo/playlist.rs @@ -7,15 +7,19 @@ pub async fn save(pool: Pool, playlist: Playlist) -> Result<(), sqlx::Er INSERT INTO playlist ( id, name, + image, + description, folder_id, created_at, updated_at ) - VALUES ($1, $2, $3, $4, $5) + VALUES ($1, $2, $3, $4, $5, $6, $7) "#, ) .bind(&playlist.id) .bind(&playlist.name) + .bind(&playlist.image) + .bind(&playlist.description) .bind(&playlist.folder_id) .bind(playlist.created_at) .bind(playlist.updated_at) From 036139bf00f858b9cb68395934005f6331270f15 Mon Sep 17 00:00:00 2001 From: Tsiry Sandratraina Date: Fri, 27 Dec 2024 05:52:31 +0100 Subject: [PATCH 04/26] playlist: add playlist track position column --- .../20241227044632_add-playlist-track-position.sql | 2 ++ crates/library/src/entity/playlist_tracks.rs | 4 +++- crates/library/src/lib.rs | 10 ++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 crates/library/migrations/20241227044632_add-playlist-track-position.sql diff --git a/crates/library/migrations/20241227044632_add-playlist-track-position.sql b/crates/library/migrations/20241227044632_add-playlist-track-position.sql new file mode 100644 index 00000000000..063e7872b49 --- /dev/null +++ b/crates/library/migrations/20241227044632_add-playlist-track-position.sql @@ -0,0 +1,2 @@ +-- Add migration script here +ALTER TABLE playlist_tracks ADD COLUMN position INT NOT NULL DEFAULT 0; diff --git a/crates/library/src/entity/playlist_tracks.rs b/crates/library/src/entity/playlist_tracks.rs index 3a66c9aad41..f91729dffbe 100644 --- a/crates/library/src/entity/playlist_tracks.rs +++ b/crates/library/src/entity/playlist_tracks.rs @@ -1,10 +1,12 @@ use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; -#[derive(sqlx::FromRow, Default)] +#[derive(sqlx::FromRow, Default, Serialize, Deserialize)] pub struct PlaylistTracks { pub id: String, pub playlist_id: String, pub track_id: String, + pub position: u32, #[serde(with = "chrono::serde::ts_seconds")] pub created_at: DateTime, } diff --git a/crates/library/src/lib.rs b/crates/library/src/lib.rs index 44368d8e929..189c00feac9 100644 --- a/crates/library/src/lib.rs +++ b/crates/library/src/lib.rs @@ -43,6 +43,16 @@ pub async fn create_connection_pool() -> Result, Error> { Err(_) => println!("album_id column already exists"), } + match pool + .execute(include_str!( + "../migrations/20241227044632_add-playlist-track-position.sql" + )) + .await + { + Ok(_) => {} + Err(_) => println!("position column already exists"), + } + sqlx::query("PRAGMA journal_mode=WAL") .execute(&pool) .await?; From 94851fd2b52adde2efa84f9b46a8ab67e42312bb Mon Sep 17 00:00:00 2001 From: Tsiry Sandratraina Date: Fri, 27 Dec 2024 06:00:05 +0100 Subject: [PATCH 05/26] playlist: allow deleting playlist track at specified position --- crates/library/src/repo/playlist_tracks.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/crates/library/src/repo/playlist_tracks.rs b/crates/library/src/repo/playlist_tracks.rs index 0ab04890026..922e21c0a86 100644 --- a/crates/library/src/repo/playlist_tracks.rs +++ b/crates/library/src/repo/playlist_tracks.rs @@ -8,6 +8,7 @@ pub async fn save(pool: Pool, playlist_track: PlaylistTracks) -> Result< id, playlist_id, track_id, + position, created_at ) VALUES ($1, $2, $3, $4) @@ -16,6 +17,7 @@ pub async fn save(pool: Pool, playlist_track: PlaylistTracks) -> Result< .bind(&playlist_track.id) .bind(&playlist_track.playlist_id) .bind(&playlist_track.track_id) + .bind(playlist_track.position) .bind(playlist_track.created_at) .execute(&pool) .await?; @@ -31,7 +33,7 @@ pub async fn find_by_playlist( SELECT * FROM playlist_tracks LEFT JOIN track ON playlist_tracks.track_id = track.id WHERE playlist_tracks.playlist_id = $1 - ORDER BY playlist_tracks.created_at ASC + ORDER BY playlist_tracks.position ASC "#, ) .bind(playlist_id) @@ -53,3 +55,16 @@ pub async fn delete(pool: Pool, id: &str) -> Result<(), sqlx::Error> { .await?; Ok(()) } + +pub async fn delete_track_at( + pool: Pool, + playlist_id: &str, + position: u32, +) -> Result<(), sqlx::Error> { + sqlx::query(r#"DELETE FROM playlist_tracks WHERE playlist_id = $1 AND position = $2"#) + .bind(playlist_id) + .bind(position) + .execute(&pool) + .await?; + Ok(()) +} From 65f3254755f99f152c128d7c3f2a53cf92a3ec12 Mon Sep 17 00:00:00 2001 From: Tsiry Sandratraina Date: Sun, 29 Dec 2024 15:45:19 +0100 Subject: [PATCH 06/26] playlist: finish playlist api --- Cargo.lock | 2 + cli/src/api/rockbox.v1alpha1.rs | 1455 ++++++++++++++--- cli/src/api/rockbox_descriptor.bin | Bin 62996 -> 69311 bytes crates/graphql/src/schema/objects/folder.rs | 34 + crates/graphql/src/schema/objects/mod.rs | 1 + crates/graphql/src/schema/objects/playlist.rs | 35 + crates/graphql/src/schema/objects/track.rs | 6 +- crates/graphql/src/schema/playlist.rs | 219 ++- crates/library/src/repo/folder.rs | 16 +- crates/library/src/repo/playlist.rs | 22 +- crates/library/src/repo/playlist_tracks.rs | 34 +- crates/mpd/src/handlers/queue.rs | 12 +- .../rpc/proto/rockbox/v1alpha1/playlist.proto | 99 +- crates/rpc/src/api/rockbox.v1alpha1.rs | 1451 +++++++++++++--- crates/rpc/src/api/rockbox_descriptor.bin | Bin 65911 -> 72212 bytes crates/rpc/src/playback.rs | 23 +- crates/rpc/src/playlist.rs | 298 +++- crates/server/Cargo.toml | 2 + crates/server/src/handlers/folders.rs | 69 + crates/server/src/handlers/mod.rs | 10 + crates/server/src/handlers/playlists.rs | 285 +++- crates/server/src/lib.rs | 11 + crates/sys/src/types/playlist_info.rs | 8 + crates/types/src/lib.rs | 30 + gtk/proto/rockbox/v1alpha1/playlist.proto | 111 +- gtk/src/api/rockbox.v1alpha1.rs | 1455 ++++++++++++++--- gtk/src/api/rockbox_descriptor.bin | Bin 62996 -> 69311 bytes 27 files changed, 4937 insertions(+), 751 deletions(-) create mode 100644 crates/graphql/src/schema/objects/folder.rs create mode 100644 crates/server/src/handlers/folders.rs diff --git a/Cargo.lock b/Cargo.lock index 11bbe4f6930..cb226f711a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8907,6 +8907,8 @@ version = "0.1.0" dependencies = [ "anyhow", "async-std", + "chrono", + "cuid", "futures-util", "lazy_static", "local-ip-addr", diff --git a/cli/src/api/rockbox.v1alpha1.rs b/cli/src/api/rockbox.v1alpha1.rs index 2dc76196977..362ec36547e 100644 --- a/cli/src/api/rockbox.v1alpha1.rs +++ b/cli/src/api/rockbox.v1alpha1.rs @@ -4316,21 +4316,26 @@ pub struct StartResponse {} pub struct SyncRequest {} #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct SyncResponse {} -#[derive(Clone, Copy, PartialEq, ::prost::Message)] -pub struct RemoveAllTracksRequest {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemoveAllTracksRequest { + #[prost(string, optional, tag = "1")] + pub playlist_id: ::core::option::Option<::prost::alloc::string::String>, +} #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct RemoveAllTracksResponse {} #[derive(Clone, PartialEq, ::prost::Message)] pub struct RemoveTracksRequest { #[prost(int32, repeated, tag = "1")] pub positions: ::prost::alloc::vec::Vec, + #[prost(string, optional, tag = "2")] + pub playlist_id: ::core::option::Option<::prost::alloc::string::String>, } #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct RemoveTracksResponse {} #[derive(Clone, PartialEq, ::prost::Message)] pub struct CreatePlaylistRequest { - #[prost(string, tag = "1")] - pub name: ::prost::alloc::string::String, + #[prost(string, optional, tag = "1")] + pub name: ::core::option::Option<::prost::alloc::string::String>, #[prost(string, repeated, tag = "2")] pub tracks: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, } @@ -4388,6 +4393,8 @@ pub struct InsertAlbumRequest { pub album_id: ::prost::alloc::string::String, #[prost(bool, optional, tag = "3")] pub shuffle: ::core::option::Option, + #[prost(string, optional, tag = "4")] + pub playlist_id: ::core::option::Option<::prost::alloc::string::String>, } #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct InsertAlbumResponse {} @@ -4399,6 +4406,8 @@ pub struct InsertArtistTracksRequest { pub artist_id: ::prost::alloc::string::String, #[prost(bool, optional, tag = "3")] pub shuffle: ::core::option::Option, + #[prost(string, optional, tag = "4")] + pub playlist_id: ::core::option::Option<::prost::alloc::string::String>, } #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct InsertArtistTracksResponse {} @@ -4409,6 +4418,128 @@ pub struct ShufflePlaylistRequest { } #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct ShufflePlaylistResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPlaylistRequest { + #[prost(string, tag = "1")] + pub playlist_id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPlaylistResponse { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, + #[prost(string, optional, tag = "3")] + pub folder_id: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "4")] + pub image: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "5")] + pub description: ::core::option::Option<::prost::alloc::string::String>, + #[prost(int32, tag = "6")] + pub amount: i32, + #[prost(string, tag = "7")] + pub created_at: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub updated_at: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "9")] + pub tracks: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CreateFolderRequest { + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, + #[prost(string, optional, tag = "2")] + pub parent_id: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CreateFolderResponse { + #[prost(string, tag = "1")] + pub folder_id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetFolderRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetFolderResponse { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, + #[prost(string, optional, tag = "3")] + pub parent_id: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetFoldersRequest { + #[prost(string, optional, tag = "1")] + pub parent_id: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetFoldersResponse { + #[prost(message, repeated, tag = "1")] + pub folders: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemoveFolderRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct RemoveFolderResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemovePlaylistRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct RemovePlaylistResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RenamePlaylistRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct RenamePlaylistResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RenameFolderRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct RenameFolderResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MovePlaylistRequest { + #[prost(string, tag = "1")] + pub playlist_id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub folder_id: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MovePlaylistResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MoveFolderRequest { + #[prost(string, tag = "1")] + pub folder_id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub parent_id: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MoveFolderResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPlaylistsRequest { + #[prost(string, optional, tag = "1")] + pub folder_id: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPlaylistsResponse { + #[prost(message, repeated, tag = "1")] + pub playlists: ::prost::alloc::vec::Vec, +} /// Generated client implementations. pub mod playlist_service_client { #![allow( @@ -5020,79 +5151,365 @@ pub mod playlist_service_client { ); self.inner.unary(req, path, codec).await } - } -} -/// Generated server implementations. -pub mod playlist_service_server { - #![allow( - unused_variables, - dead_code, - missing_docs, - clippy::wildcard_imports, - clippy::let_unit_value, - )] - use tonic::codegen::*; - /// Generated trait containing gRPC methods that should be implemented for use with PlaylistServiceServer. - #[async_trait] - pub trait PlaylistService: std::marker::Send + std::marker::Sync + 'static { - async fn get_current( - &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; - async fn get_resume_info( - &self, - request: tonic::Request, + pub async fn get_playlist( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn get_track_info( - &self, - request: tonic::Request, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/GetPlaylist", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "GetPlaylist"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn get_playlists( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn get_first_index( - &self, - request: tonic::Request, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/GetPlaylists", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "GetPlaylists"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn create_folder( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn get_display_index( - &self, - request: tonic::Request, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/CreateFolder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "CreateFolder"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn get_folder( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn amount( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - async fn playlist_resume( - &self, - request: tonic::Request, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/GetFolder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "GetFolder"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn get_folders( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn resume_track( - &self, - request: tonic::Request, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/GetFolders", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "GetFolders"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn remove_folder( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn set_modified( - &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/RemoveFolder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "RemoveFolder"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn remove_playlist( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/RemovePlaylist", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "RemovePlaylist"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn rename_playlist( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/RenamePlaylist", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "RenamePlaylist"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn rename_folder( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/RenameFolder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "RenameFolder"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn move_playlist( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/MovePlaylist", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "MovePlaylist"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn move_folder( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/MoveFolder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "MoveFolder"), + ); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated server implementations. +pub mod playlist_service_server { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with PlaylistServiceServer. + #[async_trait] + pub trait PlaylistService: std::marker::Send + std::marker::Sync + 'static { + async fn get_current( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_resume_info( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_track_info( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_first_index( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_display_index( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn amount( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn playlist_resume( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn resume_track( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn set_modified( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, tonic::Status, >; async fn start( @@ -5166,6 +5583,83 @@ pub mod playlist_service_server { tonic::Response, tonic::Status, >; + async fn get_playlist( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_playlists( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn create_folder( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_folder( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_folders( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn remove_folder( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn remove_playlist( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn rename_playlist( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn rename_folder( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn move_playlist( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn move_folder( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct PlaylistServiceServer { @@ -5245,23 +5739,522 @@ pub mod playlist_service_server { match req.uri().path() { "/rockbox.v1alpha1.PlaylistService/GetCurrent" => { #[allow(non_camel_case_types)] - struct GetCurrentSvc(pub Arc); + struct GetCurrentSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for GetCurrentSvc { + type Response = super::GetCurrentResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_current(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetCurrentSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/GetResumeInfo" => { + #[allow(non_camel_case_types)] + struct GetResumeInfoSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for GetResumeInfoSvc { + type Response = super::GetResumeInfoResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_resume_info(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetResumeInfoSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/GetTrackInfo" => { + #[allow(non_camel_case_types)] + struct GetTrackInfoSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for GetTrackInfoSvc { + type Response = super::GetTrackInfoResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_track_info(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetTrackInfoSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/GetFirstIndex" => { + #[allow(non_camel_case_types)] + struct GetFirstIndexSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for GetFirstIndexSvc { + type Response = super::GetFirstIndexResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_first_index(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetFirstIndexSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/GetDisplayIndex" => { + #[allow(non_camel_case_types)] + struct GetDisplayIndexSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for GetDisplayIndexSvc { + type Response = super::GetDisplayIndexResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_display_index(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetDisplayIndexSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/Amount" => { + #[allow(non_camel_case_types)] + struct AmountSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for AmountSvc { + type Response = super::AmountResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::amount(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = AmountSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/PlaylistResume" => { + #[allow(non_camel_case_types)] + struct PlaylistResumeSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for PlaylistResumeSvc { + type Response = super::PlaylistResumeResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::playlist_resume(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = PlaylistResumeSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/ResumeTrack" => { + #[allow(non_camel_case_types)] + struct ResumeTrackSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for ResumeTrackSvc { + type Response = super::ResumeTrackResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::resume_track(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ResumeTrackSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/SetModified" => { + #[allow(non_camel_case_types)] + struct SetModifiedSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for SetModifiedSvc { + type Response = super::SetModifiedResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::set_modified(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SetModifiedSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/Start" => { + #[allow(non_camel_case_types)] + struct StartSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService for StartSvc { + type Response = super::StartResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::start(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = StartSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/Sync" => { + #[allow(non_camel_case_types)] + struct SyncSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService for SyncSvc { + type Response = super::SyncResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::sync(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SyncSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/RemoveAllTracks" => { + #[allow(non_camel_case_types)] + struct RemoveAllTracksSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for GetCurrentSvc { - type Response = super::GetCurrentResponse; + > tonic::server::UnaryService + for RemoveAllTracksSvc { + type Response = super::RemoveAllTracksResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::get_current(&inner, request).await + ::remove_all_tracks(&inner, request) + .await }; Box::pin(fut) } @@ -5272,7 +6265,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = GetCurrentSvc(inner); + let method = RemoveAllTracksSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5288,26 +6281,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/GetResumeInfo" => { + "/rockbox.v1alpha1.PlaylistService/RemoveTracks" => { #[allow(non_camel_case_types)] - struct GetResumeInfoSvc(pub Arc); + struct RemoveTracksSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for GetResumeInfoSvc { - type Response = super::GetResumeInfoResponse; + > tonic::server::UnaryService + for RemoveTracksSvc { + type Response = super::RemoveTracksResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::get_resume_info(&inner, request) - .await + ::remove_tracks(&inner, request).await }; Box::pin(fut) } @@ -5318,7 +6310,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = GetResumeInfoSvc(inner); + let method = RemoveTracksSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5334,25 +6326,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/GetTrackInfo" => { + "/rockbox.v1alpha1.PlaylistService/CreatePlaylist" => { #[allow(non_camel_case_types)] - struct GetTrackInfoSvc(pub Arc); + struct CreatePlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for GetTrackInfoSvc { - type Response = super::GetTrackInfoResponse; + > tonic::server::UnaryService + for CreatePlaylistSvc { + type Response = super::CreatePlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::get_track_info(&inner, request) + ::create_playlist(&inner, request) .await }; Box::pin(fut) @@ -5364,7 +6356,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = GetTrackInfoSvc(inner); + let method = CreatePlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5380,26 +6372,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/GetFirstIndex" => { + "/rockbox.v1alpha1.PlaylistService/InsertTracks" => { #[allow(non_camel_case_types)] - struct GetFirstIndexSvc(pub Arc); + struct InsertTracksSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for GetFirstIndexSvc { - type Response = super::GetFirstIndexResponse; + > tonic::server::UnaryService + for InsertTracksSvc { + type Response = super::InsertTracksResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::get_first_index(&inner, request) - .await + ::insert_tracks(&inner, request).await }; Box::pin(fut) } @@ -5410,7 +6401,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = GetFirstIndexSvc(inner); + let method = InsertTracksSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5426,25 +6417,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/GetDisplayIndex" => { + "/rockbox.v1alpha1.PlaylistService/InsertDirectory" => { #[allow(non_camel_case_types)] - struct GetDisplayIndexSvc(pub Arc); + struct InsertDirectorySvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for GetDisplayIndexSvc { - type Response = super::GetDisplayIndexResponse; + > tonic::server::UnaryService + for InsertDirectorySvc { + type Response = super::InsertDirectoryResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::get_display_index(&inner, request) + ::insert_directory(&inner, request) .await }; Box::pin(fut) @@ -5456,7 +6447,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = GetDisplayIndexSvc(inner); + let method = InsertDirectorySvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5472,25 +6463,26 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/Amount" => { + "/rockbox.v1alpha1.PlaylistService/InsertPlaylist" => { #[allow(non_camel_case_types)] - struct AmountSvc(pub Arc); + struct InsertPlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for AmountSvc { - type Response = super::AmountResponse; + > tonic::server::UnaryService + for InsertPlaylistSvc { + type Response = super::InsertPlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::amount(&inner, request).await + ::insert_playlist(&inner, request) + .await }; Box::pin(fut) } @@ -5501,7 +6493,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = AmountSvc(inner); + let method = InsertPlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5517,26 +6509,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/PlaylistResume" => { + "/rockbox.v1alpha1.PlaylistService/InsertAlbum" => { #[allow(non_camel_case_types)] - struct PlaylistResumeSvc(pub Arc); + struct InsertAlbumSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for PlaylistResumeSvc { - type Response = super::PlaylistResumeResponse; + > tonic::server::UnaryService + for InsertAlbumSvc { + type Response = super::InsertAlbumResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::playlist_resume(&inner, request) - .await + ::insert_album(&inner, request).await }; Box::pin(fut) } @@ -5547,7 +6538,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = PlaylistResumeSvc(inner); + let method = InsertAlbumSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5563,25 +6554,29 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/ResumeTrack" => { + "/rockbox.v1alpha1.PlaylistService/InsertArtistTracks" => { #[allow(non_camel_case_types)] - struct ResumeTrackSvc(pub Arc); + struct InsertArtistTracksSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for ResumeTrackSvc { - type Response = super::ResumeTrackResponse; + > tonic::server::UnaryService + for InsertArtistTracksSvc { + type Response = super::InsertArtistTracksResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::resume_track(&inner, request).await + ::insert_artist_tracks( + &inner, + request, + ) + .await }; Box::pin(fut) } @@ -5592,7 +6587,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = ResumeTrackSvc(inner); + let method = InsertArtistTracksSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5608,25 +6603,26 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/SetModified" => { + "/rockbox.v1alpha1.PlaylistService/ShufflePlaylist" => { #[allow(non_camel_case_types)] - struct SetModifiedSvc(pub Arc); + struct ShufflePlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for SetModifiedSvc { - type Response = super::SetModifiedResponse; + > tonic::server::UnaryService + for ShufflePlaylistSvc { + type Response = super::ShufflePlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::set_modified(&inner, request).await + ::shuffle_playlist(&inner, request) + .await }; Box::pin(fut) } @@ -5637,7 +6633,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = SetModifiedSvc(inner); + let method = ShufflePlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5653,24 +6649,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/Start" => { + "/rockbox.v1alpha1.PlaylistService/GetPlaylist" => { #[allow(non_camel_case_types)] - struct StartSvc(pub Arc); + struct GetPlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService for StartSvc { - type Response = super::StartResponse; + > tonic::server::UnaryService + for GetPlaylistSvc { + type Response = super::GetPlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::start(&inner, request).await + ::get_playlist(&inner, request).await }; Box::pin(fut) } @@ -5681,7 +6678,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = StartSvc(inner); + let method = GetPlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5697,24 +6694,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/Sync" => { + "/rockbox.v1alpha1.PlaylistService/GetPlaylists" => { #[allow(non_camel_case_types)] - struct SyncSvc(pub Arc); + struct GetPlaylistsSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService for SyncSvc { - type Response = super::SyncResponse; + > tonic::server::UnaryService + for GetPlaylistsSvc { + type Response = super::GetPlaylistsResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::sync(&inner, request).await + ::get_playlists(&inner, request).await }; Box::pin(fut) } @@ -5725,7 +6723,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = SyncSvc(inner); + let method = GetPlaylistsSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5741,26 +6739,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/RemoveAllTracks" => { + "/rockbox.v1alpha1.PlaylistService/CreateFolder" => { #[allow(non_camel_case_types)] - struct RemoveAllTracksSvc(pub Arc); + struct CreateFolderSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for RemoveAllTracksSvc { - type Response = super::RemoveAllTracksResponse; + > tonic::server::UnaryService + for CreateFolderSvc { + type Response = super::CreateFolderResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::remove_all_tracks(&inner, request) - .await + ::create_folder(&inner, request).await }; Box::pin(fut) } @@ -5771,7 +6768,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = RemoveAllTracksSvc(inner); + let method = CreateFolderSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5787,25 +6784,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/RemoveTracks" => { + "/rockbox.v1alpha1.PlaylistService/GetFolder" => { #[allow(non_camel_case_types)] - struct RemoveTracksSvc(pub Arc); + struct GetFolderSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for RemoveTracksSvc { - type Response = super::RemoveTracksResponse; + > tonic::server::UnaryService + for GetFolderSvc { + type Response = super::GetFolderResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::remove_tracks(&inner, request).await + ::get_folder(&inner, request).await }; Box::pin(fut) } @@ -5816,7 +6813,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = RemoveTracksSvc(inner); + let method = GetFolderSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5832,26 +6829,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/CreatePlaylist" => { + "/rockbox.v1alpha1.PlaylistService/GetFolders" => { #[allow(non_camel_case_types)] - struct CreatePlaylistSvc(pub Arc); + struct GetFoldersSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for CreatePlaylistSvc { - type Response = super::CreatePlaylistResponse; + > tonic::server::UnaryService + for GetFoldersSvc { + type Response = super::GetFoldersResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::create_playlist(&inner, request) - .await + ::get_folders(&inner, request).await }; Box::pin(fut) } @@ -5862,7 +6858,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = CreatePlaylistSvc(inner); + let method = GetFoldersSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5878,25 +6874,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/InsertTracks" => { + "/rockbox.v1alpha1.PlaylistService/RemoveFolder" => { #[allow(non_camel_case_types)] - struct InsertTracksSvc(pub Arc); + struct RemoveFolderSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for InsertTracksSvc { - type Response = super::InsertTracksResponse; + > tonic::server::UnaryService + for RemoveFolderSvc { + type Response = super::RemoveFolderResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::insert_tracks(&inner, request).await + ::remove_folder(&inner, request).await }; Box::pin(fut) } @@ -5907,7 +6903,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = InsertTracksSvc(inner); + let method = RemoveFolderSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5923,25 +6919,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/InsertDirectory" => { + "/rockbox.v1alpha1.PlaylistService/RemovePlaylist" => { #[allow(non_camel_case_types)] - struct InsertDirectorySvc(pub Arc); + struct RemovePlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for InsertDirectorySvc { - type Response = super::InsertDirectoryResponse; + > tonic::server::UnaryService + for RemovePlaylistSvc { + type Response = super::RemovePlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::insert_directory(&inner, request) + ::remove_playlist(&inner, request) .await }; Box::pin(fut) @@ -5953,7 +6949,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = InsertDirectorySvc(inner); + let method = RemovePlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5969,25 +6965,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/InsertPlaylist" => { + "/rockbox.v1alpha1.PlaylistService/RenamePlaylist" => { #[allow(non_camel_case_types)] - struct InsertPlaylistSvc(pub Arc); + struct RenamePlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for InsertPlaylistSvc { - type Response = super::InsertPlaylistResponse; + > tonic::server::UnaryService + for RenamePlaylistSvc { + type Response = super::RenamePlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::insert_playlist(&inner, request) + ::rename_playlist(&inner, request) .await }; Box::pin(fut) @@ -5999,7 +6995,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = InsertPlaylistSvc(inner); + let method = RenamePlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6015,25 +7011,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/InsertAlbum" => { + "/rockbox.v1alpha1.PlaylistService/RenameFolder" => { #[allow(non_camel_case_types)] - struct InsertAlbumSvc(pub Arc); + struct RenameFolderSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for InsertAlbumSvc { - type Response = super::InsertAlbumResponse; + > tonic::server::UnaryService + for RenameFolderSvc { + type Response = super::RenameFolderResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::insert_album(&inner, request).await + ::rename_folder(&inner, request).await }; Box::pin(fut) } @@ -6044,7 +7040,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = InsertAlbumSvc(inner); + let method = RenameFolderSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6060,29 +7056,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/InsertArtistTracks" => { + "/rockbox.v1alpha1.PlaylistService/MovePlaylist" => { #[allow(non_camel_case_types)] - struct InsertArtistTracksSvc(pub Arc); + struct MovePlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for InsertArtistTracksSvc { - type Response = super::InsertArtistTracksResponse; + > tonic::server::UnaryService + for MovePlaylistSvc { + type Response = super::MovePlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::insert_artist_tracks( - &inner, - request, - ) - .await + ::move_playlist(&inner, request).await }; Box::pin(fut) } @@ -6093,7 +7085,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = InsertArtistTracksSvc(inner); + let method = MovePlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6109,26 +7101,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/ShufflePlaylist" => { + "/rockbox.v1alpha1.PlaylistService/MoveFolder" => { #[allow(non_camel_case_types)] - struct ShufflePlaylistSvc(pub Arc); + struct MoveFolderSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for ShufflePlaylistSvc { - type Response = super::ShufflePlaylistResponse; + > tonic::server::UnaryService + for MoveFolderSvc { + type Response = super::MoveFolderResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::shuffle_playlist(&inner, request) - .await + ::move_folder(&inner, request).await }; Box::pin(fut) } @@ -6139,7 +7130,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = ShufflePlaylistSvc(inner); + let method = MoveFolderSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( diff --git a/cli/src/api/rockbox_descriptor.bin b/cli/src/api/rockbox_descriptor.bin index f9e87edaf4110ca4a535f248a856b8f376c490d4..a09a379c13217e5c0372821db31500d972b44da7 100644 GIT binary patch delta 8804 zcmb`MdyrMtmB!EB_w?!8r<+IbeqFkoru*^`P~@$EkVLFFk{B@U2$Mi;8o4~1huuxe zhLV#i^7!m5P~4MQ2jNOiHKXOcX?XqReldz4tk{ zwesKm1>afgTi@DiueHyRLd(nRu?L_u9-4p>FBtj zZ|6Y&HwHEj4fkzcUmO>=^_I5n_igQI{|_>qaXaBUD$~|pRa=}No4+XyS6-bx zt5Ez89XA24aAo%iRQA?1S1!*tc6G;f8+Ht=FAcIGg`6u<-acBkzOpkvVfo~^etl`^ zn!(LGhd1xoUZ_c&bZ_-Ts$g21uYb5uTY0Xw zt1~Y#dh2%WTrbZr9yXteqv50j3U!rZ^X4sB+7QQmX<|$Ban!eYTmME|->PhiUx}M8 zNupnxtfHdUbe37u&i=vDc4@ML_G_|_?2bwF)TKB#Zmy2uYh*gAYm>B3Z(5mRF&;}@ zt!i)S+FhlgVKX|`C{`YbFxm50{0p5xbL6Yupd#mRA#9X0Dv`F32Gl8)apB+fF3-nqSUS-yFCF=3?7s~HO=6|tnLvPxufs%BL=p5yEmkRnr^p!lr?qgQd}K3SIvF4-Eofw zgKOJrt;xibq@j%CW_rm493xRSs{MDF1f) z^;ZQ?oTZt?IkF8e{!^=_rFtroGLM)GRcej1X{hv+#!t#%l@iOS?)s$ABOXxbN!1Uk zxKu6cWUAI&4Jq7&%$l*jaQd@xt*HruJN41oo6gph<5-8SCcG^8f{Nof7q%*syDZ-o z*T-Slssoc-ri*byTq7V96nj(ys&DiN+A>}{&NBz{0N)!I@3HD!UdNdzFCtMg4B5pQ*CTe9R%6J8x$ zW8-z=b+y~9PKnp&>I`7XeJ)uL$@aNqLD2eKnLz~aqs(RLvrgHqwYnt{2EbeEk^+e> zZ?_x-Z*5a^QmIa@O|IWn3V?WjDy|9ApNfk>zpE6U1nH+zXqOQOt<#-OJV%suX_OpM z*42;kHlnN>+vbt*+Iid1&Erk3UO;R@5e-NUZ zoG1v8vxp7S2mE?T-iX-HoLNQN!hk&yNogj-WHut zRt18$rOtQ+Z%a$7lLKsZh3e8$sI6(vQmC!2P}m5v)fEaPJPKuVhBlA}q5cBxnbM_0 zq70-_LZS?$Q9_~&xN=W0xgG9InSj#{ccyfk@Y>+(w%px3zt#{{5QFgh~fQ08t(_?bi1wF}`)q~S@betTwMH5~h zlx=B>Jik6~Pn&X4YO~wb27t_NR~rzXyIpBO$n18dDatx-(41g2FaX*OZjB(Z)!A1A z2-*$JEy)s#Qkp$(iGYyvXOCMWkSKfH8bL(asf!Z|CE4k#+;AdwCzN@pX1ZdKII8p{+UXE&1tbAMW%R(dfMA^ORJ?+m z8NEA|dk39k!fz?2Ui8kv?^}wo7rm(_`i=^|>-45#`i`Q#MQ^I;RTQ%*0YS(CZOwtI zESPb0X7nnGag?yrO!Pe!Jm|tsBkcEVhlJrY3452)cB4Ur1=_GceD6|q^+{A9QSVZt z4Mlhpxrwlk?!_;2PD$n zil0NynMijljwl-mbPo+xc2;Qvun#3|a8DLW+Tb2#Y)4I#F#@`dnkHF%-**(qLLZ4E z9jj|7tVH_0Zzv$=ADE7^S>b%I(sui&=^6`da{%GqtMa2=$~92$RgLnhlF~#byw5il z2rAH5HG+Dds`G&(sP{=<@%|NVtqJeXxV3PBo?8p|{)}4-_x^;NQ1d2yKH$?h%Ug-`fSP@wheRqrpcY-k3UoN#L_bi$4_&)W$Mpxk-KI;sJ?wi1M1nw@ zAQ0b&eaip|`>=1B>Cy#{_?7{YAkZcVl=*waZx1-}c0B_m)FZZMba<|beyoCja0#A^ z=Z_Wl9I5`flHjBMYy%M$XcGkD`>1k98<41v+M`XE!}Cn^6BYc_g*^|~pQyY{U>Ke! zVIT8j1|lrbh6UpLm>)ABVIQ+&ro$N~`k4xjx~Mbo{F%zj8#xSTNYukFYFQv*!8R-q z=fgfMkg$jS^v;lSKJIq{1QqD1QohIiPGE)lxZjBxGQ3CpPJq~nBb@(sE5L+0;&%c_ zs3U%QfrL8Zcj9~#J)wesa*I13&nNui&X>hK=~Y0e0IdiRkte+fP|m+6y$TqWC%wu{ z6a8ET|Ljy|qVjWptj-jbr<7ilbTSAPpj83V_D`w$8Qu!@DRusQ4-t7vEm)XzeR-CN zexZV2I+a^?>L->-FZE@YgDkYk4l5i{G#9 z3r~mhO!S-z{?+Nt!}Oe&n;p15LBR}^8QQA?uCaL?(clA7n<<*ej6{u@ArNi7ntY|D)@Jo>Hpv#i$OZJr?h6^Oum;E^gf(!IqN%duaj$wuRvYca5 z)`cegqfd1qet-0-E;7+8D)>*A>LN_9_+eed{l|pIydDrepw$E7e9Y?s(L3g^go`BA z;~7;_1$wHadOV{_s>gk*7n$%+Dv)m$xv+c@j(@Uqt;5A8dQ}Dg?Q&g==~Z9W#ZuPS z{J{cZsCCp@*ovt`;wmgCz<~^cTffuH+IQNj`s3dHKy7MuCXDq4Xv2 z$~6M9zM-PzHYbpS`VG~XT#*G5_6;@TvyO}Jn@V3Uni!?dZ>lJ{SO|prrfQz*tx(@o zb1!pLj3<;{=8Up|C(0^HZh~;-{cu7xP4Q;9C)DiEJ1*#CCMy@RlbLJ|>d8!2?q?@6 zS!(!}(!DOO+`!&aQSu8W3d%Z!`<7}w&zs@Cr7m3VWZBkJN+&lKQj{CmDHSz1-x{c= z)Tnk3p`KEc=Q=8T^|sP0oKbFIZ>uP|X%i`e`nGDBp4>kL!+l%L|Dxk^Av>+~rH(5% zu+u6^ew5%_3-`3*4|sM9=UJd??ehI%HG9S!wNCOaDHnM`(!2|vmf zTOI@VqinTf;C_^?b`0E)vek|?;m27^jfMJgmho7qA7>elh5B)paia;(W^K_3^{li- z+4fK)+_PCH93)Fr5 zKyoRzK;5V9K~tvvTHx-}=}E(11NLWJ{vH5Kxvg;bJ1*2#sQWW&8{aIn{+!d{b3ZUj zK1<-+2K5#_Hu>=?5b7mS?we+vQ!O8@`> delta 3312 zcmYL~+iz4=6vofmXZQ5XncikkJDpCa)9KI_V*OTEDgS`u1hs?8xQ6?O)$s z691k$_~+7`q;zRwAYJ->AWL1PKL@%pg_Kv{UA#4Mx7a)V&DC#bx{EWD6SrrIg_EVB z!E`BkwZ61C*m&^E;2(nSmhO$*C|ww-PB(bTGf0~L?$euB?%XOfe(A*J8J$pidwIq_ z_PX|C4A=E2cJYO$1BM6J_<;6mwN^d;D9O+b*jufi&HiwI9RvC8xi?jiDHmmCmibB9ZV6lU| zSSVB<(Q1&pa(oSWC zK=a{pbAc+u<>tD>Fgt}z6d8t7+L5dlBO=R1Y!n#@ieUc{LzR(uZ4^Y6k-El6X)x0q z9LN@BU*WUSf}|^aHgZZ{vu=d8ouCs3t;I8v#Lg^UW1_kUo+m;isZB&F~KmZ%%g9!y}G^P(N=7$6~+K>vI%4spi zPC;PNW93C_qsG`M#8737je^n~jM8@J^e&B;i^xEQR}mo;8IOwiLZZrexr#)Uakjfv z**E$Aw<75#-~YUlx2>7b?mWKV=Bt?3c2BTT5NI>OMnNHQf{lVgmx;hAU&_38V^ZXU z4Tk_X$xcD(SgbjUft$>=1~cZh!Be7%L)ze}GNwyT#ptv7qEV>waiW0pIVrnV@MwTQkenKwz!2 zp*6mQMCL4e1BEuTe25BqjyaJE=70b<$1_6dSS);{pn%QQH*h;xGtV;?f-5`EBSN9b zJdaoqzV0y3Ga`s8^E~4rWk0a=T(&%fqzA!cBxJj)@U0&x9I_n&-)+PCq-@8K@_WLR z)p#kODgs#FYhxETRty*CmW%QZ3y`22orXj)HwixG*6qlw2T88wPRo zwe%v1N(+Q}If_aPgn3!|D78SCSZ`m4l8?yhfQPp1K;k2E^_weXr*a;X^&^JXp-zMz z6SiEp@6=O2Aw2fFA{6>ThEqc#_X**-=P24eA%5-;EBVwX+%R4AFcO~X?t$I|^4Nu1ObwL)-_oWNEsVa6gQ3Q-jO7U{?*j3Rf5#5oS)07-v| zoM3Ta3G5QpzY~SQE>YKMW)XZ&;tU7%emy5A*b$((i;&6AC<^pB9sQh9s28R!ZWSbV z^(|q8ePP<-nn9M^VmDus=;p$BtRS7>h@q_n`jS%bMNyzH>G%b1i=8NuIL^Tepe1su zA_=ra)qW<@U`y1|#jK;`GKnua=zv`&r#_Nkm#N|1NCI7^kG^2EQppt(r#M&%bcLKm zB!RAwYLBEoe=GF*NGC2+1DUb&98=DA;vsJHjiDE4g9zCk}MO>`xr% zhS{Gu&<(RcRZ4F9=15h6-84t43hbsiQdM9#&5^2Ba?9*bHP9`yKh;3D%>GmZ-7@=A zqvUqEt1oK6Zkx6>V7E=%8nD}@ZLN|!X4+byJ7(HipgU&TTA({-+Bzk7&5G-Q?qbD0 zyIKc!*DSdX?5rcHv~H`6B3cHc~!1iFuD50a&y@Ba@&Su8^U diff --git a/crates/graphql/src/schema/objects/folder.rs b/crates/graphql/src/schema/objects/folder.rs new file mode 100644 index 00000000000..b9813a2d3db --- /dev/null +++ b/crates/graphql/src/schema/objects/folder.rs @@ -0,0 +1,34 @@ +use async_graphql::*; +use serde::{Deserialize, Serialize}; + +#[derive(Default, Clone, Serialize, Deserialize)] +pub struct Folder { + pub id: String, + pub name: String, + pub parent_id: Option, + pub created_at: u64, + pub updated_at: u64, +} + +#[Object] +impl Folder { + async fn id(&self) -> &str { + &self.id + } + + async fn name(&self) -> &str { + &self.name + } + + async fn parent_id(&self) -> Option { + self.parent_id.clone() + } + + async fn created_at(&self) -> u64 { + self.created_at + } + + async fn updated_at(&self) -> u64 { + self.updated_at + } +} diff --git a/crates/graphql/src/schema/objects/mod.rs b/crates/graphql/src/schema/objects/mod.rs index dbf17f2efcc..7b6a1d6d261 100644 --- a/crates/graphql/src/schema/objects/mod.rs +++ b/crates/graphql/src/schema/objects/mod.rs @@ -5,6 +5,7 @@ pub mod compressor_settings; pub mod device; pub mod entry; pub mod eq_band_setting; +pub mod folder; pub mod new_global_settings; pub mod playlist; pub mod replaygain_settings; diff --git a/crates/graphql/src/schema/objects/playlist.rs b/crates/graphql/src/schema/objects/playlist.rs index efc7d1b8d90..6e7ff4272aa 100644 --- a/crates/graphql/src/schema/objects/playlist.rs +++ b/crates/graphql/src/schema/objects/playlist.rs @@ -12,6 +12,13 @@ pub struct Playlist { pub seed: i32, pub last_shuffled_start: i32, pub tracks: Vec, + pub folder_id: Option, + pub name: Option, + pub created_at: Option, + pub updated_at: Option, + pub description: Option, + pub image: Option, + pub id: Option, } #[Object] @@ -47,4 +54,32 @@ impl Playlist { async fn tracks(&self) -> &Vec { &self.tracks } + + async fn folder_id(&self) -> Option { + self.folder_id.clone() + } + + async fn name(&self) -> Option { + self.name.clone() + } + + async fn created_at(&self) -> Option { + self.created_at.clone() + } + + async fn updated_at(&self) -> Option { + self.updated_at.clone() + } + + async fn description(&self) -> Option { + self.description.clone() + } + + async fn image(&self) -> Option { + self.image.clone() + } + + async fn id(&self) -> Option { + self.id.clone() + } } diff --git a/crates/graphql/src/schema/objects/track.rs b/crates/graphql/src/schema/objects/track.rs index 65aae9d810d..1afc774a6d3 100644 --- a/crates/graphql/src/schema/objects/track.rs +++ b/crates/graphql/src/schema/objects/track.rs @@ -39,8 +39,8 @@ pub struct Track { #[Object] impl Track { - async fn id(&self) -> Option<&str> { - self.id.as_deref() + async fn id(&self) -> Option { + self.id.clone() } async fn title(&self) -> &str { @@ -146,6 +146,7 @@ impl Track { impl From for Track { fn from(mp3entry: Mp3Entry) -> Self { + let id = mp3entry.id; let title = mp3entry.title; let artist = mp3entry.artist; let album = mp3entry.album; @@ -173,6 +174,7 @@ impl From for Track { let album_art = mp3entry.album_art; Track { + id, title, artist, album, diff --git a/crates/graphql/src/schema/playlist.rs b/crates/graphql/src/schema/playlist.rs index 73dc7b92e92..1c61f56df19 100644 --- a/crates/graphql/src/schema/playlist.rs +++ b/crates/graphql/src/schema/playlist.rs @@ -9,7 +9,8 @@ use rockbox_sys::{ }; use crate::{ - rockbox_url, schema::objects::playlist::Playlist, simplebroker::SimpleBroker, types::StatusCode, + rockbox_url, schema::objects::folder::Folder, schema::objects::playlist::Playlist, + simplebroker::SimpleBroker, types::StatusCode, }; #[derive(Default)] @@ -31,6 +32,7 @@ impl PlaylistQuery { seed: response.seed, last_shuffled_start: response.last_shuffled_start, tracks: response.entries.into_iter().map(|t| t.into()).collect(), + ..Default::default() }) } @@ -57,6 +59,88 @@ impl PlaylistQuery { let response = response.json::().await?; Ok(response.amount) } + + async fn playlist(&self, _ctx: &Context<'_>, id: String) -> Result { + let url = format!("{}/playlists/{}", rockbox_url(), id); + let client = reqwest::Client::new(); + let response = client.get(url).send().await?; + let response = response.json::().await?; + Ok(Playlist { + amount: response.amount, + index: response.index, + max_playlist_size: response.max_playlist_size, + first_index: response.first_index, + last_insert_pos: response.last_insert_pos, + seed: response.seed, + last_shuffled_start: response.last_shuffled_start, + tracks: response.entries.into_iter().map(|t| t.into()).collect(), + name: response.name, + description: response.description, + image: response.image, + created_at: response.created_at, + updated_at: response.updated_at, + id: response.id, + ..Default::default() + }) + } + + async fn playlists( + &self, + _ctx: &Context<'_>, + folder_id: Option, + ) -> Result, Error> { + let url = match folder_id { + Some(folder_id) => format!("{}/playlists?folder_id={}", rockbox_url(), folder_id), + None => format!("{}/playlists", rockbox_url()), + }; + let client = reqwest::Client::new(); + let response = client.get(url).send().await?; + let response = response.json::>().await?; + Ok(response + .into_iter() + .map(|p| Playlist { + id: Some(p.id), + name: Some(p.name), + folder_id: p.folder_id, + description: p.description, + image: p.image, + created_at: Some( + chrono::DateTime::from_timestamp(p.created_at as i64, 0) + .unwrap() + .to_rfc3339(), + ), + updated_at: Some( + chrono::DateTime::from_timestamp(p.updated_at as i64, 0) + .unwrap() + .to_rfc3339(), + ), + ..Default::default() + }) + .collect()) + } + + async fn folder(&self, _ctx: &Context<'_>, id: String) -> Result { + let url = format!("{}/folders/{}", rockbox_url(), id); + let client = reqwest::Client::new(); + let response = client.get(url).send().await?; + let response = response.json::().await?; + Ok(response) + } + + async fn folders( + &self, + _ctx: &Context<'_>, + parent_id: Option, + ) -> Result, Error> { + let url = match parent_id { + Some(parent_id) => format!("{}/folders?parent_id={}", rockbox_url(), parent_id), + None => format!("{}/folders", rockbox_url()), + }; + let client = reqwest::Client::new(); + let response = client.get(url).send().await?; + let response = response.json::>().await?; + Ok(response) + } } #[derive(Default)] @@ -117,9 +201,15 @@ impl PlaylistMutation { Ok(0) } - async fn playlist_remove_track(&self, ctx: &Context<'_>, index: i32) -> Result { + async fn playlist_remove_track( + &self, + ctx: &Context<'_>, + index: i32, + playlist_id: Option, + ) -> Result { let client = ctx.data::().unwrap(); - let url = format!("{}/playlists/current/tracks", rockbox_url()); + let playlist_id = playlist_id.unwrap_or("current".to_string()); + let url = format!("{}/playlists/{}/tracks", rockbox_url(), playlist_id); let body = serde_json::json!({ "positions": vec![index], }); @@ -131,12 +221,17 @@ impl PlaylistMutation { "playlist sync".to_string() } - async fn playlist_remove_all_tracks(&self, ctx: &Context<'_>) -> Result { + async fn playlist_remove_all_tracks( + &self, + ctx: &Context<'_>, + playlist_id: Option, + ) -> Result { let client = ctx.data::().unwrap(); let body = serde_json::json!({ "positions": [], }); - let url = format!("{}/playlists/current/tracks", rockbox_url()); + let playlist_id = playlist_id.unwrap_or("current".to_string()); + let url = format!("{}/playlists/{}/tracks", rockbox_url(), playlist_id); let response = client.delete(&url).json(&body).send().await?; let start_index = response.text().await?.parse()?; Ok(start_index) @@ -163,7 +258,7 @@ impl PlaylistMutation { async fn insert_tracks( &self, ctx: &Context<'_>, - _playlist_id: Option, + playlist_id: Option, position: i32, tracks: Vec, ) -> Result { @@ -172,7 +267,8 @@ impl PlaylistMutation { "position": position, "tracks": tracks, }); - let url = format!("{}/playlists/current/tracks", rockbox_url()); + let playlist_id = playlist_id.unwrap_or("current".to_string()); + let url = format!("{}/playlists/{}/tracks", rockbox_url(), playlist_id); let response = client.post(&url).json(&body).send().await?; let start_index = response.text().await?.parse()?; Ok(start_index) @@ -181,7 +277,7 @@ impl PlaylistMutation { async fn insert_directory( &self, ctx: &Context<'_>, - _playlist_id: Option, + playlist_id: Option, position: i32, directory: String, ) -> Result { @@ -191,7 +287,8 @@ impl PlaylistMutation { "tracks": [], "directory": directory, }); - let url = format!("{}/playlists/current/tracks", rockbox_url()); + let playlist_id = playlist_id.unwrap_or("current".to_string()); + let url = format!("{}/playlists/{}/tracks", rockbox_url(), playlist_id); let response = client.post(&url).json(&body).send().await?; let start_index = response.text().await?.parse()?; Ok(start_index) @@ -213,6 +310,7 @@ impl PlaylistMutation { ctx: &Context<'_>, album_id: String, position: i32, + playlist_id: Option, ) -> Result { let client = ctx.data::().unwrap(); let pool = ctx.data::>()?; @@ -222,7 +320,8 @@ impl PlaylistMutation { "position": position, "tracks": tracks, }); - let url = format!("{}/playlists/current/tracks", rockbox_url()); + let playlist_id = playlist_id.unwrap_or("current".to_string()); + let url = format!("{}/playlists/{}/tracks", rockbox_url(), playlist_id); let response = client.post(&url).json(&body).send().await?; let start_index = response.text().await?.parse()?; Ok(start_index) @@ -235,6 +334,106 @@ impl PlaylistMutation { let ret = response.text().await?.parse()?; Ok(ret) } + + async fn create_folder( + &self, + _ctx: &Context<'_>, + name: String, + parent_id: Option, + ) -> Result { + let url = format!("{}/folders", rockbox_url()); + let body = match parent_id { + Some(parent_id) => serde_json::json!({ + "name": name, + "parent_id": parent_id, + }), + None => serde_json::json!({ + "name": name, + }), + }; + let client = reqwest::Client::new(); + let response = client.post(&url).json(&body).send().await?; + let response = response.json::().await?; + Ok(response) + } + + async fn remove_folder(&self, _ctx: &Context<'_>, id: String) -> Result { + let client = reqwest::Client::new(); + let url = format!("{}/folders/{}", rockbox_url(), id); + client.delete(&url).send().await?; + Ok(id) + } + + async fn remove_playlist(&self, _ctx: &Context<'_>, id: String) -> Result { + let client = reqwest::Client::new(); + let url = format!("{}/playlists/{}", rockbox_url(), id); + client.delete(&url).send().await?; + Ok(id) + } + + async fn rename_folder( + &self, + _ctx: &Context<'_>, + id: String, + name: String, + ) -> Result { + let client = reqwest::Client::new(); + let url = format!("{}/folders/{}", rockbox_url(), id); + client + .put(&url) + .json(&serde_json::json!({"name": name})) + .send() + .await?; + Ok(id) + } + + async fn rename_playlist( + &self, + _ctx: &Context<'_>, + id: String, + name: String, + ) -> Result { + let client = reqwest::Client::new(); + let url = format!("{}/playlists/{}", rockbox_url(), id); + client + .put(&url) + .json(&serde_json::json!({"name": name})) + .send() + .await?; + Ok(id) + } + + async fn move_folder( + &self, + _ctx: &Context<'_>, + folder_id: String, + destination: String, + ) -> Result { + let client = reqwest::Client::new(); + let url = format!("{}/folders/{}", rockbox_url(), folder_id); + client + .put(&url) + .json(&serde_json::json!({"parent_id": destination})) + .send() + .await?; + Ok(folder_id) + } + + async fn move_playlist( + &self, + _ctx: &Context<'_>, + playlist_id: String, + destination: String, + ) -> Result { + let client = reqwest::Client::new(); + let url = format!("{}/playlists/{}", rockbox_url(), playlist_id); + client + .put(&url) + .json(&serde_json::json!({"folder_id": destination})) + .send() + .await?; + Ok(playlist_id) + } } #[derive(Default)] diff --git a/crates/library/src/repo/folder.rs b/crates/library/src/repo/folder.rs index e31f5968941..b603e65c97f 100644 --- a/crates/library/src/repo/folder.rs +++ b/crates/library/src/repo/folder.rs @@ -1,7 +1,7 @@ use crate::entity::folder::Folder; use sqlx::{types::chrono, Pool, Sqlite}; -pub async fn save(pool: Pool, folder: Folder) -> Result<(), sqlx::Error> { +pub async fn save(pool: Pool, folder: Folder) -> Result { sqlx::query( r#" INSERT INTO folder ( @@ -13,13 +13,13 @@ pub async fn save(pool: Pool, folder: Folder) -> Result<(), sqlx::Error> VALUES ($1, $2, $3, $4) "#, ) - .bind(folder.id) + .bind(&folder.id) .bind(&folder.name) .bind(folder.created_at) .bind(folder.updated_at) .execute(&pool) .await?; - Ok(()) + Ok(folder.id) } pub async fn find(pool: Pool, id: &str) -> Result, sqlx::Error> { @@ -31,9 +31,9 @@ pub async fn find(pool: Pool, id: &str) -> Result, sqlx:: pub async fn find_by_parent( pool: Pool, - parent_id: &str, + parent_id: Option<&str>, ) -> Result, sqlx::Error> { - sqlx::query_as::<_, Folder>(r#"SELECT * FROM folder WHERE parent_id = $1"#) + sqlx::query_as::<_, Folder>(r#"SELECT * FROM folder WHERE parent_id IS $1 ORDER BY name ASC"#) .bind(parent_id) .fetch_all(&pool) .await @@ -54,6 +54,10 @@ pub async fn delete(pool: Pool, id: &str) -> Result<(), sqlx::Error> { } pub async fn update(pool: Pool, folder: Folder) -> Result<(), sqlx::Error> { + let name = match folder.name.is_empty() { + true => None, + false => Some(&folder.name), + }; sqlx::query( r#" UPDATE folder SET @@ -64,7 +68,7 @@ pub async fn update(pool: Pool, folder: Folder) -> Result<(), sqlx::Erro "#, ) .bind(&folder.id) - .bind(&folder.name) + .bind(name) .bind(chrono::Utc::now()) .bind(&folder.parent_id) .execute(&pool) diff --git a/crates/library/src/repo/playlist.rs b/crates/library/src/repo/playlist.rs index b6c5a0c8d4c..5e7dcadb225 100644 --- a/crates/library/src/repo/playlist.rs +++ b/crates/library/src/repo/playlist.rs @@ -1,7 +1,7 @@ use crate::entity::playlist::Playlist; use sqlx::{Pool, Sqlite}; -pub async fn save(pool: Pool, playlist: Playlist) -> Result<(), sqlx::Error> { +pub async fn save(pool: Pool, playlist: Playlist) -> Result { sqlx::query( r#" INSERT INTO playlist ( @@ -25,7 +25,7 @@ pub async fn save(pool: Pool, playlist: Playlist) -> Result<(), sqlx::Er .bind(playlist.updated_at) .execute(&pool) .await?; - Ok(()) + Ok(playlist.id) } pub async fn find(pool: Pool, id: &str) -> Result, sqlx::Error> { @@ -37,11 +37,11 @@ pub async fn find(pool: Pool, id: &str) -> Result, sqlx pub async fn find_by_folder( pool: Pool, - folder_id: &str, + folder_id: Option<&str>, ) -> Result, sqlx::Error> { sqlx::query_as::<_, Playlist>( r#" - SELECT * FROM playlist WHERE folder_id = $1 ORDER BY name ASC + SELECT * FROM playlist WHERE folder_id IS $1 ORDER BY name ASC "#, ) .bind(folder_id) @@ -64,17 +64,25 @@ pub async fn delete(pool: Pool, id: &str) -> Result<(), sqlx::Error> { } pub async fn update(pool: Pool, playlist: Playlist) -> Result<(), sqlx::Error> { + let name = match playlist.name.is_empty() { + true => None, + false => Some(&playlist.name), + }; sqlx::query( r#" UPDATE playlist SET name = $2, - updated_at = $3, - folder_id = $4 + description = $3, + image = $4, + updated_at = $5, + folder_id = $6 WHERE id = $1 "#, ) .bind(&playlist.id) - .bind(&playlist.name) + .bind(name) + .bind(playlist.description) + .bind(playlist.image) .bind(chrono::Utc::now()) .bind(&playlist.folder_id) .execute(&pool) diff --git a/crates/library/src/repo/playlist_tracks.rs b/crates/library/src/repo/playlist_tracks.rs index 922e21c0a86..e12564c12a3 100644 --- a/crates/library/src/repo/playlist_tracks.rs +++ b/crates/library/src/repo/playlist_tracks.rs @@ -11,7 +11,7 @@ pub async fn save(pool: Pool, playlist_track: PlaylistTracks) -> Result< position, created_at ) - VALUES ($1, $2, $3, $4) + VALUES ($1, $2, $3, $4, $5) "#, ) .bind(&playlist_track.id) @@ -56,6 +56,14 @@ pub async fn delete(pool: Pool, id: &str) -> Result<(), sqlx::Error> { Ok(()) } +pub async fn delete_by_playlist(pool: Pool, playlist_id: &str) -> Result<(), sqlx::Error> { + sqlx::query(r#"DELETE FROM playlist_tracks WHERE playlist_id = $1"#) + .bind(playlist_id) + .execute(&pool) + .await?; + Ok(()) +} + pub async fn delete_track_at( pool: Pool, playlist_id: &str, @@ -66,5 +74,29 @@ pub async fn delete_track_at( .bind(position) .execute(&pool) .await?; + + let tracks = sqlx::query_as::<_, Track>( + r#" + SELECT * FROM playlist_tracks + LEFT JOIN track ON playlist_tracks.track_id = track.id + WHERE playlist_tracks.playlist_id = $1 + ORDER BY playlist_tracks.created_at ASC + "#, + ) + .bind(playlist_id) + .fetch_all(&pool) + .await?; + + for (i, track) in tracks.iter().enumerate() { + sqlx::query( + r#"UPDATE playlist_tracks SET position = $1 WHERE playlist_id = $2 AND track_id = $3"#, + ) + .bind(i as u32) + .bind(playlist_id) + .bind(&track.id) + .execute(&pool) + .await?; + } + Ok(()) } diff --git a/crates/mpd/src/handlers/queue.rs b/crates/mpd/src/handlers/queue.rs index b67908703ca..b685e0778ae 100644 --- a/crates/mpd/src/handlers/queue.rs +++ b/crates/mpd/src/handlers/queue.rs @@ -318,7 +318,10 @@ pub async fn handle_delete( let range: Vec = arg.split(':').map(|x| x.parse::().unwrap()).collect(); let positions: Vec = (range[0]..=range[1]).collect(); ctx.playlist - .remove_tracks(RemoveTracksRequest { positions }) + .remove_tracks(RemoveTracksRequest { + positions, + playlist_id: None, + }) .await?; if !ctx.batch { tx.send("OK\n".to_string()).await?; @@ -336,7 +339,10 @@ pub async fn handle_delete( } }; ctx.playlist - .remove_tracks(RemoveTracksRequest { positions }) + .remove_tracks(RemoveTracksRequest { + positions, + playlist_id: None, + }) .await?; if !ctx.batch { tx.send("OK\n".to_string()).await?; @@ -356,7 +362,7 @@ pub async fn handle_clear( tx: Sender, ) -> Result { ctx.playlist - .remove_all_tracks(RemoveAllTracksRequest {}) + .remove_all_tracks(RemoveAllTracksRequest { playlist_id: None }) .await?; if !ctx.batch { tx.send("OK\n".to_string()).await?; diff --git a/crates/rpc/proto/rockbox/v1alpha1/playlist.proto b/crates/rpc/proto/rockbox/v1alpha1/playlist.proto index 20e5674ea17..70394430b15 100644 --- a/crates/rpc/proto/rockbox/v1alpha1/playlist.proto +++ b/crates/rpc/proto/rockbox/v1alpha1/playlist.proto @@ -66,16 +66,19 @@ message SyncRequest {} message SyncResponse {} -message RemoveAllTracksRequest {} +message RemoveAllTracksRequest { optional string playlist_id = 1; } message RemoveAllTracksResponse {} -message RemoveTracksRequest { repeated int32 positions = 1; } +message RemoveTracksRequest { + repeated int32 positions = 1; + optional string playlist_id = 2; +} message RemoveTracksResponse {} message CreatePlaylistRequest { - string name = 1; + optional string name = 1; repeated string tracks = 2; optional string folder_id = 3; } @@ -114,6 +117,7 @@ message InsertAlbumRequest { int32 position = 1; string album_id = 2; optional bool shuffle = 3; + optional string playlist_id = 4; } message InsertAlbumResponse {} @@ -122,6 +126,7 @@ message InsertArtistTracksRequest { int32 position = 1; string artist_id = 2; optional bool shuffle = 3; + optional string playlist_id = 4; } message InsertArtistTracksResponse {} @@ -130,6 +135,83 @@ message ShufflePlaylistRequest { int32 start_index = 1; } message ShufflePlaylistResponse {} +message GetPlaylistRequest { string playlist_id = 1; } + +message GetPlaylistResponse { + string id = 1; + string name = 2; + optional string folder_id = 3; + optional string image = 4; + optional string description = 5; + int32 amount = 6; + string created_at = 7; + string updated_at = 8; + repeated rockbox.v1alpha1.CurrentTrackResponse tracks = 9; +} + +message CreateFolderRequest { + string name = 1; + optional string parent_id = 2; +} + +message CreateFolderResponse { string folder_id = 1; } + +message GetFolderRequest { string id = 1; } + +message GetFolderResponse { + string id = 1; + string name = 2; + optional string parent_id = 3; +} + +message GetFoldersRequest { optional string parent_id = 1; } + +message GetFoldersResponse { + repeated rockbox.v1alpha1.GetFolderResponse folders = 1; +} + +message RemoveFolderRequest { string id = 1; } + +message RemoveFolderResponse {} + +message RemovePlaylistRequest { string id = 1; } + +message RemovePlaylistResponse {} + +message RenamePlaylistRequest { + string id = 1; + string name = 2; +} + +message RenamePlaylistResponse {} + +message RenameFolderRequest { + string id = 1; + string name = 2; +} + +message RenameFolderResponse {} + +message MovePlaylistRequest { + string playlist_id = 1; + string folder_id = 2; +} + +message MovePlaylistResponse {} + +message MoveFolderRequest { + string folder_id = 1; + string parent_id = 2; +} + +message MoveFolderResponse {} + +message GetPlaylistsRequest { optional string folder_id = 1; } + +message GetPlaylistsResponse { + repeated rockbox.v1alpha1.GetPlaylistResponse playlists = 1; +} + service PlaylistService { rpc GetCurrent(GetCurrentRequest) returns (GetCurrentResponse) {} rpc GetResumeInfo(GetResumeInfoRequest) returns (GetResumeInfoResponse) {} @@ -156,4 +238,15 @@ service PlaylistService { returns (InsertArtistTracksResponse) {} rpc ShufflePlaylist(ShufflePlaylistRequest) returns (ShufflePlaylistResponse) {} + rpc GetPlaylist(GetPlaylistRequest) returns (GetPlaylistResponse) {} + rpc GetPlaylists(GetPlaylistsRequest) returns (GetPlaylistsResponse) {} + rpc CreateFolder(CreateFolderRequest) returns (CreateFolderResponse) {} + rpc GetFolder(GetFolderRequest) returns (GetFolderResponse) {} + rpc GetFolders(GetFoldersRequest) returns (GetFoldersResponse) {} + rpc RemoveFolder(RemoveFolderRequest) returns (RemoveFolderResponse) {} + rpc RemovePlaylist(RemovePlaylistRequest) returns (RemovePlaylistResponse) {} + rpc RenamePlaylist(RenamePlaylistRequest) returns (RenamePlaylistResponse) {} + rpc RenameFolder(RenameFolderRequest) returns (RenameFolderResponse) {} + rpc MovePlaylist(MovePlaylistRequest) returns (MovePlaylistResponse) {} + rpc MoveFolder(MoveFolderRequest) returns (MoveFolderResponse) {} } diff --git a/crates/rpc/src/api/rockbox.v1alpha1.rs b/crates/rpc/src/api/rockbox.v1alpha1.rs index b6a3b22ee13..6ee8d4399ff 100644 --- a/crates/rpc/src/api/rockbox.v1alpha1.rs +++ b/crates/rpc/src/api/rockbox.v1alpha1.rs @@ -4910,21 +4910,26 @@ pub struct StartResponse {} pub struct SyncRequest {} #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct SyncResponse {} -#[derive(Clone, Copy, PartialEq, ::prost::Message)] -pub struct RemoveAllTracksRequest {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemoveAllTracksRequest { + #[prost(string, optional, tag = "1")] + pub playlist_id: ::core::option::Option<::prost::alloc::string::String>, +} #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct RemoveAllTracksResponse {} #[derive(Clone, PartialEq, ::prost::Message)] pub struct RemoveTracksRequest { #[prost(int32, repeated, tag = "1")] pub positions: ::prost::alloc::vec::Vec, + #[prost(string, optional, tag = "2")] + pub playlist_id: ::core::option::Option<::prost::alloc::string::String>, } #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct RemoveTracksResponse {} #[derive(Clone, PartialEq, ::prost::Message)] pub struct CreatePlaylistRequest { - #[prost(string, tag = "1")] - pub name: ::prost::alloc::string::String, + #[prost(string, optional, tag = "1")] + pub name: ::core::option::Option<::prost::alloc::string::String>, #[prost(string, repeated, tag = "2")] pub tracks: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, #[prost(string, optional, tag = "3")] @@ -4984,6 +4989,8 @@ pub struct InsertAlbumRequest { pub album_id: ::prost::alloc::string::String, #[prost(bool, optional, tag = "3")] pub shuffle: ::core::option::Option, + #[prost(string, optional, tag = "4")] + pub playlist_id: ::core::option::Option<::prost::alloc::string::String>, } #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct InsertAlbumResponse {} @@ -4995,6 +5002,8 @@ pub struct InsertArtistTracksRequest { pub artist_id: ::prost::alloc::string::String, #[prost(bool, optional, tag = "3")] pub shuffle: ::core::option::Option, + #[prost(string, optional, tag = "4")] + pub playlist_id: ::core::option::Option<::prost::alloc::string::String>, } #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct InsertArtistTracksResponse {} @@ -5005,6 +5014,128 @@ pub struct ShufflePlaylistRequest { } #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct ShufflePlaylistResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPlaylistRequest { + #[prost(string, tag = "1")] + pub playlist_id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPlaylistResponse { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, + #[prost(string, optional, tag = "3")] + pub folder_id: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "4")] + pub image: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "5")] + pub description: ::core::option::Option<::prost::alloc::string::String>, + #[prost(int32, tag = "6")] + pub amount: i32, + #[prost(string, tag = "7")] + pub created_at: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub updated_at: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "9")] + pub tracks: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CreateFolderRequest { + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, + #[prost(string, optional, tag = "2")] + pub parent_id: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CreateFolderResponse { + #[prost(string, tag = "1")] + pub folder_id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetFolderRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetFolderResponse { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, + #[prost(string, optional, tag = "3")] + pub parent_id: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetFoldersRequest { + #[prost(string, optional, tag = "1")] + pub parent_id: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetFoldersResponse { + #[prost(message, repeated, tag = "1")] + pub folders: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemoveFolderRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct RemoveFolderResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemovePlaylistRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct RemovePlaylistResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RenamePlaylistRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct RenamePlaylistResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RenameFolderRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct RenameFolderResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MovePlaylistRequest { + #[prost(string, tag = "1")] + pub playlist_id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub folder_id: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MovePlaylistResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MoveFolderRequest { + #[prost(string, tag = "1")] + pub folder_id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub parent_id: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MoveFolderResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPlaylistsRequest { + #[prost(string, optional, tag = "1")] + pub folder_id: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPlaylistsResponse { + #[prost(message, repeated, tag = "1")] + pub playlists: ::prost::alloc::vec::Vec, +} /// Generated client implementations. pub mod playlist_service_client { #![allow( @@ -5616,77 +5747,363 @@ pub mod playlist_service_client { ); self.inner.unary(req, path, codec).await } - } -} -/// Generated server implementations. -pub mod playlist_service_server { - #![allow( - unused_variables, - dead_code, - missing_docs, - clippy::wildcard_imports, - clippy::let_unit_value, - )] - use tonic::codegen::*; - /// Generated trait containing gRPC methods that should be implemented for use with PlaylistServiceServer. - #[async_trait] - pub trait PlaylistService: std::marker::Send + std::marker::Sync + 'static { - async fn get_current( - &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; - async fn get_resume_info( - &self, - request: tonic::Request, + pub async fn get_playlist( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn get_track_info( - &self, - request: tonic::Request, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/GetPlaylist", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "GetPlaylist"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn get_playlists( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn get_first_index( - &self, - request: tonic::Request, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/GetPlaylists", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "GetPlaylists"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn create_folder( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn get_display_index( - &self, - request: tonic::Request, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/CreateFolder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "CreateFolder"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn get_folder( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn amount( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - async fn playlist_resume( - &self, - request: tonic::Request, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/GetFolder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "GetFolder"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn get_folders( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn resume_track( - &self, - request: tonic::Request, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/GetFolders", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "GetFolders"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn remove_folder( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn set_modified( - &self, - request: tonic::Request, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/RemoveFolder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "RemoveFolder"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn remove_playlist( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/RemovePlaylist", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "RemovePlaylist"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn rename_playlist( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/RenamePlaylist", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "RenamePlaylist"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn rename_folder( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/RenameFolder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "RenameFolder"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn move_playlist( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/MovePlaylist", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "MovePlaylist"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn move_folder( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/MoveFolder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "MoveFolder"), + ); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated server implementations. +pub mod playlist_service_server { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with PlaylistServiceServer. + #[async_trait] + pub trait PlaylistService: std::marker::Send + std::marker::Sync + 'static { + async fn get_current( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_resume_info( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_track_info( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_first_index( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_display_index( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn amount( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn playlist_resume( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn resume_track( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn set_modified( + &self, + request: tonic::Request, ) -> std::result::Result< tonic::Response, tonic::Status, @@ -5762,6 +6179,83 @@ pub mod playlist_service_server { tonic::Response, tonic::Status, >; + async fn get_playlist( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_playlists( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn create_folder( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_folder( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_folders( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn remove_folder( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn remove_playlist( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn rename_playlist( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn rename_folder( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn move_playlist( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn move_folder( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct PlaylistServiceServer { @@ -5841,23 +6335,522 @@ pub mod playlist_service_server { match req.uri().path() { "/rockbox.v1alpha1.PlaylistService/GetCurrent" => { #[allow(non_camel_case_types)] - struct GetCurrentSvc(pub Arc); + struct GetCurrentSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for GetCurrentSvc { + type Response = super::GetCurrentResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_current(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetCurrentSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/GetResumeInfo" => { + #[allow(non_camel_case_types)] + struct GetResumeInfoSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for GetResumeInfoSvc { + type Response = super::GetResumeInfoResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_resume_info(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetResumeInfoSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/GetTrackInfo" => { + #[allow(non_camel_case_types)] + struct GetTrackInfoSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for GetTrackInfoSvc { + type Response = super::GetTrackInfoResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_track_info(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetTrackInfoSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/GetFirstIndex" => { + #[allow(non_camel_case_types)] + struct GetFirstIndexSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for GetFirstIndexSvc { + type Response = super::GetFirstIndexResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_first_index(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetFirstIndexSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/GetDisplayIndex" => { + #[allow(non_camel_case_types)] + struct GetDisplayIndexSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for GetDisplayIndexSvc { + type Response = super::GetDisplayIndexResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_display_index(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetDisplayIndexSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/Amount" => { + #[allow(non_camel_case_types)] + struct AmountSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for AmountSvc { + type Response = super::AmountResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::amount(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = AmountSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/PlaylistResume" => { + #[allow(non_camel_case_types)] + struct PlaylistResumeSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for PlaylistResumeSvc { + type Response = super::PlaylistResumeResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::playlist_resume(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = PlaylistResumeSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/ResumeTrack" => { + #[allow(non_camel_case_types)] + struct ResumeTrackSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for ResumeTrackSvc { + type Response = super::ResumeTrackResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::resume_track(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ResumeTrackSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/SetModified" => { + #[allow(non_camel_case_types)] + struct SetModifiedSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for SetModifiedSvc { + type Response = super::SetModifiedResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::set_modified(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SetModifiedSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/Start" => { + #[allow(non_camel_case_types)] + struct StartSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService for StartSvc { + type Response = super::StartResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::start(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = StartSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/Sync" => { + #[allow(non_camel_case_types)] + struct SyncSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService for SyncSvc { + type Response = super::SyncResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::sync(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SyncSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/RemoveAllTracks" => { + #[allow(non_camel_case_types)] + struct RemoveAllTracksSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for GetCurrentSvc { - type Response = super::GetCurrentResponse; + > tonic::server::UnaryService + for RemoveAllTracksSvc { + type Response = super::RemoveAllTracksResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::get_current(&inner, request).await + ::remove_all_tracks(&inner, request) + .await }; Box::pin(fut) } @@ -5868,7 +6861,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = GetCurrentSvc(inner); + let method = RemoveAllTracksSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5884,26 +6877,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/GetResumeInfo" => { + "/rockbox.v1alpha1.PlaylistService/RemoveTracks" => { #[allow(non_camel_case_types)] - struct GetResumeInfoSvc(pub Arc); + struct RemoveTracksSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for GetResumeInfoSvc { - type Response = super::GetResumeInfoResponse; + > tonic::server::UnaryService + for RemoveTracksSvc { + type Response = super::RemoveTracksResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::get_resume_info(&inner, request) - .await + ::remove_tracks(&inner, request).await }; Box::pin(fut) } @@ -5914,7 +6906,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = GetResumeInfoSvc(inner); + let method = RemoveTracksSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5930,25 +6922,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/GetTrackInfo" => { + "/rockbox.v1alpha1.PlaylistService/CreatePlaylist" => { #[allow(non_camel_case_types)] - struct GetTrackInfoSvc(pub Arc); + struct CreatePlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for GetTrackInfoSvc { - type Response = super::GetTrackInfoResponse; + > tonic::server::UnaryService + for CreatePlaylistSvc { + type Response = super::CreatePlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::get_track_info(&inner, request) + ::create_playlist(&inner, request) .await }; Box::pin(fut) @@ -5960,7 +6952,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = GetTrackInfoSvc(inner); + let method = CreatePlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5976,26 +6968,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/GetFirstIndex" => { + "/rockbox.v1alpha1.PlaylistService/InsertTracks" => { #[allow(non_camel_case_types)] - struct GetFirstIndexSvc(pub Arc); + struct InsertTracksSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for GetFirstIndexSvc { - type Response = super::GetFirstIndexResponse; + > tonic::server::UnaryService + for InsertTracksSvc { + type Response = super::InsertTracksResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::get_first_index(&inner, request) - .await + ::insert_tracks(&inner, request).await }; Box::pin(fut) } @@ -6006,7 +6997,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = GetFirstIndexSvc(inner); + let method = InsertTracksSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6022,25 +7013,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/GetDisplayIndex" => { + "/rockbox.v1alpha1.PlaylistService/InsertDirectory" => { #[allow(non_camel_case_types)] - struct GetDisplayIndexSvc(pub Arc); + struct InsertDirectorySvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for GetDisplayIndexSvc { - type Response = super::GetDisplayIndexResponse; + > tonic::server::UnaryService + for InsertDirectorySvc { + type Response = super::InsertDirectoryResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::get_display_index(&inner, request) + ::insert_directory(&inner, request) .await }; Box::pin(fut) @@ -6052,7 +7043,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = GetDisplayIndexSvc(inner); + let method = InsertDirectorySvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6068,25 +7059,26 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/Amount" => { + "/rockbox.v1alpha1.PlaylistService/InsertPlaylist" => { #[allow(non_camel_case_types)] - struct AmountSvc(pub Arc); + struct InsertPlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for AmountSvc { - type Response = super::AmountResponse; + > tonic::server::UnaryService + for InsertPlaylistSvc { + type Response = super::InsertPlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::amount(&inner, request).await + ::insert_playlist(&inner, request) + .await }; Box::pin(fut) } @@ -6097,7 +7089,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = AmountSvc(inner); + let method = InsertPlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6113,26 +7105,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/PlaylistResume" => { + "/rockbox.v1alpha1.PlaylistService/InsertAlbum" => { #[allow(non_camel_case_types)] - struct PlaylistResumeSvc(pub Arc); + struct InsertAlbumSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for PlaylistResumeSvc { - type Response = super::PlaylistResumeResponse; + > tonic::server::UnaryService + for InsertAlbumSvc { + type Response = super::InsertAlbumResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::playlist_resume(&inner, request) - .await + ::insert_album(&inner, request).await }; Box::pin(fut) } @@ -6143,7 +7134,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = PlaylistResumeSvc(inner); + let method = InsertAlbumSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6159,25 +7150,29 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/ResumeTrack" => { + "/rockbox.v1alpha1.PlaylistService/InsertArtistTracks" => { #[allow(non_camel_case_types)] - struct ResumeTrackSvc(pub Arc); + struct InsertArtistTracksSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for ResumeTrackSvc { - type Response = super::ResumeTrackResponse; + > tonic::server::UnaryService + for InsertArtistTracksSvc { + type Response = super::InsertArtistTracksResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::resume_track(&inner, request).await + ::insert_artist_tracks( + &inner, + request, + ) + .await }; Box::pin(fut) } @@ -6188,7 +7183,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = ResumeTrackSvc(inner); + let method = InsertArtistTracksSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6204,25 +7199,26 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/SetModified" => { + "/rockbox.v1alpha1.PlaylistService/ShufflePlaylist" => { #[allow(non_camel_case_types)] - struct SetModifiedSvc(pub Arc); + struct ShufflePlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for SetModifiedSvc { - type Response = super::SetModifiedResponse; + > tonic::server::UnaryService + for ShufflePlaylistSvc { + type Response = super::ShufflePlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::set_modified(&inner, request).await + ::shuffle_playlist(&inner, request) + .await }; Box::pin(fut) } @@ -6233,7 +7229,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = SetModifiedSvc(inner); + let method = ShufflePlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6249,24 +7245,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/Start" => { + "/rockbox.v1alpha1.PlaylistService/GetPlaylist" => { #[allow(non_camel_case_types)] - struct StartSvc(pub Arc); + struct GetPlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService for StartSvc { - type Response = super::StartResponse; + > tonic::server::UnaryService + for GetPlaylistSvc { + type Response = super::GetPlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::start(&inner, request).await + ::get_playlist(&inner, request).await }; Box::pin(fut) } @@ -6277,7 +7274,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = StartSvc(inner); + let method = GetPlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6293,24 +7290,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/Sync" => { + "/rockbox.v1alpha1.PlaylistService/GetPlaylists" => { #[allow(non_camel_case_types)] - struct SyncSvc(pub Arc); + struct GetPlaylistsSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService for SyncSvc { - type Response = super::SyncResponse; + > tonic::server::UnaryService + for GetPlaylistsSvc { + type Response = super::GetPlaylistsResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::sync(&inner, request).await + ::get_playlists(&inner, request).await }; Box::pin(fut) } @@ -6321,7 +7319,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = SyncSvc(inner); + let method = GetPlaylistsSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6337,26 +7335,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/RemoveAllTracks" => { + "/rockbox.v1alpha1.PlaylistService/CreateFolder" => { #[allow(non_camel_case_types)] - struct RemoveAllTracksSvc(pub Arc); + struct CreateFolderSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for RemoveAllTracksSvc { - type Response = super::RemoveAllTracksResponse; + > tonic::server::UnaryService + for CreateFolderSvc { + type Response = super::CreateFolderResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::remove_all_tracks(&inner, request) - .await + ::create_folder(&inner, request).await }; Box::pin(fut) } @@ -6367,7 +7364,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = RemoveAllTracksSvc(inner); + let method = CreateFolderSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6383,25 +7380,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/RemoveTracks" => { + "/rockbox.v1alpha1.PlaylistService/GetFolder" => { #[allow(non_camel_case_types)] - struct RemoveTracksSvc(pub Arc); + struct GetFolderSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for RemoveTracksSvc { - type Response = super::RemoveTracksResponse; + > tonic::server::UnaryService + for GetFolderSvc { + type Response = super::GetFolderResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::remove_tracks(&inner, request).await + ::get_folder(&inner, request).await }; Box::pin(fut) } @@ -6412,7 +7409,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = RemoveTracksSvc(inner); + let method = GetFolderSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6428,26 +7425,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/CreatePlaylist" => { + "/rockbox.v1alpha1.PlaylistService/GetFolders" => { #[allow(non_camel_case_types)] - struct CreatePlaylistSvc(pub Arc); + struct GetFoldersSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for CreatePlaylistSvc { - type Response = super::CreatePlaylistResponse; + > tonic::server::UnaryService + for GetFoldersSvc { + type Response = super::GetFoldersResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::create_playlist(&inner, request) - .await + ::get_folders(&inner, request).await }; Box::pin(fut) } @@ -6458,7 +7454,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = CreatePlaylistSvc(inner); + let method = GetFoldersSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6474,25 +7470,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/InsertTracks" => { + "/rockbox.v1alpha1.PlaylistService/RemoveFolder" => { #[allow(non_camel_case_types)] - struct InsertTracksSvc(pub Arc); + struct RemoveFolderSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for InsertTracksSvc { - type Response = super::InsertTracksResponse; + > tonic::server::UnaryService + for RemoveFolderSvc { + type Response = super::RemoveFolderResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::insert_tracks(&inner, request).await + ::remove_folder(&inner, request).await }; Box::pin(fut) } @@ -6503,7 +7499,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = InsertTracksSvc(inner); + let method = RemoveFolderSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6519,25 +7515,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/InsertDirectory" => { + "/rockbox.v1alpha1.PlaylistService/RemovePlaylist" => { #[allow(non_camel_case_types)] - struct InsertDirectorySvc(pub Arc); + struct RemovePlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for InsertDirectorySvc { - type Response = super::InsertDirectoryResponse; + > tonic::server::UnaryService + for RemovePlaylistSvc { + type Response = super::RemovePlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::insert_directory(&inner, request) + ::remove_playlist(&inner, request) .await }; Box::pin(fut) @@ -6549,7 +7545,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = InsertDirectorySvc(inner); + let method = RemovePlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6565,25 +7561,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/InsertPlaylist" => { + "/rockbox.v1alpha1.PlaylistService/RenamePlaylist" => { #[allow(non_camel_case_types)] - struct InsertPlaylistSvc(pub Arc); + struct RenamePlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for InsertPlaylistSvc { - type Response = super::InsertPlaylistResponse; + > tonic::server::UnaryService + for RenamePlaylistSvc { + type Response = super::RenamePlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::insert_playlist(&inner, request) + ::rename_playlist(&inner, request) .await }; Box::pin(fut) @@ -6595,7 +7591,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = InsertPlaylistSvc(inner); + let method = RenamePlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6611,25 +7607,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/InsertAlbum" => { + "/rockbox.v1alpha1.PlaylistService/RenameFolder" => { #[allow(non_camel_case_types)] - struct InsertAlbumSvc(pub Arc); + struct RenameFolderSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for InsertAlbumSvc { - type Response = super::InsertAlbumResponse; + > tonic::server::UnaryService + for RenameFolderSvc { + type Response = super::RenameFolderResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::insert_album(&inner, request).await + ::rename_folder(&inner, request).await }; Box::pin(fut) } @@ -6640,7 +7636,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = InsertAlbumSvc(inner); + let method = RenameFolderSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6656,29 +7652,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/InsertArtistTracks" => { + "/rockbox.v1alpha1.PlaylistService/MovePlaylist" => { #[allow(non_camel_case_types)] - struct InsertArtistTracksSvc(pub Arc); + struct MovePlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for InsertArtistTracksSvc { - type Response = super::InsertArtistTracksResponse; + > tonic::server::UnaryService + for MovePlaylistSvc { + type Response = super::MovePlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::insert_artist_tracks( - &inner, - request, - ) - .await + ::move_playlist(&inner, request).await }; Box::pin(fut) } @@ -6689,7 +7681,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = InsertArtistTracksSvc(inner); + let method = MovePlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6705,26 +7697,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/ShufflePlaylist" => { + "/rockbox.v1alpha1.PlaylistService/MoveFolder" => { #[allow(non_camel_case_types)] - struct ShufflePlaylistSvc(pub Arc); + struct MoveFolderSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for ShufflePlaylistSvc { - type Response = super::ShufflePlaylistResponse; + > tonic::server::UnaryService + for MoveFolderSvc { + type Response = super::MoveFolderResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::shuffle_playlist(&inner, request) - .await + ::move_folder(&inner, request).await }; Box::pin(fut) } @@ -6735,7 +7726,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = ShufflePlaylistSvc(inner); + let method = MoveFolderSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( diff --git a/crates/rpc/src/api/rockbox_descriptor.bin b/crates/rpc/src/api/rockbox_descriptor.bin index 5da9ae91af658444901cc0f76ecbf23c882b9c92..891e8f3fb095e41cb3a67608f6061468e75b2297 100644 GIT binary patch delta 8713 zcmbtZX>eTCm44^-)l=(9mZht$CAC^oYqKm%w!8@2*x+SY?1aG<<%yS66d|>YZAliA zY~oDdjgz7>REP(7o(iNKCqTv(5|i@8z*H(Q#RR4@z*NeFnXm=S5|*&v(YwT{H;4Vhhfcped`Oi2ZCE>)o7jIaw|;y){_*Z* z6&uRKvZ1N*;X~tlW@d->jK+t@(zGW&KDKN?wuhw!mXzN@3ra5b21EOB)961E{Y8LB z$Lg0Jrm$w?bZ&Syx5b1W%w2gPH!~~iLNPf!kxP*YrVzr!wYwM9(O`0H|M+NbT1PGp zi-y?w^p@TK>-#4u?%ca~!{@6KDiD3XsxV9r&0KL{Y-~LD7Zo1cn-X_ZSRemjx;{R$ zcl(9^|Crfy*bqNF-56iCZ(DJ8MJO-I&BkZfEUC*r?T1wWPKTMP{gX5CKyhchcz0_& zQI(E5!qU;)%*gbfso6dICsRdgMgCynLntI`!(ez~|AEQbQ~-~nL4#yd7>+2dM~8-I zQ^m|4EHO{k&$9Wz)F@h^%t>uFPhdVTEDvUEHLM_pIci( zDeevamD)BI#F?>q<}A=o^j`^bnVJi(HIti06tljyVXn}2!JM62*!3|r%RD&t3!wMk2ik4!cuV2vN0sx9=2 z4_{O>2j72Zy0aikzP79Df80H_(NHyS=@?Xhj`?F%I#{NVx@%dAMg(!t#*0$WV$dkFS{Bsk&KBJiN zQ&+Yz1qxMFDzC!fjo}sOsb$9^^)o&*RaZ7=lv$EF4^T&@@Ik>6A*Y(^mJ8BC{aANF zTLM22wYmrEcM~St`lk1f?7Mvb*ZL0j506h>G2Gwhtnow1#%2dyhRr`*7Z%GR&-*jQ zQ-1yF*_k(s1~-Obm=Luj6MvJ;gr%VnwY~??x;`umix>z--4+!AEnH#|)B4v~lmI$^ zT|9XxRT_rANJ(+A_XUb?I8+;L@|%@cO2ymchZZ5;rqT+F5N}gugGGq9sYw@=@?qNS zXN`$a)aHB;LXgd+mDa|dcx`d{pdrZSmZ&u>K}Gd4af#QgR$LFSOOk2)_C>EGGp*(k=B3CJ0Q?R$mv?;B)C) z^HI3;t@$W;ODDFswH`5>&+APy{DijN?JnW$N< zzfmT(d8^bq8{xIhbi9$*xvljaMFBv#ZLOUav18X#ix6(xiUB2CT8b}uU)Hjv;q|3t zqpCH{;kKJz0if1syD1hB(YKpofxz2tngxXD+gn;q6qt7SH7ar1XQ6iZ#TKzGsmBI3 z&~{W+8ybY#Y1B^pEYwavj0}&J+L=$zO6@dq!xd3>8oAR9cKK;TOCZXw{0b5Xva58y zwIRr^iaLv!*MPSL#;QpszG9{=YJ%5S%(!Kw_^LOib<5!SS4|r-tlO~B4FE}pO;R8v z9X6E%fi`Sp147baBU^?Sb-9rZ0JO{fV!eJqHX7Z4z`NY&mhqw6h_BZH0N#k7RI364 zZKOn61lmYVt&%&#LX8@s08sO2zGfC`R0$Oo2^bM&)F=hSL@32aPKMi*%SRCk=_3Lr zM9CSsfe<8@4ZDu0BGYzC?K|#=)DI7+IXfJON@kQVSy+7dL<$NcoTUZ z$DAmswl?r4>QYLY78ZEYNCNTBMlJqj5Mv0OkC-;Ds5WfbtNW_ zwaH2`<9$s_lg0Cyq&~B;OkQm0JH;oiID(g zV~IYcfxtUZU8B~RWoZtYH3DFb2hAFR5apm*BM^cdG;0Jxkb`E1vJ9>=y9WS4uF40A zSgEVb_JI*mt}@#Ph>6%fyl2~F;_DuZlMroi`no#Oe9VAfaGrVG%=!Wvs*yY8j}wkc$VX zLyB*ahd)4}R|ovQMair(bV_k8;Z?(iPLdH2W{#70LNOq`Z8#nfvH^Blh$z<*-Z#dI zY}b-`;dDvyZNe7kpk46$Hkm!XK#J?g8&HM?FkD9%WKOn#lU+wm(Q*|J5ZQp+EL6_z zi!DU9>uBjRaDCA&gYS^{&uBX5>xSod2;;zEyE*Lj}o}uNU_kbnytQ8e~mnwMIFx8jh2;uBuae&Y_K;1V$L^@*o28c*U z2p0i3N9>JIM+nD}4h8g2gh|q&cmx1#C~Ox%GXmYbUjXs(#W*Xj8K!Qo;s!fRKpNUe zIK5$w@}Y2k1Dk1rH$vS&m?m8moNpw*%H%21u-HOSZ=__og`nO@mHbv>X#y#3B0pt} z0jPjh)hGb>CMvO!18{GmT7KIxw^)kUaf`tPwA^A)V@E9pHFngb6i3NlW6~zEctE@O zB#JsprAxv{3ztNwqtvfQzuQkD)KOY}E~@awLK%FIyziTFTL{nZ*>PLQ<94$h86Xr0 zs0##y@6C2(01@?OJ2DG-3T~mu%nTqZyv0@sh)}oKMguBuJu?Cjp>E-k;l17?#WB0d zdf<1AaGzoQdbqq})U5Xy5Mly$C`|z28y%xgy~%(P^cZh44!TH+?0<56kX1maf^H+-7?au90I~P#T z2_Qn*Ju2KRnmcdWR`>7FdF+6`_57fn+1+ik}ni+|YKp;>7EtMzm9y@`sf_e{6pj!V5DSl~dT>-~m+FA!> z@GJ8E-PAe&)30nJ2DsFFZK*)W2dMJ_!uMWVDj@RRYfByAQtz{+4n(R}V9VuN@3XbS z8Ql9!t>PRh?zc@m2Y&bKgT@ytW$r5|yv z4-jtH#*BOq5U$uf0V}!I2ML!kZDd&iEtgAukZ>I{R!|=#+{bu^S4r_3Tk0zK{l=EM zS_Ti1_ur<})e&qD*`2zYYkk<}142GPoevPc58Hfz$oDYk<5E|1sgF1+mkMa9TPJD}bg zfJlCZy7XoTRMbBGasx#2Gxp^ct(C#=$on6o$6C1l&b~g@a+b%)KTin^ge-viNCCu= z@)(usw+A4okI|A<))`qIqcv;!+zLDy{GRZ2OWoK4_WV61)jK{4JkIhs`5T$Y2-e3b zP&YV+IG-PSc)e)sGvupIG6MA(3d#(%2-Ih2 zUW0|8K0_URXJ#t8^(^_98Y5r3o~58VvKZWFsm4_0^EK>QTJZ(L#Wn0K`4<{rzIUCa zK>Znlz{Q}RCH$*R_m8h(XKC>UL&Y`hIY;Gt)^m=U^drW3F5kPJbKDXso+n@3UXZ5* z+~+A!mv@Fp`#hDYdnH3qpQkqd0LrTkrFen-ep6Ej>I)R8$z>y`FHmVMtPzh~2<{8i z+G|==DuWlv|D$b@Ukdh%u0y3@zvwzt3i2OahsvaQiF`X%WuU&~rm76om)um9@!uaW zxv`oj#mlZm^T2%>Ei!AE2ky(RL-UaKW!Ir{DPD1D%Rzm`r7Z{b6_>Ug)K@qwCX)Bx zd>On-{-5&eoe%b_ZoTute$}maKG=V9>#dODHCJ;5sIR%2D?okC)m#DUYp&)>DPE7< zY*d2#x|@wka9?+$Q3>wrJQ{i%Ng2FB{+p!EIIKZ}{00Sf8YIYXP`&zNm8~GZN%Ol6 zxk?6ak^eR?I8tX$71(dN6<2}%mRoTZ*l)WPS4;7ZtGXK0cU;xgpuXd(t_JlTH_$aw zyz9DD18VfHYf}xl@47bCfcvf+j#??+b6osi05E@C)q?t-qt=4@o}<=D@jm(M%plc) z`aT8o6^uN;4&3*tLjCOut?IyipL+Oz2fUH+zk(0k;hX~Z19v#5K>ffS&M8noaEEif z6d$^Z@m(J{r>?Xgz@(P delta 3389 zcmYL~+fN%u6vlUEhh@FCu|3=j7-KtJ(hAxpG^x@ms(MS)G(cp9Kox~xBA07Oz!Zg0 zu@y?vB!o+1NFcX|N_nf)O7y?zYx^Jcwd!O0*l%Xf?!NiA=X~eP`R3x?-^9P`;@7`R z{I4$$|0%5qGwn20e_3v7FSIz##q#wV%jHkz<}NOluFY18<;u+)^ObU;zxv0w{ngWx zExi?|@w3HpX{mf+uCy{YU0EuY7rrZ3mZWsVeCc{Q&2sE$q^N&a?@#tt)7R?`f1mu5 zv*qefGc(n9PRFZ5v(2XKv{dtR4b`>TEBae@u3{d4lQ>*od{gV3`>)ffl{JR(`tZV9 zt>xw&$1z0{lji4k)`>V=G)wc0QP7{8@%fD1p+BdkdDb|sKd15etlj2B9U;=(0AxRM zVor?$p{U!Z8c!z)$=>V6y6aZ}oxa|`X2O@Ew&}JZ+A{j!1yq!V}Yjp>?<0GmJMpHhiRGIb(RR-HK zRE0}(i03H8QDrD7!ck->D8f->NVfTzC^D4w+-#F((KzKeF3fL3RuSeaJKNM`#ry|a z0zkQ9-m?>=5_^vOF_bHwIH`@wNO95l#xp8|tc$ce8C7nW7qkR`wGPu-K`8DH(_(?p z4NK1)5ULO7@_JDjHOD31NL3hgmw2sDDrP5rg6vX#1Ib|22-%(C%BYc`xiV@bnsP~} zI*gFrNJW(qvOA+-lxHZ>M3vE?iis+t(S#pEkRGA2>2vnIMyAeZ?39`FGnq_)II*?Sx6QZtjPKrrm z&T~75?~``BtDEMO-BaWg0BxqoDG)NJ=zxLHW{Ql;DKn<&CITRvCZj+q7V+*L2(oG1 zJvCxZ`8&f~)H!h#K{pfVRLz-4gFZxvK{wN!CLLgwtjTGEXUSj?ip-KVAQYJ;Yd}gz z*5su*Z{+ohmPe91j}xc7DM)eCSn|9nAaK)e)lCb^ngy~3fHn(c4G4(~WDN*y7RZ`{ z8e@?+=`jG1Ez*b}6^rPX&J{rD78@F=9lWW~j0JsXD>NerRVp+i2vsUHBM3z*G~*Fz zE*okrQyf9kG9Du}Vy6_hjPJb>JMsONop)TdA)RW*6`B!%HY+qE2$?H1BM5C)XvR*p zg4=XY0Fd3L89^#W_XGslZMr9&YWr7dL>Gi3zDhHKP-T^71fj|*%?Lu3RhqF&nrlXv zp0Nu_Yj#1;*e%5m3=ex0vv)HE*xwjt?8b~ByzFuOQG#kTy4^nOWIXN^HdUBj_Z}(M z8SaxR+Jn4xh6@#QxMfJ|4l`aera~5+5_g!b-VI?Hs^4A4KT`!2A$XTrNguhwRKfKb z{qC~9k4cN3C|13!n{E_jmC-ErB6gOQJ zKK2D^QR#lz7MBPZv^AloZf0pkzZ+tdkZp%!*NR4YV69-s&T?8?39J)@(`fi18r`T97_sR)dd_K4Ojj zqAW-su@hgDv{njtlkqc@Tnp_cvr;}nyUApykI-(icRwYqEyY$SwISUKr8cBnq11+S zE0jj0*k=5FUDq{u1lnz8MX65&+HDp~`v~neJMtd2b)?u~{1^otNOzd!_z39^i#GWP z=?=^H(GEqW^_cM|!45?se(Z)@6ovY6xJ6N@pQtVJb|@xAH9S@^Xsh9|ia}as!Lf=# zS`ANCT#DUrhvJa#20P^PIJCRr7R9064Y#OHioLLH9khF4+d4@1!nSpg?y0ukiA+fA zDdW$Ac@q#n4aZGD{FJ%DkxW4SESxtf#eTTxB((d%qInY9{cz1mNcY1vr=&Otk46g8 zgYamiAUz0=hMR)+K%EV5(NbE^8Gph0Xb&aS&za?)1_||Z)}mi2ToeiM3zm3`#P!m8 g$@r^a;(CZ*h7;FA{4(6&dWc_{nD}t&_0OyS10XapGynhq diff --git a/crates/rpc/src/playback.rs b/crates/rpc/src/playback.rs index d02790ff892..25c92aa0af9 100644 --- a/crates/rpc/src/playback.rs +++ b/crates/rpc/src/playback.rs @@ -325,9 +325,28 @@ impl PlaybackService for Playback { async fn play_playlist( &self, - _request: tonic::Request, + request: tonic::Request, ) -> Result, tonic::Status> { - todo!() + let request = request.into_inner(); + let playlist_id = request.playlist_id; + let shuffle = match request.shuffle { + Some(true) => 1, + Some(false) => 0, + None => 0, + }; + let url = format!( + "{}/playlists/{}/play?shuffle={}", + rockbox_url(), + playlist_id, + shuffle + ); + let client = reqwest::Client::new(); + client + .put(&url) + .send() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + Ok(tonic::Response::new(PlayPlaylistResponse::default())) } async fn play_directory( diff --git a/crates/rpc/src/playlist.rs b/crates/rpc/src/playlist.rs index a75d9d7e4b1..01b730ee4b1 100644 --- a/crates/rpc/src/playlist.rs +++ b/crates/rpc/src/playlist.rs @@ -1,6 +1,6 @@ use std::sync::{mpsc::Sender, Arc, Mutex}; -use rockbox_library::repo; +use rockbox_library::{entity::folder::Folder, repo}; use rockbox_sys::{ events::RockboxCommand, types::{playlist_amount::PlaylistAmount, playlist_info::PlaylistInfo}, @@ -197,12 +197,14 @@ impl PlaylistService for Playlist { async fn remove_all_tracks( &self, - _request: tonic::Request, + request: tonic::Request, ) -> Result, tonic::Status> { + let request = request.into_inner(); + let playlist_id = request.playlist_id.unwrap_or("current".to_string()); let body = serde_json::json!({ "positions": [], }); - let url = format!("{}/playlists/current/tracks", rockbox_url()); + let url = format!("{}/playlists/{}/tracks", rockbox_url(), playlist_id); self.client .delete(&url) .json(&body) @@ -217,10 +219,11 @@ impl PlaylistService for Playlist { request: tonic::Request, ) -> Result, tonic::Status> { let request = request.into_inner(); + let playlist_id = request.playlist_id.unwrap_or("current".to_string()); let body = serde_json::json!({ "positions": request.positions, }); - let url = format!("{}/playlists/current/tracks", rockbox_url()); + let url = format!("{}/playlists/{}/tracks", rockbox_url(), playlist_id); self.client .delete(&url) .json(&body) @@ -235,11 +238,17 @@ impl PlaylistService for Playlist { request: tonic::Request, ) -> Result, tonic::Status> { let request = request.into_inner(); - let body = serde_json::json!({ - "name": request.name, - "tracks": request.tracks, - "folder_id": request.folder_id, - }); + let body = match request.name { + Some(name) => serde_json::json!({ + "name": name, + "tracks": request.tracks, + "folder_id": request.folder_id, + }), + None => serde_json::json!({ + "tracks": request.tracks, + "folder_id": request.folder_id, + }), + }; let url = format!("{}/playlists", rockbox_url()); let response = self @@ -263,12 +272,14 @@ impl PlaylistService for Playlist { request: tonic::Request, ) -> Result, tonic::Status> { let request = request.into_inner(); + let playlist_id = request.playlist_id.unwrap_or("current".to_string()); let body = serde_json::json!({ "position": request.position, "tracks": request.tracks, }); - let url = format!("{}/playlists/current/tracks", rockbox_url()); - self.client + let url = format!("{}/playlists/{}/tracks", rockbox_url(), playlist_id); + let client = reqwest::Client::new(); + client .post(&url) .json(&body) .send() @@ -282,12 +293,13 @@ impl PlaylistService for Playlist { request: tonic::Request, ) -> Result, tonic::Status> { let request = request.into_inner(); + let playlist_id = request.playlist_id.unwrap_or("current".to_string()); let body = serde_json::json!({ "position": request.position, "tracks": [], "directory": request.directory, }); - let url = format!("{}/playlists/current/tracks", rockbox_url()); + let url = format!("{}/playlists/{}/tracks", rockbox_url(), playlist_id); self.client .post(&url) .json(&body) @@ -337,7 +349,9 @@ impl PlaylistService for Playlist { "position": position, "tracks": tracks, }); - let url = format!("{}/playlists/current/tracks", rockbox_url()); + let playlist_id = request.playlist_id.unwrap_or("current".to_string()); + let url = format!("{}/playlists/{}/tracks", rockbox_url(), playlist_id); + self.client .post(&url) .json(&body) @@ -363,7 +377,8 @@ impl PlaylistService for Playlist { "position": position, "tracks": tracks, }); - let url = format!("{}/playlists/current/tracks", rockbox_url()); + let playlist_id = request.playlist_id.unwrap_or("current".to_string()); + let url = format!("{}/playlists/{}/tracks", rockbox_url(), playlist_id); self.client .post(&url) .json(&body) @@ -373,4 +388,259 @@ impl PlaylistService for Playlist { Ok(tonic::Response::new(InsertArtistTracksResponse::default())) } + + async fn get_playlist( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + let request = request.into_inner(); + let url = format!("{}/playlists/{}", rockbox_url(), request.playlist_id); + let client = reqwest::Client::new(); + let response = client + .get(url) + .send() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + let playlist = response + .json::() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + let tracks = playlist + .entries + .iter() + .map(|track| CurrentTrackResponse::from(track.clone())) + .collect::>(); + Ok(tonic::Response::new(GetPlaylistResponse { + id: playlist.id.unwrap_or_default(), + amount: playlist.amount, + name: playlist.name.unwrap_or_default(), + folder_id: playlist.folder_id, + created_at: playlist.created_at.unwrap_or_default(), + updated_at: playlist.updated_at.unwrap_or_default(), + tracks, + ..Default::default() + })) + } + async fn get_playlists( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + let request = request.into_inner(); + let url = match request.folder_id { + Some(folder_id) => match folder_id.is_empty() { + false => format!("{}/playlists?folder_id={}", rockbox_url(), folder_id), + true => format!("{}/playlists", rockbox_url()), + }, + None => format!("{}/playlists", rockbox_url()), + }; + let client = reqwest::Client::new(); + let response = client + .get(url) + .send() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + let playlists = response + .json::>() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + let playlists = playlists + .into_iter() + .map(|playlist| GetPlaylistResponse { + id: playlist.id, + name: playlist.name, + folder_id: playlist.folder_id, + image: playlist.image, + description: playlist.description, + created_at: chrono::DateTime::from_timestamp(playlist.created_at as i64, 0) + .unwrap() + .to_rfc3339(), + updated_at: chrono::DateTime::from_timestamp(playlist.updated_at as i64, 0) + .unwrap() + .to_rfc3339(), + ..Default::default() + }) + .collect::>(); + Ok(tonic::Response::new(GetPlaylistsResponse { playlists })) + } + + async fn create_folder( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + let request = request.into_inner(); + let url = format!("{}/folders", rockbox_url()); + let body = match request.parent_id { + Some(parent_id) => serde_json::json!({ + "name": request.name, + "parent_id": parent_id, + }), + None => serde_json::json!({ + "name": request.name, + }), + }; + let client = reqwest::Client::new(); + let response = client + .post(&url) + .json(&body) + .send() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + let response = response + .json::() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + let folder_id = response.id; + + Ok(tonic::Response::new(CreateFolderResponse { folder_id })) + } + + async fn get_folder( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + let request = request.into_inner(); + let url = format!("{}/folders/{}", rockbox_url(), request.id); + let client = reqwest::Client::new(); + let response = client + .get(url) + .send() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + let folder = response + .json::() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + Ok(tonic::Response::new(GetFolderResponse { + id: folder.id, + name: folder.name, + parent_id: folder.parent_id, + })) + } + + async fn get_folders( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + let request = request.into_inner(); + let url = match request.parent_id { + Some(parent_id) => match parent_id.is_empty() { + false => format!("{}/folders?parent_id={}", rockbox_url(), parent_id), + true => format!("{}/folder", rockbox_url()), + }, + None => format!("{}/folders", rockbox_url()), + }; + let client = reqwest::Client::new(); + let response = client + .get(url) + .send() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + let folders = response + .json::>() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + let folders = folders + .into_iter() + .map(|folder| GetFolderResponse { + id: folder.id, + name: folder.name, + parent_id: folder.parent_id, + }) + .collect::>(); + Ok(tonic::Response::new(GetFoldersResponse { folders })) + } + + async fn remove_folder( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + let request = request.into_inner(); + let url = format!("{}/folders/{}", rockbox_url(), request.id); + let client = reqwest::Client::new(); + client + .delete(&url) + .send() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + Ok(tonic::Response::new(RemoveFolderResponse::default())) + } + + async fn remove_playlist( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + let request = request.into_inner(); + let url = format!("{}/playlists/{}", rockbox_url(), request.id); + let client = reqwest::Client::new(); + client + .delete(&url) + .send() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + Ok(tonic::Response::new(RemovePlaylistResponse::default())) + } + + async fn rename_playlist( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + let request = request.into_inner(); + let url = format!("{}/playlists/{}", rockbox_url(), request.id); + let client = reqwest::Client::new(); + client + .put(&url) + .json(&serde_json::json!({"name": request.name})) + .send() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + Ok(tonic::Response::new(RenamePlaylistResponse::default())) + } + + async fn rename_folder( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + let request = request.into_inner(); + let url = format!("{}/folders/{}", rockbox_url(), request.id); + let client = reqwest::Client::new(); + client + .put(&url) + .json(&serde_json::json!({"name": request.name})) + .send() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + Ok(tonic::Response::new(RenameFolderResponse::default())) + } + + async fn move_playlist( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + let request = request.into_inner(); + let url = format!("{}/playlists/{}", rockbox_url(), request.playlist_id); + let client = reqwest::Client::new(); + client + .put(&url) + .json(&serde_json::json!({"folder_id": request.folder_id})) + .send() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + Ok(tonic::Response::new(MovePlaylistResponse::default())) + } + + async fn move_folder( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + let request = request.into_inner(); + let url = format!("{}/folders/{}", rockbox_url(), request.folder_id); + let client = reqwest::Client::new(); + client + .put(&url) + .json(&serde_json::json!({"parent_id": request.parent_id})) + .send() + .await + .map_err(|e| tonic::Status::internal(e.to_string()))?; + Ok(tonic::Response::new(MoveFolderResponse::default())) + } } diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index 71bda3e8593..60cd4865c18 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -9,6 +9,7 @@ crate-type = ["staticlib"] [dependencies] anyhow = "1.0.89" async-std = {version = "1.13.0", features = ["unstable"]} +cuid = "1.3.3" futures-util = "0.3.31" lazy_static = "1.5.0" local-ip-addr = "0.1.1" @@ -16,6 +17,7 @@ md5 = "0.7.0" owo-colors = "4.0.0" queryst = "3.0.0" rand = "0.8.5" +chrono = {version = "0.4.38", features = ["serde"]} reqwest = {version = "0.12.5", features = ["blocking", "rustls-tls"], default-features = false} rockbox-chromecast = {path = "../chromecast"} rockbox-discovery = {path = "../discovery"} diff --git a/crates/server/src/handlers/folders.rs b/crates/server/src/handlers/folders.rs new file mode 100644 index 00000000000..4c2277f9dd2 --- /dev/null +++ b/crates/server/src/handlers/folders.rs @@ -0,0 +1,69 @@ +use crate::http::{Context, Request, Response}; +use anyhow::Error; +use cuid::cuid1; +use rockbox_library::{entity, repo}; +use rockbox_types::{Folder, FolderUpdate}; +use serde_json::json; + +pub async fn create_folder(ctx: &Context, req: &Request, res: &mut Response) -> Result<(), Error> { + if req.body.is_none() { + res.set_status(400); + return Ok(()); + } + let body = req.body.as_ref().unwrap(); + let folder: Folder = serde_json::from_str(body)?; + let id = repo::folder::save( + ctx.pool.clone(), + entity::folder::Folder { + id: cuid1()?, + name: folder.name, + parent_id: folder.parent_id, + created_at: chrono::Utc::now(), + updated_at: chrono::Utc::now(), + }, + ) + .await?; + res.json(&json!({ "id": id })); + Ok(()) +} + +pub async fn get_folder(ctx: &Context, req: &Request, res: &mut Response) -> Result<(), Error> { + let folder = repo::folder::find(ctx.pool.clone(), &req.params[0]).await?; + res.json(&folder); + Ok(()) +} + +pub async fn get_folders(ctx: &Context, req: &Request, res: &mut Response) -> Result<(), Error> { + let parent_id = req.query_params.get("parent_id"); + let parent_id = parent_id.map(|s| s.as_str().unwrap()); + let folders = repo::folder::find_by_parent(ctx.pool.clone(), parent_id).await?; + res.json(&folders); + Ok(()) +} + +pub async fn update_folder(ctx: &Context, req: &Request, res: &mut Response) -> Result<(), Error> { + if req.body.is_none() { + res.set_status(400); + return Ok(()); + } + let body = req.body.as_ref().unwrap(); + let folder: FolderUpdate = serde_json::from_str(body)?; + repo::folder::update( + ctx.pool.clone(), + entity::folder::Folder { + id: req.params[0].clone(), + name: folder.name.unwrap_or_default(), + parent_id: folder.parent_id, + ..Default::default() + }, + ) + .await?; + res.json(&json!({ "id": req.params[0] })); + Ok(()) +} + +pub async fn delete_folder(ctx: &Context, req: &Request, res: &mut Response) -> Result<(), Error> { + repo::folder::delete(ctx.pool.clone(), &req.params[0]).await?; + res.json(&json!({ "id": req.params[0] })); + Ok(()) +} diff --git a/crates/server/src/handlers/mod.rs b/crates/server/src/handlers/mod.rs index 6d4170d3a90..2891d4bd73e 100644 --- a/crates/server/src/handlers/mod.rs +++ b/crates/server/src/handlers/mod.rs @@ -3,6 +3,7 @@ pub mod artists; pub mod browse; pub mod devices; pub mod docs; +pub mod folders; pub mod player; pub mod playlists; pub mod search; @@ -60,6 +61,15 @@ async_handler!(playlists, get_playlist_tracks); async_handler!(playlists, insert_tracks); async_handler!(playlists, remove_tracks); async_handler!(playlists, get_playlist); +async_handler!(playlists, get_playlists); +async_handler!(playlists, delete_playlist); +async_handler!(playlists, update_playlist); +async_handler!(playlists, play_playlist); +async_handler!(folders, create_folder); +async_handler!(folders, get_folder); +async_handler!(folders, get_folders); +async_handler!(folders, update_folder); +async_handler!(folders, delete_folder); async_handler!(tracks, get_tracks); async_handler!(tracks, get_track); async_handler!(system, get_rockbox_version); diff --git a/crates/server/src/handlers/playlists.rs b/crates/server/src/handlers/playlists.rs index 59b5de71dc5..1dd1a06232d 100644 --- a/crates/server/src/handlers/playlists.rs +++ b/crates/server/src/handlers/playlists.rs @@ -6,22 +6,23 @@ use anyhow::Error; use local_ip_addr::get_local_ip_address; use rand::seq::SliceRandom; use rockbox_graphql::read_files; -use rockbox_library::repo; +use rockbox_library::{entity, repo}; use rockbox_network::download_tracks; +use rockbox_sys::types::mp3_entry::Mp3Entry; use rockbox_sys::{ self as rb, types::{playlist_amount::PlaylistAmount, playlist_info::PlaylistInfo}, PLAYLIST_INSERT_LAST, PLAYLIST_INSERT_LAST_SHUFFLED, }; use rockbox_traits::types::track::Track; -use rockbox_types::{DeleteTracks, InsertTracks, NewPlaylist, StatusCode}; +use rockbox_types::{DeleteTracks, InsertTracks, NewPlaylist, PlaylistUpdate, StatusCode}; +use serde_json::json; pub async fn create_playlist( - _ctx: &Context, + ctx: &Context, req: &Request, res: &mut Response, ) -> Result<(), Error> { - let player_mutex = PLAYER_MUTEX.lock().unwrap(); if req.body.is_none() { res.set_status(400); return Ok(()); @@ -29,12 +30,57 @@ pub async fn create_playlist( let body = req.body.as_ref().unwrap(); let mut new_playlist: NewPlaylist = serde_json::from_str(body).unwrap(); + if let Some(playlist_name) = new_playlist.name.as_ref() { + if playlist_name.is_empty() { + res.set_status(400); + return Ok(()); + } + let playlist_id = repo::playlist::save( + ctx.pool.clone(), + entity::playlist::Playlist { + id: cuid::cuid1()?, + name: playlist_name.clone(), + folder_id: new_playlist.folder_id, + created_at: chrono::Utc::now(), + updated_at: chrono::Utc::now(), + ..Default::default() + }, + ) + .await?; + + let tracks = download_tracks(new_playlist.tracks).await?; + for (position, track_path) in tracks.iter().enumerate() { + let hash = format!("{:x}", md5::compute(track_path.as_bytes())); + let track = repo::track::find_by_md5(ctx.pool.clone(), &hash).await?; + if track.is_none() { + continue; + } + repo::playlist_tracks::save( + ctx.pool.clone(), + entity::playlist_tracks::PlaylistTracks { + id: cuid::cuid1()?, + playlist_id: playlist_id.clone(), + track_id: track.unwrap().id, + position: position as u32, + created_at: chrono::Utc::now(), + }, + ) + .await?; + } + + res.set_status(200); + res.text("0"); + return Ok(()); + } + if new_playlist.tracks.is_empty() { return Ok(()); } new_playlist.tracks = download_tracks(new_playlist.tracks).await?; + let player_mutex = PLAYER_MUTEX.lock().unwrap(); + let dir = new_playlist.tracks[0].clone(); let dir_parts: Vec<_> = dir.split('/').collect(); let dir = dir_parts[0..dir_parts.len() - 1].join("/"); @@ -143,10 +189,37 @@ pub async fn resume_track( } pub async fn get_playlist_tracks( - _ctx: &Context, - _req: &Request, + ctx: &Context, + req: &Request, res: &mut Response, ) -> Result<(), Error> { + let playlist_id = &req.params[0]; + + if playlist_id != "current" { + let tracks = repo::playlist_tracks::find_by_playlist(ctx.pool.clone(), playlist_id).await?; + let mut entries: Vec = vec![]; + + for track in tracks { + entries.push(Mp3Entry { + id: Some(track.id), + path: track.path, + title: track.title, + artist: track.artist, + album: track.album, + length: track.length as u64, + tracknum: track.track_number.unwrap_or_default() as i32, + album_art: track.album_art, + artist_id: Some(track.artist_id), + album_id: Some(track.album_id), + filesize: track.filesize as u64, + frequency: track.frequency as u64, + ..Default::default() + }); + } + res.json(&entries); + return Ok(()); + } + let player_mutex = PLAYER_MUTEX.lock().unwrap(); let mut entries = vec![]; let amount = rb::playlist::amount(); @@ -164,6 +237,45 @@ pub async fn get_playlist_tracks( } pub async fn insert_tracks(ctx: &Context, req: &Request, res: &mut Response) -> Result<(), Error> { + let playlist_id = &req.params[0]; + if playlist_id != "current" { + let req_body = req.body.as_ref().unwrap(); + let mut tracklist: InsertTracks = serde_json::from_str(&req_body)?; + let tracks = download_tracks(tracklist.tracks).await?; + + if let Some(dir) = &tracklist.directory { + tracklist.tracks = read_files(dir.clone()).await?; + } + + let playlist = repo::playlist::find(ctx.pool.clone(), playlist_id).await?; + if playlist.is_none() { + res.set_status(404); + return Ok(()); + } + + for track_path in tracks { + let current_tracks = + repo::playlist_tracks::find_by_playlist(ctx.pool.clone(), playlist_id).await?; + let hash = format!("{:x}", md5::compute(track_path.as_bytes())); + + if let Some(track) = repo::track::find_by_md5(ctx.pool.clone(), &hash).await? { + repo::playlist_tracks::save( + ctx.pool.clone(), + entity::playlist_tracks::PlaylistTracks { + id: cuid::cuid1()?, + playlist_id: playlist_id.clone(), + track_id: track.id, + position: current_tracks.len() as u32, + created_at: chrono::Utc::now(), + }, + ) + .await?; + } + } + res.text("0"); + return Ok(()); + } + let player_mutex = PLAYER_MUTEX.lock().unwrap(); let req_body = req.body.as_ref().unwrap(); let mut tracklist: InsertTracks = serde_json::from_str(&req_body).unwrap(); @@ -262,6 +374,24 @@ pub async fn insert_tracks(ctx: &Context, req: &Request, res: &mut Response) -> } pub async fn remove_tracks(ctx: &Context, req: &Request, res: &mut Response) -> Result<(), Error> { + let playlist_id = &req.params[0]; + if playlist_id != "current" { + let req_body = req.body.as_ref().unwrap(); + let params = serde_json::from_str::(&req_body)?; + + if params.positions.is_empty() { + res.text("0"); + return Ok(()); + } + + for position in params.positions { + repo::playlist_tracks::delete_track_at(ctx.pool.clone(), playlist_id, position as u32) + .await?; + } + res.text("0"); + return Ok(()); + } + let player_mutex = PLAYER_MUTEX.lock().unwrap(); let player = ctx.player.lock().unwrap(); @@ -332,7 +462,45 @@ pub async fn current_playlist( Ok(()) } -pub async fn get_playlist(ctx: &Context, _req: &Request, res: &mut Response) -> Result<(), Error> { +pub async fn get_playlist(ctx: &Context, req: &Request, res: &mut Response) -> Result<(), Error> { + let playlist_id = &req.params[0]; + if playlist_id != "current" { + let playlist = repo::playlist::find(ctx.pool.clone(), playlist_id).await?; + if playlist.is_none() { + res.set_status(404); + return Ok(()); + } + + let playlist = playlist.unwrap(); + + let tracks = repo::playlist_tracks::find_by_playlist(ctx.pool.clone(), playlist_id).await?; + let mut entries: Vec = vec![]; + for track in tracks.clone() { + let mut entry = rb::metadata::get_metadata(-1, &track.path); + entry.album_art = track.album_art; + entry.album_id = Some(track.album_id); + entry.artist_id = Some(track.artist_id); + entry.genre_id = Some(track.genre_id); + entry.id = Some(track.id); + entries.push(entry); + } + + let result = PlaylistInfo { + id: Some(playlist.id), + amount: tracks.len() as i32, + entries, + name: Some(playlist.name), + folder_id: playlist.folder_id, + image: playlist.image, + description: playlist.description, + created_at: Some(playlist.created_at.to_rfc3339()), + updated_at: Some(playlist.updated_at.to_rfc3339()), + ..Default::default() + }; + res.json(&result); + return Ok(()); + } + let player_mutex = PLAYER_MUTEX.lock().unwrap(); let mut player = ctx.player.lock().unwrap(); @@ -399,3 +567,106 @@ pub async fn get_playlist(ctx: &Context, _req: &Request, res: &mut Response) -> drop(player_mutex); Ok(()) } + +pub async fn delete_playlist( + ctx: &Context, + req: &Request, + res: &mut Response, +) -> Result<(), Error> { + let playlist_id = &req.params[0]; + repo::playlist::delete(ctx.pool.clone(), playlist_id).await?; + repo::playlist_tracks::delete_by_playlist(ctx.pool.clone(), playlist_id).await?; + res.json(&json!({ "id": playlist_id })); + Ok(()) +} + +pub async fn update_playlist( + ctx: &Context, + req: &Request, + res: &mut Response, +) -> Result<(), Error> { + let playlist_id = &req.params[0]; + if req.body.is_none() { + res.set_status(400); + return Ok(()); + } + + let body = req.body.as_ref().unwrap(); + let playlist: PlaylistUpdate = serde_json::from_str(body)?; + repo::playlist::update( + ctx.pool.clone(), + entity::playlist::Playlist { + id: playlist_id.clone(), + name: playlist.name.unwrap_or_default(), + folder_id: playlist.folder_id, + ..Default::default() + }, + ) + .await?; + + res.json(&json!({ "id": playlist_id })); + Ok(()) +} + +pub async fn get_playlists(ctx: &Context, req: &Request, res: &mut Response) -> Result<(), Error> { + let folder_id = req.query_params.get("folder_id"); + let folder_id = folder_id.map(|f| f.as_str().unwrap()); + let playlist = repo::playlist::find_by_folder(ctx.pool.clone(), folder_id).await?; + res.json(&playlist); + Ok(()) +} + +pub async fn play_playlist(ctx: &Context, req: &Request, res: &mut Response) -> Result<(), Error> { + let playlist_id = &req.params[0]; + let tracks = repo::playlist_tracks::find_by_playlist(ctx.pool.clone(), playlist_id).await?; + + if tracks.is_empty() { + res.set_status(200); + return Ok(()); + } + + let player_mutex = PLAYER_MUTEX.lock().unwrap(); + + let dir = tracks[0].clone(); + let dir = dir.path.clone(); + let dir_parts: Vec<_> = dir.split('/').collect(); + let dir = dir_parts[0..dir_parts.len() - 1].join("/"); + let status = rb::playlist::create(&dir, None); + if status == -1 { + res.set_status(500); + return Ok(()); + } + rb::playlist::build_playlist( + tracks.iter().map(|t| t.path.as_str()).collect(), + 0, + tracks.len() as i32, + ); + + let shuffle = match req.query_params.get("shuffle") { + Some(shuffle) => shuffle.as_str().unwrap_or("0").parse().unwrap_or(0), + None => 0, + }; + + if shuffle == 1 { + let seed = rb::system::current_tick(); + rb::playlist::shuffle(seed as i32, 0); + } + + let start_index = match req.query_params.get("start_index") { + Some(start_index) => start_index.as_str().unwrap_or("0").parse().unwrap_or(0), + None => 0, + }; + let elapsed = match req.query_params.get("elapsed") { + Some(elapsed) => elapsed.as_str().unwrap_or("0").parse().unwrap_or(0), + None => 0, + }; + let offset = match req.query_params.get("offset") { + Some(offset) => offset.as_str().unwrap_or("0").parse().unwrap_or(0), + None => 0, + }; + rb::playlist::start(start_index, elapsed, offset); + + res.set_status(200); + drop(player_mutex); + Ok(()) +} diff --git a/crates/server/src/lib.rs b/crates/server/src/lib.rs index e86ef894e9b..3f789d5296c 100644 --- a/crates/server/src/lib.rs +++ b/crates/server/src/lib.rs @@ -82,6 +82,7 @@ pub extern "C" fn start_server() { app.put("/player/volume", adjust_volume); app.post("/playlists", create_playlist); + app.get("/playlists", get_playlists); app.put("/playlists/start", start_playlist); app.put("/playlists/shuffle", shuffle_playlist); app.get("/playlists/amount", get_playlist_amount); @@ -91,6 +92,15 @@ pub extern "C" fn start_server() { app.post("/playlists/:id/tracks", insert_tracks); app.delete("/playlists/:id/tracks", remove_tracks); app.get("/playlists/:id", get_playlist); + app.put("/playlists/:id", update_playlist); + app.delete("/playlists/:id", delete_playlist); + app.put("/playlists/:id/play", play_playlist); + + app.post("/folders", create_folder); + app.get("/folders", get_folders); + app.get("/folders/:id", get_folder); + app.put("/folders/:id", update_folder); + app.delete("/folders/:id", delete_folder); app.get("/tracks", get_tracks); app.get("/tracks/:id", get_track); @@ -346,6 +356,7 @@ pub extern "C" fn start_broker() { .into_iter() .map(|t| t.into()) .collect(), + ..Default::default() }); thread::sleep(std::time::Duration::from_millis(100)); diff --git a/crates/sys/src/types/playlist_info.rs b/crates/sys/src/types/playlist_info.rs index 8f867a326e0..e4aa222f76b 100644 --- a/crates/sys/src/types/playlist_info.rs +++ b/crates/sys/src/types/playlist_info.rs @@ -24,6 +24,13 @@ pub struct PlaylistInfo { pub control_filename: String, // char control_filename[sizeof(PLAYLIST_CONTROL_FILE) + 8] pub dcfrefs_handle: i32, // int dcfrefs_handle pub entries: Vec, + pub name: Option, + pub created_at: Option, + pub updated_at: Option, + pub folder_id: Option, + pub image: Option, + pub description: Option, + pub id: Option, } impl From for PlaylistInfo { @@ -56,6 +63,7 @@ impl From for PlaylistInfo { }, dcfrefs_handle: info.dcfrefs_handle, entries: vec![], + ..Default::default() } } } diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 264d1b7c3d2..f9b1fbb279f 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -11,6 +11,7 @@ pub mod device; pub struct NewPlaylist { pub name: Option, pub tracks: Vec, + pub folder_id: Option, } #[derive(Debug, Serialize, Deserialize)] @@ -68,3 +69,32 @@ pub struct ReplaygainSettings { pub peak: i32, pub clip: i32, } + +#[derive(Debug, Serialize, Deserialize)] +pub struct Folder { + pub name: String, + pub parent_id: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct FolderUpdate { + pub name: Option, + pub parent_id: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct PlaylistUpdate { + pub name: Option, + pub folder_id: Option, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Playlist { + pub id: String, + pub name: String, + pub created_at: u64, + pub updated_at: u64, + pub folder_id: Option, + pub image: Option, + pub description: Option, +} diff --git a/gtk/proto/rockbox/v1alpha1/playlist.proto b/gtk/proto/rockbox/v1alpha1/playlist.proto index 90b5c8d3763..598f2712766 100644 --- a/gtk/proto/rockbox/v1alpha1/playlist.proto +++ b/gtk/proto/rockbox/v1alpha1/playlist.proto @@ -70,18 +70,21 @@ message SyncRequest {} message SyncResponse {} -message RemoveAllTracksRequest {} +message RemoveAllTracksRequest { + optional string playlist_id = 1; +} message RemoveAllTracksResponse {} message RemoveTracksRequest { repeated int32 positions = 1; + optional string playlist_id = 2; } message RemoveTracksResponse {} message CreatePlaylistRequest { - string name = 1; + optional string name = 1; repeated string tracks = 2; } @@ -121,6 +124,7 @@ message InsertAlbumRequest { int32 position = 1; string album_id = 2; optional bool shuffle = 3; + optional string playlist_id = 4; } message InsertAlbumResponse {} @@ -129,6 +133,7 @@ message InsertArtistTracksRequest { int32 position = 1; string artist_id = 2; optional bool shuffle = 3; + optional string playlist_id = 4; } message InsertArtistTracksResponse {} @@ -139,6 +144,97 @@ message ShufflePlaylistRequest { message ShufflePlaylistResponse {} +message GetPlaylistRequest { + string playlist_id = 1; +} + +message GetPlaylistResponse { + string id = 1; + string name = 2; + optional string folder_id = 3; + optional string image = 4; + optional string description = 5; + int32 amount = 6; + string created_at = 7; + string updated_at = 8; + repeated rockbox.v1alpha1.CurrentTrackResponse tracks = 9; +} + +message CreateFolderRequest { + string name = 1; + optional string parent_id = 2; +} + +message CreateFolderResponse { + string folder_id = 1; +} + +message GetFolderRequest { + string id = 1; +} + +message GetFolderResponse { + string id = 1; + string name = 2; + optional string parent_id = 3; +} + +message GetFoldersRequest { + optional string parent_id = 1; +} + +message GetFoldersResponse { + repeated rockbox.v1alpha1.GetFolderResponse folders = 1; +} + +message RemoveFolderRequest { + string id = 1; +} + +message RemoveFolderResponse {} + +message RemovePlaylistRequest { + string id = 1; +} + +message RemovePlaylistResponse {} + +message RenamePlaylistRequest { + string id = 1; + string name = 2; +} + +message RenamePlaylistResponse {} + +message RenameFolderRequest { + string id = 1; + string name = 2; +} + +message RenameFolderResponse {} + +message MovePlaylistRequest { + string playlist_id = 1; + string folder_id = 2; +} + +message MovePlaylistResponse {} + +message MoveFolderRequest { + string folder_id = 1; + string parent_id = 2; +} + +message MoveFolderResponse {} + +message GetPlaylistsRequest { + optional string folder_id = 1; +} + +message GetPlaylistsResponse { + repeated rockbox.v1alpha1.GetPlaylistResponse playlists = 1; +} + service PlaylistService { rpc GetCurrent(GetCurrentRequest) returns (GetCurrentResponse) {} rpc GetResumeInfo(GetResumeInfoRequest) returns (GetResumeInfoResponse) {} @@ -160,4 +256,15 @@ service PlaylistService { rpc InsertAlbum(InsertAlbumRequest) returns (InsertAlbumResponse) {} rpc InsertArtistTracks(InsertArtistTracksRequest) returns (InsertArtistTracksResponse) {} rpc ShufflePlaylist(ShufflePlaylistRequest) returns (ShufflePlaylistResponse) {} + rpc GetPlaylist(GetPlaylistRequest) returns (GetPlaylistResponse) {} + rpc GetPlaylists(GetPlaylistsRequest) returns (GetPlaylistsResponse) {} + rpc CreateFolder(CreateFolderRequest) returns (CreateFolderResponse) {} + rpc GetFolder(GetFolderRequest) returns (GetFolderResponse) {} + rpc GetFolders(GetFoldersRequest) returns (GetFoldersResponse) {} + rpc RemoveFolder(RemoveFolderRequest) returns (RemoveFolderResponse) {} + rpc RemovePlaylist(RemovePlaylistRequest) returns (RemovePlaylistResponse) {} + rpc RenamePlaylist(RenamePlaylistRequest) returns (RenamePlaylistResponse) {} + rpc RenameFolder(RenameFolderRequest) returns (RenameFolderResponse) {} + rpc MovePlaylist(MovePlaylistRequest) returns (MovePlaylistResponse) {} + rpc MoveFolder(MoveFolderRequest) returns (MoveFolderResponse) {} } diff --git a/gtk/src/api/rockbox.v1alpha1.rs b/gtk/src/api/rockbox.v1alpha1.rs index 2dc76196977..362ec36547e 100644 --- a/gtk/src/api/rockbox.v1alpha1.rs +++ b/gtk/src/api/rockbox.v1alpha1.rs @@ -4316,21 +4316,26 @@ pub struct StartResponse {} pub struct SyncRequest {} #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct SyncResponse {} -#[derive(Clone, Copy, PartialEq, ::prost::Message)] -pub struct RemoveAllTracksRequest {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemoveAllTracksRequest { + #[prost(string, optional, tag = "1")] + pub playlist_id: ::core::option::Option<::prost::alloc::string::String>, +} #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct RemoveAllTracksResponse {} #[derive(Clone, PartialEq, ::prost::Message)] pub struct RemoveTracksRequest { #[prost(int32, repeated, tag = "1")] pub positions: ::prost::alloc::vec::Vec, + #[prost(string, optional, tag = "2")] + pub playlist_id: ::core::option::Option<::prost::alloc::string::String>, } #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct RemoveTracksResponse {} #[derive(Clone, PartialEq, ::prost::Message)] pub struct CreatePlaylistRequest { - #[prost(string, tag = "1")] - pub name: ::prost::alloc::string::String, + #[prost(string, optional, tag = "1")] + pub name: ::core::option::Option<::prost::alloc::string::String>, #[prost(string, repeated, tag = "2")] pub tracks: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, } @@ -4388,6 +4393,8 @@ pub struct InsertAlbumRequest { pub album_id: ::prost::alloc::string::String, #[prost(bool, optional, tag = "3")] pub shuffle: ::core::option::Option, + #[prost(string, optional, tag = "4")] + pub playlist_id: ::core::option::Option<::prost::alloc::string::String>, } #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct InsertAlbumResponse {} @@ -4399,6 +4406,8 @@ pub struct InsertArtistTracksRequest { pub artist_id: ::prost::alloc::string::String, #[prost(bool, optional, tag = "3")] pub shuffle: ::core::option::Option, + #[prost(string, optional, tag = "4")] + pub playlist_id: ::core::option::Option<::prost::alloc::string::String>, } #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct InsertArtistTracksResponse {} @@ -4409,6 +4418,128 @@ pub struct ShufflePlaylistRequest { } #[derive(Clone, Copy, PartialEq, ::prost::Message)] pub struct ShufflePlaylistResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPlaylistRequest { + #[prost(string, tag = "1")] + pub playlist_id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPlaylistResponse { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, + #[prost(string, optional, tag = "3")] + pub folder_id: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "4")] + pub image: ::core::option::Option<::prost::alloc::string::String>, + #[prost(string, optional, tag = "5")] + pub description: ::core::option::Option<::prost::alloc::string::String>, + #[prost(int32, tag = "6")] + pub amount: i32, + #[prost(string, tag = "7")] + pub created_at: ::prost::alloc::string::String, + #[prost(string, tag = "8")] + pub updated_at: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "9")] + pub tracks: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CreateFolderRequest { + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, + #[prost(string, optional, tag = "2")] + pub parent_id: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CreateFolderResponse { + #[prost(string, tag = "1")] + pub folder_id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetFolderRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetFolderResponse { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, + #[prost(string, optional, tag = "3")] + pub parent_id: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetFoldersRequest { + #[prost(string, optional, tag = "1")] + pub parent_id: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetFoldersResponse { + #[prost(message, repeated, tag = "1")] + pub folders: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemoveFolderRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct RemoveFolderResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RemovePlaylistRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct RemovePlaylistResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RenamePlaylistRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct RenamePlaylistResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct RenameFolderRequest { + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub name: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct RenameFolderResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MovePlaylistRequest { + #[prost(string, tag = "1")] + pub playlist_id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub folder_id: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MovePlaylistResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MoveFolderRequest { + #[prost(string, tag = "1")] + pub folder_id: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub parent_id: ::prost::alloc::string::String, +} +#[derive(Clone, Copy, PartialEq, ::prost::Message)] +pub struct MoveFolderResponse {} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPlaylistsRequest { + #[prost(string, optional, tag = "1")] + pub folder_id: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPlaylistsResponse { + #[prost(message, repeated, tag = "1")] + pub playlists: ::prost::alloc::vec::Vec, +} /// Generated client implementations. pub mod playlist_service_client { #![allow( @@ -5020,79 +5151,365 @@ pub mod playlist_service_client { ); self.inner.unary(req, path, codec).await } - } -} -/// Generated server implementations. -pub mod playlist_service_server { - #![allow( - unused_variables, - dead_code, - missing_docs, - clippy::wildcard_imports, - clippy::let_unit_value, - )] - use tonic::codegen::*; - /// Generated trait containing gRPC methods that should be implemented for use with PlaylistServiceServer. - #[async_trait] - pub trait PlaylistService: std::marker::Send + std::marker::Sync + 'static { - async fn get_current( - &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; - async fn get_resume_info( - &self, - request: tonic::Request, + pub async fn get_playlist( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn get_track_info( - &self, - request: tonic::Request, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/GetPlaylist", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "GetPlaylist"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn get_playlists( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn get_first_index( - &self, - request: tonic::Request, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/GetPlaylists", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "GetPlaylists"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn create_folder( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn get_display_index( - &self, - request: tonic::Request, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/CreateFolder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "CreateFolder"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn get_folder( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn amount( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - async fn playlist_resume( - &self, - request: tonic::Request, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/GetFolder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "GetFolder"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn get_folders( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn resume_track( - &self, - request: tonic::Request, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/GetFolders", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "GetFolders"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn remove_folder( + &mut self, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, - >; - async fn set_modified( - &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/RemoveFolder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "RemoveFolder"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn remove_playlist( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/RemovePlaylist", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "RemovePlaylist"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn rename_playlist( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/RenamePlaylist", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "RenamePlaylist"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn rename_folder( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/RenameFolder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "RenameFolder"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn move_playlist( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/MovePlaylist", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "MovePlaylist"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn move_folder( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/rockbox.v1alpha1.PlaylistService/MoveFolder", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("rockbox.v1alpha1.PlaylistService", "MoveFolder"), + ); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated server implementations. +pub mod playlist_service_server { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with PlaylistServiceServer. + #[async_trait] + pub trait PlaylistService: std::marker::Send + std::marker::Sync + 'static { + async fn get_current( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_resume_info( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_track_info( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_first_index( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_display_index( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn amount( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn playlist_resume( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn resume_track( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn set_modified( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, tonic::Status, >; async fn start( @@ -5166,6 +5583,83 @@ pub mod playlist_service_server { tonic::Response, tonic::Status, >; + async fn get_playlist( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_playlists( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn create_folder( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_folder( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_folders( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn remove_folder( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn remove_playlist( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn rename_playlist( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn rename_folder( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn move_playlist( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn move_folder( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct PlaylistServiceServer { @@ -5245,23 +5739,522 @@ pub mod playlist_service_server { match req.uri().path() { "/rockbox.v1alpha1.PlaylistService/GetCurrent" => { #[allow(non_camel_case_types)] - struct GetCurrentSvc(pub Arc); + struct GetCurrentSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for GetCurrentSvc { + type Response = super::GetCurrentResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_current(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetCurrentSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/GetResumeInfo" => { + #[allow(non_camel_case_types)] + struct GetResumeInfoSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for GetResumeInfoSvc { + type Response = super::GetResumeInfoResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_resume_info(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetResumeInfoSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/GetTrackInfo" => { + #[allow(non_camel_case_types)] + struct GetTrackInfoSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for GetTrackInfoSvc { + type Response = super::GetTrackInfoResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_track_info(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetTrackInfoSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/GetFirstIndex" => { + #[allow(non_camel_case_types)] + struct GetFirstIndexSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for GetFirstIndexSvc { + type Response = super::GetFirstIndexResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_first_index(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetFirstIndexSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/GetDisplayIndex" => { + #[allow(non_camel_case_types)] + struct GetDisplayIndexSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for GetDisplayIndexSvc { + type Response = super::GetDisplayIndexResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_display_index(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetDisplayIndexSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/Amount" => { + #[allow(non_camel_case_types)] + struct AmountSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for AmountSvc { + type Response = super::AmountResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::amount(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = AmountSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/PlaylistResume" => { + #[allow(non_camel_case_types)] + struct PlaylistResumeSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for PlaylistResumeSvc { + type Response = super::PlaylistResumeResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::playlist_resume(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = PlaylistResumeSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/ResumeTrack" => { + #[allow(non_camel_case_types)] + struct ResumeTrackSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for ResumeTrackSvc { + type Response = super::ResumeTrackResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::resume_track(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ResumeTrackSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/SetModified" => { + #[allow(non_camel_case_types)] + struct SetModifiedSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService + for SetModifiedSvc { + type Response = super::SetModifiedResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::set_modified(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SetModifiedSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/Start" => { + #[allow(non_camel_case_types)] + struct StartSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService for StartSvc { + type Response = super::StartResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::start(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = StartSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/Sync" => { + #[allow(non_camel_case_types)] + struct SyncSvc(pub Arc); + impl< + T: PlaylistService, + > tonic::server::UnaryService for SyncSvc { + type Response = super::SyncResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::sync(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SyncSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/rockbox.v1alpha1.PlaylistService/RemoveAllTracks" => { + #[allow(non_camel_case_types)] + struct RemoveAllTracksSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for GetCurrentSvc { - type Response = super::GetCurrentResponse; + > tonic::server::UnaryService + for RemoveAllTracksSvc { + type Response = super::RemoveAllTracksResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::get_current(&inner, request).await + ::remove_all_tracks(&inner, request) + .await }; Box::pin(fut) } @@ -5272,7 +6265,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = GetCurrentSvc(inner); + let method = RemoveAllTracksSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5288,26 +6281,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/GetResumeInfo" => { + "/rockbox.v1alpha1.PlaylistService/RemoveTracks" => { #[allow(non_camel_case_types)] - struct GetResumeInfoSvc(pub Arc); + struct RemoveTracksSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for GetResumeInfoSvc { - type Response = super::GetResumeInfoResponse; + > tonic::server::UnaryService + for RemoveTracksSvc { + type Response = super::RemoveTracksResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::get_resume_info(&inner, request) - .await + ::remove_tracks(&inner, request).await }; Box::pin(fut) } @@ -5318,7 +6310,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = GetResumeInfoSvc(inner); + let method = RemoveTracksSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5334,25 +6326,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/GetTrackInfo" => { + "/rockbox.v1alpha1.PlaylistService/CreatePlaylist" => { #[allow(non_camel_case_types)] - struct GetTrackInfoSvc(pub Arc); + struct CreatePlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for GetTrackInfoSvc { - type Response = super::GetTrackInfoResponse; + > tonic::server::UnaryService + for CreatePlaylistSvc { + type Response = super::CreatePlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::get_track_info(&inner, request) + ::create_playlist(&inner, request) .await }; Box::pin(fut) @@ -5364,7 +6356,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = GetTrackInfoSvc(inner); + let method = CreatePlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5380,26 +6372,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/GetFirstIndex" => { + "/rockbox.v1alpha1.PlaylistService/InsertTracks" => { #[allow(non_camel_case_types)] - struct GetFirstIndexSvc(pub Arc); + struct InsertTracksSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for GetFirstIndexSvc { - type Response = super::GetFirstIndexResponse; + > tonic::server::UnaryService + for InsertTracksSvc { + type Response = super::InsertTracksResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::get_first_index(&inner, request) - .await + ::insert_tracks(&inner, request).await }; Box::pin(fut) } @@ -5410,7 +6401,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = GetFirstIndexSvc(inner); + let method = InsertTracksSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5426,25 +6417,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/GetDisplayIndex" => { + "/rockbox.v1alpha1.PlaylistService/InsertDirectory" => { #[allow(non_camel_case_types)] - struct GetDisplayIndexSvc(pub Arc); + struct InsertDirectorySvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for GetDisplayIndexSvc { - type Response = super::GetDisplayIndexResponse; + > tonic::server::UnaryService + for InsertDirectorySvc { + type Response = super::InsertDirectoryResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::get_display_index(&inner, request) + ::insert_directory(&inner, request) .await }; Box::pin(fut) @@ -5456,7 +6447,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = GetDisplayIndexSvc(inner); + let method = InsertDirectorySvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5472,25 +6463,26 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/Amount" => { + "/rockbox.v1alpha1.PlaylistService/InsertPlaylist" => { #[allow(non_camel_case_types)] - struct AmountSvc(pub Arc); + struct InsertPlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for AmountSvc { - type Response = super::AmountResponse; + > tonic::server::UnaryService + for InsertPlaylistSvc { + type Response = super::InsertPlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::amount(&inner, request).await + ::insert_playlist(&inner, request) + .await }; Box::pin(fut) } @@ -5501,7 +6493,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = AmountSvc(inner); + let method = InsertPlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5517,26 +6509,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/PlaylistResume" => { + "/rockbox.v1alpha1.PlaylistService/InsertAlbum" => { #[allow(non_camel_case_types)] - struct PlaylistResumeSvc(pub Arc); + struct InsertAlbumSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for PlaylistResumeSvc { - type Response = super::PlaylistResumeResponse; + > tonic::server::UnaryService + for InsertAlbumSvc { + type Response = super::InsertAlbumResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::playlist_resume(&inner, request) - .await + ::insert_album(&inner, request).await }; Box::pin(fut) } @@ -5547,7 +6538,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = PlaylistResumeSvc(inner); + let method = InsertAlbumSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5563,25 +6554,29 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/ResumeTrack" => { + "/rockbox.v1alpha1.PlaylistService/InsertArtistTracks" => { #[allow(non_camel_case_types)] - struct ResumeTrackSvc(pub Arc); + struct InsertArtistTracksSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for ResumeTrackSvc { - type Response = super::ResumeTrackResponse; + > tonic::server::UnaryService + for InsertArtistTracksSvc { + type Response = super::InsertArtistTracksResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::resume_track(&inner, request).await + ::insert_artist_tracks( + &inner, + request, + ) + .await }; Box::pin(fut) } @@ -5592,7 +6587,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = ResumeTrackSvc(inner); + let method = InsertArtistTracksSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5608,25 +6603,26 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/SetModified" => { + "/rockbox.v1alpha1.PlaylistService/ShufflePlaylist" => { #[allow(non_camel_case_types)] - struct SetModifiedSvc(pub Arc); + struct ShufflePlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for SetModifiedSvc { - type Response = super::SetModifiedResponse; + > tonic::server::UnaryService + for ShufflePlaylistSvc { + type Response = super::ShufflePlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::set_modified(&inner, request).await + ::shuffle_playlist(&inner, request) + .await }; Box::pin(fut) } @@ -5637,7 +6633,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = SetModifiedSvc(inner); + let method = ShufflePlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5653,24 +6649,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/Start" => { + "/rockbox.v1alpha1.PlaylistService/GetPlaylist" => { #[allow(non_camel_case_types)] - struct StartSvc(pub Arc); + struct GetPlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService for StartSvc { - type Response = super::StartResponse; + > tonic::server::UnaryService + for GetPlaylistSvc { + type Response = super::GetPlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::start(&inner, request).await + ::get_playlist(&inner, request).await }; Box::pin(fut) } @@ -5681,7 +6678,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = StartSvc(inner); + let method = GetPlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5697,24 +6694,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/Sync" => { + "/rockbox.v1alpha1.PlaylistService/GetPlaylists" => { #[allow(non_camel_case_types)] - struct SyncSvc(pub Arc); + struct GetPlaylistsSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService for SyncSvc { - type Response = super::SyncResponse; + > tonic::server::UnaryService + for GetPlaylistsSvc { + type Response = super::GetPlaylistsResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::sync(&inner, request).await + ::get_playlists(&inner, request).await }; Box::pin(fut) } @@ -5725,7 +6723,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = SyncSvc(inner); + let method = GetPlaylistsSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5741,26 +6739,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/RemoveAllTracks" => { + "/rockbox.v1alpha1.PlaylistService/CreateFolder" => { #[allow(non_camel_case_types)] - struct RemoveAllTracksSvc(pub Arc); + struct CreateFolderSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for RemoveAllTracksSvc { - type Response = super::RemoveAllTracksResponse; + > tonic::server::UnaryService + for CreateFolderSvc { + type Response = super::CreateFolderResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::remove_all_tracks(&inner, request) - .await + ::create_folder(&inner, request).await }; Box::pin(fut) } @@ -5771,7 +6768,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = RemoveAllTracksSvc(inner); + let method = CreateFolderSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5787,25 +6784,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/RemoveTracks" => { + "/rockbox.v1alpha1.PlaylistService/GetFolder" => { #[allow(non_camel_case_types)] - struct RemoveTracksSvc(pub Arc); + struct GetFolderSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for RemoveTracksSvc { - type Response = super::RemoveTracksResponse; + > tonic::server::UnaryService + for GetFolderSvc { + type Response = super::GetFolderResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::remove_tracks(&inner, request).await + ::get_folder(&inner, request).await }; Box::pin(fut) } @@ -5816,7 +6813,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = RemoveTracksSvc(inner); + let method = GetFolderSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5832,26 +6829,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/CreatePlaylist" => { + "/rockbox.v1alpha1.PlaylistService/GetFolders" => { #[allow(non_camel_case_types)] - struct CreatePlaylistSvc(pub Arc); + struct GetFoldersSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for CreatePlaylistSvc { - type Response = super::CreatePlaylistResponse; + > tonic::server::UnaryService + for GetFoldersSvc { + type Response = super::GetFoldersResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::create_playlist(&inner, request) - .await + ::get_folders(&inner, request).await }; Box::pin(fut) } @@ -5862,7 +6858,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = CreatePlaylistSvc(inner); + let method = GetFoldersSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5878,25 +6874,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/InsertTracks" => { + "/rockbox.v1alpha1.PlaylistService/RemoveFolder" => { #[allow(non_camel_case_types)] - struct InsertTracksSvc(pub Arc); + struct RemoveFolderSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for InsertTracksSvc { - type Response = super::InsertTracksResponse; + > tonic::server::UnaryService + for RemoveFolderSvc { + type Response = super::RemoveFolderResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::insert_tracks(&inner, request).await + ::remove_folder(&inner, request).await }; Box::pin(fut) } @@ -5907,7 +6903,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = InsertTracksSvc(inner); + let method = RemoveFolderSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5923,25 +6919,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/InsertDirectory" => { + "/rockbox.v1alpha1.PlaylistService/RemovePlaylist" => { #[allow(non_camel_case_types)] - struct InsertDirectorySvc(pub Arc); + struct RemovePlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for InsertDirectorySvc { - type Response = super::InsertDirectoryResponse; + > tonic::server::UnaryService + for RemovePlaylistSvc { + type Response = super::RemovePlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::insert_directory(&inner, request) + ::remove_playlist(&inner, request) .await }; Box::pin(fut) @@ -5953,7 +6949,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = InsertDirectorySvc(inner); + let method = RemovePlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -5969,25 +6965,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/InsertPlaylist" => { + "/rockbox.v1alpha1.PlaylistService/RenamePlaylist" => { #[allow(non_camel_case_types)] - struct InsertPlaylistSvc(pub Arc); + struct RenamePlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for InsertPlaylistSvc { - type Response = super::InsertPlaylistResponse; + > tonic::server::UnaryService + for RenamePlaylistSvc { + type Response = super::RenamePlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::insert_playlist(&inner, request) + ::rename_playlist(&inner, request) .await }; Box::pin(fut) @@ -5999,7 +6995,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = InsertPlaylistSvc(inner); + let method = RenamePlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6015,25 +7011,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/InsertAlbum" => { + "/rockbox.v1alpha1.PlaylistService/RenameFolder" => { #[allow(non_camel_case_types)] - struct InsertAlbumSvc(pub Arc); + struct RenameFolderSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for InsertAlbumSvc { - type Response = super::InsertAlbumResponse; + > tonic::server::UnaryService + for RenameFolderSvc { + type Response = super::RenameFolderResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::insert_album(&inner, request).await + ::rename_folder(&inner, request).await }; Box::pin(fut) } @@ -6044,7 +7040,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = InsertAlbumSvc(inner); + let method = RenameFolderSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6060,29 +7056,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/InsertArtistTracks" => { + "/rockbox.v1alpha1.PlaylistService/MovePlaylist" => { #[allow(non_camel_case_types)] - struct InsertArtistTracksSvc(pub Arc); + struct MovePlaylistSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for InsertArtistTracksSvc { - type Response = super::InsertArtistTracksResponse; + > tonic::server::UnaryService + for MovePlaylistSvc { + type Response = super::MovePlaylistResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::insert_artist_tracks( - &inner, - request, - ) - .await + ::move_playlist(&inner, request).await }; Box::pin(fut) } @@ -6093,7 +7085,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = InsertArtistTracksSvc(inner); + let method = MovePlaylistSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( @@ -6109,26 +7101,25 @@ pub mod playlist_service_server { }; Box::pin(fut) } - "/rockbox.v1alpha1.PlaylistService/ShufflePlaylist" => { + "/rockbox.v1alpha1.PlaylistService/MoveFolder" => { #[allow(non_camel_case_types)] - struct ShufflePlaylistSvc(pub Arc); + struct MoveFolderSvc(pub Arc); impl< T: PlaylistService, - > tonic::server::UnaryService - for ShufflePlaylistSvc { - type Response = super::ShufflePlaylistResponse; + > tonic::server::UnaryService + for MoveFolderSvc { + type Response = super::MoveFolderResponse; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::shuffle_playlist(&inner, request) - .await + ::move_folder(&inner, request).await }; Box::pin(fut) } @@ -6139,7 +7130,7 @@ pub mod playlist_service_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = ShufflePlaylistSvc(inner); + let method = MoveFolderSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( diff --git a/gtk/src/api/rockbox_descriptor.bin b/gtk/src/api/rockbox_descriptor.bin index f9e87edaf4110ca4a535f248a856b8f376c490d4..a09a379c13217e5c0372821db31500d972b44da7 100644 GIT binary patch delta 8804 zcmb`MdyrMtmB!EB_w?!8r<+IbeqFkoru*^`P~@$EkVLFFk{B@U2$Mi;8o4~1huuxe zhLV#i^7!m5P~4MQ2jNOiHKXOcX?XqReldz4tk{ zwesKm1>afgTi@DiueHyRLd(nRu?L_u9-4p>FBtj zZ|6Y&HwHEj4fkzcUmO>=^_I5n_igQI{|_>qaXaBUD$~|pRa=}No4+XyS6-bx zt5Ez89XA24aAo%iRQA?1S1!*tc6G;f8+Ht=FAcIGg`6u<-acBkzOpkvVfo~^etl`^ zn!(LGhd1xoUZ_c&bZ_-Ts$g21uYb5uTY0Xw zt1~Y#dh2%WTrbZr9yXteqv50j3U!rZ^X4sB+7QQmX<|$Ban!eYTmME|->PhiUx}M8 zNupnxtfHdUbe37u&i=vDc4@ML_G_|_?2bwF)TKB#Zmy2uYh*gAYm>B3Z(5mRF&;}@ zt!i)S+FhlgVKX|`C{`YbFxm50{0p5xbL6Yupd#mRA#9X0Dv`F32Gl8)apB+fF3-nqSUS-yFCF=3?7s~HO=6|tnLvPxufs%BL=p5yEmkRnr^p!lr?qgQd}K3SIvF4-Eofw zgKOJrt;xibq@j%CW_rm493xRSs{MDF1f) z^;ZQ?oTZt?IkF8e{!^=_rFtroGLM)GRcej1X{hv+#!t#%l@iOS?)s$ABOXxbN!1Uk zxKu6cWUAI&4Jq7&%$l*jaQd@xt*HruJN41oo6gph<5-8SCcG^8f{Nof7q%*syDZ-o z*T-Slssoc-ri*byTq7V96nj(ys&DiN+A>}{&NBz{0N)!I@3HD!UdNdzFCtMg4B5pQ*CTe9R%6J8x$ zW8-z=b+y~9PKnp&>I`7XeJ)uL$@aNqLD2eKnLz~aqs(RLvrgHqwYnt{2EbeEk^+e> zZ?_x-Z*5a^QmIa@O|IWn3V?WjDy|9ApNfk>zpE6U1nH+zXqOQOt<#-OJV%suX_OpM z*42;kHlnN>+vbt*+Iid1&Erk3UO;R@5e-NUZ zoG1v8vxp7S2mE?T-iX-HoLNQN!hk&yNogj-WHut zRt18$rOtQ+Z%a$7lLKsZh3e8$sI6(vQmC!2P}m5v)fEaPJPKuVhBlA}q5cBxnbM_0 zq70-_LZS?$Q9_~&xN=W0xgG9InSj#{ccyfk@Y>+(w%px3zt#{{5QFgh~fQ08t(_?bi1wF}`)q~S@betTwMH5~h zlx=B>Jik6~Pn&X4YO~wb27t_NR~rzXyIpBO$n18dDatx-(41g2FaX*OZjB(Z)!A1A z2-*$JEy)s#Qkp$(iGYyvXOCMWkSKfH8bL(asf!Z|CE4k#+;AdwCzN@pX1ZdKII8p{+UXE&1tbAMW%R(dfMA^ORJ?+m z8NEA|dk39k!fz?2Ui8kv?^}wo7rm(_`i=^|>-45#`i`Q#MQ^I;RTQ%*0YS(CZOwtI zESPb0X7nnGag?yrO!Pe!Jm|tsBkcEVhlJrY3452)cB4Ur1=_GceD6|q^+{A9QSVZt z4Mlhpxrwlk?!_;2PD$n zil0NynMijljwl-mbPo+xc2;Qvun#3|a8DLW+Tb2#Y)4I#F#@`dnkHF%-**(qLLZ4E z9jj|7tVH_0Zzv$=ADE7^S>b%I(sui&=^6`da{%GqtMa2=$~92$RgLnhlF~#byw5il z2rAH5HG+Dds`G&(sP{=<@%|NVtqJeXxV3PBo?8p|{)}4-_x^;NQ1d2yKH$?h%Ug-`fSP@wheRqrpcY-k3UoN#L_bi$4_&)W$Mpxk-KI;sJ?wi1M1nw@ zAQ0b&eaip|`>=1B>Cy#{_?7{YAkZcVl=*waZx1-}c0B_m)FZZMba<|beyoCja0#A^ z=Z_Wl9I5`flHjBMYy%M$XcGkD`>1k98<41v+M`XE!}Cn^6BYc_g*^|~pQyY{U>Ke! zVIT8j1|lrbh6UpLm>)ABVIQ+&ro$N~`k4xjx~Mbo{F%zj8#xSTNYukFYFQv*!8R-q z=fgfMkg$jS^v;lSKJIq{1QqD1QohIiPGE)lxZjBxGQ3CpPJq~nBb@(sE5L+0;&%c_ zs3U%QfrL8Zcj9~#J)wesa*I13&nNui&X>hK=~Y0e0IdiRkte+fP|m+6y$TqWC%wu{ z6a8ET|Ljy|qVjWptj-jbr<7ilbTSAPpj83V_D`w$8Qu!@DRusQ4-t7vEm)XzeR-CN zexZV2I+a^?>L->-FZE@YgDkYk4l5i{G#9 z3r~mhO!S-z{?+Nt!}Oe&n;p15LBR}^8QQA?uCaL?(clA7n<<*ej6{u@ArNi7ntY|D)@Jo>Hpv#i$OZJr?h6^Oum;E^gf(!IqN%duaj$wuRvYca5 z)`cegqfd1qet-0-E;7+8D)>*A>LN_9_+eed{l|pIydDrepw$E7e9Y?s(L3g^go`BA z;~7;_1$wHadOV{_s>gk*7n$%+Dv)m$xv+c@j(@Uqt;5A8dQ}Dg?Q&g==~Z9W#ZuPS z{J{cZsCCp@*ovt`;wmgCz<~^cTffuH+IQNj`s3dHKy7MuCXDq4Xv2 z$~6M9zM-PzHYbpS`VG~XT#*G5_6;@TvyO}Jn@V3Uni!?dZ>lJ{SO|prrfQz*tx(@o zb1!pLj3<;{=8Up|C(0^HZh~;-{cu7xP4Q;9C)DiEJ1*#CCMy@RlbLJ|>d8!2?q?@6 zS!(!}(!DOO+`!&aQSu8W3d%Z!`<7}w&zs@Cr7m3VWZBkJN+&lKQj{CmDHSz1-x{c= z)Tnk3p`KEc=Q=8T^|sP0oKbFIZ>uP|X%i`e`nGDBp4>kL!+l%L|Dxk^Av>+~rH(5% zu+u6^ew5%_3-`3*4|sM9=UJd??ehI%HG9S!wNCOaDHnM`(!2|vmf zTOI@VqinTf;C_^?b`0E)vek|?;m27^jfMJgmho7qA7>elh5B)paia;(W^K_3^{li- z+4fK)+_PCH93)Fr5 zKyoRzK;5V9K~tvvTHx-}=}E(11NLWJ{vH5Kxvg;bJ1*2#sQWW&8{aIn{+!d{b3ZUj zK1<-+2K5#_Hu>=?5b7mS?we+vQ!O8@`> delta 3312 zcmYL~+iz4=6vofmXZQ5XncikkJDpCa)9KI_V*OTEDgS`u1hs?8xQ6?O)$s z691k$_~+7`q;zRwAYJ->AWL1PKL@%pg_Kv{UA#4Mx7a)V&DC#bx{EWD6SrrIg_EVB z!E`BkwZ61C*m&^E;2(nSmhO$*C|ww-PB(bTGf0~L?$euB?%XOfe(A*J8J$pidwIq_ z_PX|C4A=E2cJYO$1BM6J_<;6mwN^d;D9O+b*jufi&HiwI9RvC8xi?jiDHmmCmibB9ZV6lU| zSSVB<(Q1&pa(oSWC zK=a{pbAc+u<>tD>Fgt}z6d8t7+L5dlBO=R1Y!n#@ieUc{LzR(uZ4^Y6k-El6X)x0q z9LN@BU*WUSf}|^aHgZZ{vu=d8ouCs3t;I8v#Lg^UW1_kUo+m;isZB&F~KmZ%%g9!y}G^P(N=7$6~+K>vI%4spi zPC;PNW93C_qsG`M#8737je^n~jM8@J^e&B;i^xEQR}mo;8IOwiLZZrexr#)Uakjfv z**E$Aw<75#-~YUlx2>7b?mWKV=Bt?3c2BTT5NI>OMnNHQf{lVgmx;hAU&_38V^ZXU z4Tk_X$xcD(SgbjUft$>=1~cZh!Be7%L)ze}GNwyT#ptv7qEV>waiW0pIVrnV@MwTQkenKwz!2 zp*6mQMCL4e1BEuTe25BqjyaJE=70b<$1_6dSS);{pn%QQH*h;xGtV;?f-5`EBSN9b zJdaoqzV0y3Ga`s8^E~4rWk0a=T(&%fqzA!cBxJj)@U0&x9I_n&-)+PCq-@8K@_WLR z)p#kODgs#FYhxETRty*CmW%QZ3y`22orXj)HwixG*6qlw2T88wPRo zwe%v1N(+Q}If_aPgn3!|D78SCSZ`m4l8?yhfQPp1K;k2E^_weXr*a;X^&^JXp-zMz z6SiEp@6=O2Aw2fFA{6>ThEqc#_X**-=P24eA%5-;EBVwX+%R4AFcO~X?t$I|^4Nu1ObwL)-_oWNEsVa6gQ3Q-jO7U{?*j3Rf5#5oS)07-v| zoM3Ta3G5QpzY~SQE>YKMW)XZ&;tU7%emy5A*b$((i;&6AC<^pB9sQh9s28R!ZWSbV z^(|q8ePP<-nn9M^VmDus=;p$BtRS7>h@q_n`jS%bMNyzH>G%b1i=8NuIL^Tepe1su zA_=ra)qW<@U`y1|#jK;`GKnua=zv`&r#_Nkm#N|1NCI7^kG^2EQppt(r#M&%bcLKm zB!RAwYLBEoe=GF*NGC2+1DUb&98=DA;vsJHjiDE4g9zCk}MO>`xr% zhS{Gu&<(RcRZ4F9=15h6-84t43hbsiQdM9#&5^2Ba?9*bHP9`yKh;3D%>GmZ-7@=A zqvUqEt1oK6Zkx6>V7E=%8nD}@ZLN|!X4+byJ7(HipgU&TTA({-+Bzk7&5G-Q?qbD0 zyIKc!*DSdX?5rcHv~H`6B3cHc~!1iFuD50a&y@Ba@&Su8^U From c687bf37b737b07104a216f522368a5671ec63d4 Mon Sep 17 00:00:00 2001 From: Tsiry Sandratraina Date: Mon, 30 Dec 2024 05:51:40 +0000 Subject: [PATCH 07/26] gtk: add new playlist navigator screen --- gtk/data/gtk/file.blp | 1 - gtk/data/gtk/playlist.blp | 63 +++++++++++ gtk/data/gtk/playlist_details.blp | 15 +++ gtk/data/gtk/playlist_folder.blp | 60 ++++++++++ gtk/data/gtk/playlists.blp | 15 +++ gtk/data/gtk/window.blp | 52 ++++++++- gtk/data/icons/svg/playlist-symbolic.svg | 4 + gtk/data/meson.build | 4 + gtk/data/rockbox.gresource.xml.in | 5 + gtk/src/ui/media_controls.rs | 12 +- gtk/src/ui/mod.rs | 2 + gtk/src/ui/pages/album_details.rs | 7 ++ gtk/src/ui/pages/artist_details.rs | 7 ++ gtk/src/ui/pages/current_playlist.rs | 7 ++ gtk/src/ui/pages/mod.rs | 2 + gtk/src/ui/pages/playlist_details.rs | 55 ++++++++++ gtk/src/ui/pages/playlists.rs | 133 +++++++++++++++++++++++ gtk/src/ui/playlist.rs | 64 +++++++++++ gtk/src/ui/playlist_folder.rs | 64 +++++++++++ gtk/src/ui/song.rs | 1 + gtk/src/ui/window.rs | 90 ++++++++++++++- 21 files changed, 656 insertions(+), 7 deletions(-) create mode 100644 gtk/data/gtk/playlist.blp create mode 100644 gtk/data/gtk/playlist_details.blp create mode 100644 gtk/data/gtk/playlist_folder.blp create mode 100644 gtk/data/gtk/playlists.blp create mode 100644 gtk/data/icons/svg/playlist-symbolic.svg create mode 100644 gtk/src/ui/pages/playlist_details.rs create mode 100644 gtk/src/ui/pages/playlists.rs create mode 100644 gtk/src/ui/playlist.rs create mode 100644 gtk/src/ui/playlist_folder.rs diff --git a/gtk/data/gtk/file.blp b/gtk/data/gtk/file.blp index cd3bd88d6c2..01456cc6910 100644 --- a/gtk/data/gtk/file.blp +++ b/gtk/data/gtk/file.blp @@ -80,7 +80,6 @@ menu directory_context_menu { } } - menu file_context_menu { section { item (_("Play"), "app.dir.play") diff --git a/gtk/data/gtk/playlist.blp b/gtk/data/gtk/playlist.blp new file mode 100644 index 00000000000..d6190ac5190 --- /dev/null +++ b/gtk/data/gtk/playlist.blp @@ -0,0 +1,63 @@ + +using Gtk 4.0; + +template $Playlist : Box { + orientation: horizontal; + spacing: 10; + halign: fill; + valign: center; + hexpand: true; + margin-start: 15; + margin-end: 15; + + Box row { + orientation: horizontal; + halign: fill; + valign: fill; + margin-top: 5; + margin-bottom: 5; + + Image playlist_icon { + icon-name: "playlist-symbolic"; + pixel-size: 20; + } + + Label playlist_name { + halign: start; + valign: center; + hexpand: true; + margin-start: 10; + } + } + + MenuButton playlist_menu { + tooltip-text: _("More"); + menu-model: playlist_context_menu; + child: Image { + icon-name: "options-symbolic"; + pixel-size: 24; + }; + + halign: center; + valign: center; + width-request: 40; + height-request: 40; + + styles [ + "transparent-button" + ] + } + +} + +menu playlist_context_menu { + section { + item (_("Play Now"), "app.playlist.play") + item (_("Play Next"), "app.playlist.play-next") + item (_("Play Last"), "app.playlist.play-last") + item (_("Add Shuffled"), "app.playlist.add-shuffled") + item (_("Play Last Shuffled"), "app.playlist.play-last-shuffled") + item (_("Play Shuffled"), "app.playlist.play-shuffled") + } +} + diff --git a/gtk/data/gtk/playlist_details.blp b/gtk/data/gtk/playlist_details.blp new file mode 100644 index 00000000000..8ecabd6dcc2 --- /dev/null +++ b/gtk/data/gtk/playlist_details.blp @@ -0,0 +1,15 @@ + +using Gtk 4.0; + +template $PlaylistDetails : Box { + ListBox tracks { + hexpand: true; + margin-top: 15; + margin-bottom: 15; + selection-mode: none; + + styles [ + "album-track-list" + ] + } +} diff --git a/gtk/data/gtk/playlist_folder.blp b/gtk/data/gtk/playlist_folder.blp new file mode 100644 index 00000000000..e688cf58d59 --- /dev/null +++ b/gtk/data/gtk/playlist_folder.blp @@ -0,0 +1,60 @@ + +using Gtk 4.0; + +template $PlaylistFolder : Box { + orientation: horizontal; + spacing: 10; + halign: fill; + valign: center; + hexpand: true; + margin-start: 15; + margin-end: 15; + + Box row { + orientation: horizontal; + halign: fill; + valign: fill; + margin-top: 5; + margin-bottom: 5; + + Image folder_icon { + icon-name: "directory-symbolic"; + pixel-size: 20; + } + + Label folder_name { + halign: start; + valign: center; + hexpand: true; + margin-start: 10; + } + } + + MenuButton folder_menu { + tooltip-text: _("More"); + menu-model: folder_context_menu; + child: Image { + icon-name: "options-symbolic"; + pixel-size: 24; + }; + + halign: center; + valign: center; + width-request: 40; + height-request: 40; + + styles [ + "transparent-button" + ] + } + +} + +menu folder_context_menu { + section { + item (_("Rename Folder"), "app.folder.rename") + item (_("Delete Folder"), "app.folder.delete") + item (_("Create Playlist"), "app.folder.create-playlist") + } +} + diff --git a/gtk/data/gtk/playlists.blp b/gtk/data/gtk/playlists.blp new file mode 100644 index 00000000000..e4f59c44630 --- /dev/null +++ b/gtk/data/gtk/playlists.blp @@ -0,0 +1,15 @@ + +using Gtk 4.0; + +template $Playlists : Box { + ListBox playlists { + hexpand: true; + margin-top: 15; + margin-bottom: 15; + selection-mode: none; + + styles [ + "file-list" + ] + } +} diff --git a/gtk/data/gtk/window.blp b/gtk/data/gtk/window.blp index 39c3bab92ab..92dc12a6a86 100644 --- a/gtk/data/gtk/window.blp +++ b/gtk/data/gtk/window.blp @@ -130,6 +130,26 @@ template $RbApplicationWindow : Adw.ApplicationWindow { wrap-mode: char; } } + + Box playlists_row_box { + margin-top: 12; + margin-bottom: 12; + margin-start: 6; + spacing: 10; + + Image { + icon-name: "playlist-symbolic"; + pixel-size: 20; + } + + Label { + halign: start; + label: _("Playlists"); + margin-end: 6; + wrap: true; + wrap-mode: char; + } + } Box files_row_box { margin-top: 12; @@ -149,7 +169,7 @@ template $RbApplicationWindow : Adw.ApplicationWindow { wrap-mode: char; } } - + styles [ "navigation-sidebar" ] @@ -179,6 +199,14 @@ template $RbApplicationWindow : Adw.ApplicationWindow { visible: false; } + [start] + MenuButton new_playlist_menu_button { + tooltip-text: _("Create Playlist or Folder"); + icon-name: "list-add-symbolic"; + menu-model: new_playlist_menu; + visible: false; + } + [start] Button play_all_button { tooltip-text: _("Play All Songs"); @@ -379,6 +407,22 @@ template $RbApplicationWindow : Adw.ApplicationWindow { title: _("Search Results"); child: $Search search {}; } + + Adw.ViewStackPage playlists_page { + name: "playlists-page"; + title: _("Playlists"); + child: ScrolledWindow { + $Playlists playlists {} + }; + } + + Adw.ViewStackPage playlist_details_page { + name: "playlist-details-page"; + title: _("Playlist"); + child: ScrolledWindow { + $PlaylistDetails playlist_details {} + }; + } } } @@ -408,3 +452,9 @@ menu primary_menu { } } +menu new_playlist_menu { + section { + item (_("Create Playlist"), "app.create_playlist") + item (_("Create Folder"), "app.create_folder") + } +} diff --git a/gtk/data/icons/svg/playlist-symbolic.svg b/gtk/data/icons/svg/playlist-symbolic.svg new file mode 100644 index 00000000000..63c6e6ad3ec --- /dev/null +++ b/gtk/data/icons/svg/playlist-symbolic.svg @@ -0,0 +1,4 @@ + + + diff --git a/gtk/data/meson.build b/gtk/data/meson.build index b1e19769d36..a938a6c44c3 100644 --- a/gtk/data/meson.build +++ b/gtk/data/meson.build @@ -21,6 +21,10 @@ blueprints = custom_target( 'gtk/help-overlay.blp', 'gtk/likes.blp', 'gtk/media_controls.blp', + 'gtk/playlist.blp', + 'gtk/playlist_folder.blp', + 'gtk/playlists.blp', + 'gtk/playlist_details.blp', 'gtk/preferences.blp', 'gtk/search.blp', 'gtk/song.blp', diff --git a/gtk/data/rockbox.gresource.xml.in b/gtk/data/rockbox.gresource.xml.in index e801468469e..d5b06e9cc51 100644 --- a/gtk/data/rockbox.gresource.xml.in +++ b/gtk/data/rockbox.gresource.xml.in @@ -14,6 +14,10 @@ gtk/help-overlay.ui gtk/likes.ui gtk/media_controls.ui + gtk/playlist.ui + gtk/playlist_folder.ui + gtk/playlists.ui + gtk/playlist_details.ui gtk/preferences.ui gtk/search.ui gtk/song.ui @@ -34,6 +38,7 @@ icons/svg/options-symbolic.svg icons/svg/chevronup-symbolic.svg icons/svg/chevrondown-symbolic.svg + icons/svg/playlist-symbolic.svg icons/svg/close-alt-symbolic.svg diff --git a/gtk/src/ui/media_controls.rs b/gtk/src/ui/media_controls.rs index b527d73f358..d337b8d3568 100644 --- a/gtk/src/ui/media_controls.rs +++ b/gtk/src/ui/media_controls.rs @@ -239,6 +239,7 @@ mod imp { library_page_ref.set_title("Album"); go_back_button_ref.set_visible(true); album_details_ref.imp().hide_top_buttons(true); + album_details_ref.imp().hide_playlist_buttons(true); state.push_navigation("Album", "album-details-page"); album_details_ref.imp().load_album(album_id); } @@ -863,11 +864,17 @@ impl MediaControls { let current_playlist = self.imp().current_playlist.borrow(); let current_playlist_ref = current_playlist.as_ref().unwrap(); - if state.current_page().1 == "likes-page" || state.current_page().1 == "songs-page" + if state.current_page().1 == "likes-page" + || state.current_page().1 == "songs-page" + || state.current_page().1 == "playlist-details-page" { current_playlist_ref.hide_top_buttons(false); } + if state.current_page().1 == "playlists-page" { + current_playlist_ref.hide_playlist_buttons(false); + } + if state.current_page().1 == "files-page" && state.current_path() != state.music_directory() && state.current_path().is_some() @@ -894,6 +901,7 @@ impl MediaControls { let current_playlist = self.imp().current_playlist.borrow(); let current_playlist_ref = current_playlist.as_ref().unwrap(); current_playlist_ref.hide_top_buttons(true); + current_playlist_ref.hide_playlist_buttons(true); current_playlist_ref.load_current_track(); current_playlist_ref.load_current_playlist(); self.imp().playlist_displayed.set(true); @@ -930,6 +938,7 @@ impl MediaControls { library_page_ref.set_title("Artist"); go_back_button_ref.set_visible(true); artist_details_ref.imp().hide_top_buttons(true); + artist_details_ref.imp().hide_playlist_buttons(true); artist_details_ref.imp().load_artist(current_artist_id_ref); state.push_navigation("Artist", "artist-details-page"); } @@ -962,6 +971,7 @@ impl MediaControls { go_back_button_ref.set_visible(true); state.push_navigation("Album", "album-details-page"); album_details_ref.imp().hide_top_buttons(true); + album_details_ref.imp().hide_playlist_buttons(true); album_details_ref.imp().load_album(album_id); } } diff --git a/gtk/src/ui/mod.rs b/gtk/src/ui/mod.rs index 69da6cfedcd..d9ef2fc1928 100644 --- a/gtk/src/ui/mod.rs +++ b/gtk/src/ui/mod.rs @@ -4,6 +4,8 @@ pub mod artist; pub mod file; pub mod media_controls; pub mod pages; +pub mod playlist; +pub mod playlist_folder; pub mod preferences_dialog; pub mod song; pub mod window; diff --git a/gtk/src/ui/pages/album_details.rs b/gtk/src/ui/pages/album_details.rs index 2d8bdb9637e..bc787d1c7da 100644 --- a/gtk/src/ui/pages/album_details.rs +++ b/gtk/src/ui/pages/album_details.rs @@ -40,6 +40,7 @@ mod imp { pub album_id: RefCell, pub play_all_button: RefCell>, pub shuffle_all_button: RefCell>, + pub new_playlist_menu_button: RefCell>, } #[glib::object_subclass] @@ -132,6 +133,12 @@ mod imp { shuffle_all_button_ref.unwrap().set_visible(!hide); } + pub fn hide_playlist_buttons(&self, hide: bool) { + let new_playlist_menu_button = self.new_playlist_menu_button.borrow(); + let new_playlist_menu_button_ref = new_playlist_menu_button.as_ref(); + new_playlist_menu_button_ref.unwrap().set_visible(!hide); + } + pub fn load_album(&self, id: &str) { let id = id.to_string(); self.album_id.replace(id.clone()); diff --git a/gtk/src/ui/pages/artist_details.rs b/gtk/src/ui/pages/artist_details.rs index adfd3288558..6a61cc5a35d 100644 --- a/gtk/src/ui/pages/artist_details.rs +++ b/gtk/src/ui/pages/artist_details.rs @@ -47,6 +47,7 @@ mod imp { pub artist: RefCell, pub play_all_button: RefCell>, pub shuffle_all_button: RefCell>, + pub new_playlist_menu_button: RefCell>, } #[glib::object_subclass] @@ -157,6 +158,12 @@ mod imp { shuffle_all_button_ref.unwrap().set_visible(!hide); } + pub fn hide_playlist_buttons(&self, hide: bool) { + let new_playlist_menu_button = self.new_playlist_menu_button.borrow(); + let new_playlist_menu_button_ref = new_playlist_menu_button.as_ref(); + new_playlist_menu_button_ref.unwrap().set_visible(!hide); + } + pub fn load_artist(&self, id: &str) { let id = id.to_string(); let rt = tokio::runtime::Runtime::new().unwrap(); diff --git a/gtk/src/ui/pages/current_playlist.rs b/gtk/src/ui/pages/current_playlist.rs index 15bf10601f2..bad97eee087 100644 --- a/gtk/src/ui/pages/current_playlist.rs +++ b/gtk/src/ui/pages/current_playlist.rs @@ -46,6 +46,7 @@ mod imp { pub size: Cell, pub play_all_button: RefCell>, pub shuffle_all_button: RefCell>, + pub new_playlist_menu_button: RefCell>, } #[glib::object_subclass] @@ -229,6 +230,12 @@ impl CurrentPlaylist { shuffle_all_button_ref.unwrap().set_visible(!hide); } + pub fn hide_playlist_buttons(&self, hide: bool) { + let new_playlist_menu_button = self.imp().new_playlist_menu_button.borrow(); + let new_playlist_menu_button_ref = new_playlist_menu_button.as_ref(); + new_playlist_menu_button_ref.unwrap().set_visible(!hide); + } + pub fn load_current_track(&self) { let state = self.imp().state.upgrade().unwrap(); match state.current_track() { diff --git a/gtk/src/ui/pages/mod.rs b/gtk/src/ui/pages/mod.rs index f19215a1ae7..2a1b78f7f89 100644 --- a/gtk/src/ui/pages/mod.rs +++ b/gtk/src/ui/pages/mod.rs @@ -5,5 +5,7 @@ pub mod artists; pub mod current_playlist; pub mod files; pub mod likes; +pub mod playlist_details; +pub mod playlists; pub mod search; pub mod songs; diff --git a/gtk/src/ui/pages/playlist_details.rs b/gtk/src/ui/pages/playlist_details.rs new file mode 100644 index 00000000000..f9436ca4e97 --- /dev/null +++ b/gtk/src/ui/pages/playlist_details.rs @@ -0,0 +1,55 @@ +use crate::state::AppState; +use adw::subclass::prelude::*; +use glib::subclass; +use gtk::glib; +use gtk::{Button, CompositeTemplate}; +use std::cell::RefCell; + +mod imp { + + use super::*; + + #[derive(Debug, Default, CompositeTemplate)] + #[template(resource = "/io/github/tsirysndr/Rockbox/gtk/playlist_details.ui")] + pub struct PlaylistDetails { + pub main_stack: RefCell>, + pub go_back_button: RefCell>, + pub state: glib::WeakRef, + } + + #[glib::object_subclass] + impl ObjectSubclass for PlaylistDetails { + const NAME: &'static str = "PlaylistDetails"; + type ParentType = gtk::Box; + type Type = super::PlaylistDetails; + + fn class_init(klass: &mut Self::Class) { + Self::bind_template(klass); + } + + fn instance_init(obj: &subclass::InitializingObject) { + obj.init_template(); + } + } + + impl ObjectImpl for PlaylistDetails { + fn constructed(&self) { + self.parent_constructed(); + } + } + + impl WidgetImpl for PlaylistDetails {} + impl BoxImpl for PlaylistDetails {} +} + +glib::wrapper! { + pub struct PlaylistDetails(ObjectSubclass) + @extends gtk::Widget, gtk::Box; +} + +#[gtk::template_callbacks] +impl PlaylistDetails { + pub fn new() -> Self { + glib::Object::new() + } +} diff --git a/gtk/src/ui/pages/playlists.rs b/gtk/src/ui/pages/playlists.rs new file mode 100644 index 00000000000..5bd02d7a9d6 --- /dev/null +++ b/gtk/src/ui/pages/playlists.rs @@ -0,0 +1,133 @@ +use crate::api::rockbox::v1alpha1::playlist_service_client::PlaylistServiceClient; +use crate::api::rockbox::v1alpha1::{ + GetFoldersRequest, GetFoldersResponse, GetPlaylistsRequest, GetPlaylistsResponse, +}; +use crate::state::AppState; +use crate::ui::playlist::Playlist; +use crate::ui::playlist_folder::PlaylistFolder; +use adw::subclass::prelude::*; +use anyhow::Error; +use glib::subclass; +use gtk::glib; +use gtk::{Button, CompositeTemplate, ListBox}; +use std::cell::RefCell; +use std::env; + +mod imp { + + use super::*; + + #[derive(Debug, Default, CompositeTemplate)] + #[template(resource = "/io/github/tsirysndr/Rockbox/gtk/playlists.ui")] + pub struct Playlists { + #[template_child] + pub playlists: TemplateChild, + + pub main_stack: RefCell>, + pub go_back_button: RefCell>, + pub state: glib::WeakRef, + } + + #[glib::object_subclass] + impl ObjectSubclass for Playlists { + const NAME: &'static str = "Playlists"; + type ParentType = gtk::Box; + type Type = super::Playlists; + + fn class_init(klass: &mut Self::Class) { + Self::bind_template(klass); + } + + fn instance_init(obj: &subclass::InitializingObject) { + obj.init_template(); + } + } + + impl ObjectImpl for Playlists { + fn constructed(&self) { + self.parent_constructed(); + + let self_weak = self.downgrade(); + glib::idle_add_local(move || { + let self_ = match self_weak.upgrade() { + Some(self_) => self_, + None => return glib::ControlFlow::Continue, + }; + + glib::spawn_future_local(async move { + let obj = self_.obj(); + obj.load_playlists(None); + }); + + let self_ = match self_weak.upgrade() { + Some(self_) => self_, + None => return glib::ControlFlow::Continue, + }; + + glib::ControlFlow::Break + }); + } + } + + impl WidgetImpl for Playlists {} + impl BoxImpl for Playlists {} +} + +glib::wrapper! { + pub struct Playlists(ObjectSubclass) + @extends gtk::Widget, gtk::Box; +} + +#[gtk::template_callbacks] +impl Playlists { + pub fn new() -> Self { + glib::Object::new() + } + + pub fn load_playlists(&self, folder: Option) { + let rt = tokio::runtime::Runtime::new().unwrap(); + let parent_id = folder.clone(); + let folder_id = folder.clone(); + let response = rt.block_on(async { + let url = build_url(); + let mut client = PlaylistServiceClient::connect(url).await?; + let response = client + .get_folders(GetFoldersRequest { parent_id }) + .await? + .into_inner(); + Ok::(response) + }); + + if let Ok(response) = response { + for entry in response.folders { + let folder = PlaylistFolder::new(); + folder.imp().folder_name.set_text(&entry.name); + self.imp().playlists.append(&folder); + } + } + + let response = rt.block_on(async { + let url = build_url(); + let mut client = PlaylistServiceClient::connect(url).await?; + let response = client + .get_playlists(GetPlaylistsRequest { folder_id }) + .await? + .into_inner(); + Ok::(response) + }); + + if let Ok(response) = response { + for entry in response.playlists { + let playlist = Playlist::new(); + playlist.imp().playlist_name.set_text(&entry.name); + self.imp().playlists.append(&playlist); + } + } + } +} + +fn build_url() -> String { + let host = env::var("ROCKBOX_HOST").unwrap_or("localhost".to_string()); + let port = env::var("ROCKBOX_PORT").unwrap_or("6061".to_string()); + format!("tcp://{}:{}", host, port) +} diff --git a/gtk/src/ui/playlist.rs b/gtk/src/ui/playlist.rs new file mode 100644 index 00000000000..68fa84f5855 --- /dev/null +++ b/gtk/src/ui/playlist.rs @@ -0,0 +1,64 @@ +use crate::state::AppState; +use adw::subclass::prelude::*; +use glib::subclass; +use gtk::glib; +use gtk::{Button, CompositeTemplate, Image, Label, MenuButton}; +use std::cell::RefCell; + +mod imp { + + use super::*; + + #[derive(Debug, Default, CompositeTemplate)] + #[template(resource = "/io/github/tsirysndr/Rockbox/gtk/playlist.ui")] + pub struct Playlist { + #[template_child] + pub playlist_icon: TemplateChild, + #[template_child] + pub playlist_name: TemplateChild