From 76cf8f41f7924dcf1afa96c4713f5c8ad84d8158 Mon Sep 17 00:00:00 2001 From: Drew Short Date: Mon, 25 May 2020 18:19:23 -0500 Subject: [PATCH] Fixed downloads added progress --- Cargo.lock | 229 ++++++++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 3 +- src/main.rs | 69 ++++++++++++---- 3 files changed, 279 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bf3083e..12a9d77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,6 +6,7 @@ version = "0.1.0" dependencies = [ "chrono", "clap", + "crossterm", "curl", "lazy_static", "serde", @@ -19,9 +20,15 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ - "winapi", + "winapi 0.3.8", ] +[[package]] +name = "arc-swap" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b585a98a234c46fc563103e9278c9391fde1f4e6850334da895d27edb9580f62" + [[package]] name = "atty" version = "0.2.14" @@ -30,7 +37,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi", + "winapi 0.3.8", ] [[package]] @@ -84,6 +91,40 @@ dependencies = [ "vec_map", ] +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "crossterm" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9851d20b9809e561297ec3ca85d7cba3a57507fe8d01d07ba7b52469e1c89a11" +dependencies = [ + "bitflags", + "crossterm_winapi", + "lazy_static", + "libc", + "mio", + "parking_lot", + "signal-hook", + "winapi 0.3.8", +] + +[[package]] +name = "crossterm_winapi" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057b7146d02fb50175fd7dbe5158f6097f33d02831f43b4ee8ae4ddf67b68f5c" +dependencies = [ + "winapi 0.3.8", +] + [[package]] name = "curl" version = "0.4.29" @@ -96,7 +137,7 @@ dependencies = [ "openssl-sys", "schannel", "socket2", - "winapi", + "winapi 0.3.8", ] [[package]] @@ -111,9 +152,25 @@ dependencies = [ "openssl-sys", "pkg-config", "vcpkg", - "winapi", + "winapi 0.3.8", ] +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + [[package]] name = "hermit-abi" version = "0.1.13" @@ -134,12 +191,31 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + [[package]] name = "itoa" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -164,12 +240,72 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "lock_api" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +dependencies = [ + "cfg-if", +] + [[package]] name = "matches" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +[[package]] +name = "mio" +version = "0.6.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" +dependencies = [ + "cfg-if", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + +[[package]] +name = "miow" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + +[[package]] +name = "net2" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7" +dependencies = [ + "cfg-if", + "libc", + "winapi 0.3.8", +] + [[package]] name = "num-integer" version = "0.1.42" @@ -208,6 +344,30 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "parking_lot" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" +dependencies = [ + "cfg-if", + "cloudabi", + "libc", + "redox_syscall", + "smallvec", + "winapi 0.3.8", +] + [[package]] name = "percent-encoding" version = "2.1.0" @@ -257,9 +417,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" dependencies = [ "lazy_static", - "winapi", + "winapi 0.3.8", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "serde" version = "1.0.110" @@ -291,6 +457,33 @@ dependencies = [ "serde", ] +[[package]] +name = "signal-hook" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ff2db2112d6c761e12522c65f7768548bd6e8cd23d2a9dae162520626629bd6" +dependencies = [ + "libc", + "mio", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41" +dependencies = [ + "arc-swap", + "libc", +] + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + [[package]] name = "smallvec" version = "1.4.0" @@ -306,7 +499,7 @@ dependencies = [ "cfg-if", "libc", "redox_syscall", - "winapi", + "winapi 0.3.8", ] [[package]] @@ -342,7 +535,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" dependencies = [ "libc", - "winapi", + "winapi 0.3.8", ] [[package]] @@ -398,6 +591,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + [[package]] name = "winapi" version = "0.3.8" @@ -408,6 +607,12 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -419,3 +624,13 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] diff --git a/Cargo.toml b/Cargo.toml index 08630bc..bee2d07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,8 +13,9 @@ incremental = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] chrono = { version = "0.4.11", features = ["serde"] } -curl = "0.4.29" clap = "2.33.1" +crossterm = "0.17.5" +curl = "0.4.29" lazy_static = "1.4.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/src/main.rs b/src/main.rs index 192cdf0..3acaf97 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use std::env; use std::error::Error; -use std::fs::File; -use std::io::{BufReader, Write}; +use std::fs::{create_dir_all, File, OpenOptions}; +use std::io::{stdout, BufReader, Write}; use std::path::Path; use std::process::exit; @@ -11,6 +11,7 @@ use serde_json::from_reader; use url::Url; use crate::config::{Config, ConfigManager}; +use crossterm::{cursor, QueueableCommand}; use lazy_static::lazy_static; const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION"); @@ -31,12 +32,25 @@ fn read_animeboxes_backup>( } fn write_to_file(data: &[u8], path: &Path) -> std::io::Result<()> { - let mut file = File::create(path)?; - file.write_all(data)?; + if !path.exists() { + let mut file = File::create(path)?; + file.write_all(data)?; + } else { + let mut file = OpenOptions::new().append(true).open(path)?; + file.write_all(data)?; + } Ok(()) } fn download_command(backup: model::anime_boxes::Backup, mut config: config::ConfigManager) { + let temp_directory = env::current_dir().unwrap().join( + config + .config + .save_directory + .as_ref() + .unwrap_or(&String::from("tmp")), + ); + create_dir_all(&temp_directory); let favorites: Vec = backup .favorites .iter() @@ -48,8 +62,11 @@ fn download_command(backup: model::anime_boxes::Backup, mut config: config::Conf favorites_to_download.push(favorite); } } + let to_download_count = favorites_to_download.len(); + let mut count = 0; let mut favorites_downloaded = Vec::new(); for favorite in favorites_to_download { + count += 1; let mut easy = Easy::new(); let favorite_url = Url::parse(&favorite); match favorite_url { @@ -58,22 +75,46 @@ fn download_command(backup: model::anime_boxes::Backup, mut config: config::Conf continue; } Ok(url) => { - let target_path = env::current_dir().unwrap().join( - config - .config - .save_directory - .as_ref() - .unwrap_or(&String::from("tmp")), - ); + let path_segments = url.path_segments().unwrap(); + let filename = path_segments.last().unwrap(); + let target_path = temp_directory.as_path().join(&filename); + + let progress_count = format!("{}/{}", count, to_download_count); + let progress_filename = String::from(filename); + easy.url(url.as_str()); + easy.progress(true); + easy.progress_function( + move |total_bytes_to_download, + bytes_downloaded, + total_bytes_to_upload, + bytes_uploaded| { + let percentage = (bytes_downloaded / total_bytes_to_download) * 100.0; + let mut stdout = stdout(); + stdout.queue(cursor::SavePosition); + stdout.write( + format!( + " {} {}: {:.2}", + &progress_count, progress_filename, percentage + ) + .as_bytes(), + ); + stdout.queue(cursor::RestorePosition); + stdout.flush(); + true + }, + ); match easy.write_function(move |data| match write_to_file(data, &target_path) { - Err(e) => Err(WriteError::Pause), + Err(e) => { + println!("Error writing to {:#?}: {}%", target_path, e); + Err(WriteError::Pause) + } Ok(d) => Ok(data.len()), }) { Err(e) => { - println!("Error downloading {}", favorite); + println!("Error downloading {}", &favorite); } - Ok(_) => favorites_downloaded.push(String::from(favorite)), + Ok(_) => favorites_downloaded.push(String::from(&favorite)), } easy.perform().unwrap(); }