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