mediafire_rs 0.1.5

Downloads files and folders from mediafire
mod api;
mod download;
mod global;
mod types;
mod utils;

use crate::api::file;
use crate::api::folder;
use crate::download::{download_file, download_folder};
use crate::utils::{create_directory_if_not_exists, match_mediafire_valid_url};
use anyhow::anyhow;
use anyhow::Result;
use clap::{arg, command, value_parser};
use global::*;
use std::path::PathBuf;
use std::time::Duration;
use tokio::time::sleep;
use types::download::DownloadJob;

#[tokio::main]
async fn main() -> Result<()> {
    let get_matches = command!()
        .author("NicKoehler")
        .color(clap::ColorChoice::Always)
        .arg(
            arg!([URL] "Folder or file to download")
                .required(true)
                .value_parser(value_parser!(String)),
        )
        .arg(
            arg!(-o --output <OUTPUT> "Output directory")
                .required(false)
                .default_value(".")
                .value_parser(value_parser!(PathBuf)),
        )
        .arg(
            arg!(-m --max <MAX> "Maximum number of concurrent downloads")
                .required(false)
                .default_value("10")
                .value_parser(value_parser!(usize)),
        )
        .get_matches();
    let matches = get_matches;

    let url = matches.get_one::<String>("URL").unwrap();
    let path = matches.get_one::<PathBuf>("output").unwrap().to_path_buf();
    let max = *matches.get_one::<usize>("max").unwrap();
    let option = match_mediafire_valid_url(url);

    TOTAL_PROGRESS_BAR.enable_steady_tick(Duration::from_millis(120));
    TOTAL_PROGRESS_BAR.set_style(PROGRESS_STYLE_TOTAL_START.clone());

    if option.is_none() {
        return Err(anyhow!("Invalid Mediafire URL"));
    }

    let (mode, key) = option.unwrap();

    match mode.as_str() {
        "folder" => {
            if let Some(folder) = folder::get_info(&key).await?.folder_info {
                download_folder(&key, path.join(PathBuf::from(folder.name)), 1).await?;
            } else {
                return Err(anyhow!("Invalid Mediafire folder URL"));
            }
        }
        "file" | "file_premium" => {
            create_directory_if_not_exists(&path).await?;
            let response = file::get_info(&key).await?;
            if let Some(file_info) = response.file_info {
                let path = path.join(PathBuf::from(&file_info.filename));
                QUEUE.push(DownloadJob::new(file_info.into(), path));
            } else {
                return Err(anyhow!("Invalid Mediafire file URL"));
            }
        }
        _ => return Err(anyhow!("Invalid Mediafire URL")),
    }

    if QUEUE.len() == 0 {
        return Err(anyhow!("No files to download"));
    }

    TOTAL_PROGRESS_BAR.disable_steady_tick();
    TOTAL_PROGRESS_BAR.set_length(QUEUE.len() as u64);
    TOTAL_PROGRESS_BAR.set_style(PROGRESS_STYLE_TOTAL_DOWNLOAD.clone());

    TOTAL_PROGRESS_BAR.set_message("Downloading");

    for _ in 0..max {
        tokio::spawn(async move {
            loop {
                let task = QUEUE.pop().await;
                match download_file(&task).await {
                    Ok(_) => SUCCESSFUL_DOWNLOADS.lock().await.push(task),
                    Err(_) => FAILED_DOWNLOADS.lock().await.push(task),
                };

                TOTAL_PROGRESS_BAR.set_prefix(format!(
                    "Failed downloads {}",
                    FAILED_DOWNLOADS.lock().await.len()
                ));

                TOTAL_PROGRESS_BAR.set_message(format!(
                    "Successful downloads {}",
                    SUCCESSFUL_DOWNLOADS.lock().await.len()
                ));

                TOTAL_PROGRESS_BAR.inc(1);
            }
        });
    }

    if let Some(total_bar_length) = TOTAL_PROGRESS_BAR.length() {
        while TOTAL_PROGRESS_BAR.position() < total_bar_length {
            sleep(Duration::from_millis(100)).await;
        }
    }

    TOTAL_PROGRESS_BAR.finish();

    let failed = FAILED_DOWNLOADS.lock().await;
    if failed.len() > 0 {
        println!("Failed downloads:");
        failed.iter().for_each(|job| {
            println!(
                "{} ยท {}",
                job.path.file_name().unwrap().to_str().unwrap(),
                job.file.links.normal_download
            )
        });
    }

    Ok(())
}