diff options
author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2024-08-25 15:48:54 +0200 |
---|---|---|
committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2024-08-25 15:48:54 +0200 |
commit | 09d03dc79c6e39f12392b3a9edf5c121519bfc92 (patch) | |
tree | 58b4d43f696a4e1de16bedb931677a577b81d3ea | |
parent | docs(cache): Add context to the cache_path deletion error (diff) | |
download | yt-09d03dc79c6e39f12392b3a9edf5c121519bfc92.tar.gz yt-09d03dc79c6e39f12392b3a9edf5c121519bfc92.zip |
fix(downloader): Be smarter, when checking for available cache
-rw-r--r-- | src/download/mod.rs | 98 |
1 files changed, 86 insertions, 12 deletions
diff --git a/src/download/mod.rs b/src/download/mod.rs index d1de3ff..b29594f 100644 --- a/src/download/mod.rs +++ b/src/download/mod.rs @@ -53,9 +53,22 @@ impl CurrentDownload { } } +enum CacheSizeCheck { + /// The video can be downloaded + Fits, + + /// The video and the current cache size together would exceed the size + TooLarge, + + /// The video would not even fit into the empty cache + ExceedsMaxCacheSize, +} + pub struct Downloader { current_download: Option<CurrentDownload>, video_size_cache: HashMap<ExtractorHash, u64>, + printed_warning: bool, + cached_cache_allocation: Option<u64>, } impl Downloader { @@ -63,6 +76,71 @@ impl Downloader { Self { current_download: None, video_size_cache: HashMap::new(), + printed_warning: false, + cached_cache_allocation: None, + } + } + + /// Check if enough cache is available. Will wait for 10s if it's not. + async fn is_enough_cache_available( + &mut self, + app: &App, + max_cache_size: u64, + next_video: &Video, + ) -> Result<CacheSizeCheck> { + if let Some(cdownload) = &self.current_download { + if cdownload.extractor_hash == next_video.extractor_hash { + // If the video is already being downloaded it will always fit. Otherwise the + // download would not have been started. + return Ok(CacheSizeCheck::Fits); + } + } + let cache_allocation = Self::get_current_cache_allocation(&app).await?; + let video_size = self.get_approx_video_size(&app, &next_video).await?; + + if video_size >= max_cache_size { + error!( + "The video '{}' ({}) exceeds the maximum cache size ({})! \ + Please set a bigger maximum (`--max-cache-size`) or skip it.", + next_video.title, + Bytes::new(video_size), + Bytes::new(max_cache_size) + ); + + return Ok(CacheSizeCheck::ExceedsMaxCacheSize); + } + + if cache_allocation + video_size >= max_cache_size { + if !self.printed_warning { + warn!( + "Can't download video: '{}' ({}) as it's too large for the cache ({} of {} allocated). \ + Waiting for cache size reduction..", + next_video.title, Bytes::new(video_size), Bytes::new(cache_allocation), Bytes::new(max_cache_size) + ); + self.printed_warning = true; + } + if let Some(cca) = self.cached_cache_allocation { + if cca != cache_allocation { + warn!( + "Current cache size has changed, it's now: '{}'", + Bytes::new(cache_allocation) + ); + self.cached_cache_allocation = Some(cache_allocation); + } + } else { + info!( + "Current cache size allocation: '{}'", + Bytes::new(cache_allocation) + ); + self.cached_cache_allocation = Some(cache_allocation); + } + + // Wait and hope, that a large video is deleted from the cache. + time::sleep(Duration::from_secs(10)).await; + Ok(CacheSizeCheck::TooLarge) + } else { + self.printed_warning = false; + Ok(CacheSizeCheck::Fits) } } @@ -72,18 +150,14 @@ impl Downloader { /// This will run, until the database doesn't contain any watchable videos pub async fn consume(&mut self, app: Arc<App>, max_cache_size: u64) -> Result<()> { while let Some(next_video) = get_next_uncached_video(&app).await? { - let cache_allocation = Self::get_current_cache_allocation(&app).await?; - let video_size = self.get_approx_video_size(&app, &next_video).await?; - if cache_allocation + video_size >= max_cache_size { - warn!( - "Can't download video: '{}' ({}) as it's too large for the cache ({} of {} allocated).", - next_video.title, Bytes::new(video_size), Bytes::new(cache_allocation), Bytes::new(max_cache_size) - ); - - // Wait and hope, that a large video is deleted from the cache. - time::sleep(Duration::from_secs(10)).await; - continue; - } + match self + .is_enough_cache_available(&app, max_cache_size, &next_video) + .await? + { + CacheSizeCheck::Fits => (), + CacheSizeCheck::TooLarge => continue, + CacheSizeCheck::ExceedsMaxCacheSize => bail!("Giving up."), + }; if let Some(_) = &self.current_download { let current_download = self.current_download.take().expect("Is Some"); |