use std::convert::TryInto;
use std::time::{SystemTime, UNIX_EPOCH};
use crate::error::Error;
use crate::raw::request::{ListenType, Payload, SubmitListens, TrackMetadata};
use crate::raw::Client;
#[derive(Debug)]
struct Auth {
token: String,
user: String,
}
#[derive(Debug)]
pub struct ListenBrainz {
client: Client,
auth: Option<Auth>,
}
impl ListenBrainz {
pub fn new() -> Self {
Self {
client: Client::new(),
auth: None,
}
}
pub fn new_with_url(url: &str) -> Self {
Self {
client: Client::new_with_url(url),
auth: None,
}
}
pub fn api_url(&self) -> &str {
self.client.api_url()
}
pub fn is_authenticated(&self) -> bool {
self.auth.is_some()
}
pub fn authenticated_token(&self) -> Option<&str> {
self.auth.as_ref().map(|auth| auth.token.as_str())
}
pub fn authenticated_user(&self) -> Option<&str> {
self.auth.as_ref().map(|auth| auth.user.as_str())
}
pub fn authenticate(&mut self, token: &str) -> Result<(), Error> {
let result = self.client.validate_token(token)?;
if result.valid && result.user_name.is_some() {
self.auth.replace(Auth {
token: token.to_string(),
user: result.user_name.unwrap(),
});
return Ok(());
}
Err(Error::InvalidToken)
}
fn submit_listen(
&self,
listen_type: ListenType,
timestamp: Option<i64>,
artist: &str,
track: &str,
release: Option<&str>,
) -> Result<(), Error> {
let token = self.authenticated_token().ok_or(Error::NotAuthenticated)?;
let payload = Payload {
listened_at: timestamp,
track_metadata: TrackMetadata {
artist_name: artist,
track_name: track,
release_name: release,
additional_info: None,
},
};
self.client.submit_listens(
token,
SubmitListens {
listen_type,
payload: &[payload],
},
)?;
Ok(())
}
pub fn listen(&self, artist: &str, track: &str, release: Option<&str>) -> Result<(), Error> {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
.try_into()
.unwrap();
self.submit_listen(ListenType::Single, Some(now), artist, track, release)
}
pub fn import(
&self,
artist: &str,
track: &str,
release: Option<&str>,
timestamp: i64,
) -> Result<(), Error> {
self.submit_listen(ListenType::Import, Some(timestamp), artist, track, release)
}
pub fn playing_now(
&self,
artist: &str,
track: &str,
release: Option<&str>,
) -> Result<(), Error> {
self.submit_listen(ListenType::PlayingNow, None, artist, track, release)
}
}
impl Default for ListenBrainz {
fn default() -> Self {
Self::new()
}
}