Skip to main content

binkget/
lib.rs

1use indicatif::{HumanBytes, ProgressBar, ProgressStyle, ProgressDrawTarget};
2use reqwest::Client;
3use tokio::io::AsyncWriteExt;
4use tokio::fs::File;
5use url::Url;
6use console::style;
7use futures_util::StreamExt; // For async streaming
8
9fn create_progress_bar(quiet_mode: bool, msg: &str, length: Option<u64>) -> ProgressBar {
10    let bar = if quiet_mode {
11        ProgressBar::hidden()
12    } else {
13        match length {
14            Some(len) => ProgressBar::new(len),
15            None => ProgressBar::new_spinner(),
16        }
17    };
18
19    bar.set_message(msg.to_string());
20    bar.set_draw_target(ProgressDrawTarget::stderr_with_hz(10)); // Ensure it updates in place
21    if length.is_some() {
22        bar.set_style(
23            ProgressStyle::default_bar()
24                .template("{msg} {spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} eta: {eta}")
25                .unwrap()
26                .progress_chars("=>"),
27        );
28    } else {
29        bar.set_style(ProgressStyle::default_spinner());
30    }
31
32    bar
33}
34
35pub async fn download(target: &str, quiet_mode: bool, fname: &str) -> Result<(), Box<dyn std::error::Error>> {
36    let url = Url::parse(target)?;
37    let client = Client::new();
38    let resp = client.get(url.clone()).send().await?; // Await here
39
40    if !quiet_mode {
41        println!("HTTP request sent.. {}", style(resp.status()).green());
42    }
43
44    if resp.status().is_success() {
45        let headers = resp.headers();
46
47        let ct_len = headers.get("content-length")
48            .and_then(|v| v.to_str().ok())
49            .and_then(|s| s.parse::<u64>().ok());
50
51        let ct_type = headers.get("content-type")
52            .map(|v| v.to_str().unwrap_or("unknown"))
53            .unwrap_or("unknown");
54
55        if !quiet_mode {
56            match ct_len {
57                Some(len) => {
58                    println!(
59                        "Length: {} ({})",
60                        style(len).green(),
61                        style(HumanBytes(len)).red()
62                    );
63                }
64                None => {
65                    println!("Length: {}", style("unknown").red());
66                }
67            }
68            println!("Type: {}", style(ct_type).green());
69        }
70        
71        if !quiet_mode {
72            println!("Saving to: {}", style(&fname).green());
73        }
74
75        let mut file = File::create(fname).await?;
76        let bar = create_progress_bar(quiet_mode, &fname, ct_len);
77        
78        
79        let mut stream = resp.bytes_stream();
80        while let Some(chunk) = stream.next().await {
81            let chunk = chunk?;
82            file.write_all(&chunk).await?;
83            bar.inc(chunk.len() as u64);
84        }
85
86        bar.finish();
87        if !quiet_mode {
88            println!("Download complete!");
89        }
90    }
91
92    Ok(())
93}