3YR56Y65UIAL3J7PUXWVJMOOHYZYDIX4V54OT2TJPZ25WQ6MXHCQC TV3GOKIHRVTPGEFYLMTNFQYZBNJRL46ZLOKSQACHVIGW4IWOMDFQC TE6ACJLE7GUBYSV7B77L5YFKUMTV2PYR7CQRKG6A3XZ6YZWBR7TAC L3I4GC7R74HPQS3VCQ44UTBAKKBOW6UDVXV2EF7XSWH7H2Z3RRJQC GE7XXDPC73SUY6I6F3X6I4QFQO2BCPHD4MZALYOWG7H7SRE5XAFQC XIHPYOWDLQY2MVMVUQPH23O3TBALRG4G2CHSLWSCAYMY5NVJ32WQC IFBRAMVLQ4Z6BAEMWDIXD2V5HSZK4DHRWYZNB32IBY7ZRTNZJVCQC O53GR2OQHGRKAVJT2RVPRHYFB54W5LM4DQYT7EYVGKU7HDK5CJJQC JYSIHNS67XTGAR4HN7ZHWFMGGYSK5IY6J6EHO4YUZOR7UMMWAORQC ADXMUSFXOKBPCHW4XS3T4KLWMPGQPYDMZW6YFFSHZPAQKEGIKCBQC UIMZBURR7KOWSREO4GDH5C2LZDUTEZBKQNYWBYSFGUTRYJ4GKSNQC 5GQNHICLSFAA7ZUFXUCNACCPAIIGK4DV2QPTONDNXLS4TJJTOFHAC 2CKX4R6ONNXDXGRYZ5NZEBJZFX5Z6BYPGNJ7LMXUHHFB4MUFJRCAC NE63ERXN7OUYSQ4PGPIQIIKEYD7OAOWXXSGMTORD6RJNUZHRLVJAC M4FCDZ745GHHL3OLH64EVYOEOEGGGVIBCVFGX5JUJDJRE5OLCXLQC Y6BVNXQ747WQKVB4JO3AHYOMBWNNJNPC6SG2UUCCZRIIXDMXJYDQC HSDBPX2AMUS4NRA52EHIYOR7H37ABNGJWBJKPQABFMFDU7EITSIAC 476KTQSS5NXVCTVLVZQRGSYD5OAFBYG75VTSWBN26Q45RSMRT5YQC 5JMYBRF3UYX4LFH7JK6S4BEDKRVKDFIL4YKTCWKMKP4TMNNGQFKQC EZMX4SYFEBYNJVQETRVAYONU5MIMQYTTSA5DRMTQET5B7CL6CI6AC J64KBLKALQ3HQCY4HJU5H6WBXTATS7TKBYNNUUSNJE7JLWLYO66QC ZD3G3BCXBEXELHH3KMXMDUQUJ4BXIF4ZSZKFIJJCRO7IDK4XPOWAC THSENT35O3PIXQ343QPPE3DJGR4YVULN6YPS5ETW5PXSVGZZQIZAC JPN37V6Q35ZAW7A2DTGX2WJ3IJ66BAGHXHWXOGHQRHGFAOETFQ7AC FFAFJQ5QVMHTLULZTGVM5PX7XQEZQUWLPH2GAN5BGVAYZOZZYG5QC 6FJACP6KUOZ4HWK4PSS5PFPGDYXZSCAWSKIARWBDGCZTPJWXA62AC SBPKWZNQF5BWAJ7SZHWVK5BG6DTVJNDYND6UG5PDZCWZ2W4W2HXQC JJ4SMY257MAHSJSZH5PJZMLBH3GJX5VKH2ZZSBGWLL7FWP7OA7TQC BSPWOOHZMN3RAOHGJ2A3XKUOUCFFAOXS7YR67E3AARPPPIA5YPDAC LUJ3HQBUNLRIQILJ2MU43XU46E4KLHQQ25JXLL56UJVLWA3QXJJQC ZYS43ILR4OXI7S2AYNGYSTK3IU2UVELIWVCCWDS7RVZQDSNJMDHQC H5MQEP35FJNDLARTAB7J5GEHRNBSL6RTHFUGURG5HIVGLCG4FGUAC 76TBVFPIFU3LSMXY5NAHZBH6HRJLSLK43PGOPL6QQ2YYVBJ64QAQC MQKOX2CQ7AON24UJC7RORAC7Y2UROROVG7BBKLVWURPXKY75JV5AC RJYDXOHXMLODTAP3LNIWD4NLPIDL7IXZYS4EURZLJESLWJUEZGHAC EEJ6CBJRTXLPQP44I2RLWVLJBX565DXXAWU4JIWNA3MMNE7WB5LQC let re = Regex::new(&format!("(?i){}", &search)).expect("Failed to parse regex");let mut path = get_podcast_dir();
let re = Regex::new(&format!("(?i){}", &search)).chain_err(|| UNABLE_TO_PARSE_REGEX)?;let mut path = get_podcast_dir()?;
DirBuilder::new().recursive(true).create(&path).unwrap();for entry in fs::read_dir(&path).unwrap() {let entry = entry.unwrap();
DirBuilder::new().recursive(true).create(&path).chain_err(|| UNABLE_TO_CREATE_DIRECTORY)?;for entry in fs::read_dir(&path).chain_err(|| UNABLE_TO_READ_DIRECTORY)? {let entry = entry.chain_err(|| UNABLE_TO_READ_ENTRY)?;
let file = File::open(&entry.path()).unwrap();let channel = Channel::read_from(BufReader::new(file)).unwrap();
let file = File::open(&entry.path()).chain_err(|| UNABLE_TO_OPEN_FILE)?;let channel = Channel::read_from(BufReader::new(file)).chain_err(|| UNABLE_TO_CREATE_CHANNEL_FROM_FILE)?;
match download_rss_feed(url) {Ok(channel) => {let download_limit = config.auto_download_limit as usize;if download_limit > 0 {let podcast = Podcast::from(channel);let episodes = podcast.episodes();episodes[..download_limit].par_iter().for_each(|ep| {if let Err(err) = ep.download(podcast.title()) {eprintln!("Error downloading {}: {}", podcast.title(), err);}});
let channel = download_rss_feed(url)?;let download_limit = config.auto_download_limit as usize;if download_limit > 0 {let podcast = Podcast::from(channel);let episodes = podcast.episodes();episodes[..download_limit].par_iter().for_each(|ep| {if let Err(err) = ep.download(podcast.title()) {eprintln!("Error downloading {}: {}", podcast.title(), err);
pub fn update_rss(state: &mut State) {println!("Checking for new episodes...");state.subscriptions.par_iter_mut().for_each(|sub| {let mut path = get_podcast_dir();path.push(&sub.title);DirBuilder::new().recursive(true).create(&path).unwrap();
pub fn update_subscription(sub: &mut Subscription) -> Result<()> {let mut path: PathBuf = get_podcast_dir()?;path.push(&sub.title);DirBuilder::new().recursive(true).create(&path).chain_err(|| UNABLE_TO_CREATE_DIRECTORY)?;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()));}
let mut titles = HashSet::new();for entry in fs::read_dir(&path).unwrap() {let entry = entry.unwrap();titles.insert(trim_extension(&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)?);path = get_podcast_dir()?;path.push(".rss");
let mut resp = reqwest::get(&sub.url).unwrap();let mut content: Vec<u8> = Vec::new();resp.read_to_end(&mut content).unwrap();let podcast = Podcast::from(Channel::read_from(BufReader::new(&content[..])).unwrap());path = get_podcast_dir();path.push(".rss");
let mut filename = String::from(podcast.title());filename.push_str(".xml");path.push(&filename);let mut file = File::create(&path).unwrap();file.write_all(&content).unwrap();
let mut filename = String::from(podcast.title());filename.push_str(".xml");path.push(&filename);let mut file = File::create(&path).unwrap();file.write_all(&content).unwrap();
if podcast.episodes().len() > sub.num_episodes {podcast.episodes()[..podcast.episodes().len() - sub.num_episodes].par_iter().for_each(|ep: &Episode| {if let Err(err) = ep.download(podcast.title()) {eprintln!("Error downloading {}: {}", podcast.title(), err);}});}sub.num_episodes = podcast.episodes().len();Ok(())}
if podcast.episodes().len() > sub.num_episodes {podcast.episodes()[..podcast.episodes().len() - sub.num_episodes].par_iter().for_each(|ep| {if let Err(err) = ep.download(podcast.title()) {eprintln!("Error downloading {}: {}", podcast.title(), err);}});}sub.num_episodes = podcast.episodes().len();});
pub fn update_rss(state: &mut State) {println!("Checking for new episodes...");let _result: Vec<Result<()>> = state.subscriptions.par_iter_mut().map(|sub: &mut Subscription| update_subscription(sub)).collect();
pub fn download_range(state: &State, p_search: &str, e_search: &str) {let re_pod = Regex::new(&format!("(?i){}", &p_search)).expect("Failed to parse regex");
pub fn download_range(state: &State, p_search: &str, e_search: &str) -> Result<()> {let re_pod = Regex::new(&format!("(?i){}", &p_search)).chain_err(|| UNABLE_TO_PARSE_REGEX)?;
match Podcast::from_title(&subscription.title) {Ok(podcast) => match parse_download_episodes(e_search) {Ok(episodes_to_download) => {if let Err(err) = podcast.download_specific(&episodes_to_download) {eprintln!("Error: {}", err);}}Err(err) => eprintln!("Error: {}", err),},Err(err) => eprintln!("Error: {}", err),}
let podcast = Podcast::from_title(&subscription.title).chain_err(|| UNABLE_TO_RETRIEVE_PODCAST_BY_TITLE)?;let episodes_to_download = parse_download_episodes(e_search).chain_err(|| "unable to parse episodes to download")?;podcast.download_specific(&episodes_to_download).chain_err(|| "unable to download episodes")?;
pub fn download_episode(state: &State, p_search: &str, e_search: &str) {let re_pod = Regex::new(&format!("(?i){}", &p_search)).expect("Failed to parse regex");let ep_num = e_search.parse::<usize>().unwrap();
pub fn download_episode(state: &State, p_search: &str, e_search: &str) -> Result<()> {let re_pod = Regex::new(&format!("(?i){}", &p_search)).chain_err(|| UNABLE_TO_PARSE_REGEX)?;let ep_num = e_search.parse::<usize>().chain_err(|| "unable to parse number")?;
match Podcast::from_title(&subscription.title) {Ok(podcast) => {let episodes = podcast.episodes();if let Err(err) = episodes[episodes.len() - ep_num].download(podcast.title()) {eprintln!("{}", err);}}Err(err) => eprintln!("Error: {}", err),}
let podcast = Podcast::from_title(&subscription.title).chain_err(|| UNABLE_TO_RETRIEVE_PODCAST_BY_TITLE)?;let episodes = podcast.episodes();episodes[episodes.len() - ep_num].download(podcast.title()).chain_err(|| "unable to download episode")?;
pub fn download_all(state: &State, p_search: &str) {let re_pod = Regex::new(&format!("(?i){}", &p_search)).expect("Failed to parse regex");
pub fn download_all(state: &State, p_search: &str) -> Result<()> {let re_pod = Regex::new(&format!("(?i){}", &p_search)).chain_err(|| UNABLE_TO_PARSE_REGEX)?;
match Podcast::from_title(&subscription.title) {Ok(podcast) => if let Err(err) = podcast.download() {eprintln!("{}", err);},Err(err) => eprintln!("Error: {}", err),}
let podcast = Podcast::from_title(&subscription.title).chain_err(|| UNABLE_TO_RETRIEVE_PODCAST_BY_TITLE)?;podcast.download().chain_err(|| "unable to download podcast")?;
pub fn play_latest(state: &State, p_search: &str) {let re_pod = Regex::new(&format!("(?i){}", &p_search)).expect("Failed to parse regex");let mut path = get_xml_dir();if let Err(err) = DirBuilder::new().recursive(true).create(&path) {eprintln!("Couldn't create directory: {}\nReason: {}",path.to_str().unwrap(),err);return;}
pub fn play_latest(state: &State, p_search: &str) -> Result<()> {let re_pod: Regex =Regex::new(&format!("(?i){}", &p_search)).chain_err(|| UNABLE_TO_PARSE_REGEX)?;let mut path: PathBuf = get_xml_dir()?;DirBuilder::new().recursive(true).create(&path).chain_err(|| UNABLE_TO_CREATE_DIRECTORY)?;
filename = String::from(episode.title().unwrap());filename.push_str(episode.extension().unwrap());path = get_podcast_dir();
filename = String::from(episode.title().chain_err(|| "unable to retrieve episode name")?);filename.push_str(episode.extension().chain_err(|| "unable to retrieve episode extension")?);path = get_podcast_dir()?;
pub fn play_episode(state: &State, p_search: &str, ep_num_string: &str) {let re_pod = Regex::new(&format!("(?i){}", &p_search)).expect("Failed to parse regex");let ep_num = ep_num_string.parse::<usize>().unwrap();let mut path = get_xml_dir();
pub fn play_episode(state: &State, p_search: &str, ep_num_string: &str) -> Result<()> {let re_pod: Regex =Regex::new(&format!("(?i){}", &p_search)).chain_err(|| UNABLE_TO_PARSE_REGEX)?;let ep_num: usize = ep_num_string.parse::<usize>().unwrap();let mut path: PathBuf = get_xml_dir()?;
match resp.parse::<toml::Value>() {Ok(config) => {let latest = config["package"]["version"].as_str().unwrap();if version != latest {println!("New version avaliable: {} -> {}", version, latest);}}Err(err) => eprintln!("{}", err),
let config = resp.parse::<toml::Value>().chain_err(|| "unable to parse toml")?;let latest = config["package"]["version"].as_str().chain_err(|| UNABLE_TO_CONVERT_TO_STR)?;if version != latest {println!("New version avaliable: {} -> {}", version, latest);
fn main() {if let Err(err) = create_directories() {eprintln!("{}", err);return;}let mut state = match State::new(VERSION) {Ok(val) => val,Err(err) => {eprintln!("{}", err);return;}};let config = Config::new();
fn main() -> Result<()> {create_directories().chain_err(|| "unable to create directories")?;let mut state = State::new(VERSION).chain_err(|| "unable to load state")?;let config = Config::new()?;
let download_matches = matches.subcommand_matches("download").unwrap();let podcast = download_matches.value_of("PODCAST").unwrap();
let download_matches = matches.subcommand_matches("download").chain_err(|| "unable to find subcommand matches")?;let podcast = download_matches.value_of("PODCAST").chain_err(|| "unable to find subcommand match")?;
let play_matches = matches.subcommand_matches("play").unwrap();let podcast = play_matches.value_of("PODCAST").unwrap();
let play_matches = matches.subcommand_matches("play").chain_err(|| "unable to find subcommand matches")?;let podcast = play_matches.value_of("PODCAST").chain_err(|| "unable to find subcommand match")?;
let subscribe_matches = matches.subcommand_matches("subscribe").unwrap();let url = subscribe_matches.value_of("URL").unwrap();state.subscribe(url);
let subscribe_matches = matches.subcommand_matches("subscribe").chain_err(|| "unable to find subcommand matches")?;let url = subscribe_matches.value_of("URL").chain_err(|| "unable to find subcommand match")?;state.subscribe(url).chain_err(|| "unable to subscribe")?;
let rm_matches = matches.subcommand_matches("rm").unwrap();match rm_matches.value_of("PODCAST") {Some(regex) => remove_podcast(&mut state, regex),None => println!(),}
let rm_matches = matches.subcommand_matches("rm").chain_err(|| "unable to find subcommand matches")?;let regex = rm_matches.value_of("PODCAST").chain_err(|| "")?;remove_podcast(&mut state, regex)?
File::open(&path).unwrap().read_to_string(&mut s).unwrap();let config = YamlLoader::load_from_str(&s).unwrap();
File::open(&path).chain_err(|| UNABLE_TO_OPEN_FILE)?.read_to_string(&mut s).chain_err(|| UNABLE_TO_READ_FILE_TO_STRING)?;let config =YamlLoader::load_from_str(&s).chain_err(|| "unable to load yaml from string")?;
let mut file = match File::open(&path) {Ok(val) => val,Err(err) => return Err(format!("{}", err)),};if let Err(err) = file.read_to_string(&mut s) {return Err(format!("{}", err));};
let mut file = File::open(&path).chain_err(|| UNABLE_TO_OPEN_FILE)?;file.read_to_string(&mut s).chain_err(|| UNABLE_TO_READ_FILE_TO_STRING)?;
let serialized = serde_json::to_string(self)?;let mut file = File::create(&path)?;file.write_all(serialized.as_bytes())?;fs::rename(&path, get_sub_file())?;
let serialized = serde_json::to_string(self).chain_err(|| "unable to serialize state")?;let mut file = File::create(&path).chain_err(|| UNABLE_TO_CREATE_FILE)?;file.write_all(serialized.as_bytes()).chain_err(|| UNABLE_TO_WRITE_FILE)?;fs::rename(&path, get_sub_file()?).chain_err(|| "unable to rename file")?;
pub fn from_url(url: &str) -> Result<Podcast, rss::Error> {match Channel::from_url(url) {Ok(val) => Ok(Podcast::from(val)),Err(err) => Err(err),}
pub fn from_url(url: &str) -> Result<Podcast> {Ok(Podcast::from(Channel::from_url(url).chain_err(|| UNABLE_TO_CREATE_CHANNEL_FROM_RESPONSE)?),)
match File::open(&path) {Ok(file) => match Channel::read_from(BufReader::new(file)) {Ok(podcast) => Ok(Podcast::from(podcast)),Err(err) => Err(format!("Error: {}", err)),},Err(err) => Err(format!("Error: {}", err)),}
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)?))
pub fn download_specific(&self, episode_numbers: &[usize]) -> Result<(), io::Error> {let mut path = get_podcast_dir();
pub fn download_specific(&self, episode_numbers: &[usize]) -> Result<()> {let mut path = get_podcast_dir()?;
match self.0.enclosure() {Some(enclosure) => match enclosure.mime_type() {"audio/mpeg" => Some(".mp3"),"audio/mp4" => Some(".m4a"),"audio/ogg" => Some(".ogg"),_ => find_extension(self.url().unwrap()),},None => None,
match self.0.enclosure()?.mime_type() {"audio/mpeg" => Some(".mp3"),"audio/mp4" => Some(".m4a"),"audio/ogg" => Some(".ogg"),_ => find_extension(self.url().unwrap()),
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 ="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 fn create_directories() -> Result<(), String> {let mut path = get_podcast_dir();path.push(".rss");if let Err(err) = DirBuilder::new().recursive(true).create(&path) {return Err(format!("Couldn't create directory: {}\nReason: {}",path.to_str().unwrap(),err));
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")?;path.push("Podcasts");Ok(path)}
pub fn already_downloaded(dir: &str) -> Result<HashSet<String>, io::Error> {
pub fn create_directories() -> Result<()> {let mut path = get_podcast_dir()?;path.push(".rss");DirBuilder::new().recursive(true).create(&path).chain_err(|| "unable to create directory")}pub fn already_downloaded(dir: &str) -> Result<HashSet<String>> {
}pub fn get_podcast_dir() -> PathBuf {match env::var_os("PODCAST") {Some(val) => PathBuf::from(val),None => {let mut path = env::home_dir().expect("Couldn't find your home directory");path.push("Podcasts");path}}
DirBuilder::new().recursive(true).create(&path).unwrap();let mut resp = reqwest::get(url).unwrap();
DirBuilder::new().recursive(true).create(&path).chain_err(|| "unable to open directory")?;let mut resp = reqwest::get(url).chain_err(|| "unable to open url")?;
resp.read_to_end(&mut content).unwrap();let channel = Channel::read_from(BufReader::new(&content[..])).unwrap();
resp.read_to_end(&mut content).chain_err(|| "unable to read http response to end")?;let channel = Channel::read_from(BufReader::new(&content[..])).chain_err(|| "unable to create channel from xml http response")?;