diff --git a/src-tauri/src/commands/dependencies.rs b/src-tauri/src/commands/dependencies.rs index 0d7a629..7dfbad9 100644 --- a/src-tauri/src/commands/dependencies.rs +++ b/src-tauri/src/commands/dependencies.rs @@ -1,14 +1,15 @@ use serde::Serialize; use std::io::{BufRead, BufReader}; use std::process::{Command, Stdio}; +use std::thread; use tauri::ipc::Channel; -use crate::models::DependencyStatus; +use crate::models::{CookieSource, DependencyStatus}; use crate::services::dependency_manager; #[tauri::command] -pub fn check_dependencies() -> Vec { - dependency_manager::get_all_dependency_statuses() +pub fn check_dependencies(cookie_source: CookieSource) -> Vec { + dependency_manager::get_all_dependency_statuses(&cookie_source) } #[derive(Clone, Serialize)] @@ -33,11 +34,31 @@ pub async fn install_dependency( .spawn() .map_err(|e| format!("Failed to start install: {e}"))?; - if let Some(stdout) = child.stdout.take() { - let reader = BufReader::new(stdout); - for line in reader.lines().map_while(Result::ok) { - let _ = on_event.send(InstallEvent::Output { line }); - } + let stdout_handle = child.stdout.take().map(|stdout| { + let on_event_stdout = on_event.clone(); + thread::spawn(move || { + let reader = BufReader::new(stdout); + for line in reader.lines().map_while(Result::ok) { + let _ = on_event_stdout.send(InstallEvent::Output { line }); + } + }) + }); + + let stderr_handle = child.stderr.take().map(|stderr| { + let on_event_stderr = on_event.clone(); + thread::spawn(move || { + let reader = BufReader::new(stderr); + for line in reader.lines().map_while(Result::ok) { + let _ = on_event_stderr.send(InstallEvent::Output { line }); + } + }) + }); + + if let Some(handle) = stdout_handle { + let _ = handle.join(); + } + if let Some(handle) = stderr_handle { + let _ = handle.join(); } let status = child.wait().map_err(|e| format!("Install failed: {e}"))?; diff --git a/src-tauri/src/services/dependency_manager.rs b/src-tauri/src/services/dependency_manager.rs index 2d533a9..f8a494a 100644 --- a/src-tauri/src/services/dependency_manager.rs +++ b/src-tauri/src/services/dependency_manager.rs @@ -1,4 +1,4 @@ -use crate::models::DependencyStatus; +use crate::models::{CookieSource, DependencyStatus}; use std::process::Command; pub fn check_tool_exists(name: &str) -> Option { @@ -22,10 +22,14 @@ pub fn check_js_runtime() -> Option { check_tool_exists("deno").or_else(|| check_tool_exists("node")) } -pub fn check_pot_plugin() -> bool { - let output = Command::new("yt-dlp") - .args(["-v", "--simulate", "https://www.youtube.com/watch?v=dQw4w9WgXcQ"]) - .output(); +pub fn check_pot_plugin(cookie_source: &CookieSource) -> bool { + let mut command = Command::new("yt-dlp"); + command + .arg("-v") + .arg("--simulate") + .args(cookie_source.to_ytdlp_args()) + .arg("https://www.youtube.com/watch?v=dQw4w9WgXcQ"); + let output = command.output(); match output { Ok(out) => { @@ -36,12 +40,12 @@ pub fn check_pot_plugin() -> bool { } } -pub fn get_all_dependency_statuses() -> Vec { +pub fn get_all_dependency_statuses(cookie_source: &CookieSource) -> Vec { let ffmpeg = check_tool_exists("ffmpeg"); let ytdlp = check_tool_exists("yt-dlp"); let js_runtime = check_js_runtime(); let pot_plugin = if ytdlp.is_some() { - check_pot_plugin() + check_pot_plugin(cookie_source) } else { false }; @@ -95,6 +99,7 @@ pub fn get_install_args(dep_name: &str) -> Result, String> { #[cfg(test)] mod tests { use super::*; + use crate::models::CookieSource; #[test] fn test_get_install_args_ffmpeg() { @@ -121,7 +126,7 @@ mod tests { #[test] fn test_dependency_statuses_has_four_entries() { - let statuses = get_all_dependency_statuses(); + let statuses = get_all_dependency_statuses(&CookieSource::default()); assert_eq!(statuses.len(), 4); assert_eq!(statuses[0].name, "ffmpeg"); assert_eq!(statuses[1].name, "yt-dlp"); diff --git a/src/lib/bindings/dependencies.ts b/src/lib/bindings/dependencies.ts index 8bddc17..6edb02a 100644 --- a/src/lib/bindings/dependencies.ts +++ b/src/lib/bindings/dependencies.ts @@ -7,12 +7,24 @@ export interface DependencyStatus { installCommand: string; } +export type CookieSource = + | { type: 'browser'; browser: string } + | { type: 'file'; path: string } + | { type: 'none' }; + +const DEFAULT_COOKIE_SOURCE: CookieSource = { + type: 'browser', + browser: 'firefox', +}; + type InstallEvent = | { event: 'output'; data: { line: string } } | { event: 'finished'; data: { success: boolean } }; -export async function checkDependencies(): Promise { - return invoke('check_dependencies'); +export async function checkDependencies( + cookieSource: CookieSource = DEFAULT_COOKIE_SOURCE +): Promise { + return invoke('check_dependencies', { cookieSource }); } export async function installDependency(