quickdeck 0.1.1

A CLI tool to quickly open SlideShare presentations.
use regex::Regex;
use reqwest;
use tokio;
use webbrowser;

async fn run_app(url: &str) -> Result<(), String> {
    let html = reqwest::get(url)
        .await
        .map_err(|e| e.to_string())?
        .text()
        .await
        .map_err(|e| e.to_string())?;
    let embed_url = extract_embed_url(&html)?;
    if webbrowser::open(&embed_url).is_err() {
        return Err("Failed to open web browser.".to_string());
    }
    println!("Slide opened in web browser: {}", embed_url);
    Ok(())
}

fn extract_embed_url(html: &str) -> Result<String, String> {
    let re = Regex::new(r"https://www\.slideshare\.net/slideshow/embed_code/key/\w+")
        .map_err(|e| e.to_string())?;
    let mut captures = re.captures_iter(html);
    if let Some(cap) = captures.next() {
        Ok(cap[0].to_string())
    } else {
        Err("No embed URL found".to_string())
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let args: Vec<String> = std::env::args().collect();
    if args.len() < 2 {
        eprintln!("Usage: {} <slideshare-url>", args[0]);
        std::process::exit(1);
    }
    let url = &args[1];
    run_app(url).await.map_err(|e| e.into())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_run_app_with_valid_args() {
        let url = "https://www.slideshare.net/iTooooooooooooT/itolab-how-to-survey-2017";
        assert!(run_app(url).await.is_ok());
    }

    #[tokio::test]
    async fn test_run_app_with_invalid_args() {
        let url = "https://www.slideshare.net/mei28/notty";
        assert!(run_app(url).await.is_err());
    }

    #[test]
    fn test_extract_embed_url_valid() {
        let html = r#"
"iframeEmbed":{"url":"https://www.slideshare.net/slideshow/embed_code/key/6ab6KSKYN23bGZ","height":486,"width":597},
        "#;
        let result = extract_embed_url(html);
        assert!(result.is_ok());
        assert_eq!(
            result.unwrap(),
            "https://www.slideshare.net/slideshow/embed_code/key/6ab6KSKYN23bGZ"
        );
    }

    #[test]
    fn test_extract_embed_url_invalid() {
        let html = "<html></html>";
        let result = extract_embed_url(html);
        assert!(result.is_err());
    }
}