use thiserror::Error;
use crate::{
REQWEST_CLIENT,
library::track::ResolvedTrack,
scrobbling::lastfm::{
LASTFM_API_KEY, LASTFM_SCROBBLER_ORIGIN, LastFmClient, LastFmClientError, LastFmResult,
request_sig,
},
};
#[derive(Debug, Error)]
pub enum LastFmMethodError {
#[error("Could not scrobble the given track because the track has no title")]
MissingTrackTitle,
#[error("Could not scrobble the given track because the track has no artists")]
MissingArtist,
}
impl LastFmClient {
pub async fn now_playing(&self, track: &ResolvedTrack) -> Result<(), LastFmClientError> {
let mut query: Vec<(&'static str, String)> = vec![
("method", "track.updatenowplaying".to_owned()),
("api_key", LASTFM_API_KEY.to_owned()),
("sk", self.key.clone()),
];
add_form_by_track(&mut query, track)?;
let sig = request_sig(&query);
query.push(("api_sig", sig));
query.push(("format", "json".to_owned()));
REQWEST_CLIENT
.post(LASTFM_SCROBBLER_ORIGIN)
.form(&query)
.send()
.await
.unwrap()
.json::<LastFmResult<serde::de::IgnoredAny>>()
.await
.unwrap()
.into_result()?;
Ok(())
}
pub async fn scrobble(
&self,
track: &ResolvedTrack,
started_at: u64,
chosen_by_user: bool,
) -> Result<(), LastFmClientError> {
let mut query: Vec<(&'static str, String)> = vec![
("method", "track.scrobble".to_owned()),
("api_key", LASTFM_API_KEY.to_owned()),
("sk", self.key.clone()),
("timestamp", started_at.to_string()),
("chosenByUser", u8::from(chosen_by_user).to_string()),
];
add_form_by_track(&mut query, track)?;
let sig = request_sig(&query);
query.push(("api_sig", sig));
query.push(("format", "json".to_owned()));
REQWEST_CLIENT
.post(LASTFM_SCROBBLER_ORIGIN)
.form(&query)
.send()
.await
.unwrap()
.json::<LastFmResult<serde::de::IgnoredAny>>()
.await
.unwrap()
.into_result()?;
Ok(())
}
}
fn add_form_by_track(
query: &mut Vec<(&'static str, String)>,
track: &ResolvedTrack,
) -> Result<(), LastFmMethodError> {
let track_title = track
.metadata
.title
.as_ref()
.ok_or(LastFmMethodError::MissingTrackTitle)?
.to_owned();
let main_track_artist = track
.artists()
.first()
.ok_or(LastFmMethodError::MissingArtist)?
.name()
.to_owned();
let duration = track.container().stream().duration();
query.extend([
("artist", main_track_artist.clone()),
("track", track_title),
("duration", duration.to_string()),
]);
if let Some((album, artists, ..)) = track.album_info() {
query.push(("album", album.name().to_owned()));
if let Some(main_album_artist) = artists.first().map(|a| a.name())
&& main_album_artist != main_track_artist
{
query.push(("albumArtist", main_album_artist.to_owned()));
}
}
Ok(())
}