UIMZBURR7KOWSREO4GDH5C2LZDUTEZBKQNYWBYSFGUTRYJ4GKSNQC use regex::Regex;use structs::*;pub fn list_episodes(state: State, search: &str) {let re = Regex::new(&search).unwrap();for podcast in state.subscriptions() {if re.is_match(&podcast.name) {println!("Episodes for {}:", &podcast.name);match Podcast::from_url(&podcast.url) {Ok(podcast) => {for title in podcast.list_episodes() {println!("{}", title)}}Err(err) => println!("{}", err),}}}}pub fn list_subscriptions(state: State) {for podcast in state.subscriptions() {println!("{}", podcast.name);}}
for title in podcast.list_titles() {println!("{}", title);}let ep = &podcast.episodes()[0];println!("{}",match ep.download_url() {Some(val) => val,None => "",
let matches = App::new("podcast").version("1.0").author("Nathan J. <njaremko@gmail.com>").about("Does awesome things").subcommand(SubCommand::with_name("list").about("list episodes of podcast").arg(Arg::with_name("PODCAST").help("Regex for subscribed podcast")//.required(true).index(1),),).subcommand(SubCommand::with_name("search").about("searches for podcasts").arg(Arg::with_name("debug").short("d").help("print debug information verbosely"),),).subcommand(SubCommand::with_name("subscribe").about("subscribes to a podcast RSS feed").arg(Arg::with_name("URL").help("URL to RSS feed").required(true).index(1),),).subcommand(SubCommand::with_name("update").about("update subscribed podcasts"),).get_matches();match matches.subcommand_name() {Some("list") => {let list_matches = matches.subcommand_matches("list").unwrap();match list_matches.value_of("PODCAST") {Some(regex) => list_episodes(state, regex),None => list_subscriptions(state),}
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 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),_ => (),}}}}
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(());}
use std::fs;use std::path::PathBuf;use std::collections::BTreeSet;use std::env;pub fn already_downloaded(dir: &str) -> BTreeSet<String> {let mut result = BTreeSet::new();let mut path = get_podcast_dir();path.push(dir);if let Ok(entries) = fs::read_dir(path) {for entry in entries {if let Ok(entry) = entry {match entry.file_name().into_string() {Ok(val) => {result.insert(String::from(val.trim_right_matches(".mp3")));}Err(err) => {println!("OsString: {:?} couldn't be converted to String", err);}}}}}result}pub fn get_podcast_dir() -> PathBuf {let mut path = env::home_dir().unwrap();path.push("Podcasts");path}