diff --git a/.gitignore b/.gitignore index e18d350..1d63ba5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ target/ # Error / Debug Logging *.log +*.txt # MSVC Windows builds of rustc generate these, which store debugging information *.pdb @@ -19,4 +20,4 @@ target/ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ \ No newline at end of file +#.idea/ diff --git a/Cargo.lock b/Cargo.lock index d2875b7..2679b20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,6 +113,19 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "console" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys 0.59.0", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -200,6 +213,12 @@ dependencies = [ "syn", ] +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -647,6 +666,19 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.17.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width", + "web-time", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -780,6 +812,12 @@ dependencies = [ "libc", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "object" version = "0.36.7" @@ -869,6 +907,12 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "portable-atomic" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + [[package]] name = "proc-macro2" version = "1.0.94" @@ -1386,6 +1430,12 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + [[package]] name = "untrusted" version = "0.9.0" @@ -1532,6 +1582,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1849,6 +1909,7 @@ dependencies = [ "colored", "ctrlc", "flate2", + "indicatif", "md-5", "reqwest", "serde", diff --git a/Cargo.toml b/Cargo.toml index 314634e..80e98dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ serde = "1.0.219" ctrlc = "3.4.7" shellexpand = "3.1.1" flate2 = "1.1.1" +indicatif = "0.17.11" [target.'cfg(windows)'.dependencies] winconsole = "0.11.1" diff --git a/src/io/util.rs b/src/io/util.rs index 567a846..fafaaa1 100644 --- a/src/io/util.rs +++ b/src/io/util.rs @@ -2,11 +2,7 @@ use colored::Colorize; use reqwest::blocking::Client; use serde_json::Value; use std::{ - fs::{self, File}, - io::{self, Write}, - sync::Arc, - thread, - time::{Duration, Instant}, + fs::{self, File}, io::{self, Write}, process::Command, sync::Arc, thread, time::{Duration, Instant} }; #[cfg(windows)] use winconsole::console::{clear, set_title}; @@ -122,6 +118,9 @@ pub fn calculate_total_size(resources: &[Value], client: &Client, config: &Confi bytes_to_human(total_size).cyan() ); + #[cfg(not(target_os = "windows"))] + Command::new("clear").status().unwrap(); + total_size } diff --git a/src/main.rs b/src/main.rs index 148ab9f..4f03f3e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +use std::process::Command; + use colored::*; use reqwest::blocking::Client; use serde_json::Value; @@ -33,6 +35,9 @@ fn main() { #[cfg(windows)] clear().unwrap(); + #[cfg(not(target_os = "windows"))] + Command::new("clear").status().unwrap(); + println!( "\n{} Download folder: {}\n", Status::info(), diff --git a/src/network/client.rs b/src/network/client.rs index 08e697d..680afa8 100644 --- a/src/network/client.rs +++ b/src/network/client.rs @@ -1,13 +1,10 @@ use colored::Colorize; use flate2::read::GzDecoder; +use indicatif::{ProgressBar, ProgressStyle}; use reqwest::blocking::Client; use serde_json::{Value, from_reader, from_str}; use std::{ - fs, - io::{self, Read, Write}, - path::Path, - time::Duration, - u64, + fs, io::{self, Read, Write}, path::Path, process::Command, time::Duration, u64 }; #[cfg(windows)] use winconsole::console::clear; @@ -234,16 +231,23 @@ pub fn download_file( println!("{} Downloading: {}", Status::progress(), filename.purple()); + let pb = ProgressBar::new(expected_size.unwrap_or(0)); + pb.set_style(ProgressStyle::default_bar() + .template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta}, {binary_bytes_per_sec})") + .unwrap() + .progress_chars("#>-")); + let mut retries = MAX_RETRIES; let mut last_error = None; while retries > 0 { - let result = download_single_file(&client, &url, &path, should_stop, progress); + let result = download_single_file(&client, &url, &path, should_stop, progress, &pb); match result { Ok(_) => break, Err(e) => { if should_stop.load(std::sync::atomic::Ordering::SeqCst) { + pb.finish_and_clear(); return false; } @@ -263,6 +267,8 @@ pub fn download_file( } } + pb.finish_and_clear(); + if should_stop.load(std::sync::atomic::Ordering::SeqCst) { return false; } @@ -315,6 +321,7 @@ fn download_single_file( path: &Path, should_stop: &std::sync::atomic::AtomicBool, progress: &DownloadProgress, + pb: &ProgressBar, ) -> Result<(), String> { let mut response = client .get(url) @@ -329,6 +336,7 @@ fn download_single_file( let mut file = fs::File::create(path).map_err(|e| format!("File error: {}", e))?; let mut buffer = [0; BUFFER_SIZE]; + let mut downloaded: u64 = 0; loop { if should_stop.load(std::sync::atomic::Ordering::SeqCst) { return Err("Download interrupted".into()); @@ -345,6 +353,8 @@ fn download_single_file( file.write_all(&buffer[..bytes_read]) .map_err(|e| format!("Write error: {}", e))?; + downloaded += bytes_read as u64; + pb.set_position(downloaded); progress .downloaded_bytes .fetch_add(bytes_read as u64, std::sync::atomic::Ordering::SeqCst); @@ -519,6 +529,9 @@ pub fn fetch_gist(client: &Client) -> Result { from_reader(response).map_err(|e| format!("Invalid JSON: {}", e))? }; + #[cfg(not(target_os = "windows"))] + Command::new("clear").status().unwrap(); + println!("{} Available versions:", Status::info()); println!("1. Live - OS"); println!("2. Live - CN");