use gettextrs::gettext;
use serde_json::Value;
use soup::prelude::SessionExt;
use std::error::Error;
use crate::core::thread_messages::*;
use crate::core::fingerprinting::communication::{
obtain_raw_cover_image, recognize_song_from_signature,
};
use crate::core::fingerprinting::signature_format::DecodedSignature;
async fn try_recognize_song(
session: &soup::Session,
signature: DecodedSignature,
) -> Result<SongRecognizedMessage, Box<dyn Error>> {
let json_object = recognize_song_from_signature(session, &signature).await?;
let mut album_name: Option<String> = None;
let mut release_year: Option<String> = None;
if let Value::Array(sections) = &json_object["track"]["sections"] {
for section in sections {
if let Value::String(string) = §ion["type"]
&& string == "SONG"
{
if let Value::Array(metadata) = §ion["metadata"] {
for metadatum in metadata {
if let Value::String(title) = &metadatum["title"] {
if title == "Album"
&& let Value::String(text) = &metadatum["text"]
{
album_name = Some(text.to_string());
} else if title == "Released"
&& let Value::String(text) = &metadatum["text"]
{
release_year = Some(text.to_string());
}
}
}
break;
}
}
}
}
Ok(SongRecognizedMessage {
artist_name: match &json_object["track"]["subtitle"] {
Value::String(string) => string.to_string(),
_ => {
return Err(Box::new(std::io::Error::other(
gettext("No match for this song").as_str(),
)));
}
},
album_name,
song_name: match &json_object["track"]["title"] {
Value::String(string) => string.to_string(),
_ => {
return Err(Box::new(std::io::Error::other(
gettext("No match for this song").as_str(),
)));
}
},
cover_image: match &json_object["track"]["images"]["coverart"] {
Value::String(string) => Some(obtain_raw_cover_image(session, string).await?),
_ => None,
},
track_key: match &json_object["track"]["key"] {
Value::String(string) => string.to_string(),
_ => {
return Err(Box::new(std::io::Error::other(
gettext("No match for this song").as_str(),
)));
}
},
release_year,
genre: match &json_object["track"]["genres"]["primary"] {
Value::String(string) => Some(string.to_string()),
_ => None,
},
shazam_json: serde_json::to_string(&json_object).unwrap(),
})
}
pub async fn http_task(
http_rx: async_channel::Receiver<HTTPMessage>,
gui_tx: async_channel::Sender<GUIMessage>,
microphone_tx: async_channel::Sender<MicrophoneMessage>,
) {
let session = soup::Session::new();
session.set_timeout(20);
session.set_idle_timeout(2);
while let Ok(message) = http_rx.recv().await {
match message {
HTTPMessage::RecognizeSignature(signature) => {
match try_recognize_song(&session, *signature).await {
Ok(recognized_song) => {
gui_tx
.try_send(GUIMessage::SongRecognized(Box::new(recognized_song)))
.unwrap();
gui_tx.try_send(GUIMessage::NetworkStatus(true)).unwrap();
gui_tx.try_send(GUIMessage::RateLimitState(false)).unwrap();
}
Err(error) => match error.to_string().as_str() {
a if a == gettext("No match for this song") => {
gui_tx
.try_send(GUIMessage::ErrorMessage(error.to_string()))
.unwrap();
gui_tx.try_send(GUIMessage::NetworkStatus(true)).unwrap();
gui_tx.try_send(GUIMessage::RateLimitState(false)).unwrap();
}
a if a == gettext("Your IP has been rate-limited") => {
gui_tx.try_send(GUIMessage::RateLimitState(true)).unwrap();
}
_ => {
log::error!("Network reach error: {:?}", error);
gui_tx.try_send(GUIMessage::NetworkStatus(false)).unwrap();
}
},
};
microphone_tx
.try_send(MicrophoneMessage::ProcessingDone)
.unwrap();
}
}
}
}