spotify_cli/spotify/
artists.rs1use anyhow::bail;
2use reqwest::blocking::Client as HttpClient;
3use serde::Deserialize;
4
5use crate::domain::artist::Artist;
6use crate::error::Result;
7use crate::spotify::auth::AuthService;
8use crate::spotify::base::api_base;
9use crate::spotify::error::format_api_error;
10
11#[derive(Debug, Clone)]
13pub struct ArtistsClient {
14 http: HttpClient,
15 auth: AuthService,
16}
17
18impl ArtistsClient {
19 pub fn new(http: HttpClient, auth: AuthService) -> Self {
20 Self { http, auth }
21 }
22
23 pub fn get(&self, artist_id: &str) -> Result<Artist> {
24 let token = self.auth.token()?;
25 let url = format!("{}/artists/{artist_id}", api_base());
26
27 let response = self.http.get(url).bearer_auth(token.access_token).send()?;
28
29 if !response.status().is_success() {
30 let status = response.status();
31 let body = response.text().unwrap_or_else(|_| "<no body>".to_string());
32 bail!(format_api_error(
33 "spotify artist request failed",
34 status,
35 &body
36 ));
37 }
38
39 let payload: SpotifyArtist = response.json()?;
40 Ok(Artist {
41 id: payload.id,
42 name: payload.name,
43 uri: payload.uri,
44 genres: payload.genres,
45 followers: payload.followers.map(|followers| followers.total),
46 })
47 }
48}
49
50#[derive(Debug, Deserialize)]
51struct SpotifyArtist {
52 id: String,
53 name: String,
54 uri: String,
55 #[serde(default)]
56 genres: Vec<String>,
57 followers: Option<SpotifyFollowers>,
58}
59
60#[derive(Debug, Deserialize)]
61struct SpotifyFollowers {
62 total: u64,
63}