use clap::Parser;
use gdown_core::download::{Downloader, DownloadOptions};
use gdown_core::folder::{download_folder, FolderDownloadOptions};
use gdown_core::{Result};
use std::path::PathBuf;
use tracing_subscriber::EnvFilter;
#[derive(Parser, Debug)]
#[command(
name = "gdown",
about = "Download files from Google Drive",
long_about = None,
author = "gdown-rs contributors"
)]
struct Args {
#[arg()]
url: String,
#[arg(short = 'O', long)]
output: Option<PathBuf>,
#[arg(short = 'q', long)]
quiet: bool,
#[arg(long)]
proxy: Option<String>,
#[arg(long)]
speed: Option<String>,
#[arg(long)]
no_cookies: bool,
#[arg(long)]
no_check_certificate: bool,
#[arg(short = 'c', long)]
continue_resume: bool,
#[arg(long)]
folder: bool,
#[arg(long)]
format: Option<String>,
#[arg(long)]
md5: Option<String>,
#[arg(long)]
sha1: Option<String>,
#[arg(long)]
sha256: Option<String>,
#[arg(long)]
sha512: Option<String>,
#[arg(long)]
extract: bool,
}
impl Args {
fn parse_speed(&self) -> Option<u64> {
self.speed.as_ref().map(|s| {
let s = s.trim().to_uppercase();
if let Some(num) = s.strip_suffix("KB/S") {
num.parse::<u64>().unwrap_or(0) * 1024
} else if let Some(num) = s.strip_suffix("MB/S") {
num.parse::<u64>().unwrap_or(0) * 1024 * 1024
} else if let Some(num) = s.strip_suffix("GB/S") {
num.parse::<u64>().unwrap_or(0) * 1024 * 1024 * 1024
} else {
s.parse::<u64>().unwrap_or_default()
}
})
}
}
#[tokio::main]
async fn main() -> Result<()> {
let args = Args::parse();
if !args.quiet {
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env())
.init();
}
let mut downloader = Downloader::new();
if let Some(proxy) = &args.proxy {
downloader = downloader.proxy(proxy);
}
if args.no_check_certificate {
downloader = downloader.verify_ssl(false);
}
if args.folder {
download_folder_cmd(&args, &downloader).await?;
} else {
download_file_cmd(&args, &downloader).await?;
}
Ok(())
}
async fn download_file_cmd(args: &Args, downloader: &Downloader) -> Result<()> {
let output = args.output.clone().unwrap_or_else(|| {
PathBuf::from("download")
});
let speed_limit = args.parse_speed();
let options = DownloadOptions {
speed_limit,
resume: args.continue_resume,
format: args.format.clone(),
progress_callback: None,
};
if !args.quiet {
println!("Downloading {} to {}", args.url, output.display());
}
let size = downloader.download(&args.url, &output, options).await?;
if !args.quiet {
println!("Downloaded {} bytes to {}", size, output.display());
}
Ok(())
}
async fn download_folder_cmd(args: &Args, downloader: &Downloader) -> Result<()> {
let output = args.output.clone().unwrap_or_else(|| PathBuf::from("download"));
let speed_limit = args.parse_speed();
let options = FolderDownloadOptions {
speed_limit,
resume: args.continue_resume,
};
if !args.quiet {
println!("Downloading folder {} to {}", args.url, output.display());
}
let files = download_folder(downloader, &args.url, output, options).await?;
if !args.quiet {
println!("Downloaded {} files/folders", files.len());
}
Ok(())
}