aboutsummaryrefslogtreecommitdiffstats
path: root/src/structs.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/structs.rs')
-rw-r--r--src/structs.rs144
1 files changed, 138 insertions, 6 deletions
diff --git a/src/structs.rs b/src/structs.rs
index 626072b..5e50307 100644
--- a/src/structs.rs
+++ b/src/structs.rs
@@ -1,6 +1,64 @@
-use std::fs::File;
-use std::io::BufReader;
-use rss::{Channel, Item};
+use reqwest;
+use rss::{self, Channel, Item};
+use std::fs::{DirBuilder, File};
+use std::io::{self, Read, Write};
+use utils::*;
+use serde_json;
+use std::collections::BTreeSet;
+
+#[derive(Serialize, Deserialize, Clone)]
+pub struct Subscription {
+ pub name: String,
+ pub url: String,
+}
+
+#[derive(Serialize, Deserialize, Clone)]
+pub struct State(Vec<Subscription>);
+
+impl State {
+ pub fn new() -> State {
+ let mut path = get_podcast_dir();
+ path.push(".subscriptions");
+ if path.exists() {
+ let mut s = String::new();
+ File::open(&path).unwrap().read_to_string(&mut s).unwrap();
+ serde_json::from_str(&s).unwrap()
+ } else {
+ State(Vec::new())
+ }
+ }
+
+ pub fn subscribe(&mut self, url: &str) {
+ let mut set = BTreeSet::new();
+ for sub in self.subscriptions() {
+ set.insert(sub.url);
+ }
+ if !set.contains(url) {
+ let channel = Channel::from_url(url).unwrap();
+ self.0.push(Subscription {
+ name: String::from(channel.title()),
+ url: String::from(url),
+ });
+ }
+ match self.save() {
+ Err(err) => println!("{}", err),
+ _ => (),
+ }
+ }
+
+ pub fn subscriptions(&self) -> Vec<Subscription> {
+ self.0.clone()
+ }
+
+ pub fn save(&self) -> Result<(), io::Error> {
+ let mut path = get_podcast_dir();
+ path.push(".subscriptions");
+ let serialized = serde_json::to_string(self)?;
+ let mut file = File::create(&path)?;
+ file.write_all(serialized.as_bytes())?;
+ Ok(())
+ }
+}
pub struct Podcast(Channel);
@@ -19,6 +77,21 @@ impl From<Item> for Episode {
}
impl Podcast {
+ pub fn title(&self) -> &str {
+ self.0.title()
+ }
+
+ pub fn url(&self) -> &str {
+ self.0.link()
+ }
+
+ 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 episodes(&self) -> Vec<Episode> {
let mut result = Vec::new();
@@ -29,8 +102,7 @@ impl Podcast {
result
}
-
- pub fn list_titles(&self) -> Vec<&str> {
+ pub fn list_episodes(&self) -> Vec<&str> {
let mut result = Vec::new();
let items = self.0.items();
@@ -42,13 +114,73 @@ impl Podcast {
}
result
}
+
+ pub fn download(&self) {
+ let mut path = get_podcast_dir();
+ path.push(self.title());
+
+ DirBuilder::new().recursive(true).create(path).unwrap();
+
+ let downloaded = already_downloaded(self.title());
+
+ for ep in self.episodes() {
+ if let Some(ep_title) = ep.title() {
+ if !downloaded.contains(ep_title) {
+ match ep.download(self.title()) {
+ Err(err) => println!("{}", err),
+ _ => (),
+ }
+ }
+ }
+ }
+ }
}
impl Episode {
+ pub fn title(&self) -> Option<&str> {
+ self.0.title()
+ }
+
pub fn download_url(&self) -> Option<&str> {
match self.0.enclosure() {
Some(val) => Some(val.url()),
- None => None,
+ None => None,
+ }
+ }
+
+ fn download_extension(&self) -> Option<&str> {
+ match self.0.enclosure() {
+ Some(enclosure) => {
+ match enclosure.mime_type() {
+ "audio/mpeg" => Some(".mp3"),
+ "audio/mp4" => Some(".m4a"),
+ "audio/ogg" => Some(".ogg"),
+ _ => None,
+ }
+ }
+ None => None,
+ }
+ }
+
+ pub fn download(&self, podcast_name: &str) -> Result<(), io::Error> {
+ let mut path = get_podcast_dir();
+ path.push(podcast_name);
+
+ if let Some(url) = self.download_url() {
+ if let Some(title) = self.title() {
+ println!("Downloading: {}", title);
+ let mut filename = String::from(title);
+ filename.push_str(self.download_extension().unwrap());
+ path.push(filename);
+
+ let mut file = File::create(&path)?;
+ let mut resp = reqwest::get(url).unwrap();
+ let mut content: Vec<u8> = Vec::new();
+ resp.read_to_end(&mut content)?;
+ file.write_all(&content)?;
+ return Ok(());
+ }
}
+ Ok(())
}
}