aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNathan Jaremko2017-07-24 23:52:15 -0400
committerNathan Jaremko2017-07-24 23:52:15 -0400
commit404c468a4c51b07c27e92ccd952f647db11a6369 (patch)
tree35372d1fe61c608eadb45e0bef52e0d01e342c7e /src
parent237a0be7f0ca4d7dceca1c9e43391381593064fb (diff)
downloadpodcast-404c468a4c51b07c27e92ccd952f647db11a6369.tar.bz2
Basic subscriptions are working now
Diffstat (limited to 'src')
-rw-r--r--src/actions.rs51
-rw-r--r--src/main.rs6
-rw-r--r--src/structs.rs61
-rw-r--r--src/utils.rs29
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);