hyperfetch 0.1.3

A superfast multithreaded downloader
Documentation
pub fn format_bytes(bytes: u64) -> String {
    const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB"];
    let mut size = bytes as f64;
    let mut unit_index = 0;

    while size >= 1024.0 && unit_index < UNITS.len() - 1 {
        size /= 1024.0;
        unit_index += 1;
    }

    format!("{:.2} {}", size, UNITS[unit_index])
}

pub fn format_speed(bytes_per_sec: f64) -> String {
    format!("{}/s", format_bytes(bytes_per_sec as u64))
}

pub fn format_duration(seconds: u64) -> String {
    let hours = seconds / 3600;
    let minutes = (seconds % 3600) / 60;
    let secs = seconds % 60;

    if hours > 0 {
        format!("{}h {}m {}s", hours, minutes, secs)
    } else if minutes > 0 {
        format!("{}m {}s", minutes, secs)
    } else {
        format!("{}s", secs)
    }
}

pub fn extract_filename_from_url(url: &str) -> String {
    url::Url::parse(url)
        .ok()
        .and_then(|u| {
            u.path_segments()
                .and_then(|segments| segments.last())
                .filter(|name| !name.is_empty())
                .map(|name| name.to_string())
        })
        .unwrap_or_else(|| "downloaded_file".to_string())
}

pub fn parse_size(size_str: &str) -> Result<u64, anyhow::Error> {
    let size_str = size_str.trim().to_uppercase();

    let (number_part, suffix) = if size_str.ends_with('K') {
        (&size_str[..size_str.len() - 1], 1024u64)
    } else if size_str.ends_with('M') {
        (&size_str[..size_str.len() - 1], 1024u64.pow(2))
    } else if size_str.ends_with('G') {
        (&size_str[..size_str.len() - 1], 1024u64.pow(3))
    } else if size_str.ends_with('T') {
        (&size_str[..size_str.len() - 1], 1024u64.pow(4))
    } else {
        (size_str.as_str(), 1u64)
    };

    let number: f64 = number_part.parse()?;
    Ok((number * suffix as f64) as u64)
}