From 7b84bc32df7bc00840b3edfd745a9c98e6f478fb Mon Sep 17 00:00:00 2001 From: Markury Date: Sat, 4 Oct 2025 20:58:34 -0400 Subject: [PATCH] fix(dl): add progress events for tracks from new downloader --- src-tauri/src/lib.rs | 40 +++++++++++++++++++++++++++ src/lib/services/deezer/downloader.ts | 29 +++++++++++++------ 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 8aefeee..a8a20be 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -56,10 +56,12 @@ async fn download_and_decrypt_track( track_id: String, output_path: String, is_encrypted: bool, + window: tauri::Window, ) -> Result<(), String> { use tokio::io::AsyncWriteExt; use tokio::fs::File; use deezer_crypto::StreamingDecryptor; + use tauri::Emitter; // Build HTTP client let client = reqwest::Client::builder() @@ -79,11 +81,16 @@ async fn download_and_decrypt_track( return Err(format!("HTTP error: {}", response.status())); } + let total_size = response.content_length().unwrap_or(0) as f64; + // Open output file let mut file = File::create(&output_path) .await .map_err(|e| format!("Failed to create output file: {}", e))?; + let mut downloaded_bytes = 0u64; + let mut last_reported_percentage = 0u8; + // Stream download with optional decryption if is_encrypted { let mut decryptor = StreamingDecryptor::new(&track_id); @@ -93,6 +100,7 @@ async fn download_and_decrypt_track( while let Some(chunk_result) = stream.next().await { let chunk = chunk_result.map_err(|e| format!("Download stream error: {}", e))?; + downloaded_bytes += chunk.len() as u64; // Decrypt chunk and write to file let decrypted = decryptor.process(&chunk); @@ -101,6 +109,21 @@ async fn download_and_decrypt_track( .await .map_err(|e| format!("Failed to write to file: {}", e))?; } + + // Emit progress every 5% + if total_size > 0.0 { + let percentage = ((downloaded_bytes as f64 / total_size) * 100.0) as u8; + let rounded_percentage = (percentage / 5) * 5; + + if rounded_percentage > last_reported_percentage || percentage == 100 { + last_reported_percentage = rounded_percentage; + let _ = window.emit("download-progress", serde_json::json!({ + "downloaded": downloaded_bytes, + "total": total_size as u64, + "percentage": percentage + })); + } + } } // Write any remaining buffered data @@ -118,9 +141,26 @@ async fn download_and_decrypt_track( while let Some(chunk_result) = stream.next().await { let chunk = chunk_result.map_err(|e| format!("Download stream error: {}", e))?; + downloaded_bytes += chunk.len() as u64; + file.write_all(&chunk) .await .map_err(|e| format!("Failed to write to file: {}", e))?; + + // Emit progress every 5% + if total_size > 0.0 { + let percentage = ((downloaded_bytes as f64 / total_size) * 100.0) as u8; + let rounded_percentage = (percentage / 5) * 5; + + if rounded_percentage > last_reported_percentage || percentage == 100 { + last_reported_percentage = rounded_percentage; + let _ = window.emit("download-progress", serde_json::json!({ + "downloaded": downloaded_bytes, + "total": total_size as u64, + "percentage": percentage + })); + } + } } } diff --git a/src/lib/services/deezer/downloader.ts b/src/lib/services/deezer/downloader.ts index 762bd5f..e9418fb 100644 --- a/src/lib/services/deezer/downloader.ts +++ b/src/lib/services/deezer/downloader.ts @@ -31,6 +31,7 @@ export async function downloadTrack( retryCount: number = 0, decryptionTrackId?: string ): Promise { + const { listen } = await import('@tauri-apps/api/event'); // Generate paths const paths = generateTrackPath(track, musicFolder, format, false); @@ -60,16 +61,28 @@ export async function downloadTrack( // Use the provided decryption track ID (for fallback tracks) or the original track ID const trackIdForDecryption = decryptionTrackId ? decryptionTrackId.toString() : track.id.toString(); - // Download and decrypt in Rust backend (streaming, no memory accumulation) - console.log('Downloading and decrypting track in Rust backend...'); - await invoke('download_and_decrypt_track', { - url: downloadURL, - trackId: trackIdForDecryption, - outputPath: paths.tempPath, - isEncrypted: isCrypted + // Set up progress listener + const unlisten = await listen('download-progress', (event) => { + if (onProgress) { + onProgress(event.payload); + } }); - console.log('Download and decryption complete!'); + try { + // Download and decrypt in Rust backend (streaming, no memory accumulation) + console.log('Downloading and decrypting track in Rust backend...'); + await invoke('download_and_decrypt_track', { + url: downloadURL, + trackId: trackIdForDecryption, + outputPath: paths.tempPath, + isEncrypted: isCrypted + }); + + console.log('Download and decryption complete!'); + } finally { + // Clean up event listener + unlisten(); + } // Get user settings const appSettings = get(settings);