podcast 0.12.1

A command line podcast manager
use clap::{App, ArgMatches};

use std::env;
use std::io;
use std::io::Write;
use std::path::Path;

use crate::actions::*;
use crate::download;
use crate::errors::*;
use crate::playback;
use crate::search;
use crate::structs::*;

pub fn download(state: &mut State, matches: &ArgMatches) -> Result<()> {
    let download_matches = matches.subcommand_matches("download").unwrap();
    let podcast = download_matches.value_of("PODCAST").unwrap();
    match download_matches.value_of("EPISODE") {
        Some(ep) => {
            if String::from(ep).contains(|c| c == '-' || c == ',') {
                download::download_range(&state, podcast, ep)?
            } else if download_matches.occurrences_of("name") > 0 {
                download::download_episode_by_name(
                    &state,
                    podcast,
                    ep,
                    download_matches.occurrences_of("all") > 0,
                )?
            } else {
                download::download_episode_by_num(&state, podcast, ep)?
            }
        }
        None => download::download_all(&state, podcast)?,
    }
    Ok(())
}

pub fn list(state: &mut State, matches: &ArgMatches) -> Result<()> {
    let list_matches = matches
        .subcommand_matches("ls")
        .or_else(|| matches.subcommand_matches("list"))
        .unwrap();
    match list_matches.value_of("PODCAST") {
        Some(regex) => list_episodes(regex)?,
        None => list_subscriptions(&state)?,
    }
    Ok(())
}

pub fn play(state: &mut State, matches: &ArgMatches) -> Result<()> {
    let play_matches = matches.subcommand_matches("play").unwrap();
    let podcast = play_matches.value_of("PODCAST").unwrap();
    match play_matches.value_of("EPISODE") {
        Some(episode) => {
            if play_matches.occurrences_of("name") > 0 {
                playback::play_episode_by_name(&state, podcast, episode)?
            } else {
                playback::play_episode_by_num(&state, podcast, episode)?
            }
        }
        None => playback::play_latest(&state, podcast)?,
    }
    Ok(())
}

pub fn subscribe(state: &mut State, config: Config, matches: &ArgMatches) -> Result<()> {
    let subscribe_matches = matches
        .subcommand_matches("sub")
        .or_else(|| matches.subcommand_matches("subscribe"))
        .unwrap();
    let url = subscribe_matches.value_of("URL").unwrap();
    sub(state, config, url)?;
    Ok(())
}

fn sub(state: &mut State, config: Config, url: &str) -> Result<()> {
    state.subscribe(url)?;
    download::download_rss(config, url)?;
    Ok(())
}

pub fn remove(state: &mut State, matches: &ArgMatches) -> Result<()> {
    let rm_matches = matches.subcommand_matches("rm").unwrap();
    let regex = rm_matches.value_of("PODCAST").unwrap();
    remove_podcast(state, regex)?;
    Ok(())
}

pub fn complete(app: &mut App, matches: &ArgMatches) -> Result<()> {
    let matches = matches.subcommand_matches("completion").unwrap();
    match matches.value_of("SHELL") {
        Some(shell) => print_completion(app, shell),
        None => {
            let shell_path_env = env::var("SHELL");
            if let Ok(p) = shell_path_env {
                let shell_path = Path::new(&p);
                if let Some(shell) = shell_path.file_name() {
                    print_completion(app, shell.to_str().unwrap())
                }
            }
        }
    }
    Ok(())
}

pub fn search(state: &mut State, config: Config, matches: &ArgMatches) -> Result<()> {
    let matches = matches.subcommand_matches("search").unwrap();
    let podcast = matches.value_of("PODCAST").unwrap();
    let resp = search::search_for_podcast(podcast)?;
    if resp.found().is_empty() {
        println!("No Results");
        return Ok(());
    }

    {
        let stdout = io::stdout();
        let mut lock = stdout.lock();
        for (i, r) in resp.found().iter().enumerate() {
            writeln!(&mut lock, "({}) {}", i, r)?;
        }
    }

    print!("Would you like to subscribe to any of these? (y/n): ");
    io::stdout().flush().ok();
    let mut input = String::new();
    io::stdin().read_line(&mut input)?;
    if input.to_lowercase().trim() != "y" {
        return Ok(());
    }

    print!("Which one? (#): ");
    io::stdout().flush().ok();
    let mut num_input = String::new();
    io::stdin().read_line(&mut num_input)?;
    let n: usize = num_input.trim().parse()?;
    if n > resp.found().len() {
        eprintln!("Invalid!");
        return Ok(());
    }

    let rss_resp = search::retrieve_rss(&resp.found()[n])?;
    if let Some(err) = rss_resp.error() {
        eprintln!("{}", err);
        return Ok(());
    }
    match rss_resp.url() {
        Some(r) => sub(state, config, r)?,
        None => eprintln!("Subscription failed. No url in API response."),
    }

    Ok(())
}