diff options
| author | Nathan Jaremko | 2017-07-24 23:52:15 -0400 |
|---|---|---|
| committer | Nathan Jaremko | 2017-07-24 23:52:15 -0400 |
| commit | 404c468a4c51b07c27e92ccd952f647db11a6369 (patch) | |
| tree | 35372d1fe61c608eadb45e0bef52e0d01e342c7e /src | |
| parent | 237a0be7f0ca4d7dceca1c9e43391381593064fb (diff) | |
| download | podcast-404c468a4c51b07c27e92ccd952f647db11a6369.tar.bz2 | |
Basic subscriptions are working now
Diffstat (limited to 'src')
| -rw-r--r-- | src/actions.rs | 51 | ||||
| -rw-r--r-- | src/main.rs | 6 | ||||
| -rw-r--r-- | src/structs.rs | 61 | ||||
| -rw-r--r-- | src/utils.rs | 29 |
4 files changed, 119 insertions, 28 deletions
diff --git a/src/actions.rs b/src/actions.rs index 120d58b..8f54359 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -1,10 +1,11 @@ use regex::Regex; use reqwest; +use rayon::prelude::*; use rss::Channel; -use std::fs::{DirBuilder, File}; +use std::collections::HashSet; +use std::fs::{self, DirBuilder, File}; use std::io::{self, BufReader, Read, Write}; use std::process::Command; -use rayon::prelude::*; use structs::*; use utils::*; @@ -26,7 +27,7 @@ pub fn list_episodes(state: &State, search: &str) { } } -pub fn download_rss(url: &str) { +pub fn download_rss(url: &str, config: &Config) { println!("Downloading RSS feed..."); let mut path = get_podcast_dir(); path.push(".rss"); @@ -40,23 +41,53 @@ pub fn download_rss(url: &str) { path.push(filename); let mut file = File::create(&path).unwrap(); file.write_all(&content).unwrap(); + + 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(|ref ep| { + if let Err(err) = ep.download(podcast.title()) { + eprintln!("Error downloading {}: {}", podcast.title(), err); + } + }); + } } -pub fn update_rss(state: &State) { - println!("Updating RSS feeds..."); - state.subscriptions().par_iter().for_each(|ref sub| { +pub fn update_rss(state: &mut State) { + println!("Checking for new episodes..."); + state.subs.par_iter_mut().for_each(|mut sub| { let mut path = get_podcast_dir(); - path.push(".rss"); + path.push(sub.title()); DirBuilder::new().recursive(true).create(&path).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()).unwrap(); let mut content: Vec<u8> = Vec::new(); resp.read_to_end(&mut content).unwrap(); - let channel = Channel::read_from(BufReader::new(&content[..])).unwrap(); - let mut filename = String::from(channel.title()); + 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); + 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(|ref ep| if let Err(err) = ep.download(podcast.title()) { + eprintln!("Error downloading {}: {}", podcast.title(), err); + }); + } + sub.num_episodes = podcast.episodes().len(); }); } diff --git a/src/main.rs b/src/main.rs index 6d56a33..800c867 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; +extern crate yaml_rust; mod actions; mod structs; @@ -19,7 +20,7 @@ use structs::*; fn main() { let mut state = State::new(); - + let config = Config::new(); let matches = App::new("podcast") .version("1.0") .author("Nathan J. <njaremko@gmail.com>") @@ -117,10 +118,11 @@ fn main() { .unwrap() .value_of("URL") .unwrap(), + &config, ) } Some("search") => (), - Some("update") => update_rss(&state), + Some("update") => update_rss(&mut state), _ => (), } if let Err(err) = state.save() { diff --git a/src/structs.rs b/src/structs.rs index 07cb901..bb42cdb 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -8,11 +8,46 @@ use std::collections::BTreeSet; use std::fs::{self, DirBuilder, File}; use std::io::{self, Read, Write}; use utils::*; +use yaml_rust::YamlLoader; + +pub struct Config { + pub auto_download_limit: i64, + pub auto_delete_limit: i64, +} + +impl Config { + pub fn new() -> Config { + let mut path = get_podcast_dir(); + let mut download_limit = 1; + let mut delete_limit = 0; + path.push(".config"); + if path.exists() { + let mut s = String::new(); + File::open(&path).unwrap().read_to_string(&mut s).unwrap(); + let config = YamlLoader::load_from_str(&s).unwrap(); + if config.len() > 0 { + let doc = &config[0]; + if let Some(val) = doc["auto_download_limit"].as_i64() { + download_limit = val; + } + if let Some(val) = doc["auto_delete_limit"].as_i64() { + delete_limit = val; + } + } + } + Config { + auto_download_limit: download_limit, + auto_delete_limit: delete_limit, + } + } +} + #[derive(Serialize, Deserialize, Clone)] pub struct Subscription { - title: String, - url: String, + pub title: String, + pub url: String, + pub num_episodes: usize, } impl Subscription { @@ -27,8 +62,8 @@ impl Subscription { #[derive(Serialize, Deserialize, Clone)] pub struct State { - last_run_time: DateTime<Utc>, - subs: Vec<Subscription>, + pub last_run_time: DateTime<Utc>, + pub subs: Vec<Subscription>, } impl State { @@ -45,7 +80,7 @@ impl State { .signed_duration_since(Utc::now()) .num_seconds() < -86400 { - update_rss(&state.clone()); + update_rss(&mut state); } state.last_run_time = Utc::now(); state @@ -57,22 +92,23 @@ impl State { } } - pub fn subscribe(&mut self, url: &str) { + pub fn subscribe(&mut self, url: &str, config: &Config) { let mut set = BTreeSet::new(); for sub in self.subscriptions() { set.insert(sub.title()); } - let channel = Channel::from_url(url).unwrap(); - if !set.contains(channel.title()) { + let podcast = Podcast::from(Channel::from_url(url).unwrap()); + if !set.contains(podcast.title()) { self.subs.push(Subscription { - title: String::from(channel.title()), + title: String::from(podcast.title()), url: String::from(url), + num_episodes: podcast.episodes().len(), }); } if let Err(err) = self.save() { eprintln!("{}", err); } - download_rss(url); + download_rss(url, config); } pub fn subscriptions(&self) -> Vec<Subscription> { @@ -195,13 +231,14 @@ impl Episode { "audio/mpeg" => Some(".mp3"), "audio/mp4" => Some(".m4a"), "audio/ogg" => Some(".ogg"), - _ => None, + _ => find_extension(self.url().unwrap()), } } None => None, } } + pub fn download(&self, podcast_name: &str) -> Result<(), io::Error> { let mut path = get_podcast_dir(); path.push(podcast_name); @@ -209,10 +246,10 @@ impl Episode { if let Some(url) = self.url() { if let Some(title) = self.title() { - println!("Downloading: {}", title); let mut filename = String::from(title); filename.push_str(self.extension().unwrap()); path.push(filename); + println!("Downloading: {}", path.to_str().unwrap()); let mut file = File::create(&path)?; let mut resp = reqwest::get(url).unwrap(); let mut content: Vec<u8> = Vec::new(); diff --git a/src/utils.rs b/src/utils.rs index a3d7260..7d355b3 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,12 +1,33 @@ -use std::collections::BTreeSet; +use std::collections::HashSet; use std::env; use std::fs; -use std::path::PathBuf; use std::num::ParseIntError; +use std::path::PathBuf; -pub fn already_downloaded(dir: &str) -> BTreeSet<String> { - let mut result = BTreeSet::new(); +pub fn trim_extension(filename: &str) -> String { + let name = String::from(filename); + let index = name.rfind('.').unwrap(); + String::from(&name[0..index]) +} + +pub fn find_extension(input: &str) -> Option<&str> { + let tmp = String::from(input); + if tmp.contains(".mp3") { + Some(".mp3") + } else if tmp.contains(".m4a") { + Some(".m4a") + } else if tmp.contains(".wav") { + Some(".wav") + } else if tmp.contains(".ogg") { + Some(".ogg") + } else { + None + } +} + +pub fn already_downloaded(dir: &str) -> HashSet<String> { + let mut result = HashSet::new(); let mut path = get_podcast_dir(); path.push(dir); |
