commit b43351e5afe73c57a917be308645939439eb14b3
parent 58a3978b0b5f52143a465ebd31d64d9f06e63a86
Author: egor-achkasov <eaachkasov@gmail.com>
Date: Thu, 12 Mar 2026 21:53:05 +0000
Fix FLAC resolution
Diffstat:
1 file changed, 33 insertions(+), 8 deletions(-)
diff --git a/src/lib/lib.rs b/src/lib/lib.rs
@@ -16,21 +16,21 @@ pub async fn run(config: Config, tx: Sender<Event>) -> Result<()> {
let main_page = client.get(&config.url).send().await.context("Failed to get main page")?;
tx.send(Event::GetPageCompleted)?;
- let (name, image_urls, track_urls) = parse_page(main_page, config.images, config.flac).await?;
+ let (name, image_urls, track_urls) = parse_page(main_page, config.images).await?;
let dest_dir = std::path::Path::new(&name).to_path_buf();
std::fs::create_dir_all(&dest_dir)?;
let mut joinset = tokio::task::JoinSet::new();
for url in track_urls {
- joinset.spawn(download(client.clone(), url, dest_dir.clone(), tx.clone()));
+ joinset.spawn(download(client.clone(), url, dest_dir.clone(), tx.clone(), config.flac));
}
if config.images {
let dest_dir = std::path::Path::new(&name).join("images");
std::fs::create_dir_all(&dest_dir)?;
for url in image_urls {
- joinset.spawn(download(client.clone(), url, dest_dir.clone(), tx.clone()));
+ joinset.spawn(download(client.clone(), url, dest_dir.clone(), tx.clone(), false));
}
}
@@ -44,7 +44,6 @@ pub async fn run(config: Config, tx: Sender<Event>) -> Result<()> {
async fn parse_page(
main_page: reqwest::Response,
images: bool,
- flac: bool
) -> Result<(String, Vec<Url>, Vec<Url>)> {
let base_url = main_page.url().clone();
let html = main_page.text().await.context("Failed to read page body")?;
@@ -75,9 +74,7 @@ async fn parse_page(
Vec::new()
};
- let td = if flac { 6 } else { 5 };
- let track_sel_str = format!("#songlist tbody tr td:nth-child({td}) a");
- let track_sel = scraper::Selector::parse(&track_sel_str).unwrap();
+ let track_sel = scraper::Selector::parse("#songlist tbody tr td:nth-child(5) a").unwrap();
let track_urls = document
.select(&track_sel)
.filter_map(|el| el.value().attr("href"))
@@ -108,11 +105,28 @@ fn percent_decode(s: &str) -> String {
String::from_utf8_lossy(&bytes).into_owned()
}
+async fn resolve_flac_url(client: &reqwest::Client, track_page_url: &Url) -> Result<Url> {
+ let html = client.get(track_page_url.clone()).send().await?.text().await?;
+ let document = scraper::Html::parse_document(&html);
+ let sel = scraper::Selector::parse(
+ "#pageContent > p:nth-child(10) > a"
+ ).map_err(|e| anyhow::anyhow!("Failed to parse FLAC link selector: {e}"))?;
+ let href = document
+ .select(&sel)
+ .next()
+ .ok_or_else(|| anyhow::anyhow!("FLAC link not found on page: {}", track_page_url))?
+ .value()
+ .attr("href")
+ .ok_or_else(|| anyhow::anyhow!("FLAC link has no href on page: {}", track_page_url))?;
+ track_page_url.join(href).context("Failed to parse FLAC URL")
+}
+
async fn download(
client: reqwest::Client,
url: Url,
dest_dir: std::path::PathBuf,
tx: Sender<Event>,
+ flac: bool,
) -> Result<()> {
async fn dl(client: reqwest::Client, url: &Url, dest_dir: std::path::PathBuf) -> Result<()> {
let filename = url
@@ -128,7 +142,18 @@ async fn download(
}
tx.send(Event::DlStarted { url: url.to_string() })?;
- match dl(client, &url, dest_dir).await {
+ let download_url = if flac {
+ match resolve_flac_url(&client, &url).await {
+ Ok(u) => u,
+ Err(e) => {
+ tx.send(Event::DlFailed { error: e })?;
+ return Ok(());
+ }
+ }
+ } else {
+ url.clone()
+ };
+ match dl(client, &download_url, dest_dir).await {
Err(e) => tx.send(Event::DlFailed { error: e })?,
Ok(()) => tx.send(Event::DlCompleted { url: url.to_string() })?
};