arhivach-downloader

Download arhivach.vc threads
git clone https://git.ea.contact/arhivach-downloader
Log | Files | Refs | README

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 }