use std::collections::HashSet;
use std::env;
use std::fs::{self, DirBuilder, File};
use std::io::{BufReader, Write};
use std::path::PathBuf;
use anyhow::Result;
use rss::Channel;
const UNSUBSCRIBE_NOTE: &str = "Note: this does NOT delete any downloaded podcasts";
pub fn trim_extension(filename: &str) -> Option<String> {
let name = String::from(filename);
if name.contains('.') {
name.rfind('.').map(|index| String::from(&name[0..index]))
} else {
Some(name)
}
}
pub fn find_extension(input: &str) -> Option<String> {
let s: Vec<String> = input
.split('.')
.map(std::string::ToString::to_string)
.collect();
if s.len() > 1 {
return s.last().cloned();
}
None
}
pub fn get_podcast_dir() -> Result<PathBuf> {
match env::var_os("PODCAST") {
Some(val) => Ok(PathBuf::from(val)),
None => {
let mut path = dirs::home_dir().unwrap();
path.push("Podcasts");
Ok(path)
}
}
}
pub fn append_extension(filename: &str, ext: &str) -> String {
let mut f = filename.to_string();
if !f.ends_with('.') {
f.push('.');
}
f.push_str(ext);
f
}
pub fn create_dir_if_not_exist(path: &PathBuf) -> Result<()> {
DirBuilder::new().recursive(true).create(&path)?;
Ok(())
}
pub fn create_directories() -> Result<()> {
let mut path = get_podcast_dir()?;
path.push(".rss");
create_dir_if_not_exist(&path)
}
pub fn delete(title: &str) -> Result<()> {
let mut path = get_xml_dir()?;
let mut filename = String::from(title);
filename.push_str(".xml");
path.push(filename);
println!("Removing '{}' from subscriptions...", &title);
println!("{}", UNSUBSCRIBE_NOTE);
fs::remove_file(path).ok();
Ok(())
}
pub fn delete_all() -> Result<()> {
println!("Removing all subscriptions...");
println!("{}", UNSUBSCRIBE_NOTE);
fs::remove_dir_all(get_xml_dir()?)?;
Ok(())
}
pub fn already_downloaded(dir: &str) -> Result<HashSet<String>> {
let mut result = HashSet::new();
let mut path = get_podcast_dir()?;
path.push(dir);
let entries = fs::read_dir(path)?;
for entry in entries {
let entry = entry?;
match entry.file_name().into_string() {
Ok(name) => {
let index = name.find('.').unwrap();
result.insert(String::from(&name[0..index]));
}
Err(_) => {
eprintln!(
"OsString: {:?} couldn't be converted to String",
entry.file_name()
);
}
}
}
Ok(result)
}
pub fn get_sub_file() -> Result<PathBuf> {
let mut path = get_podcast_dir()?;
path.push(".subscriptions.json");
Ok(path)
}
pub fn config_path() -> Result<PathBuf> {
let mut path = get_podcast_dir()?;
path.push(".subscriptions.json");
Ok(path)
}
pub fn get_xml_dir() -> Result<PathBuf> {
let mut path = get_podcast_dir()?;
path.push(".rss");
create_dir_if_not_exist(&path)?;
Ok(path)
}
pub async fn download_rss_feed(url: &str) -> Result<Channel> {
println!("Downloading RSS feed...");
let mut path = get_podcast_dir()?;
path.push(".rss");
create_dir_if_not_exist(&path)?;
let resp = reqwest::get(url).await?.bytes().await?;
let channel = Channel::read_from(BufReader::new(&resp[..]))?;
let mut filename = String::from(channel.title());
filename.push_str(".xml");
path.push(filename);
let mut file = File::create(&path)?;
file.write_all(&resp)?;
Ok(channel)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_find_extension_mp3() {
assert_eq!(find_extension("test.mp3"), Some("mp3".into()))
}
#[test]
fn test_find_extension_m4a() {
assert_eq!(find_extension("test.m4a"), Some("m4a".into()))
}
#[test]
fn test_find_extension_wav() {
assert_eq!(find_extension("test.wav"), Some("wav".into()))
}
#[test]
fn test_find_extension_ogg() {
assert_eq!(find_extension("test.ogg"), Some("ogg".into()))
}
#[test]
fn test_find_extension_opus() {
assert_eq!(find_extension("test.opus"), Some("opus".into()))
}
#[test]
fn test_find_weird_extension() {
assert_eq!(find_extension("test.taco"), Some("taco".into()))
}
#[test]
fn test_find_no_extension() {
assert_eq!(find_extension("test"), None)
}
#[test]
fn test_trim_extension() {
assert_eq!(trim_extension("test.taco"), Some(String::from("test")))
}
#[test]
fn test_trim_extension_invalid() {
assert_eq!(trim_extension("test"), Some("test".into()))
}
}