diff --git a/src/lib.rs b/src/lib.rs index 44e6924..feeeb92 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,5 +11,5 @@ pub mod ytdlp; pub use backend::{AudioFormat, BackendConfig, DownloadBackend, DownloadResult, DownloadTarget, SearchResult}; pub use error::{DlError, DlResult}; -pub use queue::{DlStats, SyncStats, download_single, run_queue, sync_wanted_to_queue}; +pub use queue::{DlStats, ProgressFn, SyncStats, download_single, run_queue, run_queue_with_progress, sync_wanted_to_queue}; pub use ytdlp::{SearchSource, YtDlpBackend}; diff --git a/src/queue.rs b/src/queue.rs index 4ab7d20..82acadf 100644 --- a/src/queue.rs +++ b/src/queue.rs @@ -39,15 +39,39 @@ const RETRY_DELAYS: [Duration; 3] = [ Duration::from_secs(600), ]; +/// Progress callback: (current, total, message). +pub type ProgressFn = Box; + /// Process all pending items in the download queue. pub async fn run_queue( conn: &DatabaseConnection, backend: &impl DownloadBackend, config: &BackendConfig, dry_run: bool, +) -> DlResult { + run_queue_with_progress(conn, backend, config, dry_run, None).await +} + +/// Process all pending items in the download queue, with optional progress reporting. +pub async fn run_queue_with_progress( + conn: &DatabaseConnection, + backend: &impl DownloadBackend, + config: &BackendConfig, + dry_run: bool, + on_progress: Option, ) -> DlResult { let mut stats = DlStats::default(); + // Count total for progress reporting + let total = queries::downloads::list(conn, Some(DownloadStatus::Pending)) + .await + .map(|v| v.len() as u64) + .unwrap_or(0); + + if let Some(ref cb) = on_progress { + cb(0, total, "Starting downloads..."); + } + loop { let item = match queries::downloads::get_next_pending(conn).await? { Some(item) => item, @@ -56,6 +80,10 @@ pub async fn run_queue( stats.downloads_attempted += 1; + if let Some(ref cb) = on_progress { + cb(stats.downloads_attempted, total, &format!("Downloading: {}", item.query)); + } + tracing::info!( id = item.id, query = %item.query,