use super::eapi;
use super::response::{LyricContent, LyricsResponse, SearchResponse, SyllableLyricsResponse};
use crate::providers::web::base_api;
const REFERER: &str = "https://music.163.com/";
const SYLLABLE_LYRICS_URL: &str = "https://interface3.music.163.com/eapi/song/lyric/v1";
fn standard_headers() -> Vec<(&'static str, &'static str)> {
vec![
("Referer", REFERER),
("Cookie", base_api::COOKIE),
("User-Agent", base_api::USER_AGENT),
]
}
pub(crate) async fn search(keyword: &str) -> Option<SearchResponse> {
let url = format!(
"https://music.163.com/api/search/get?s={}&type=1&limit=10&offset=0",
urlencoding::encode(keyword)
);
base_api::get_json_with_headers(&url, &standard_headers()).await
}
pub async fn get_lyrics(song_id: i64) -> Option<(Option<String>, Option<String>)> {
let url = format!(
"https://music.163.com/api/song/lyric?id={}&lv=1&kv=1&tv=-1",
song_id
);
let resp: LyricsResponse = base_api::get_json_with_headers(&url, &standard_headers()).await?;
Some((
resp.lrc.and_then(|l| l.lyric),
resp.tlyric.and_then(|t| t.lyric),
))
}
#[derive(Debug, Clone, Default)]
pub struct SyllableLyrics {
pub yrc: Option<String>,
pub ytlrc: Option<String>,
pub yromalrc: Option<String>,
}
pub async fn get_syllable_lyrics(song_id: i64) -> Option<SyllableLyrics> {
let response = eapi::post(
SYLLABLE_LYRICS_URL,
serde_json::json!({
"id": song_id.to_string(),
"cp": "false",
"lv": "0",
"kv": "0",
"tv": "0",
"rv": "0",
"yv": "0",
"ytv": "0",
"yrv": "0",
"csrf_token": "",
}),
)
.await?;
let response: SyllableLyricsResponse = serde_json::from_str(&response).ok()?;
let lyrics = SyllableLyrics {
yrc: lyric_text(response.yrc),
ytlrc: lyric_text(response.ytlrc),
yromalrc: lyric_text(response.yromalrc),
};
(lyrics.yrc.is_some() || lyrics.ytlrc.is_some() || lyrics.yromalrc.is_some()).then_some(lyrics)
}
fn lyric_text(content: Option<LyricContent>) -> Option<String> {
content
.and_then(|content| content.lyric)
.filter(|lyric| !lyric.is_empty())
}