diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..fd47b11 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,7 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [], +} \ No newline at end of file diff --git a/src/downloader.rs b/src/downloader.rs index 989e4a4..e3d71eb 100644 --- a/src/downloader.rs +++ b/src/downloader.rs @@ -1,6 +1,6 @@ use std::{ error, fmt, - fs::File, + fs::{File, OpenOptions}, io::{self, Read, Write}, }; @@ -30,6 +30,16 @@ impl DualWriter { Ok(()) } + + pub fn len(&self) -> u64 { + match self { + DualWriter::File(f) => f.metadata().and_then(|x| Ok(x.len())).unwrap_or_else(|e| { + println!("Could not get metadata from file {:?}", e); + 0 + }), + DualWriter::Buffer(buf) => buf.len() as u64, + } + } } impl TryFrom> for DualWriter { @@ -37,7 +47,18 @@ impl TryFrom> for DualWriter { fn try_from(file_name: Option<&str>) -> Result { Ok(if let Some(file_name) = file_name { - Self::File(File::create(&file_name)?) + let file = match OpenOptions::new().append(true).open(&file_name) { + Ok(f) => f, + Err(e) => { + let e = e as io::Error; + if e.kind() == io::ErrorKind::NotFound { + File::create(&file_name)? + } else { + return Err(e); + } + } + }; + Self::File(file) } else { Self::Buffer(Vec::::new()) }) @@ -72,16 +93,21 @@ pub async fn download_with_progress( let mut dual_writer: DualWriter = file_name.try_into()?; let client = Client::builder().gzip(true).deflate(true).build()?; - let resp = client.get(link).send().await?; - let content_length = if let Some(got_content_length) = resp.content_length() { - got_content_length - } else { - panic!("Could not retrive content length from server. {:?}", &resp); - }; + let builder = client + .get(link) + .header("Range", format!("bytes={}-", dual_writer.len())); + + let resp = builder.send().await?; + + let content_length = resp.content_length().unwrap_or_default(); + if content_length == 0 { + println!("File was already downloaded"); + return Ok(dual_writer); + } let progress_bar = ProgressBar::new(content_length); progress_bar.set_style(ProgressStyle::with_template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})").unwrap() - .with_key("eta", |state: &ProgressState, w: &mut dyn fmt::Write| write!(w, "{:.1}s", state.eta().as_secs_f64()).unwrap()) + .with_key("eta", |state: &ProgressState, w: &mut dyn fmt::Write| write!(w, "{:.1}m", state.eta().as_secs_f64() / 60.0 ).unwrap()) .progress_chars("#>-")); let mut downloaded: u64 = 0; diff --git a/src/grandmother.rs b/src/grandmother.rs index 10758fe..5347039 100644 --- a/src/grandmother.rs +++ b/src/grandmother.rs @@ -70,19 +70,15 @@ impl GrandMother { println!("Retrying {}/{}", counter, MAX_TRIES); }; - let watched_links = self - .parser - .get_watched() - .iter() - .map(|x| x.link.as_str()) - .collect(); + let watched_links = self.parser.get_watched_links(); + let watched_links = watched_links.iter().map(|x| x.as_str()).collect(); self.parser = Box::new(OnlineParser::new(&content, &watched_links).await); Ok(()) } pub fn save_watched(&self) { - let watched_items = self.parser.get_watched(); + let watched_items = self.parser.get_watched_links(); let resp = fs::write( &self.config.seen_links_path, diff --git a/src/main.rs b/src/main.rs index 4b1b7ee..220e461 100644 --- a/src/main.rs +++ b/src/main.rs @@ -214,7 +214,6 @@ async fn main() { println!("Not possible to refresh playlist while in offlinemode"); continue; }; - stream(to_play, &*path_link, mpv_fs); gm.save_watched(); } diff --git a/src/parser.rs b/src/parser.rs index ee9e5b6..d11e3e0 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -8,7 +8,7 @@ pub trait GetM3u8 { pub trait WatchedFind { fn find(&self, name: &str) -> Vec<&M3u8>; - fn get_watched(&self) -> Vec<&M3u8>; + fn get_watched_links(&self) -> Vec>; } impl WatchedFind for T { @@ -20,8 +20,12 @@ impl WatchedFind for T { .collect() } - fn get_watched(&self) -> Vec<&M3u8> { - self.get_m3u8().into_iter().filter(|x| x.watched).collect() + fn get_watched_links(&self) -> Vec> { + self.get_m3u8() + .into_iter() + .filter(|x| x.watched) + .map(|x| x.link.clone()) + .collect() } } pub trait GetPlayPath {