3YR56Y65UIAL3J7PUXWVJMOOHYZYDIX4V54OT2TJPZ25WQ6MXHCQC
TV3GOKIHRVTPGEFYLMTNFQYZBNJRL46ZLOKSQACHVIGW4IWOMDFQC
TE6ACJLE7GUBYSV7B77L5YFKUMTV2PYR7CQRKG6A3XZ6YZWBR7TAC
L3I4GC7R74HPQS3VCQ44UTBAKKBOW6UDVXV2EF7XSWH7H2Z3RRJQC
GE7XXDPC73SUY6I6F3X6I4QFQO2BCPHD4MZALYOWG7H7SRE5XAFQC
XIHPYOWDLQY2MVMVUQPH23O3TBALRG4G2CHSLWSCAYMY5NVJ32WQC
IFBRAMVLQ4Z6BAEMWDIXD2V5HSZK4DHRWYZNB32IBY7ZRTNZJVCQC
O53GR2OQHGRKAVJT2RVPRHYFB54W5LM4DQYT7EYVGKU7HDK5CJJQC
JYSIHNS67XTGAR4HN7ZHWFMGGYSK5IY6J6EHO4YUZOR7UMMWAORQC
ADXMUSFXOKBPCHW4XS3T4KLWMPGQPYDMZW6YFFSHZPAQKEGIKCBQC
UIMZBURR7KOWSREO4GDH5C2LZDUTEZBKQNYWBYSFGUTRYJ4GKSNQC
5GQNHICLSFAA7ZUFXUCNACCPAIIGK4DV2QPTONDNXLS4TJJTOFHAC
2CKX4R6ONNXDXGRYZ5NZEBJZFX5Z6BYPGNJ7LMXUHHFB4MUFJRCAC
NE63ERXN7OUYSQ4PGPIQIIKEYD7OAOWXXSGMTORD6RJNUZHRLVJAC
M4FCDZ745GHHL3OLH64EVYOEOEGGGVIBCVFGX5JUJDJRE5OLCXLQC
Y6BVNXQ747WQKVB4JO3AHYOMBWNNJNPC6SG2UUCCZRIIXDMXJYDQC
HSDBPX2AMUS4NRA52EHIYOR7H37ABNGJWBJKPQABFMFDU7EITSIAC
476KTQSS5NXVCTVLVZQRGSYD5OAFBYG75VTSWBN26Q45RSMRT5YQC
5JMYBRF3UYX4LFH7JK6S4BEDKRVKDFIL4YKTCWKMKP4TMNNGQFKQC
EZMX4SYFEBYNJVQETRVAYONU5MIMQYTTSA5DRMTQET5B7CL6CI6AC
J64KBLKALQ3HQCY4HJU5H6WBXTATS7TKBYNNUUSNJE7JLWLYO66QC
ZD3G3BCXBEXELHH3KMXMDUQUJ4BXIF4ZSZKFIJJCRO7IDK4XPOWAC
THSENT35O3PIXQ343QPPE3DJGR4YVULN6YPS5ETW5PXSVGZZQIZAC
JPN37V6Q35ZAW7A2DTGX2WJ3IJ66BAGHXHWXOGHQRHGFAOETFQ7AC
FFAFJQ5QVMHTLULZTGVM5PX7XQEZQUWLPH2GAN5BGVAYZOZZYG5QC
6FJACP6KUOZ4HWK4PSS5PFPGDYXZSCAWSKIARWBDGCZTPJWXA62AC
SBPKWZNQF5BWAJ7SZHWVK5BG6DTVJNDYND6UG5PDZCWZ2W4W2HXQC
JJ4SMY257MAHSJSZH5PJZMLBH3GJX5VKH2ZZSBGWLL7FWP7OA7TQC
BSPWOOHZMN3RAOHGJ2A3XKUOUCFFAOXS7YR67E3AARPPPIA5YPDAC
LUJ3HQBUNLRIQILJ2MU43XU46E4KLHQQ25JXLL56UJVLWA3QXJJQC
ZYS43ILR4OXI7S2AYNGYSTK3IU2UVELIWVCCWDS7RVZQDSNJMDHQC
H5MQEP35FJNDLARTAB7J5GEHRNBSL6RTHFUGURG5HIVGLCG4FGUAC
76TBVFPIFU3LSMXY5NAHZBH6HRJLSLK43PGOPL6QQ2YYVBJ64QAQC
MQKOX2CQ7AON24UJC7RORAC7Y2UROROVG7BBKLVWURPXKY75JV5AC
RJYDXOHXMLODTAP3LNIWD4NLPIDL7IXZYS4EURZLJESLWJUEZGHAC
EEJ6CBJRTXLPQP44I2RLWVLJBX565DXXAWU4JIWNA3MMNE7WB5LQC
let re = Regex::new(&format!("(?i){}", &search)).expect("Failed to parse regex");
let mut path = get_podcast_dir();
let re = Regex::new(&format!("(?i){}", &search)).chain_err(|| UNABLE_TO_PARSE_REGEX)?;
let mut path = get_podcast_dir()?;
DirBuilder::new().recursive(true).create(&path).unwrap();
for entry in fs::read_dir(&path).unwrap() {
let entry = entry.unwrap();
DirBuilder::new()
.recursive(true)
.create(&path)
.chain_err(|| UNABLE_TO_CREATE_DIRECTORY)?;
for entry in fs::read_dir(&path).chain_err(|| UNABLE_TO_READ_DIRECTORY)? {
let entry = entry.chain_err(|| UNABLE_TO_READ_ENTRY)?;
let file = File::open(&entry.path()).unwrap();
let channel = Channel::read_from(BufReader::new(file)).unwrap();
let file = File::open(&entry.path()).chain_err(|| UNABLE_TO_OPEN_FILE)?;
let channel = Channel::read_from(BufReader::new(file))
.chain_err(|| UNABLE_TO_CREATE_CHANNEL_FROM_FILE)?;
match download_rss_feed(url) {
Ok(channel) => {
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(|ep| {
if let Err(err) = ep.download(podcast.title()) {
eprintln!("Error downloading {}: {}", podcast.title(), err);
}
});
let channel = download_rss_feed(url)?;
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(|ep| {
if let Err(err) = ep.download(podcast.title()) {
eprintln!("Error downloading {}: {}", podcast.title(), err);
pub fn update_rss(state: &mut State) {
println!("Checking for new episodes...");
state.subscriptions.par_iter_mut().for_each(|sub| {
let mut path = get_podcast_dir();
path.push(&sub.title);
DirBuilder::new().recursive(true).create(&path).unwrap();
pub fn update_subscription(sub: &mut Subscription) -> Result<()> {
let mut path: PathBuf = get_podcast_dir()?;
path.push(&sub.title);
DirBuilder::new()
.recursive(true)
.create(&path)
.chain_err(|| UNABLE_TO_CREATE_DIRECTORY)?;
let mut titles = HashSet::new();
for entry in fs::read_dir(&path).chain_err(|| UNABLE_TO_READ_DIRECTORY)? {
let unwrapped_entry = &entry.chain_err(|| UNABLE_TO_READ_ENTRY)?;
titles.insert(trim_extension(&unwrapped_entry
.file_name()
.into_string()
.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).chain_err(|| UNABLE_TO_GET_HTTP_RESPONSE)?;
let mut content: Vec<u8> = Vec::new();
resp.read_to_end(&mut content)
.chain_err(|| UNABLE_TO_READ_RESPONSE_TO_END)?;
let podcast = Podcast::from(Channel::read_from(BufReader::new(&content[..]))
.chain_err(|| UNABLE_TO_CREATE_CHANNEL_FROM_RESPONSE)?);
path = get_podcast_dir()?;
path.push(".rss");
let mut resp = reqwest::get(&sub.url).unwrap();
let mut content: Vec<u8> = Vec::new();
resp.read_to_end(&mut content).unwrap();
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);
let mut file = File::create(&path).unwrap();
file.write_all(&content).unwrap();
let mut filename = String::from(podcast.title());
filename.push_str(".xml");
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(|ep: &Episode| {
if let Err(err) = ep.download(podcast.title()) {
eprintln!("Error downloading {}: {}", podcast.title(), err);
}
});
}
sub.num_episodes = podcast.episodes().len();
Ok(())
}
if podcast.episodes().len() > sub.num_episodes {
podcast.episodes()[..podcast.episodes().len() - sub.num_episodes]
.par_iter()
.for_each(|ep| {
if let Err(err) = ep.download(podcast.title()) {
eprintln!("Error downloading {}: {}", podcast.title(), err);
}
});
}
sub.num_episodes = podcast.episodes().len();
});
pub fn update_rss(state: &mut State) {
println!("Checking for new episodes...");
let _result: Vec<Result<()>> = state
.subscriptions
.par_iter_mut()
.map(|sub: &mut Subscription| update_subscription(sub))
.collect();
pub fn download_range(state: &State, p_search: &str, e_search: &str) {
let re_pod = Regex::new(&format!("(?i){}", &p_search)).expect("Failed to parse regex");
pub fn download_range(state: &State, p_search: &str, e_search: &str) -> Result<()> {
let re_pod = Regex::new(&format!("(?i){}", &p_search)).chain_err(|| UNABLE_TO_PARSE_REGEX)?;
match Podcast::from_title(&subscription.title) {
Ok(podcast) => match parse_download_episodes(e_search) {
Ok(episodes_to_download) => {
if let Err(err) = podcast.download_specific(&episodes_to_download) {
eprintln!("Error: {}", err);
}
}
Err(err) => eprintln!("Error: {}", err),
},
Err(err) => eprintln!("Error: {}", err),
}
let podcast = Podcast::from_title(&subscription.title)
.chain_err(|| UNABLE_TO_RETRIEVE_PODCAST_BY_TITLE)?;
let episodes_to_download = parse_download_episodes(e_search)
.chain_err(|| "unable to parse episodes to download")?;
podcast
.download_specific(&episodes_to_download)
.chain_err(|| "unable to download episodes")?;
pub fn download_episode(state: &State, p_search: &str, e_search: &str) {
let re_pod = Regex::new(&format!("(?i){}", &p_search)).expect("Failed to parse regex");
let ep_num = e_search.parse::<usize>().unwrap();
pub fn download_episode(state: &State, p_search: &str, e_search: &str) -> Result<()> {
let re_pod = Regex::new(&format!("(?i){}", &p_search)).chain_err(|| UNABLE_TO_PARSE_REGEX)?;
let ep_num = e_search
.parse::<usize>()
.chain_err(|| "unable to parse number")?;
match Podcast::from_title(&subscription.title) {
Ok(podcast) => {
let episodes = podcast.episodes();
if let Err(err) = episodes[episodes.len() - ep_num].download(podcast.title()) {
eprintln!("{}", err);
}
}
Err(err) => eprintln!("Error: {}", err),
}
let podcast = Podcast::from_title(&subscription.title)
.chain_err(|| UNABLE_TO_RETRIEVE_PODCAST_BY_TITLE)?;
let episodes = podcast.episodes();
episodes[episodes.len() - ep_num]
.download(podcast.title())
.chain_err(|| "unable to download episode")?;
pub fn download_all(state: &State, p_search: &str) {
let re_pod = Regex::new(&format!("(?i){}", &p_search)).expect("Failed to parse regex");
pub fn download_all(state: &State, p_search: &str) -> Result<()> {
let re_pod = Regex::new(&format!("(?i){}", &p_search)).chain_err(|| UNABLE_TO_PARSE_REGEX)?;
match Podcast::from_title(&subscription.title) {
Ok(podcast) => if let Err(err) = podcast.download() {
eprintln!("{}", err);
},
Err(err) => eprintln!("Error: {}", err),
}
let podcast = Podcast::from_title(&subscription.title)
.chain_err(|| UNABLE_TO_RETRIEVE_PODCAST_BY_TITLE)?;
podcast
.download()
.chain_err(|| "unable to download podcast")?;
pub fn play_latest(state: &State, p_search: &str) {
let re_pod = Regex::new(&format!("(?i){}", &p_search)).expect("Failed to parse regex");
let mut path = get_xml_dir();
if let Err(err) = DirBuilder::new().recursive(true).create(&path) {
eprintln!(
"Couldn't create directory: {}\nReason: {}",
path.to_str().unwrap(),
err
);
return;
}
pub fn play_latest(state: &State, p_search: &str) -> Result<()> {
let re_pod: Regex =
Regex::new(&format!("(?i){}", &p_search)).chain_err(|| UNABLE_TO_PARSE_REGEX)?;
let mut path: PathBuf = get_xml_dir()?;
DirBuilder::new()
.recursive(true)
.create(&path)
.chain_err(|| UNABLE_TO_CREATE_DIRECTORY)?;
filename = String::from(episode.title().unwrap());
filename.push_str(episode.extension().unwrap());
path = get_podcast_dir();
filename = String::from(episode
.title()
.chain_err(|| "unable to retrieve episode name")?);
filename.push_str(episode
.extension()
.chain_err(|| "unable to retrieve episode extension")?);
path = get_podcast_dir()?;
pub fn play_episode(state: &State, p_search: &str, ep_num_string: &str) {
let re_pod = Regex::new(&format!("(?i){}", &p_search)).expect("Failed to parse regex");
let ep_num = ep_num_string.parse::<usize>().unwrap();
let mut path = get_xml_dir();
pub fn play_episode(state: &State, p_search: &str, ep_num_string: &str) -> Result<()> {
let re_pod: Regex =
Regex::new(&format!("(?i){}", &p_search)).chain_err(|| UNABLE_TO_PARSE_REGEX)?;
let ep_num: usize = ep_num_string.parse::<usize>().unwrap();
let mut path: PathBuf = get_xml_dir()?;
match resp.parse::<toml::Value>() {
Ok(config) => {
let latest = config["package"]["version"].as_str().unwrap();
if version != latest {
println!("New version avaliable: {} -> {}", version, latest);
}
}
Err(err) => eprintln!("{}", err),
let config = resp.parse::<toml::Value>()
.chain_err(|| "unable to parse toml")?;
let latest = config["package"]["version"]
.as_str()
.chain_err(|| UNABLE_TO_CONVERT_TO_STR)?;
if version != latest {
println!("New version avaliable: {} -> {}", version, latest);
fn main() {
if let Err(err) = create_directories() {
eprintln!("{}", err);
return;
}
let mut state = match State::new(VERSION) {
Ok(val) => val,
Err(err) => {
eprintln!("{}", err);
return;
}
};
let config = Config::new();
fn main() -> Result<()> {
create_directories().chain_err(|| "unable to create directories")?;
let mut state = State::new(VERSION).chain_err(|| "unable to load state")?;
let config = Config::new()?;
let download_matches = matches.subcommand_matches("download").unwrap();
let podcast = download_matches.value_of("PODCAST").unwrap();
let download_matches = matches
.subcommand_matches("download")
.chain_err(|| "unable to find subcommand matches")?;
let podcast = download_matches
.value_of("PODCAST")
.chain_err(|| "unable to find subcommand match")?;
let play_matches = matches.subcommand_matches("play").unwrap();
let podcast = play_matches.value_of("PODCAST").unwrap();
let play_matches = matches
.subcommand_matches("play")
.chain_err(|| "unable to find subcommand matches")?;
let podcast = play_matches
.value_of("PODCAST")
.chain_err(|| "unable to find subcommand match")?;
let subscribe_matches = matches.subcommand_matches("subscribe").unwrap();
let url = subscribe_matches.value_of("URL").unwrap();
state.subscribe(url);
let subscribe_matches = matches
.subcommand_matches("subscribe")
.chain_err(|| "unable to find subcommand matches")?;
let url = subscribe_matches
.value_of("URL")
.chain_err(|| "unable to find subcommand match")?;
state.subscribe(url).chain_err(|| "unable to subscribe")?;
let rm_matches = matches.subcommand_matches("rm").unwrap();
match rm_matches.value_of("PODCAST") {
Some(regex) => remove_podcast(&mut state, regex),
None => println!(),
}
let rm_matches = matches
.subcommand_matches("rm")
.chain_err(|| "unable to find subcommand matches")?;
let regex = rm_matches.value_of("PODCAST").chain_err(|| "")?;
remove_podcast(&mut state, regex)?
File::open(&path).unwrap().read_to_string(&mut s).unwrap();
let config = YamlLoader::load_from_str(&s).unwrap();
File::open(&path)
.chain_err(|| UNABLE_TO_OPEN_FILE)?
.read_to_string(&mut s)
.chain_err(|| UNABLE_TO_READ_FILE_TO_STRING)?;
let config =
YamlLoader::load_from_str(&s).chain_err(|| "unable to load yaml from string")?;
let mut file = match File::open(&path) {
Ok(val) => val,
Err(err) => return Err(format!("{}", err)),
};
if let Err(err) = file.read_to_string(&mut s) {
return Err(format!("{}", err));
};
let mut file = File::open(&path).chain_err(|| UNABLE_TO_OPEN_FILE)?;
file.read_to_string(&mut s)
.chain_err(|| UNABLE_TO_READ_FILE_TO_STRING)?;
let serialized = serde_json::to_string(self)?;
let mut file = File::create(&path)?;
file.write_all(serialized.as_bytes())?;
fs::rename(&path, get_sub_file())?;
let serialized = serde_json::to_string(self).chain_err(|| "unable to serialize state")?;
let mut file = File::create(&path).chain_err(|| UNABLE_TO_CREATE_FILE)?;
file.write_all(serialized.as_bytes())
.chain_err(|| UNABLE_TO_WRITE_FILE)?;
fs::rename(&path, get_sub_file()?).chain_err(|| "unable to rename file")?;
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 from_url(url: &str) -> Result<Podcast> {
Ok(
Podcast::from(Channel::from_url(url).chain_err(|| UNABLE_TO_CREATE_CHANNEL_FROM_RESPONSE)?),
)
match File::open(&path) {
Ok(file) => match Channel::read_from(BufReader::new(file)) {
Ok(podcast) => Ok(Podcast::from(podcast)),
Err(err) => Err(format!("Error: {}", err)),
},
Err(err) => Err(format!("Error: {}", err)),
}
let file = File::open(&path).chain_err(|| UNABLE_TO_OPEN_FILE)?;
Ok(Podcast::from(Channel::read_from(BufReader::new(file))
.chain_err(|| UNABLE_TO_CREATE_CHANNEL_FROM_FILE)?))
pub fn download_specific(&self, episode_numbers: &[usize]) -> Result<(), io::Error> {
let mut path = get_podcast_dir();
pub fn download_specific(&self, episode_numbers: &[usize]) -> Result<()> {
let mut path = get_podcast_dir()?;
match self.0.enclosure() {
Some(enclosure) => match enclosure.mime_type() {
"audio/mpeg" => Some(".mp3"),
"audio/mp4" => Some(".m4a"),
"audio/ogg" => Some(".ogg"),
_ => find_extension(self.url().unwrap()),
},
None => None,
match self.0.enclosure()?.mime_type() {
"audio/mpeg" => Some(".mp3"),
"audio/mp4" => Some(".m4a"),
"audio/ogg" => Some(".ogg"),
_ => find_extension(self.url().unwrap()),
pub const UNABLE_TO_PARSE_REGEX: &'static str = "unable to parse regex";
pub const UNABLE_TO_OPEN_FILE: &'static str = "unable to open file";
pub const UNABLE_TO_CREATE_FILE: &'static str = "unable to create file";
pub const UNABLE_TO_WRITE_FILE: &'static str = "unable to write file";
pub const UNABLE_TO_READ_FILE_TO_STRING: &'static str = "unable to read file to string";
pub const UNABLE_TO_READ_DIRECTORY: &'static str = "unable to read directory";
pub const UNABLE_TO_READ_ENTRY: &'static str = "unable to read entry";
pub const UNABLE_TO_CREATE_DIRECTORY: &'static str = "unable to create directory";
pub const UNABLE_TO_READ_RESPONSE_TO_END: &'static str = "unable to read response to end";
pub const UNABLE_TO_GET_HTTP_RESPONSE: &'static str = "unable to get http response";
pub const UNABLE_TO_CONVERT_TO_STR: &'static str = "unable to convert to &str";
pub const UNABLE_TO_REMOVE_FILE: &'static str = "unable to remove file";
pub const UNABLE_TO_CREATE_CHANNEL_FROM_RESPONSE: &'static str =
"unable to create channel from http response";
pub const UNABLE_TO_CREATE_CHANNEL_FROM_FILE: &'static str =
"unable to create channel from xml file";
pub const UNABLE_TO_RETRIEVE_PODCAST_BY_TITLE: &'static str = "unable to retrieve podcast by title";
pub fn create_directories() -> Result<(), String> {
let mut path = get_podcast_dir();
path.push(".rss");
if let Err(err) = DirBuilder::new().recursive(true).create(&path) {
return Err(format!(
"Couldn't create directory: {}\nReason: {}",
path.to_str().unwrap(),
err
));
pub fn get_podcast_dir() -> Result<PathBuf> {
match env::var_os("PODCAST") {
Some(val) => Ok(PathBuf::from(val)),
None => {
let mut path = env::home_dir().chain_err(|| "Couldn't find your home directory")?;
path.push("Podcasts");
Ok(path)
}
pub fn already_downloaded(dir: &str) -> Result<HashSet<String>, io::Error> {
pub fn create_directories() -> Result<()> {
let mut path = get_podcast_dir()?;
path.push(".rss");
DirBuilder::new()
.recursive(true)
.create(&path)
.chain_err(|| "unable to create directory")
}
pub fn already_downloaded(dir: &str) -> Result<HashSet<String>> {
}
pub fn get_podcast_dir() -> PathBuf {
match env::var_os("PODCAST") {
Some(val) => PathBuf::from(val),
None => {
let mut path = env::home_dir().expect("Couldn't find your home directory");
path.push("Podcasts");
path
}
}
DirBuilder::new().recursive(true).create(&path).unwrap();
let mut resp = reqwest::get(url).unwrap();
DirBuilder::new()
.recursive(true)
.create(&path)
.chain_err(|| "unable to open directory")?;
let mut resp = reqwest::get(url).chain_err(|| "unable to open url")?;
resp.read_to_end(&mut content).unwrap();
let channel = Channel::read_from(BufReader::new(&content[..])).unwrap();
resp.read_to_end(&mut content)
.chain_err(|| "unable to read http response to end")?;
let channel = Channel::read_from(BufReader::new(&content[..]))
.chain_err(|| "unable to create channel from xml http response")?;