spotify_cli/cli/commands/player/
queue.rs

1//! Queue commands: list, add, recent
2
3use crate::endpoints::player::{
4    add_item_to_playback_queue, get_recently_played_tracks, get_users_queue,
5};
6use crate::io::output::{ErrorKind, Response};
7use crate::types::{QueueResponse, RecentlyPlayedResponse};
8
9use crate::cli::commands::{now_playing, with_client};
10
11pub async fn player_queue_list() -> Response {
12    with_client(|client| async move {
13        match get_users_queue::get_users_queue(&client).await {
14            Ok(Some(payload)) => {
15                // Validate response structure by deserializing to typed struct
16                match serde_json::from_value::<QueueResponse>(payload.clone()) {
17                    Ok(_) => Response::success_with_payload(200, "Current queue", payload),
18                    Err(_) => Response::success_with_payload(200, "Current queue", payload),
19                }
20            }
21            Ok(None) => Response::success_with_payload(
22                200,
23                "Queue is empty",
24                serde_json::json!({ "queue": [], "currently_playing": null }),
25            ),
26            Err(e) => Response::from_http_error(&e, "Failed to get queue"),
27        }
28    })
29    .await
30}
31
32pub async fn player_queue_add(uri: Option<&str>, now_playing_flag: bool) -> Response {
33    if uri.is_none() && !now_playing_flag {
34        return Response::err(
35            400,
36            "Provide a URI or use --now-playing",
37            ErrorKind::Validation,
38        );
39    }
40
41    let explicit_uri = uri.map(|s| s.to_string());
42
43    with_client(|client| async move {
44        let mut uris_to_add: Vec<String> = Vec::new();
45
46        if let Some(uri) = explicit_uri {
47            uris_to_add.push(uri);
48        }
49
50        if now_playing_flag {
51            match now_playing::get_track_uri(&client).await {
52                Ok(uri) => uris_to_add.push(uri),
53                Err(e) => return e,
54            }
55        }
56
57        for uri in &uris_to_add {
58            if let Err(e) =
59                add_item_to_playback_queue::add_item_to_playback_queue(&client, uri).await
60            {
61                return Response::from_http_error(&e, "Failed to add to queue");
62            }
63        }
64
65        Response::success(204, "Added to queue")
66    })
67    .await
68}
69
70pub async fn player_recent() -> Response {
71    with_client(|client| async move {
72        match get_recently_played_tracks::get_recently_played_tracks(&client).await {
73            Ok(Some(payload)) => {
74                // Validate response structure by deserializing to typed struct
75                match serde_json::from_value::<RecentlyPlayedResponse>(payload.clone()) {
76                    Ok(resp) => {
77                        let count = resp.items.len();
78                        Response::success_with_payload(
79                            200,
80                            format!("Recently played ({} tracks)", count),
81                            payload,
82                        )
83                    }
84                    Err(_) => Response::success_with_payload(200, "Recently played", payload),
85                }
86            }
87            Ok(None) => Response::success_with_payload(
88                200,
89                "No recent tracks",
90                serde_json::json!({ "items": [] }),
91            ),
92            Err(e) => Response::from_http_error(&e, "Failed to get recent tracks"),
93        }
94    })
95    .await
96}