use std::fs::File;
use std::path::{Path, PathBuf};
use std::sync::mpsc::Sender;
use std::time::Duration;
use chrono::{DateTime, Utc};
use sanitize_filename::{sanitize_with_options, Options};
use crate::threadpool::Threadpool;
use crate::types::Message;
#[derive(Debug)]
pub enum DownloadMsg {
Complete(EpData),
ResponseError(EpData),
FileCreateError(EpData),
FileWriteError(EpData),
}
#[derive(Debug, Clone)]
pub struct EpData {
pub id: i64,
pub pod_id: i64,
pub title: String,
pub url: String,
pub pubdate: Option<DateTime<Utc>>,
pub file_path: Option<PathBuf>,
}
pub fn download_list(
episodes: Vec<EpData>,
dest: &Path,
max_retries: usize,
threadpool: &Threadpool,
tx_to_main: Sender<Message>,
) {
for ep in episodes.into_iter() {
let tx = tx_to_main.clone();
let dest2 = dest.to_path_buf();
threadpool.execute(move || {
let result = download_file(ep, dest2, max_retries);
tx.send(Message::Dl(result))
.expect("Thread messaging error");
});
}
}
fn download_file(mut ep_data: EpData, dest: PathBuf, mut max_retries: usize) -> DownloadMsg {
let agent_builder = ureq::builder()
.timeout_connect(Duration::from_secs(10))
.timeout_read(Duration::from_secs(120));
#[cfg(feature = "native_tls")]
let tls_connector = std::sync::Arc::new(native_tls::TlsConnector::new().unwrap());
#[cfg(feature = "native_tls")]
let agent_builder = agent_builder.tls_connector(tls_connector);
let agent = agent_builder.build();
let request: Result<ureq::Response, ()> = loop {
let response = agent.get(&ep_data.url).call();
match response {
Ok(resp) => break Ok(resp),
Err(_) => {
max_retries -= 1;
if max_retries == 0 {
break Err(());
}
}
}
};
if request.is_err() {
return DownloadMsg::ResponseError(ep_data);
};
let response = request.unwrap();
let ext = match response.header("content-type") {
Some("audio/x-m4a") => "m4a",
Some("audio/mpeg") => "mp3",
Some("video/quicktime") => "mov",
Some("video/mp4") => "mp4",
Some("video/x-m4v") => "m4v",
_ => "mp3", };
let mut file_name = sanitize_with_options(&ep_data.title, Options {
truncate: true,
windows: true, replacement: "",
});
if let Some(pubdate) = ep_data.pubdate {
file_name = format!("{}_{}", file_name, pubdate.format("%Y%m%d_%H%M%S"));
}
let mut file_path = dest;
file_path.push(format!("{file_name}.{ext}"));
let dst = File::create(&file_path);
if dst.is_err() {
return DownloadMsg::FileCreateError(ep_data);
};
ep_data.file_path = Some(file_path);
let mut reader = response.into_reader();
return match std::io::copy(&mut reader, &mut dst.unwrap()) {
Ok(_) => DownloadMsg::Complete(ep_data),
Err(_) => DownloadMsg::FileWriteError(ep_data),
};
}