diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index f4882f7..7c1e34c 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -12,13 +12,22 @@ fn greet(name: &str) -> String { /// Tag an audio file with metadata, cover art, and lyrics #[tauri::command] -fn tag_audio_file( +async fn tag_audio_file( path: String, metadata: tagger::TaggingMetadata, cover_data: Option>, embed_lyrics: bool, ) -> Result<(), String> { - tagger::tag_audio_file(&path, &metadata, cover_data.as_deref(), embed_lyrics) + // Run tagging on a background thread to avoid blocking the UI + tauri::async_runtime::spawn_blocking(move || { + tagger::tag_audio_file(&path, &metadata, cover_data.as_deref(), embed_lyrics) + }) + .await + .map_err(|e| format!("Tagging task failed: {}", e))? + // Flatten the inner Result + ?; + + Ok(()) } /// Read metadata from an audio file (MP3 or FLAC) @@ -29,8 +38,15 @@ fn read_audio_metadata(path: String) -> Result /// Decrypt Deezer track data #[tauri::command] -fn decrypt_deezer_track(data: Vec, track_id: String) -> Result, String> { - Ok(deezer_crypto::decrypt_track(&data, &track_id)) +async fn decrypt_deezer_track(data: Vec, track_id: String) -> Result, String> { + // Run decryption on a background thread to avoid blocking the UI + let result = tauri::async_runtime::spawn_blocking(move || { + deezer_crypto::decrypt_track(&data, &track_id) + }) + .await + .map_err(|e| format!("Decryption task failed: {}", e))?; + + Ok(result) } #[cfg_attr(mobile, tauri::mobile_entry_point)] diff --git a/src/lib/library/playlist.ts b/src/lib/library/playlist.ts index 6ea593d..59245f9 100644 --- a/src/lib/library/playlist.ts +++ b/src/lib/library/playlist.ts @@ -142,7 +142,7 @@ async function findActualFilePath(basePath: string): Promise { } /** - * Read metadata from audio file using Rust backend + * Read metadata from audio file on backend */ async function readAudioMetadata(filePath: string, format: AudioFormat): Promise { try { diff --git a/src/lib/services/deezer/downloader.ts b/src/lib/services/deezer/downloader.ts index 37180a6..ee46fd4 100644 --- a/src/lib/services/deezer/downloader.ts +++ b/src/lib/services/deezer/downloader.ts @@ -81,6 +81,7 @@ export async function downloadTrack( const reader = response.body!.getReader(); const chunks: Uint8Array[] = []; let downloadedBytes = 0; + let lastReportedPercentage = 0; while (true) { const { done, value } = await reader.read(); @@ -89,15 +90,19 @@ export async function downloadTrack( chunks.push(value); downloadedBytes += value.length; - // Call progress callback + // Call progress callback every 5% if (onProgress && totalSize > 0) { const percentage = (downloadedBytes / totalSize) * 100; - console.log(`[Download Progress] ${downloadedBytes}/${totalSize} bytes (${percentage.toFixed(1)}%)`); - onProgress({ - downloaded: downloadedBytes, - total: totalSize, - percentage - }); + const roundedPercentage = Math.floor(percentage / 5) * 5; + + if (roundedPercentage > lastReportedPercentage || percentage === 100) { + lastReportedPercentage = roundedPercentage; + onProgress({ + downloaded: downloadedBytes, + total: totalSize, + percentage + }); + } } } @@ -111,20 +116,23 @@ export async function downloadTrack( console.log(`Downloaded ${encryptedData.length} bytes, encrypted: ${isCrypted}`); + // Yield to the browser to keep UI responsive + await new Promise(resolve => setTimeout(resolve, 0)); + // Decrypt if needed let decryptedData: Uint8Array; if (isCrypted) { - console.log('Decrypting track using Rust...'); + console.log('Decrypting track...'); // Use the provided decryption track ID (for fallback tracks) or the original track ID - const trackIdForDecryption = decryptionTrackId || track.id.toString(); + const trackIdForDecryption = decryptionTrackId ? decryptionTrackId.toString() : track.id.toString(); console.log(`Decrypting with track ID: ${trackIdForDecryption}`); - // Call Rust decryption function - const decrypted = await invoke('decrypt_deezer_track', { - data: Array.from(encryptedData), + // Call Rust decryption function - Tauri returns Vec as number[] + const decryptedArray = await invoke('decrypt_deezer_track', { + data: encryptedData, trackId: trackIdForDecryption }); - decryptedData = new Uint8Array(decrypted); + decryptedData = new Uint8Array(decryptedArray); } else { decryptedData = encryptedData; } diff --git a/src/lib/services/deezer/tagger.ts b/src/lib/services/deezer/tagger.ts index aec86a8..fd25338 100644 --- a/src/lib/services/deezer/tagger.ts +++ b/src/lib/services/deezer/tagger.ts @@ -90,14 +90,12 @@ export async function tagAudioFile( ): Promise { const metadata = convertToTaggingMetadata(track); - // Convert Uint8Array to regular array for JSON serialization - const coverArray = coverData ? Array.from(coverData) : undefined; - + // Tauri handles Uint8Array -> Vec conversion automatically try { await invoke('tag_audio_file', { path: filePath, metadata, - coverData: coverArray, + coverData, embedLyrics, }); } catch (error) {