Improve CLI & change name

This commit is contained in:
Daniel M 2021-03-31 19:22:00 +02:00
parent 36ad1263b4
commit 8fee14d0e6
4 changed files with 45 additions and 52 deletions

2
Cargo.lock generated
View File

@ -150,7 +150,7 @@ dependencies = [
] ]
[[package]] [[package]]
name = "fdl" name = "ffdl"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"chrono", "chrono",

View File

@ -1,5 +1,5 @@
[package] [package]
name = "fdl" name = "ffdl"
version = "0.1.0" version = "0.1.0"
authors = ["daniel m <danielm@dnml.de>"] authors = ["daniel m <danielm@dnml.de>"]
edition = "2018" edition = "2018"

View File

@ -208,7 +208,7 @@ pub async fn download_feedback_chunks(url: &str, into_file: &str, rep: DlReporte
// This will spin up multiple tasks that and manage the status updates for them. // This will spin up multiple tasks that and manage the status updates for them.
// The combined status will be reported back to the caller // The combined status will be reported back to the caller
pub async fn download_feedback_multi(url: &str, into_file: &str, rep: DlReporter, numparal: i32) -> ResBE<()> { pub async fn download_feedback_multi(url: &str, into_file: &str, rep: DlReporter, conn_count: i32) -> ResBE<()> {
let (content_length, _) = http_get_filesize_and_range_support(url).await?; let (content_length, _) = http_get_filesize_and_range_support(url).await?;
@ -216,8 +216,8 @@ pub async fn download_feedback_multi(url: &str, into_file: &str, rep: DlReporter
// completion and can indicate that the file is not suitable for continuation // completion and can indicate that the file is not suitable for continuation
create_zeroed_file(into_file, content_length as usize + 1).await?; create_zeroed_file(into_file, content_length as usize + 1).await?;
let chunksize = content_length / numparal as u64; let chunksize = content_length / conn_count as u64;
let rest = content_length % numparal as u64; let rest = content_length % conn_count as u64;
let mut joiners = Vec::new(); let mut joiners = Vec::new();
@ -225,7 +225,7 @@ pub async fn download_feedback_multi(url: &str, into_file: &str, rep: DlReporter
let t_start = SystemTime::now(); let t_start = SystemTime::now();
for index in 0 .. numparal { for index in 0 .. conn_count {
let url = url.clone().to_owned(); let url = url.clone().to_owned();
let into_file = into_file.clone().to_owned(); let into_file = into_file.clone().to_owned();
@ -241,7 +241,7 @@ pub async fn download_feedback_multi(url: &str, into_file: &str, rep: DlReporter
(index+1) as u64 * chunksize - 1 (index+1) as u64 * chunksize - 1
); );
if index == numparal - 1 { if index == conn_count - 1 {
from_to.1 += rest; from_to.1 += rest;
} }
@ -263,8 +263,8 @@ pub async fn download_feedback_multi(url: &str, into_file: &str, rep: DlReporter
let rep = rep_task; let rep = rep_task;
let mut update_counter: i32 = 0; let mut update_counter: i32 = 0;
let mut dl_speeds = vec![0.0_f32; numparal as usize]; let mut dl_speeds = vec![0.0_f32; conn_count as usize];
let mut progresses = vec![0; numparal as usize]; let mut progresses = vec![0; conn_count as usize];
while let Some(update) = rx.recv().await { while let Some(update) = rx.recv().await {
match update.status { match update.status {

View File

@ -18,7 +18,7 @@ mod dlreport;
#[tokio::main] #[tokio::main]
async fn main() -> ResBE<()> { async fn main() -> ResBE<()> {
let arguments = App::new("FDL - Fast/File Downloader") let arguments = App::new("FFDL - Fast File Downloader")
.version(crate_version!()) .version(crate_version!())
.about("Download files fast") .about("Download files fast")
.arg( .arg(
@ -27,24 +27,26 @@ async fn main() -> ResBE<()> {
.long("outdir") .long("outdir")
.value_name("OUTPUT DIR") .value_name("OUTPUT DIR")
.takes_value(true) .takes_value(true)
.help("Set the output directory") .help("Set the output directory. The directory will be created \
if it doesn't exit yet")
) )
.arg( .arg(
Arg::with_name("numdl") Arg::with_name("file_count")
.short("n") .short("n")
.long("numdl") .long("num-files")
.value_name("NUMBER OF CONCURRENT DOWNLOADS") .value_name("NUMBER OF CONCURRENT FILE DOWNLOADS")
.takes_value(true) .takes_value(true)
.help("Specify the number concurrent downloads") .help("Specify the number concurrent file downloads")
) )
.arg( .arg(
Arg::with_name("boost") Arg::with_name("conn_count")
.short("b") .short("c")
.long("boost") .long("connections")
.value_name("CONNECTIONS PER FILE") .value_name("NUMBER OF CONNECTIONS")
.takes_value(true) .takes_value(true)
.help("Specify the number connections per single downloads. \ .help("The number concurrent connections per file download. \
Files started with boost can't be continued. \ Downloads might fail when the number of connections is too high. \
Files started with multiple connections can't be continued. \
NOTE: This will likely cause IO bottlenecks on HDDs") NOTE: This will likely cause IO bottlenecks on HDDs")
) )
.arg( .arg(
@ -77,10 +79,9 @@ async fn main() -> ResBE<()> {
.help("Download only the specified URL") .help("Download only the specified URL")
) )
.arg( .arg(
Arg::with_name("resolve") Arg::with_name("zippy-resolve")
.short("r") .long("zippy-resolve")
.long("resolve") .value_name("ZIPPYSHARE URL")
.value_name("URL")
.takes_value(true) .takes_value(true)
.group("action") .group("action")
.help("Resolve the zippyshare url to real download url") .help("Resolve the zippyshare url to real download url")
@ -93,39 +94,39 @@ async fn main() -> ResBE<()> {
None => "./" None => "./"
}; };
let numparal = match arguments.value_of("numdl") { let file_count = match arguments.value_of("file_count") {
Some(it) => it, Some(it) => it,
None => "1" None => "1"
}; };
let numparal: i32 = match numparal.parse() { let file_count: i32 = match file_count.parse() {
Ok(it) => it, Ok(it) => it,
Err(_) => { Err(_) => {
eprintln!("Invalid value for numdl: {}", numparal); eprintln!("Invalid value for num-files: {}", file_count);
exit(1); exit(1);
} }
}; };
if numparal <= 0 { if file_count <= 0 {
eprintln!("Invalid value for numdl: {}", numparal); eprintln!("Invalid value for num-files: {}", file_count);
exit(1); exit(1);
} }
let boost = match arguments.value_of("boost") { let conn_count = match arguments.value_of("conn_count") {
Some(it) => it, Some(it) => it,
None => "1" None => "1"
}; };
let boost: i32 = match boost.parse() { let conn_count: i32 = match conn_count.parse() {
Ok(it) => it, Ok(it) => it,
Err(_) => { Err(_) => {
eprintln!("Invalid value for boost: {}", numparal); eprintln!("Invalid value for connections: {}", conn_count);
exit(1); exit(1);
} }
}; };
if boost <= 0 { if conn_count <= 0 {
eprintln!("Invalid value for boost: {}", boost); eprintln!("Invalid value for connections: {}", conn_count);
exit(1); exit(1);
} }
@ -152,23 +153,17 @@ async fn main() -> ResBE<()> {
.filter(|url| url.len() > 0 && !url.starts_with("#")) .filter(|url| url.len() > 0 && !url.starts_with("#"))
.collect(); .collect();
download_multiple(urls, outdir, numparal, boost, is_zippy).await?; download_multiple(urls, outdir, file_count, conn_count, is_zippy).await?;
} }
if let Some(url) = arguments.value_of("download") { if let Some(url) = arguments.value_of("download") {
let boost = if boost != 1 { download_multiple(vec![url.to_string()], outdir, 1, conn_count, is_zippy).await?;
boost
} else {
numparal
};
download_multiple(vec![url.to_string()], outdir, 1, boost, is_zippy).await?;
} }
if let Some(url) = arguments.value_of("resolve") { if let Some(url) = arguments.value_of("zippy-resolve") {
match zippy::resolve_link(&url).await { match zippy::resolve_link(&url).await {
Ok(resolved_url) => { Ok(resolved_url) => {
@ -181,14 +176,12 @@ async fn main() -> ResBE<()> {
} }
} else {
println!("Something went very wrong...");
} }
Ok(()) Ok(())
} }
async fn download_multiple(urls: Vec<String>, outdir: &str, numparal: i32, boost: i32, is_zippy: bool) -> ResBE<()> { async fn download_multiple(urls: Vec<String>, outdir: &str, file_count: i32, conn_count: i32, is_zippy: bool) -> ResBE<()> {
let outdir = Path::new(outdir); let outdir = Path::new(outdir);
if !outdir.exists() { if !outdir.exists() {
@ -204,12 +197,12 @@ async fn download_multiple(urls: Vec<String>, outdir: &str, numparal: i32, boost
let (tx, rx) = mpsc::unbounded_channel::<DlReport>(); let (tx, rx) = mpsc::unbounded_channel::<DlReport>();
for offset in 0..numparal { for offset in 0..file_count {
let urls: Vec<String> = urls let urls: Vec<String> = urls
.iter() .iter()
.enumerate() .enumerate()
.filter(|(index, _)| (index) % numparal as usize == offset as usize) .filter(|(index, _)| (index) % file_count as usize == offset as usize)
.map(|(_, v)| v.to_owned()) .map(|(_, v)| v.to_owned())
.collect(); .collect();
@ -223,7 +216,7 @@ async fn download_multiple(urls: Vec<String>, outdir: &str, numparal: i32, boost
let tx = tx.clone(); let tx = tx.clone();
// Recalculated index in the main url vector, used as id // Recalculated index in the main url vector, used as id
let global_url_index = i as i32 * numparal + offset; let global_url_index = i as i32 * file_count + offset;
let rep = DlReporter::new(global_url_index, tx); let rep = DlReporter::new(global_url_index, tx);
@ -269,14 +262,14 @@ async fn download_multiple(urls: Vec<String>, outdir: &str, numparal: i32, boost
} }
} }
if boost == 1 { if conn_count == 1 {
if let Err(_e) = download::download_feedback(&url, &into_file, rep.clone()).await { if let Err(_e) = download::download_feedback(&url, &into_file, rep.clone()).await {
rep.send(DlStatus::DoneErr { rep.send(DlStatus::DoneErr {
filename: into_file.to_string() filename: into_file.to_string()
}); });
} }
} else { } else {
if let Err(_e) = download::download_feedback_multi(&url, &into_file, rep.clone(), boost).await { if let Err(_e) = download::download_feedback_multi(&url, &into_file, rep.clone(), conn_count).await {
rep.send(DlStatus::DoneErr { rep.send(DlStatus::DoneErr {
filename: into_file.to_string() filename: into_file.to_string()
}); });