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
}