use super::common::filter_by_original_album_artist;
use crate::{
AsyncDiscoveryIterator, ExactScrobbleEdit, LastFmEditClientImpl, LastFmError, Result,
ScrobbleEdit,
};
use async_trait::async_trait;
pub struct ExactMatchDiscovery {
client: LastFmEditClientImpl,
edit: ScrobbleEdit,
track_name: String,
album_name: String,
result: Option<ExactScrobbleEdit>,
completed: bool,
}
impl ExactMatchDiscovery {
pub fn new(
client: LastFmEditClientImpl,
edit: ScrobbleEdit,
track_name: String,
album_name: String,
) -> Self {
Self {
client,
edit,
track_name,
album_name,
result: None,
completed: false,
}
}
}
#[async_trait(?Send)]
impl AsyncDiscoveryIterator<ExactScrobbleEdit> for ExactMatchDiscovery {
async fn next(&mut self) -> Result<Option<ExactScrobbleEdit>> {
if self.completed {
return Ok(None);
}
if self.result.is_none() {
log::debug!(
"Looking up missing metadata for track '{}' on album '{}' by '{}'",
self.track_name,
self.album_name,
self.edit.artist_name_original
);
match self
.client
.load_edit_form_values_internal(&self.track_name, &self.edit.artist_name_original)
.await
{
Ok(all_variations) => {
let filtered_variations =
filter_by_original_album_artist(all_variations, &self.edit);
if let Some(exact_edit) = filtered_variations
.iter()
.find(|variation| variation.album_name_original == self.album_name)
{
let mut modified_edit = exact_edit.clone();
if let Some(new_track_name) = &self.edit.track_name {
modified_edit.track_name = new_track_name.clone();
}
if let Some(new_album_name) = &self.edit.album_name {
modified_edit.album_name = new_album_name.clone();
}
modified_edit.artist_name = self.edit.artist_name.clone();
if let Some(new_album_artist_name) = &self.edit.album_artist_name {
modified_edit.album_artist_name = new_album_artist_name.clone();
}
modified_edit.edit_all = self.edit.edit_all;
self.result = Some(modified_edit);
} else {
let album_artist_filter = if let Some(album_artist_name_original) =
self.edit.album_artist_name_original.as_ref()
{
format!(" with album artist '{album_artist_name_original}'")
} else {
String::new()
};
self.completed = true;
return Err(LastFmError::Parse(format!(
"Track '{}' not found on album '{}' by '{}'{} in recent scrobbles",
self.track_name,
self.album_name,
self.edit.artist_name_original,
album_artist_filter
)));
}
}
Err(e) => {
self.completed = true;
return Err(e);
}
}
}
self.completed = true;
Ok(self.result.take())
}
}