spotify_cli/cli/commands/
resource.rs1use crate::endpoints::albums::get_album;
2use crate::endpoints::artists::{
3 get_artist, get_artist_top_tracks, get_artists_albums, get_artists_related_artists,
4};
5use crate::endpoints::tracks::get_track;
6use crate::io::output::{ErrorKind, Response};
7use crate::types::{Album, Artist, ArtistTopTracksResponse, RelatedArtistsResponse, Track};
8
9use super::{extract_id, now_playing, with_client};
10
11#[derive(Debug, Clone, Copy, Default)]
13pub enum ArtistView {
14 #[default]
16 Details,
17 TopTracks,
19 Albums,
21 Related,
23}
24
25#[derive(Debug, Clone)]
27pub struct ArtistQuery {
28 pub id: Option<String>,
30 pub id_only: bool,
32 pub view: ArtistView,
34 pub market: String,
36 pub limit: u8,
38 pub offset: u32,
40}
41
42impl ArtistQuery {
43 pub fn new() -> Self {
45 Self {
46 id: None,
47 id_only: false,
48 view: ArtistView::Details,
49 market: "US".to_string(),
50 limit: 20,
51 offset: 0,
52 }
53 }
54
55 pub fn with_id(mut self, id: Option<String>) -> Self {
57 self.id = id;
58 self
59 }
60
61 pub fn id_only(mut self, id_only: bool) -> Self {
63 self.id_only = id_only;
64 self
65 }
66
67 pub fn view(mut self, view: ArtistView) -> Self {
69 self.view = view;
70 self
71 }
72
73 pub fn market(mut self, market: String) -> Self {
75 self.market = market;
76 self
77 }
78
79 pub fn paginate(mut self, limit: u8, offset: u32) -> Self {
81 self.limit = limit;
82 self.offset = offset;
83 self
84 }
85}
86
87impl Default for ArtistQuery {
88 fn default() -> Self {
89 Self::new()
90 }
91}
92
93pub async fn info_track(id: Option<&str>, id_only: bool) -> Response {
95 with_client(|client| async move {
96 let track_id = match id {
97 Some(id) => extract_id(id),
98 None => match now_playing::get_track_id(&client).await {
99 Ok(id) => id,
100 Err(e) => return e,
101 },
102 };
103
104 if id_only {
105 return Response::success(200, &track_id);
106 }
107
108 match get_track::get_track(&client, &track_id).await {
109 Ok(Some(payload)) => {
110 match serde_json::from_value::<Track>(payload.clone()) {
112 Ok(track) => {
113 let msg = format!("{} - {}", track.name, track.artist_names());
114 Response::success_with_payload(200, msg, payload)
115 }
116 Err(_) => Response::success_with_payload(200, "Track details", payload),
117 }
118 }
119 Ok(None) => Response::err(404, "Track not found", ErrorKind::NotFound),
120 Err(e) => Response::from_http_error(&e, "Failed to get track"),
121 }
122 })
123 .await
124}
125
126pub async fn info_album(id: Option<&str>, id_only: bool) -> Response {
128 with_client(|client| async move {
129 let album_id = match id {
130 Some(id) => extract_id(id),
131 None => match now_playing::get_album_id(&client).await {
132 Ok(id) => id,
133 Err(e) => return e,
134 },
135 };
136
137 if id_only {
138 return Response::success(200, &album_id);
139 }
140
141 match get_album::get_album(&client, &album_id).await {
142 Ok(Some(payload)) => {
143 match serde_json::from_value::<Album>(payload.clone()) {
145 Ok(album) => {
146 let artist = album.artist_name().unwrap_or("Unknown Artist");
147 let msg = format!("{} - {}", album.name, artist);
148 Response::success_with_payload(200, msg, payload)
149 }
150 Err(_) => Response::success_with_payload(200, "Album details", payload),
151 }
152 }
153 Ok(None) => Response::err(404, "Album not found", ErrorKind::NotFound),
154 Err(e) => Response::from_http_error(&e, "Failed to get album"),
155 }
156 })
157 .await
158}
159
160pub async fn info_artist(query: ArtistQuery) -> Response {
162 let ArtistQuery {
163 id,
164 id_only,
165 view,
166 market,
167 limit,
168 offset,
169 } = query;
170
171 with_client(|client| async move {
172 let artist_id = match id.as_deref() {
173 Some(id) => extract_id(id),
174 None => match now_playing::get_artist_id(&client).await {
175 Ok(id) => id,
176 Err(e) => return e,
177 },
178 };
179
180 if id_only {
181 return Response::success(200, &artist_id);
182 }
183
184 match view {
185 ArtistView::TopTracks => {
186 match get_artist_top_tracks::get_artist_top_tracks(
187 &client,
188 &artist_id,
189 Some(&market),
190 )
191 .await
192 {
193 Ok(Some(payload)) => {
194 match serde_json::from_value::<ArtistTopTracksResponse>(payload.clone()) {
195 Ok(resp) => {
196 let count = resp.tracks.len();
197 Response::success_with_payload(
198 200,
199 format!("Top {} tracks", count),
200 payload,
201 )
202 }
203 Err(_) => Response::success_with_payload(200, "Top tracks", payload),
204 }
205 }
206 Ok(None) => Response::success_with_payload(
207 200,
208 "No top tracks",
209 serde_json::json!({ "tracks": [] }),
210 ),
211 Err(e) => Response::from_http_error(&e, "Failed to get top tracks"),
212 }
213 }
214 ArtistView::Albums => {
215 match get_artists_albums::get_artists_albums(
216 &client,
217 &artist_id,
218 Some(limit),
219 Some(offset),
220 )
221 .await
222 {
223 Ok(Some(payload)) => {
224 Response::success_with_payload(200, "Artist albums", payload)
225 }
226 Ok(None) => Response::success_with_payload(
227 200,
228 "No albums",
229 serde_json::json!({ "items": [] }),
230 ),
231 Err(e) => Response::from_http_error(&e, "Failed to get artist albums"),
232 }
233 }
234 ArtistView::Related => {
235 match get_artists_related_artists::get_artists_related_artists(&client, &artist_id)
236 .await
237 {
238 Ok(Some(payload)) => {
239 match serde_json::from_value::<RelatedArtistsResponse>(payload.clone()) {
240 Ok(resp) => {
241 let count = resp.artists.len();
242 Response::success_with_payload(
243 200,
244 format!("{} related artists", count),
245 payload,
246 )
247 }
248 Err(_) => {
249 Response::success_with_payload(200, "Related artists", payload)
250 }
251 }
252 }
253 Ok(None) => Response::success_with_payload(
254 200,
255 "No related artists",
256 serde_json::json!({ "artists": [] }),
257 ),
258 Err(e) => Response::from_http_error(&e, "Failed to get related artists"),
259 }
260 }
261 ArtistView::Details => match get_artist::get_artist(&client, &artist_id).await {
262 Ok(Some(payload)) => match serde_json::from_value::<Artist>(payload.clone()) {
263 Ok(artist) => Response::success_with_payload(200, artist.name.clone(), payload),
264 Err(_) => Response::success_with_payload(200, "Artist details", payload),
265 },
266 Ok(None) => Response::err(404, "Artist not found", ErrorKind::NotFound),
267 Err(e) => Response::from_http_error(&e, "Failed to get artist"),
268 },
269 }
270 })
271 .await
272}