diff options
| -rw-r--r-- | CHANGELOG | 6 | ||||
| -rw-r--r-- | Cargo.toml | 14 | ||||
| -rw-r--r-- | src/actions.rs | 86 | ||||
| -rw-r--r-- | src/main.rs | 34 | ||||
| -rw-r--r-- | src/structs.rs | 38 | ||||
| -rw-r--r-- | src/utils.rs | 47 | 
6 files changed, 132 insertions, 93 deletions
| @@ -1,3 +1,9 @@ +0.6.0 +- Update to rust 2018 edition + +0.5.11 +- Code cleanup +  0.5.10  - Fix update check functionality @@ -1,6 +1,7 @@  [package]  name = "podcast" -version = "0.5.10" +edition = "2018" +version = "0.6.0"  authors = ["Nathan Jaremko <njaremko@gmail.com>"]  description = "A command line podcast manager"  license = "GPL-3.0" @@ -19,13 +20,14 @@ name = "podcast"  [dependencies]  chrono = { version = "0.4", features = ["serde"] } -clap = "2.31" -error-chain = "0.11" -lazy_static = "1.0" +clap = "2.32" +dirs = "1.0" +error-chain = "0.12" +lazy_static = "1.2"  rayon = "1.0"  regex = "1.0" -reqwest = "0.8" -rss = {version = "1.5", features = ["from_url"] } +reqwest = "0.9" +rss = {version = "1.6", features = ["from_url"] }  serde = "1.0"  serde_derive = "1.0"  serde_json = "1.0" diff --git a/src/actions.rs b/src/actions.rs index 6a8951d..0775aec 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -1,12 +1,12 @@ -use structs::*; -use utils::*; +use super::structs::*; +use super::utils::*;  use std::collections::HashSet;  use std::fs::{self, DirBuilder, File};  use std::io::{self, BufReader, Read, Write};  use std::process::Command; -use errors::*; +use crate::errors::*;  use rayon::prelude::*;  use regex::Regex;  use reqwest; @@ -34,12 +34,14 @@ pub fn list_episodes(search: &str) -> Result<()> {              let podcast = Podcast::from(channel);              let episodes = podcast.episodes();              for (num, ep) in episodes.iter().enumerate() { -                write!( +                writeln!(                      &mut handle, -                    "({}) {}\n", +                    "({}) {}",                      episodes.len() - num, -                    ep.title().chain_err(|| "unable to retrieve episode title")? -                ).chain_err(|| "unable to write to stdout")? +                    ep.title() +                        .chain_err(|| "unable to retrieve episode title")? +                ) +                .chain_err(|| "unable to write to stdout")?              }              return Ok(());          } @@ -79,18 +81,19 @@ pub fn update_subscription(sub: &mut Subscription) -> Result<()> {      let mut titles = HashSet::new();      for entry in fs::read_dir(&path).chain_err(|| UNABLE_TO_READ_DIRECTORY)? {          let unwrapped_entry = &entry.chain_err(|| UNABLE_TO_READ_ENTRY)?; -        titles.insert(trim_extension(&unwrapped_entry -            .file_name() -            .into_string() -            .unwrap())); +        titles.insert(trim_extension( +            &unwrapped_entry.file_name().into_string().unwrap(), +        ));      }      let mut resp = reqwest::get(&sub.url).chain_err(|| UNABLE_TO_GET_HTTP_RESPONSE)?;      let mut content: Vec<u8> = Vec::new();      resp.read_to_end(&mut content)          .chain_err(|| UNABLE_TO_READ_RESPONSE_TO_END)?; -    let podcast = Podcast::from(Channel::read_from(BufReader::new(&content[..])) -        .chain_err(|| UNABLE_TO_CREATE_CHANNEL_FROM_RESPONSE)?); +    let podcast = Podcast::from( +        Channel::read_from(BufReader::new(&content[..])) +            .chain_err(|| UNABLE_TO_CREATE_CHANNEL_FROM_RESPONSE)?, +    );      path = get_podcast_dir()?;      path.push(".rss"); @@ -126,7 +129,7 @@ pub fn list_subscriptions(state: &State) -> Result<()> {      let stdout = io::stdout();      let mut handle = stdout.lock();      for podcast in &state.subscriptions() { -        write!(&mut handle, "{}\n", &podcast.title).chain_err(|| "unable to write to stdout")?; +        writeln!(&mut handle, "{}", &podcast.title).chain_err(|| "unable to write to stdout")?;      }      Ok(())  } @@ -201,27 +204,35 @@ pub fn play_latest(state: &State, p_search: &str) -> Result<()> {              file.read_to_end(&mut content)                  .chain_err(|| "unable to read file to end")?; -            let podcast: Podcast = Podcast::from(Channel::read_from(content.as_slice()) -                .chain_err(|| UNABLE_TO_CREATE_CHANNEL_FROM_FILE)?); +            let podcast: Podcast = Podcast::from( +                Channel::read_from(content.as_slice()) +                    .chain_err(|| UNABLE_TO_CREATE_CHANNEL_FROM_FILE)?, +            );              let episodes = podcast.episodes();              let episode = episodes[0].clone(); -            filename = String::from(episode +            filename = episode                  .title() -                .chain_err(|| "unable to retrieve episode name")?); -            filename.push_str(episode -                .extension() -                .chain_err(|| "unable to retrieve episode extension")?); +                .chain_err(|| "unable to retrieve episode name")?; +            filename.push_str( +                episode +                    .extension() +                    .chain_err(|| "unable to retrieve episode extension")?, +            );              path = get_podcast_dir()?;              path.push(podcast.title());              path.push(filename);              if path.exists() { -                launch_player(path.to_str() -                    .chain_err(|| "unable to convert path to &str")?)?; +                launch_player( +                    path.to_str() +                        .chain_err(|| "unable to convert path to &str")?, +                )?;              } else { -                launch_player(episode -                    .url() -                    .chain_err(|| "unable to retrieve episode url")?)?; +                launch_player( +                    episode +                        .url() +                        .chain_err(|| "unable to retrieve episode url")?, +                )?;              }              return Ok(());          } @@ -256,7 +267,7 @@ pub fn play_episode(state: &State, p_search: &str, ep_num_string: &str) -> Resul              let episodes = podcast.episodes();              let episode = episodes[episodes.len() - ep_num].clone(); -            filename = String::from(episode.title().unwrap()); +            filename = episode.title().unwrap();              filename.push_str(episode.extension().unwrap());              path = get_podcast_dir()?;              path.push(podcast.title()); @@ -264,9 +275,11 @@ pub fn play_episode(state: &State, p_search: &str, ep_num_string: &str) -> Resul              if path.exists() {                  launch_player(path.to_str().chain_err(|| UNABLE_TO_CONVERT_TO_STR)?)?;              } else { -                launch_player(episode -                    .url() -                    .chain_err(|| "unable to retrieve episode url")?)?; +                launch_player( +                    episode +                        .url() +                        .chain_err(|| "unable to retrieve episode url")?, +                )?;              }              return Ok(());          } @@ -276,14 +289,15 @@ pub fn play_episode(state: &State, p_search: &str, ep_num_string: &str) -> Resul  pub fn check_for_update(version: &str) -> Result<()> {      println!("Checking for updates..."); -    let resp: String = reqwest::get( -        "https://raw.githubusercontent.com/njaremko/podcast/master/Cargo.toml", -    ).chain_err(|| UNABLE_TO_GET_HTTP_RESPONSE)? -        .text() -        .chain_err(|| "unable to convert response to text")?; +    let resp: String = +        reqwest::get("https://raw.githubusercontent.com/njaremko/podcast/master/Cargo.toml") +            .chain_err(|| UNABLE_TO_GET_HTTP_RESPONSE)? +            .text() +            .chain_err(|| "unable to convert response to text")?;      //println!("{}", resp); -    let config = resp.parse::<toml::Value>() +    let config = resp +        .parse::<toml::Value>()          .chain_err(|| "unable to parse toml")?;      let latest = config["package"]["version"]          .as_str() diff --git a/src/main.rs b/src/main.rs index 2e07e08..c3ad6c3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,9 @@ +#![feature(nll)]  #![recursion_limit = "1024"]  extern crate chrono;  extern crate clap; +extern crate dirs;  #[macro_use]  extern crate error_chain;  #[macro_use] @@ -16,22 +18,22 @@ extern crate serde_json;  extern crate toml;  extern crate yaml_rust; -mod actions; -mod structs; -mod utils; -mod errors { +pub mod actions; +pub mod structs; +pub mod utils; +pub mod errors {      // Create the Error, ErrorKind, ResultExt, and Result types      error_chain!{}  } -use actions::*; -use errors::*; -use structs::*; -use utils::*; +use self::actions::*; +use self::errors::*; +use self::structs::*; +use self::utils::*;  use clap::{App, Arg, SubCommand}; -const VERSION: &str = "0.5.10"; +const VERSION: &str = "0.6.0";  fn main() -> Result<()> {      create_directories().chain_err(|| "unable to create directories")?; @@ -138,18 +140,20 @@ fn main() -> Result<()> {                  .value_of("PODCAST")                  .chain_err(|| "unable to find subcommand match")?;              match download_matches.value_of("EPISODE") { -                Some(ep) => if String::from(ep).contains(|c| c == '-' || c == ',') { -                    download_range(&state, podcast, ep)? -                } else { -                    download_episode(&state, podcast, ep)? -                }, +                Some(ep) => { +                    if String::from(ep).contains(|c| c == '-' || c == ',') { +                        download_range(&state, podcast, ep)? +                    } else { +                        download_episode(&state, podcast, ep)? +                    } +                }                  None => download_all(&state, podcast)?,              }          }          Some("ls") | Some("list") => {              let list_matches = matches                  .subcommand_matches("ls") -                .or(matches.subcommand_matches("list")) +                .or_else(|| matches.subcommand_matches("list"))                  .chain_err(|| "unable to find subcommand matches")?;              match list_matches.value_of("PODCAST") {                  Some(regex) => list_episodes(regex)?, diff --git a/src/structs.rs b/src/structs.rs index e585677..a0d9bd7 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -1,6 +1,6 @@ -use actions::*; -use errors::*; -use utils::*; +use super::actions::*; +use super::utils::*; +use crate::errors::*;  use std::collections::BTreeSet;  use std::fs::{self, DirBuilder, File}; @@ -105,7 +105,8 @@ impl State {              // Check if a day has passed (86400 seconds) since last launch              if Utc::now()                  .signed_duration_since(state.last_run_time) -                .num_seconds() > 86400 +                .num_seconds() +                > 86400              {                  update_rss(&mut state);                  check_for_update(&state.version)?; @@ -186,9 +187,9 @@ impl Podcast {      #[allow(dead_code)]      pub fn from_url(url: &str) -> Result<Podcast> { -        Ok( -            Podcast::from(Channel::from_url(url).chain_err(|| UNABLE_TO_CREATE_CHANNEL_FROM_RESPONSE)?), -        ) +        Ok(Podcast::from( +            Channel::from_url(url).chain_err(|| UNABLE_TO_CREATE_CHANNEL_FROM_RESPONSE)?, +        ))      }      pub fn from_title(title: &str) -> Result<Podcast> { @@ -198,8 +199,10 @@ impl Podcast {          path.push(filename);          let file = File::open(&path).chain_err(|| UNABLE_TO_OPEN_FILE)?; -        Ok(Podcast::from(Channel::read_from(BufReader::new(file)) -            .chain_err(|| UNABLE_TO_CREATE_CHANNEL_FROM_FILE)?)) +        Ok(Podcast::from( +            Channel::read_from(BufReader::new(file)) +                .chain_err(|| UNABLE_TO_CREATE_CHANNEL_FROM_FILE)?, +        ))      }      pub fn delete(title: &str) -> Result<()> { @@ -284,7 +287,11 @@ impl Podcast {  impl Episode {      pub fn title(&self) -> Option<String> { -        Some(FILENAME_ESCAPE.replace_all(self.0.title()?, "_").to_string()) +        Some( +            FILENAME_ESCAPE +                .replace_all(self.0.title()?, "_") +                .to_string(), +        )      }      pub fn url(&self) -> Option<&str> { @@ -313,9 +320,11 @@ impl Episode {          if let Some(url) = self.url() {              if let Some(title) = self.title() { -                let mut filename = String::from(title); -                filename.push_str(self.extension() -                    .chain_err(|| "unable to retrieve extension")?); +                let mut filename = title; +                filename.push_str( +                    self.extension() +                        .chain_err(|| "unable to retrieve extension")?, +                );                  path.push(filename);                  if !path.exists() {                      println!("Downloading: {}", path.to_str().unwrap()); @@ -324,7 +333,8 @@ impl Episode {                      let mut content: Vec<u8> = Vec::new();                      resp.read_to_end(&mut content)                          .chain_err(|| UNABLE_TO_READ_RESPONSE_TO_END)?; -                    file.write_all(&content).chain_err(|| UNABLE_TO_WRITE_FILE)?; +                    file.write_all(&content) +                        .chain_err(|| UNABLE_TO_WRITE_FILE)?;                  } else {                      println!(                          "File already exists: {}", diff --git a/src/utils.rs b/src/utils.rs index 4648903..657ff5b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -4,27 +4,27 @@ use std::fs::{self, DirBuilder, File};  use std::io::{BufReader, Read, Write};  use std::path::PathBuf; -use errors::*; +use crate::errors::*; +use dirs;  use reqwest;  use rss::Channel; -pub const UNABLE_TO_PARSE_REGEX: &'static str = "unable to parse regex"; -pub const UNABLE_TO_OPEN_FILE: &'static str = "unable to open file"; -pub const UNABLE_TO_CREATE_FILE: &'static str = "unable to create file"; -pub const UNABLE_TO_WRITE_FILE: &'static str = "unable to write file"; -pub const UNABLE_TO_READ_FILE_TO_STRING: &'static str = "unable to read file to string"; -pub const UNABLE_TO_READ_DIRECTORY: &'static str = "unable to read directory"; -pub const UNABLE_TO_READ_ENTRY: &'static str = "unable to read entry"; -pub const UNABLE_TO_CREATE_DIRECTORY: &'static str = "unable to create directory"; -pub const UNABLE_TO_READ_RESPONSE_TO_END: &'static str = "unable to read response to end"; -pub const UNABLE_TO_GET_HTTP_RESPONSE: &'static str = "unable to get http response"; -pub const UNABLE_TO_CONVERT_TO_STR: &'static str = "unable to convert to &str"; -pub const UNABLE_TO_REMOVE_FILE: &'static str = "unable to remove file"; -pub const UNABLE_TO_CREATE_CHANNEL_FROM_RESPONSE: &'static str = +pub const UNABLE_TO_PARSE_REGEX: &str = "unable to parse regex"; +pub const UNABLE_TO_OPEN_FILE: &str = "unable to open file"; +pub const UNABLE_TO_CREATE_FILE: &str = "unable to create file"; +pub const UNABLE_TO_WRITE_FILE: &str = "unable to write file"; +pub const UNABLE_TO_READ_FILE_TO_STRING: &str = "unable to read file to string"; +pub const UNABLE_TO_READ_DIRECTORY: &str = "unable to read directory"; +pub const UNABLE_TO_READ_ENTRY: &str = "unable to read entry"; +pub const UNABLE_TO_CREATE_DIRECTORY: &str = "unable to create directory"; +pub const UNABLE_TO_READ_RESPONSE_TO_END: &str = "unable to read response to end"; +pub const UNABLE_TO_GET_HTTP_RESPONSE: &str = "unable to get http response"; +pub const UNABLE_TO_CONVERT_TO_STR: &str = "unable to convert to &str"; +pub const UNABLE_TO_REMOVE_FILE: &str = "unable to remove file"; +pub const UNABLE_TO_CREATE_CHANNEL_FROM_RESPONSE: &str =      "unable to create channel from http response"; -pub const UNABLE_TO_CREATE_CHANNEL_FROM_FILE: &'static str = -    "unable to create channel from xml file"; -pub const UNABLE_TO_RETRIEVE_PODCAST_BY_TITLE: &'static str = "unable to retrieve podcast by title"; +pub const UNABLE_TO_CREATE_CHANNEL_FROM_FILE: &str = "unable to create channel from xml file"; +pub const UNABLE_TO_RETRIEVE_PODCAST_BY_TITLE: &str = "unable to retrieve podcast by title";  pub fn trim_extension(filename: &str) -> Option<String> {      let name = String::from(filename);      let index = name.rfind('.')?; @@ -52,7 +52,7 @@ pub fn get_podcast_dir() -> Result<PathBuf> {      match env::var_os("PODCAST") {          Some(val) => Ok(PathBuf::from(val)),          None => { -            let mut path = env::home_dir().chain_err(|| "Couldn't find your home directory")?; +            let mut path = dirs::home_dir().chain_err(|| "Couldn't find your home directory")?;              path.push("Podcasts");              Ok(path)          } @@ -135,20 +135,23 @@ pub fn parse_download_episodes(e_search: &str) -> Result<Vec<usize>> {      for elem in comma_separated {          let temp = String::from(elem);          if temp.contains('-') { -            let range: Vec<usize> = elem.split('-') +            let range: Vec<usize> = elem +                .split('-')                  .map(|i| i.parse::<usize>().chain_err(|| "unable to parse number"))                  .collect::<Result<Vec<usize>>>()                  .chain_err(|| "unable to collect ranges")?;              ranges.push((range[0], range[1]));          } else { -            elements.push(elem.parse::<usize>() -                .chain_err(|| "unable to parse number")?); +            elements.push( +                elem.parse::<usize>() +                    .chain_err(|| "unable to parse number")?, +            );          }      }      for range in ranges {          // Add 1 to upper range to include given episode in the download -        for num in range.0..range.1 + 1 { +        for num in range.0..=range.1 {              elements.push(num);          }      } | 
