diff options
Diffstat (limited to 'src/structs.rs')
| -rw-r--r-- | src/structs.rs | 154 | 
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(()) -    }  } | 
