use clap::ValueEnum;
use kakasi::IsJapanese;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::fetchers::lrclib::convert_lrc;
#[derive(Serialize, Deserialize, Clone, Debug, Default, ValueEnum, PartialEq)]
pub enum Language {
#[default]
#[value(hide = true)]
Other,
#[value(name = "zh")]
Chinese,
#[value(name = "ja")]
Japanese,
#[value(name = "ko")]
Korean,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Lyrics {
pub language: Language,
pub duration: f64,
pub lyrics: Vec<(f64, String)>,
}
impl Lyrics {
pub fn from_lrc_json(object: &Value) -> Option<Lyrics> {
let synced = object["syncedLyrics"].as_str()?.to_string();
let timestamped: Vec<(f64, String)> = convert_lrc(synced)?;
let duration = object["duration"].as_f64()?;
let language = object["plainLyrics"].as_str().map_or_else(
|| get_language_from_text(×tamped
.iter()
.map(|(_, line)| line)
.fold(String::new(), |a, b| a + b + &"\n")),
get_language_from_text
);
Some(Lyrics {
language,
duration,
lyrics: timestamped,
})
}
pub fn get_line_at_time(&self, time: f64) -> &str {
match self.lyrics.iter().rev().find(|l| time > l.0) {
Some(l) => &l.1,
None => "",
}
}
}
fn get_language_from_text(lyrics: &str) -> Language {
match kakasi::is_japanese(lyrics) {
IsJapanese::Maybe => Language::Chinese,
IsJapanese::True => Language::Japanese,
IsJapanese::False => {
if korean_romanize::has_korean(lyrics) {
Language::Korean
} else {
Language::Other
}
},
}
}