arhivach-downloader

Download arhivach.vc threads
git clone https://git.ea.contact/arhivach-downloader
Log | Files | Refs | README

commit 21406a80688851194f2659c5bc0ae1cf00c7f906
parent 570f44de7f09b6e6228717fbde3434130eb2da18
Author: egor-achkasov <eaachkasov@gmail.com>
Date:   Wed,  6 May 2026 15:49:22 +0000

Replace reqwest with ureq

Diffstat:
MCargo.toml | 2+-
Msrc/lib/download.rs | 49++++++++++++++++++++++++-------------------------
Msrc/lib/lib.rs | 9++++++---
3 files changed, 31 insertions(+), 29 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -24,5 +24,5 @@ anyhow = "1.0.102" arboard = "3" clap = { version = "4.5.57", features = ["derive"] } ratatui = "0.29" -reqwest = { version = "0.12", features = ["blocking"] } scraper = "0.25.0" +ureq = "3.3.0" diff --git a/src/lib/download.rs b/src/lib/download.rs @@ -1,25 +1,24 @@ -use anyhow::{anyhow, Result}; - -/// Downloads a URL, retrying up to `tries` times. -/// -/// # Errors -/// Returns an error if all attempts fail or `tries` is 0. -pub fn download(url: &str, tries: u32) -> Result<reqwest::blocking::Response> { - static CLIENT: std::sync::LazyLock<reqwest::blocking::Client> = - std::sync::LazyLock::new(reqwest::blocking::Client::new); - - for attempt in 0..tries { - if attempt > 0 { - std::thread::sleep(std::time::Duration::from_millis(500 * 2u64.pow(attempt))); - } - let response = CLIENT.get(url).send()?; - if response.status().is_success() { - return Ok(response); - } - if response.status().is_client_error() { - return Err(anyhow!("client error: {}", response.status())); - } - } - - Err(anyhow!("failed to download {} after {} tries", url, tries)) -} +use anyhow::{anyhow, Result}; + +/// Downloads a URL, retrying up to `tries` times. +/// +/// # Errors +/// Returns an error if all attempts fail or `tries` is 0. +pub fn download(url: &str, tries: u32) -> Result<ureq::http::Response<ureq::Body>> { + static CLIENT: std::sync::LazyLock<ureq::Agent> = + std::sync::LazyLock::new(ureq::Agent::new_with_defaults); + for attempt in 0..tries { + if attempt > 0 { + std::thread::sleep(std::time::Duration::from_millis(500 * 2u64.pow(attempt))); + } + match CLIENT.get(url).call() { + Ok(response) => return Ok(response), + Err(ureq::Error::StatusCode(code)) if code >= 400 && code < 500 => { + return Err(anyhow!("client error: {}", code)); + } + Err(ureq::Error::StatusCode(_)) => continue, + Err(e) => return Err(e.into()), + } + } + Err(anyhow!("failed to download {} after {} tries", url, tries)) +} diff --git a/src/lib/lib.rs b/src/lib/lib.rs @@ -16,7 +16,10 @@ pub const BASE_URL: &str = "https://arhivach.vc"; pub fn run(config: &config::Config, tx: Sender<event::Event>) -> Result<()> { tx.send(event::Event::GetStarted)?; - let html = download::download(&config.url, config.download_retries)?.text()?; + let html = download::download(&config.url, config.download_retries)? + .body_mut() + .read_to_string() + .context("failed to read response body")?; let posts = Post::parse_posts(&html) .inspect_err(|e| { let _ = tx.send(event::Event::GetFailed { error: format!("{:#}", e) }); }) .context("failed to parse posts")?; @@ -43,8 +46,8 @@ fn run_download(posts: &[Post], config: &config::Config, tx: Sender<event::Event let download_item = |url: &str, filepath: &std::path::PathBuf| -> Result<()> { let result = download::download(url, config.download_retries)?; - anyhow::ensure!(result.status().is_success(), "failed to download {}: {}", url, result.status()); - let bytes = result.bytes()?; + let mut bytes = Vec::new(); + std::io::Read::read_to_end(&mut result.into_body().as_reader(), &mut bytes)?; anyhow::ensure!(!bytes.is_empty(), "empty file: {}", url); std::fs::write(filepath, bytes)?; Ok(())