2026-09-21 10:52:30 -04:00
|
|
|
use crate::models::{CookieSource, DependencyStatus};
|
2026-09-21 10:50:24 -04:00
|
|
|
use std::process::Command;
|
|
|
|
|
|
|
|
|
|
pub fn check_tool_exists(name: &str) -> Option<String> {
|
|
|
|
|
let output = Command::new("which").arg(name).output().ok()?;
|
|
|
|
|
|
|
|
|
|
if output.status.success() {
|
|
|
|
|
let version_output = Command::new(name).arg("--version").output().ok()?;
|
|
|
|
|
let version = String::from_utf8_lossy(&version_output.stdout)
|
|
|
|
|
.lines()
|
|
|
|
|
.next()
|
|
|
|
|
.unwrap_or("")
|
|
|
|
|
.trim()
|
|
|
|
|
.to_string();
|
|
|
|
|
Some(version)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn check_js_runtime() -> Option<String> {
|
|
|
|
|
check_tool_exists("deno").or_else(|| check_tool_exists("node"))
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-21 10:52:30 -04:00
|
|
|
pub fn check_pot_plugin(cookie_source: &CookieSource) -> bool {
|
|
|
|
|
let mut command = Command::new("yt-dlp");
|
|
|
|
|
command
|
|
|
|
|
.arg("-v")
|
|
|
|
|
.arg("--simulate")
|
2026-09-21 12:03:26 -04:00
|
|
|
.arg("--remote-components")
|
|
|
|
|
.arg("ejs:github")
|
2026-09-21 10:52:30 -04:00
|
|
|
.args(cookie_source.to_ytdlp_args())
|
|
|
|
|
.arg("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
|
|
|
|
|
let output = command.output();
|
2026-09-21 10:50:24 -04:00
|
|
|
|
|
|
|
|
match output {
|
|
|
|
|
Ok(out) => {
|
|
|
|
|
let stderr = String::from_utf8_lossy(&out.stderr);
|
|
|
|
|
stderr.contains("GetPOT")
|
|
|
|
|
}
|
|
|
|
|
Err(_) => false,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-21 10:52:30 -04:00
|
|
|
pub fn get_all_dependency_statuses(cookie_source: &CookieSource) -> Vec<DependencyStatus> {
|
2026-09-21 10:50:24 -04:00
|
|
|
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() {
|
2026-09-21 10:52:30 -04:00
|
|
|
check_pot_plugin(cookie_source)
|
2026-09-21 10:50:24 -04:00
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
vec![
|
|
|
|
|
DependencyStatus {
|
|
|
|
|
name: "ffmpeg".to_string(),
|
|
|
|
|
installed: ffmpeg.is_some(),
|
|
|
|
|
version: ffmpeg,
|
|
|
|
|
install_command: "brew install ffmpeg".to_string(),
|
|
|
|
|
},
|
|
|
|
|
DependencyStatus {
|
|
|
|
|
name: "yt-dlp".to_string(),
|
|
|
|
|
installed: ytdlp.is_some(),
|
|
|
|
|
version: ytdlp,
|
|
|
|
|
install_command: "brew install yt-dlp".to_string(),
|
|
|
|
|
},
|
|
|
|
|
DependencyStatus {
|
|
|
|
|
name: "JavaScript runtime (deno/node)".to_string(),
|
|
|
|
|
installed: js_runtime.is_some(),
|
|
|
|
|
version: js_runtime,
|
|
|
|
|
install_command: "brew install deno".to_string(),
|
|
|
|
|
},
|
|
|
|
|
DependencyStatus {
|
|
|
|
|
name: "bgutil-ytdlp-pot-provider".to_string(),
|
|
|
|
|
installed: pot_plugin,
|
|
|
|
|
version: None,
|
|
|
|
|
install_command: "python3 -m pip install -U bgutil-ytdlp-pot-provider".to_string(),
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_install_args(dep_name: &str) -> Result<Vec<String>, String> {
|
|
|
|
|
match dep_name {
|
|
|
|
|
"ffmpeg" => Ok(vec![
|
|
|
|
|
"brew".into(), "install".into(), "ffmpeg".into(),
|
|
|
|
|
]),
|
|
|
|
|
"yt-dlp" => Ok(vec![
|
|
|
|
|
"brew".into(), "install".into(), "yt-dlp".into(),
|
|
|
|
|
]),
|
|
|
|
|
"JavaScript runtime (deno/node)" => Ok(vec![
|
|
|
|
|
"brew".into(), "install".into(), "deno".into(),
|
|
|
|
|
]),
|
|
|
|
|
"bgutil-ytdlp-pot-provider" => Ok(vec![
|
|
|
|
|
"python3".into(), "-m".into(), "pip".into(), "install".into(), "-U".into(), "bgutil-ytdlp-pot-provider".into(),
|
|
|
|
|
]),
|
|
|
|
|
_ => Err(format!("Unknown dependency: {dep_name}")),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
2026-09-21 10:52:30 -04:00
|
|
|
use crate::models::CookieSource;
|
2026-09-21 10:50:24 -04:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_get_install_args_ffmpeg() {
|
|
|
|
|
let args = get_install_args("ffmpeg").unwrap();
|
|
|
|
|
assert_eq!(args, vec!["brew", "install", "ffmpeg"]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_get_install_args_ytdlp() {
|
|
|
|
|
let args = get_install_args("yt-dlp").unwrap();
|
|
|
|
|
assert_eq!(args, vec!["brew", "install", "yt-dlp"]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_get_install_args_pot_provider() {
|
|
|
|
|
let args = get_install_args("bgutil-ytdlp-pot-provider").unwrap();
|
|
|
|
|
assert_eq!(args, vec!["python3", "-m", "pip", "install", "-U", "bgutil-ytdlp-pot-provider"]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_get_install_args_unknown() {
|
|
|
|
|
assert!(get_install_args("unknown-tool").is_err());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_dependency_statuses_has_four_entries() {
|
2026-09-21 10:52:30 -04:00
|
|
|
let statuses = get_all_dependency_statuses(&CookieSource::default());
|
2026-09-21 10:50:24 -04:00
|
|
|
assert_eq!(statuses.len(), 4);
|
|
|
|
|
assert_eq!(statuses[0].name, "ffmpeg");
|
|
|
|
|
assert_eq!(statuses[1].name, "yt-dlp");
|
|
|
|
|
assert_eq!(statuses[2].name, "JavaScript runtime (deno/node)");
|
|
|
|
|
assert_eq!(statuses[3].name, "bgutil-ytdlp-pot-provider");
|
|
|
|
|
}
|
|
|
|
|
}
|