spotify_cli/cli/commands/
user.rs

1use crate::endpoints::user::{get_current_user, get_users_profile, get_users_top_items};
2use crate::io::output::{ErrorKind, Response};
3use crate::types::{TopArtistsResponse, TopTracksResponse, UserPrivate, UserPublic};
4
5use super::with_client;
6
7pub async fn user_profile() -> Response {
8    with_client(|client| async move {
9        match get_current_user::get_current_user(&client).await {
10            Ok(Some(payload)) => match serde_json::from_value::<UserPrivate>(payload.clone()) {
11                Ok(user) => {
12                    let name = user.display_name.as_deref().unwrap_or(&user.id);
13                    let product = user.product.as_deref().unwrap_or("free");
14                    Response::success_with_payload(200, format!("{} ({})", name, product), payload)
15                }
16                Err(_) => Response::success_with_payload(200, "User profile", payload),
17            },
18            Ok(None) => Response::err(404, "User not found", ErrorKind::NotFound),
19            Err(e) => Response::from_http_error(&e, "Failed to get user profile"),
20        }
21    })
22    .await
23}
24
25pub async fn user_top(item_type: &str, range: &str, limit: u8) -> Response {
26    let item_type = item_type.to_string();
27    let range = range.to_string();
28
29    with_client(|client| async move {
30        let time_range = match range.as_str() {
31            "short" => "short_term",
32            "medium" => "medium_term",
33            "long" => "long_term",
34            _ => "medium_term",
35        };
36
37        match get_users_top_items::get_users_top_items(
38            &client,
39            &item_type,
40            Some(time_range),
41            Some(limit),
42            None,
43        )
44        .await
45        {
46            Ok(Some(payload)) => {
47                let range_desc = match range.as_str() {
48                    "short" => "4 weeks",
49                    "medium" => "6 months",
50                    "long" => "all time",
51                    _ => "6 months",
52                };
53
54                // Try to get count from typed response
55                let count = if item_type == "tracks" {
56                    serde_json::from_value::<TopTracksResponse>(payload.clone())
57                        .ok()
58                        .map(|r| r.items.len())
59                } else {
60                    serde_json::from_value::<TopArtistsResponse>(payload.clone())
61                        .ok()
62                        .map(|r| r.items.len())
63                };
64
65                let msg = match count {
66                    Some(n) => format!("Top {} {} ({})", n, item_type, range_desc),
67                    None => format!("Top {} ({})", item_type, range_desc),
68                };
69                Response::success_with_payload(200, msg, payload)
70            }
71            Ok(None) => Response::success_with_payload(
72                200,
73                format!("No top {} found", item_type),
74                serde_json::json!({ "items": [] }),
75            ),
76            Err(e) => Response::from_http_error(&e, &format!("Failed to get top {}", item_type)),
77        }
78    })
79    .await
80}
81
82/// Get another user's profile
83pub async fn user_get(user_id: &str) -> Response {
84    let user_id = user_id.to_string();
85
86    with_client(|client| async move {
87        match get_users_profile::get_users_profile(&client, &user_id).await {
88            Ok(Some(payload)) => match serde_json::from_value::<UserPublic>(payload.clone()) {
89                Ok(user) => {
90                    let name = user.display_name.as_deref().unwrap_or(&user.id);
91                    Response::success_with_payload(200, name.to_string(), payload)
92                }
93                Err(_) => Response::success_with_payload(200, format!("User {}", user_id), payload),
94            },
95            Ok(None) => Response::err(404, "User not found", ErrorKind::NotFound),
96            Err(e) => Response::from_http_error(&e, "Failed to get user profile"),
97        }
98    })
99    .await
100}