diff options
| author | Nathan Jaremko | 2018-11-19 10:36:42 -0500 |
|---|---|---|
| committer | Nathan Jaremko | 2018-11-19 10:36:42 -0500 |
| commit | 118b36cbf32024f16ab7db4f1ad0b1a29b7592f5 (patch) | |
| tree | f4d4b40f20ec10ec3526bdf239a1995e6830ac36 | |
| parent | 714e8ded029907c1d8639121a3d171344808a5d5 (diff) | |
| download | podcast-118b36cbf32024f16ab7db4f1ad0b1a29b7592f5.tar.bz2 | |
Upgrade to rust 2018
| -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); } } |
