use crate::models::{CookieSource, VideoMetadata}; use crate::services::{download_manager, video_resolver}; use serde::Serialize; use std::io::{BufRead, BufReader}; use tauri::ipc::Channel; #[tauri::command] pub async fn resolve_url( url: String, cookie_source: CookieSource, ) -> Result { tokio::task::spawn_blocking(move || video_resolver::resolve(&url, &cookie_source)) .await .map_err(|e| format!("Task failed: {e}"))? } #[derive(Clone, Serialize)] #[serde(rename_all = "camelCase", tag = "event", content = "data")] pub enum DownloadEvent { Progress { percent: f64 }, FilePath { path: String }, Finished { success: bool, path: String }, Error { message: String }, } #[tauri::command] pub async fn start_download( url: String, cookie_source: CookieSource, on_event: Channel, ) -> Result<(), String> { tokio::task::spawn_blocking(move || { let temp_dir = std::env::temp_dir() .join("video-clipper") .to_string_lossy() .to_string(); std::fs::create_dir_all(&temp_dir) .map_err(|e| format!("Failed to create temp dir: {e}"))?; let (mut child, _template) = download_manager::start_download(&url, &cookie_source, &temp_dir)?; let Some(stderr) = child.stderr.take() else { let status = child .wait() .map_err(|e| format!("Download failed: {e}"))?; let _ = on_event.send(DownloadEvent::Finished { success: status.success(), path: String::new(), }); return Ok(()); }; let reader = BufReader::new(stderr); let mut last_file_path: Option = None; for line in reader.lines().map_while(Result::ok) { if let Some(pct) = download_manager::parse_progress_line(&line) { let _ = on_event.send(DownloadEvent::Progress { percent: pct }); } if line.contains("[download] Destination:") || line.contains("[Merger] Merging formats into") { if let Some(path) = line.split(": ").nth(1) { let trimmed = path.trim().trim_matches('"').to_string(); let _ = on_event.send(DownloadEvent::FilePath { path: trimmed.clone(), }); last_file_path = Some(trimmed); } } } let status = child .wait() .map_err(|e| format!("Download failed: {e}"))?; let path = last_file_path.unwrap_or_default(); let _ = on_event.send(DownloadEvent::Finished { success: status.success(), path, }); Ok(()) }) .await .map_err(|e| format!("Task failed: {e}"))? }