main.rs (5962B)
1 use arhivarch_downloader::config::Config; 2 use arhivarch_downloader::event::Event; 3 use arhivarch_downloader::export::{html::HtmlExporter, ExporterKind}; 4 5 use std::path::PathBuf; 6 use std::sync::mpsc::channel; 7 8 static HELP: &str = "Download threads from arhivach. 9 10 Usage: arhivach-downloader-cli.exe [OPTIONS] <URL> 11 12 Arguments: 13 <URL> URL to download 14 15 Options: 16 -d, --dir <DIR> Path to download directory [default: .] 17 -e, --exporter <EXPORTER> Exporter [default: html] [possible values: html] 18 -t, --thumb Download thumbnail images, default: false 19 -f, --files Download files (images, videos, gifs, etc), default: false 20 -r, --resume Resume files and thumbnails downloading instead of overwriting. Useless if neither -t nor -f are set, default: false 21 -R, --retries <DOWNLOAD_RETRIES> Download retries in case of a error [default: 3] 22 -h, --help Print help"; 23 24 fn main() { 25 let config = parse_args(); 26 let (tx, rx) = channel::<Event>(); 27 let handle = std::thread::spawn({ 28 let config = config.clone(); 29 move || arhivarch_downloader::run(&config, tx) 30 }); 31 32 for event in rx { 33 render_event(&event); 34 } 35 36 handle.join().map_err(|e| { 37 eprintln!("ERROR: {:?}", e); 38 std::process::exit(1); 39 }).ok(); 40 } 41 42 pub fn parse_args() -> Config { 43 let mut args = std::env::args().skip(1).peekable(); 44 45 let mut url: Option<String> = None; 46 let mut dir = PathBuf::from("."); 47 let mut exporter = ExporterKind::Html(HtmlExporter); 48 let mut thumb = false; 49 let mut files = false; 50 let mut resume = false; 51 let mut download_retries: u32 = 3; 52 53 while let Some(arg) = args.next() { 54 match arg.as_str() { 55 "-h" | "--help" => { 56 println!("{}", HELP); 57 std::process::exit(0); 58 } 59 "-t" | "--thumb" => thumb = true, 60 "-f" | "--files" => files = true, 61 "-r" | "--resume" => resume = true, 62 "-d" | "--dir" => { 63 let val = args.next().unwrap_or_else(|| { 64 eprintln!("ERROR: {} requires a value", arg); 65 std::process::exit(1); 66 }); 67 dir = PathBuf::from(val); 68 } 69 "-e" | "--exporter" => { 70 let val = args.next().unwrap_or_else(|| { 71 eprintln!("ERROR: {} requires a value", arg); 72 std::process::exit(1); 73 }); 74 exporter = match val.as_str() { 75 "html" => ExporterKind::Html(HtmlExporter), 76 other => { 77 eprintln!("ERROR: unknown exporter '{}'. Possible values: html", other); 78 std::process::exit(1); 79 } 80 }; 81 } 82 "-R" | "--retries" => { 83 let val = args.next().unwrap_or_else(|| { 84 eprintln!("ERROR: {} requires a value", arg); 85 std::process::exit(1); 86 }); 87 download_retries = val.parse().unwrap_or_else(|_| { 88 eprintln!("ERROR: --retries must be a non-negative integer"); 89 std::process::exit(1); 90 }); 91 } 92 _ if arg.starts_with('-') => { 93 eprintln!("ERROR: unknown option '{}'. Run with --help for usage.", arg); 94 std::process::exit(1); 95 } 96 _ => { 97 if url.is_some() { 98 eprintln!("ERROR: unexpected argument '{}'. Run with --help for usage.", arg); 99 std::process::exit(1); 100 } 101 url = Some(arg); 102 } 103 } 104 } 105 106 let url = url.unwrap_or_else(|| { 107 eprintln!("ERROR: missing required argument <URL>. Run with --help for usage."); 108 std::process::exit(1); 109 }); 110 111 Config { url, dir, exporter, thumb, files, resume, download_retries } 112 } 113 114 fn render_event(event: &Event) { 115 use std::io::Write; 116 match event { 117 Event::GetStarted => { 118 print!("Fetching thread..."); 119 std::io::stdout().flush().ok(); 120 } 121 Event::GetDone => 122 println!(" Done."), 123 Event::GetFailed { error } => 124 eprintln!("\nFailed to fetch thread: {}", error), 125 126 Event::DownloadAllStarted => 127 println!("Downloading stuff..."), 128 Event::DownloadAllDone => 129 println!("All downloads complete."), 130 Event::DownloadAllFailed { error } => 131 eprintln!("Download failed: {}", error), 132 133 Event::DownloadStarted { index, max_index } => { 134 print!("\r\tDownloading {} / {}...", index, max_index); 135 std::io::stdout().flush().ok(); 136 } 137 Event::DownloadDone { index, max_index } => { 138 println!("\r\tDownloading {} / {}... Done.", index, max_index); 139 } 140 Event::DownloadFailed { url, error } => 141 eprintln!("\r\tFailed to download {}: {}", url, error), 142 Event::DownloadSkipped { index, max_index } => 143 println!("\r\tDownloading {} / {}... Skipped.", index, max_index), 144 145 Event::DownloadFilesStarted => { 146 println!("Downloading files..."); 147 std::io::stdout().flush().ok(); 148 } 149 Event::DownloadFilesDone => 150 println!("Done."), 151 Event::DownloadThumbStarted => { 152 println!("Downloading thumbnails..."); 153 std::io::stdout().flush().ok(); 154 } 155 Event::DownloadThumbDone => 156 println!("Done."), 157 158 Event::ExportStarted => { 159 print!("Exporting..."); 160 std::io::stdout().flush().ok(); 161 } 162 Event::ExportDone => 163 println!(" Done."), 164 Event::ExportFailed { error } => 165 eprintln!("\nExport failed: {}", error), 166 } 167 }