aboutsummaryrefslogtreecommitdiffstats
path: root/src/structs.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/structs.rs')
-rw-r--r--src/structs.rs154
1 files changed, 61 insertions, 93 deletions
diff --git a/src/structs.rs b/src/structs.rs
index 9b921ee..56c1674 100644
--- a/src/structs.rs
+++ b/src/structs.rs
@@ -3,16 +3,15 @@ use super::utils::*;
use crate::errors::*;
use std::collections::BTreeSet;
-use std::fs::{self, DirBuilder, File};
-use std::io::{self, BufReader, Read, Write};
+use std::fs::{self, File};
+use std::io::{self, BufReader, Write};
use chrono::prelude::*;
use rayon::prelude::*;
use regex::Regex;
-use reqwest;
use rss::{Channel, Item};
use serde_json;
-use yaml_rust::YamlLoader;
+use std::path::PathBuf;
#[cfg(target_os = "macos")]
static ESCAPE_REGEX: &str = r"/";
@@ -25,6 +24,7 @@ lazy_static! {
static ref FILENAME_ESCAPE: Regex = Regex::new(ESCAPE_REGEX).unwrap();
}
+#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Config {
pub auto_download_limit: i64,
}
@@ -32,41 +32,47 @@ pub struct Config {
impl Config {
pub fn new() -> Result<Config> {
let mut path = get_podcast_dir()?;
- let mut download_limit = 1;
- path.push(".config");
- if path.exists() {
- let mut s = String::new();
- 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")?;
- if !config.is_empty() {
- let doc = &config[0];
- if let Some(val) = doc["auto_download_limit"].as_i64() {
- download_limit = val;
+ path.push(".config.yaml");
+ let config = if path.exists() {
+ let file = File::open(&path).chain_err(|| UNABLE_TO_OPEN_FILE)?;
+ match serde_yaml::from_reader(file) {
+ Ok(config) => config,
+ Err(err) => {
+ let mut new_path = path.clone();
+ new_path.set_extension("yaml.bk");
+ eprintln!("{}", err);
+ eprintln!("Failed to open config file, moving to {:?}", &new_path);
+ fs::rename(&path, new_path)
+ .chain_err(|| "Failed to move old config file...")?;
+ create_new_config_file(&path)?
}
}
} else {
- let mut file = File::create(&path).chain_err(|| UNABLE_TO_CREATE_FILE)?;
- file.write_all(b"auto_download_limit: 1")
- .chain_err(|| UNABLE_TO_WRITE_FILE)?;
- }
- Ok(Config {
- auto_download_limit: download_limit,
- })
+ create_new_config_file(&path)?
+ };
+ Ok(config)
}
}
-#[derive(Serialize, Deserialize, Clone, Debug)]
+fn create_new_config_file(path: &PathBuf) -> Result<Config> {
+ println!("Creating new config file at {:?}", &path);
+ let download_limit = 1;
+ let file = File::create(&path).chain_err(|| UNABLE_TO_CREATE_FILE)?;
+ let config = Config {
+ auto_download_limit: download_limit,
+ };
+ serde_yaml::to_writer(file, &config).chain_err(|| UNABLE_TO_WRITE_FILE)?;
+ Ok(config)
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Subscription {
pub title: String,
pub url: String,
pub num_episodes: usize,
}
-#[derive(Serialize, Deserialize, Clone, Debug)]
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct State {
pub version: String,
pub last_run_time: DateTime<Utc>,
@@ -75,21 +81,15 @@ pub struct State {
impl State {
pub fn new(version: &str) -> Result<State> {
- let mut path = get_podcast_dir()?;
- path.push(".subscriptions");
+ let path = get_sub_file()?;
if path.exists() {
- let mut s = String::new();
- {
- 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 mut state: State = match serde_json::from_str(&s) {
+ let file = File::open(&path).chain_err(|| UNABLE_TO_OPEN_FILE)?;
+ let mut state: State = match serde_json::from_reader(&file) {
Ok(val) => val,
// This will happen if the struct has changed between versions
Err(_) => {
- let v: serde_json::Value =
- serde_json::from_str(&s).chain_err(|| "unable to read json from string")?;
+ let v: serde_json::Value = serde_json::from_reader(&file)
+ .chain_err(|| "unable to read json from string")?;
State {
version: String::from(version),
last_run_time: Utc::now(),
@@ -103,10 +103,9 @@ impl State {
};
state.version = String::from(version);
// Check if a day has passed (86400 seconds) since last launch
- if Utc::now()
+ if 86400 < Utc::now()
.signed_duration_since(state.last_run_time)
.num_seconds()
- > 86400
{
update_rss(&mut state);
check_for_update(&state.version)?;
@@ -115,6 +114,7 @@ impl State {
state.save()?;
Ok(state)
} else {
+ println!("Creating new file {:?}", &path);
Ok(State {
version: String::from(version),
last_run_time: Utc::now(),
@@ -126,7 +126,7 @@ impl State {
pub fn subscribe(&mut self, url: &str) -> Result<()> {
let mut set = BTreeSet::new();
for sub in self.subscriptions() {
- set.insert(sub.title);
+ set.insert(sub.title.clone());
}
let podcast = Podcast::from(Channel::from_url(url).unwrap());
if !set.contains(podcast.title()) {
@@ -139,20 +139,26 @@ impl State {
self.save()
}
- pub fn subscriptions(&self) -> Vec<Subscription> {
- self.subscriptions.clone()
+ pub fn subscriptions(&self) -> &[Subscription] {
+ &self.subscriptions
+ }
+
+ pub fn subscriptions_mut(&mut self) -> &mut [Subscription] {
+ &mut self.subscriptions
}
pub fn save(&self) -> Result<()> {
- let mut path = get_podcast_dir()?;
- path.push(".subscriptions.tmp");
+ let mut path = get_sub_file()?;
+ path.set_extension("json.tmp");
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")?;
+ let sub_file_path = get_sub_file()?;
+ fs::rename(&path, &sub_file_path)
+ .chain_err(|| format!("unable to rename file {:?} to {:?}", &path, &sub_file_path))?;
Ok(())
}
}
@@ -210,25 +216,26 @@ impl Podcast {
let mut filename = String::from(title);
filename.push_str(".xml");
path.push(filename);
-
fs::remove_file(path).chain_err(|| UNABLE_TO_REMOVE_FILE)
}
pub fn delete_all() -> Result<()> {
- let path = get_xml_dir()?;
- fs::remove_dir_all(path).chain_err(|| UNABLE_TO_READ_DIRECTORY)
+ fs::remove_dir_all(get_xml_dir()?).chain_err(|| UNABLE_TO_READ_DIRECTORY)
}
pub fn episodes(&self) -> Vec<Episode> {
let mut result = Vec::new();
- for item in self.0.items().to_vec() {
+ for item in self.0.items().to_owned() {
result.push(Episode::from(item));
}
result
}
pub fn download(&self) -> Result<()> {
- print!("You are about to download all episodes of {} (y/n): ", self.title());
+ print!(
+ "You are about to download all episodes of {} (y/n): ",
+ self.title()
+ );
io::stdout().flush().ok();
let mut input = String::new();
io::stdin()
@@ -246,7 +253,7 @@ impl Podcast {
self.episodes().par_iter().for_each(|i| {
if let Some(ep_title) = i.title() {
if !downloaded.contains(&ep_title) {
- if let Err(err) = i.download(self.title()) {
+ if let Err(err) = download(self.title(), i) {
eprintln!("{}", err);
}
}
@@ -255,7 +262,7 @@ impl Podcast {
}
Err(_) => {
self.episodes().par_iter().for_each(|i| {
- if let Err(err) = i.download(self.title()) {
+ if let Err(err) = download(self.title(), i) {
eprintln!("{}", err);
}
});
@@ -275,7 +282,7 @@ impl Podcast {
episode_numbers.par_iter().for_each(|ep_num| {
if let Some(ep_title) = episodes[episodes.len() - ep_num].title() {
if !downloaded.contains(&ep_title) {
- if let Err(err) = episodes[episodes.len() - ep_num].download(self.title()) {
+ if let Err(err) = download(self.title(), &episodes[episodes.len() - ep_num]) {
eprintln!("{}", err);
}
}
@@ -309,43 +316,4 @@ impl Episode {
_ => find_extension(self.url().unwrap()),
}
}
-
- pub fn download(&self, podcast_name: &str) -> Result<()> {
- let stdout = io::stdout();
-
- let mut path = get_podcast_dir()?;
- path.push(podcast_name);
- DirBuilder::new()
- .recursive(true)
- .create(&path)
- .chain_err(|| UNABLE_TO_CREATE_DIRECTORY)?;
-
- if let Some(url) = self.url() {
- if let Some(title) = self.title() {
- let mut filename = title;
- filename.push_str(
- self.extension()
- .chain_err(|| "unable to retrieve extension")?,
- );
- path.push(filename);
- if !path.exists() {
- {
- let mut handle = stdout.lock();
- writeln!(&mut handle, "Downloading: {}", path.to_str().unwrap()).ok();
- }
- let mut file = File::create(&path).chain_err(|| UNABLE_TO_CREATE_FILE)?;
- let mut resp = reqwest::get(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)?;
- file.write_all(&content)
- .chain_err(|| UNABLE_TO_WRITE_FILE)?;
- } else {
- let mut handle = stdout.lock();
- writeln!(&mut handle, "File already exists: {}", path.to_str().chain_err(|| UNABLE_TO_CONVERT_TO_STR)?).ok();
- }
- }
- }
- Ok(())
- }
}