Hardened the lookups
This commit is contained in:
@@ -70,20 +70,59 @@ impl LastfmClient {
|
||||
Self { api_key }
|
||||
}
|
||||
|
||||
/// Fetch a URL and return the body. Returns `None` if Last.fm returns an API error.
|
||||
fn fetch_or_none(&self, url: &str) -> Result<Option<String>, Box<dyn std::error::Error>> {
|
||||
let body: String = ureq::get(url).call()?.body_mut().read_to_string()?;
|
||||
if serde_json::from_str::<ApiError>(&body).is_ok() {
|
||||
return Ok(None);
|
||||
}
|
||||
Ok(Some(body))
|
||||
}
|
||||
|
||||
/// Try fetching by MBID first, fall back to artist name.
|
||||
fn fetch_with_fallback(
|
||||
&self,
|
||||
method: &str,
|
||||
artist_mbid: &str,
|
||||
artist_name: Option<&str>,
|
||||
extra_params: &str,
|
||||
) -> Result<Option<String>, Box<dyn std::error::Error>> {
|
||||
let url = format!(
|
||||
"{}?method={}&mbid={}&api_key={}{}&format=json",
|
||||
BASE_URL, method, artist_mbid, self.api_key, extra_params
|
||||
);
|
||||
if let Some(body) = self.fetch_or_none(&url)? {
|
||||
return Ok(Some(body));
|
||||
}
|
||||
|
||||
// Fall back to artist name
|
||||
if let Some(name) = artist_name {
|
||||
let encoded = urlencoding::encode(name);
|
||||
let url = format!(
|
||||
"{}?method={}&artist={}&api_key={}{}&format=json",
|
||||
BASE_URL, method, encoded, self.api_key, extra_params
|
||||
);
|
||||
if let Some(body) = self.fetch_or_none(&url)? {
|
||||
return Ok(Some(body));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn get_similar_artists(
|
||||
&self,
|
||||
artist_mbid: &str,
|
||||
artist_name: Option<&str>,
|
||||
) -> Result<Vec<SimilarArtist>, Box<dyn std::error::Error>> {
|
||||
let url = format!(
|
||||
"{}?method=artist.getSimilar&mbid={}&api_key={}&limit=500&format=json",
|
||||
BASE_URL, artist_mbid, self.api_key
|
||||
);
|
||||
let body: String = ureq::get(&url).call()?.body_mut().read_to_string()?;
|
||||
|
||||
if let Ok(err) = serde_json::from_str::<ApiError>(&body) {
|
||||
eprintln!(" Last.fm: {}", err.message);
|
||||
let Some(body) = self.fetch_with_fallback(
|
||||
"artist.getSimilar",
|
||||
artist_mbid,
|
||||
artist_name,
|
||||
"&limit=500",
|
||||
)? else {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
};
|
||||
|
||||
let resp: SimilarArtistsResponse = serde_json::from_str(&body)?;
|
||||
Ok(resp
|
||||
@@ -104,17 +143,16 @@ impl LastfmClient {
|
||||
pub fn get_top_tracks(
|
||||
&self,
|
||||
artist_mbid: &str,
|
||||
artist_name: Option<&str>,
|
||||
) -> Result<Vec<TopTrack>, Box<dyn std::error::Error>> {
|
||||
let url = format!(
|
||||
"{}?method=artist.getTopTracks&mbid={}&api_key={}&limit=1000&format=json",
|
||||
BASE_URL, artist_mbid, self.api_key
|
||||
);
|
||||
let body: String = ureq::get(&url).call()?.body_mut().read_to_string()?;
|
||||
|
||||
if let Ok(err) = serde_json::from_str::<ApiError>(&body) {
|
||||
eprintln!(" Last.fm: {}", err.message);
|
||||
let Some(body) = self.fetch_with_fallback(
|
||||
"artist.getTopTracks",
|
||||
artist_mbid,
|
||||
artist_name,
|
||||
"&limit=1000",
|
||||
)? else {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
};
|
||||
|
||||
let resp: TopTracksResponse = serde_json::from_str(&body)?;
|
||||
Ok(resp
|
||||
|
||||
Reference in New Issue
Block a user