lastfm_client/api/user/top/
artists.rs1use crate::api::builder_ext::{FetchAndSave, LimitBuilder};
2use crate::api::constants::METHOD_TOP_ARTISTS;
3use crate::api::fetch_utils::{Period, ProgressCallback, ResourceContainer, fetch};
4use crate::client::HttpClient;
5use crate::config::Config;
6use crate::error::Result;
7use crate::types::{TopArtist, TrackLimit, TrackList, UserTopArtists};
8use crate::url_builder::QueryParams;
9
10use serde::de::DeserializeOwned;
11use std::fmt;
12use std::sync::Arc;
13
14pub struct TopArtistsRequestBuilder {
16 http: Arc<dyn HttpClient>,
17 config: Arc<Config>,
18 username: String,
19 limit: Option<u32>,
20 period: Option<Period>,
21 progress_callback: Option<ProgressCallback>,
22}
23
24impl fmt::Debug for TopArtistsRequestBuilder {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 f.debug_struct("TopArtistsRequestBuilder")
27 .field("username", &self.username)
28 .field("limit", &self.limit)
29 .field("period", &self.period)
30 .finish_non_exhaustive()
31 }
32}
33
34impl TopArtistsRequestBuilder {
35 pub(crate) fn new(http: Arc<dyn HttpClient>, config: Arc<Config>, username: String) -> Self {
36 Self {
37 http,
38 config,
39 username,
40 limit: None,
41 period: None,
42 progress_callback: None,
43 }
44 }
45
46 #[must_use]
48 pub fn on_progress(mut self, callback: impl Fn(u32, u32) + Send + Sync + 'static) -> Self {
49 self.progress_callback = Some(Arc::new(callback));
50 self
51 }
52
53 #[cfg(feature = "progress")]
55 #[must_use]
56 pub fn with_progress(self) -> Self {
57 self.on_progress(crate::api::progress::make_progress_callback())
58 }
59
60 #[must_use]
67 pub const fn period(mut self, period: Period) -> Self {
68 self.period = Some(period);
69 self
70 }
71
72 pub async fn fetch(self) -> Result<TrackList<TopArtist>> {
77 let mut params = QueryParams::new();
78
79 if let Some(period) = self.period {
80 params.insert("period".to_string(), period.as_api_str().to_string());
81 }
82
83 let limit = self
84 .limit
85 .map_or(TrackLimit::Unlimited, TrackLimit::Limited);
86
87 self.fetch_artists::<UserTopArtists>(limit, params)
88 .await
89 .map(TrackList::from)
90 }
91
92 async fn fetch_artists<T>(
93 &self,
94 limit: TrackLimit,
95 additional_params: QueryParams,
96 ) -> Result<Vec<TopArtist>>
97 where
98 T: DeserializeOwned + ResourceContainer<ItemType = TopArtist>,
99 {
100 fetch::<TopArtist, T>(
101 self.http.clone(),
102 self.config.clone(),
103 self.username.clone(),
104 METHOD_TOP_ARTISTS,
105 limit,
106 additional_params,
107 self.progress_callback.as_ref(),
108 )
109 .await
110 }
111}
112
113impl LimitBuilder for TopArtistsRequestBuilder {
114 fn limit_mut(&mut self) -> &mut Option<u32> {
115 &mut self.limit
116 }
117}
118
119impl FetchAndSave for TopArtistsRequestBuilder {
120 type Item = TopArtist;
121
122 fn resource_label() -> &'static str {
123 "top artists"
124 }
125
126 async fn do_fetch(self) -> crate::error::Result<Vec<Self::Item>> {
127 Ok(Vec::from(self.fetch().await?))
128 }
129}
130
131impl ResourceContainer for UserTopArtists {
132 type ItemType = TopArtist;
133
134 fn total(&self) -> u32 {
135 self.topartists.attr.total
136 }
137
138 fn items(self) -> Vec<Self::ItemType> {
139 self.topartists.artist
140 }
141}