use serde::{Deserialize, Serialize};
#[allow(dead_code)]
fn is_zero_i32(value: &i32) -> bool { *value == 0 }
#[allow(dead_code)]
fn is_zero_u32(value: &u32) -> bool { *value == 0 }
#[allow(dead_code)]
fn is_zero_i64(value: &i64) -> bool { *value == 0 }
#[allow(dead_code)]
fn is_zero_u64(value: &u64) -> bool { *value == 0 }
#[allow(dead_code)]
fn is_zero_f32(value: &f32) -> bool { *value == 0.0 }
#[allow(dead_code)]
fn is_zero_f64(value: &f64) -> bool { *value == 0.0 }
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FindSonicPathRequest {
#[serde(default)]
pub start_song: SongRef,
#[serde(default)]
pub end_song: SongRef,
#[serde(default)]
pub count: i32,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetSonicSimilarTracksRequest {
#[serde(default)]
pub song: SongRef,
#[serde(default)]
pub count: i32,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SongRef {
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(default)]
pub name: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub mbid: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub isrc: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub artist: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub artist_mbid: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub album: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub album_mbid: String,
#[serde(default, skip_serializing_if = "is_zero_f32")]
pub duration: f32,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SonicMatch {
#[serde(default)]
pub song: SongRef,
#[serde(default)]
pub similarity: f64,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SonicSimilarityResponse {
#[serde(default)]
pub matches: Vec<SonicMatch>,
}
#[derive(Debug)]
pub struct Error {
pub message: String,
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.message)
}
}
impl std::error::Error for Error {}
impl Error {
pub fn new(message: impl Into<String>) -> Self {
Self { message: message.into() }
}
}
pub trait SonicSimilarity {
fn get_sonic_similar_tracks(&self, req: GetSonicSimilarTracksRequest) -> Result<SonicSimilarityResponse, Error>;
fn find_sonic_path(&self, req: FindSonicPathRequest) -> Result<SonicSimilarityResponse, Error>;
}
#[macro_export]
macro_rules! register_sonicsimilarity {
($plugin_type:ty) => {
#[extism_pdk::plugin_fn]
pub fn nd_get_sonic_similar_tracks(
req: extism_pdk::Json<$crate::sonicsimilarity::GetSonicSimilarTracksRequest>
) -> extism_pdk::FnResult<extism_pdk::Json<$crate::sonicsimilarity::SonicSimilarityResponse>> {
let plugin = <$plugin_type>::default();
let result = $crate::sonicsimilarity::SonicSimilarity::get_sonic_similar_tracks(&plugin, req.into_inner())?;
Ok(extism_pdk::Json(result))
}
#[extism_pdk::plugin_fn]
pub fn nd_find_sonic_path(
req: extism_pdk::Json<$crate::sonicsimilarity::FindSonicPathRequest>
) -> extism_pdk::FnResult<extism_pdk::Json<$crate::sonicsimilarity::SonicSimilarityResponse>> {
let plugin = <$plugin_type>::default();
let result = $crate::sonicsimilarity::SonicSimilarity::find_sonic_path(&plugin, req.into_inner())?;
Ok(extism_pdk::Json(result))
}
};
}