Repository: aome510/spotify-player (language: rust)

Issue:
Search from CLI
**Is your feature already implemented in the latest `master`?**
No

**Is your feature request related to a problem? Please describe.**
Right now the current method for getting search-like information from Spotify via the CLI is to use `spotify_player get item <TYPE> --name`. Unfortunately this only returns a single result rather than the list of results that the TUI returns when searching. 

**Describe the solution you'd like**
A new CLI command called `search` which allows users to do the same kind of search that the TUI does.

**Describe alternatives you've considered**
N/A

**Additional context**
From poking through the codebase (I'm not super familiar with Rust so I'm sure I've missed something here) it looks like the CLI does item retrieval calls out directly to the `artist`, `track`, `playlist`, and `track` methods in rspotify.  Would it be too much work to wire up the `search` method as well?



Discussion / hints:
Shouldn't be too difficult to define a `search` CLI command as client does provide `search` (https://github.com/aome510/spotify-player/blob/2b8f2530cba3c83f108dfc887f4666f356f8e86a/spotify_player/src/client/mod.rs#L832) and `search_specific_type` (https://github.com/aome510/spotify-player/blob/2b8f2530cba3c83f108dfc887f4666f356f8e86a/spotify_player/src/client/mod.rs#L880)
Hi, I'd like to give this a try if that's okay with you? Thanks!
yes, please do. Lmk when you have a PR up

Fix patch:
diff --git a/spotify_player/src/cli/client.rs b/spotify_player/src/cli/client.rs
index 0db57360..dcf9798b 100644
--- a/spotify_player/src/cli/client.rs
+++ b/spotify_player/src/cli/client.rs
@@ -165,6 +165,10 @@ async fn handle_socket_request(
             let resp = handle_playlist_request(client, command).await?;
             Ok(resp.into_bytes())
         }
+        Request::Search { query } => {
+            let resp = handle_search_request(client, query).await?;
+            Ok(resp)
+        }
     }
 }
 
@@ -310,6 +314,12 @@ async fn handle_get_item_request(
     })
 }
 
+async fn handle_search_request(client: &Client, query: String) -> Result<Vec<u8>> {
+    let search_result = client.search(&query).await?;
+
+    Ok(serde_json::to_vec(&search_result)?)
+}
+
 async fn handle_playback_request(
     client: &Client,
     state: &Option<SharedState>,
diff --git a/spotify_player/src/cli/commands.rs b/spotify_player/src/cli/commands.rs
index 8a35289e..14c71c85 100644
--- a/spotify_player/src/cli/commands.rs
+++ b/spotify_player/src/cli/commands.rs
@@ -123,6 +123,12 @@ pub fn init_playback_subcommand() -> Command {
         )
 }
 
+pub fn init_search_command() -> Command {
+    Command::new("search")
+        .about("Search spotify")
+        .arg(Arg::new("query").help("Search query").required(true))
+}
+
 pub fn init_like_command() -> Command {
     Command::new("like")
         .about("Like currently playing track")
diff --git a/spotify_player/src/cli/handlers.rs b/spotify_player/src/cli/handlers.rs
index fd024574..95a466fe 100644
--- a/spotify_player/src/cli/handlers.rs
+++ b/spotify_player/src/cli/handlers.rs
@@ -210,6 +210,12 @@ pub fn handle_cli_subcommand(cmd: &str, args: &ArgMatches) -> Result<()> {
         "like" => Request::Like {
             unlike: args.get_flag("unlike"),
         },
+        "search" => Request::Search {
+            query: args
+                .get_one::<String>("query")
+                .expect("query is required")
+                .to_owned(),
+        },
         _ => unreachable!(),
     };
 
diff --git a/spotify_player/src/cli/mod.rs b/spotify_player/src/cli/mod.rs
index 13877a26..ba2ae090 100644
--- a/spotify_player/src/cli/mod.rs
+++ b/spotify_player/src/cli/mod.rs
@@ -117,6 +117,7 @@ pub enum Request {
     Connect(IdOrName),
     Like { unlike: bool },
     Playlist(PlaylistCommand),
+    Search { query: String },
 }
 
 #[derive(Debug, Serialize, Deserialize)]
@@ -161,6 +162,7 @@ pub fn init_cli() -> anyhow::Result<clap::Command> {
         .subcommand(commands::init_authenticate_command())
         .subcommand(commands::init_playlist_subcommand())
         .subcommand(commands::init_generate_command())
+        .subcommand(commands::init_search_command())
         .arg(
             clap::Arg::new("theme")
                 .short('t')
diff --git a/spotify_player/src/client/mod.rs b/spotify_player/src/client/mod.rs
index fa209d41..e8d6e733 100644
--- a/spotify_player/src/client/mod.rs
+++ b/spotify_player/src/client/mod.rs
@@ -829,7 +829,7 @@ impl Client {
     }
 
     /// Search for items (tracks, artists, albums, playlists) matching a given query
-    async fn search(&self, query: &str) -> Result<SearchResults> {
+    pub async fn search(&self, query: &str) -> Result<SearchResults> {
         let (track_result, artist_result, album_result, playlist_result) = tokio::try_join!(
             self.search_specific_type(query, rspotify_model::SearchType::Track),
             self.search_specific_type(query, rspotify_model::SearchType::Artist),
diff --git a/spotify_player/src/state/model.rs b/spotify_player/src/state/model.rs
index 512bd5c3..0c62003e 100644
--- a/spotify_player/src/state/model.rs
+++ b/spotify_player/src/state/model.rs
@@ -57,7 +57,7 @@ pub enum Playback {
     URIs(Vec<TrackId<'static>>, Option<rspotify_model::Offset>),
 }
 
-#[derive(Default, Clone, Debug)]
+#[derive(Default, Clone, Debug, Deserialize, Serialize)]
 /// Data returned when searching a query using Spotify APIs.
 pub struct SearchResults {
     pub tracks: Vec<Track>,


Test patch: