Previously only the main sidecar binary got chmod 755. Now all files in the extraction directory get execute permissions — covers ffmpeg, ffprobe, and any other bundled binaries. Applied in three places: - sidecar/mod.rs: after local extraction - commands/sidecar.rs: after download extraction - commands/media.rs: removed single-file fix (now handled globally) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
125 lines
3.9 KiB
Rust
125 lines
3.9 KiB
Rust
use std::path::PathBuf;
|
|
use std::process::Command;
|
|
|
|
#[cfg(target_os = "windows")]
|
|
use std::os::windows::process::CommandExt;
|
|
|
|
/// Extract audio from a video file to a WAV file using ffmpeg.
|
|
/// Returns the path to the extracted audio file.
|
|
#[tauri::command]
|
|
pub fn extract_audio(file_path: String, output_path: Option<String>) -> Result<String, String> {
|
|
let input = PathBuf::from(&file_path);
|
|
if !input.exists() {
|
|
return Err(format!("File not found: {}", file_path));
|
|
}
|
|
|
|
// Use provided output path, or fall back to a temp WAV file
|
|
let stem = input.file_stem().unwrap_or_default().to_string_lossy();
|
|
let output = match output_path {
|
|
Some(ref p) => PathBuf::from(p),
|
|
None => std::env::temp_dir().join(format!("{stem}_audio.wav")),
|
|
};
|
|
|
|
eprintln!(
|
|
"[media] Extracting audio: {} -> {}",
|
|
input.display(),
|
|
output.display()
|
|
);
|
|
|
|
// Find ffmpeg — check sidecar extract dir first, then system PATH
|
|
let ffmpeg = find_ffmpeg().ok_or("ffmpeg not found. Install ffmpeg or ensure it's in PATH.")?;
|
|
|
|
let mut cmd = Command::new(&ffmpeg);
|
|
cmd.args([
|
|
"-y", // Overwrite output
|
|
"-i",
|
|
&file_path,
|
|
"-vn", // No video
|
|
"-acodec",
|
|
"pcm_s16le", // WAV PCM 16-bit
|
|
"-ar",
|
|
"22050", // 22kHz mono for better playback quality
|
|
"-ac",
|
|
"1", // Mono
|
|
])
|
|
.arg(output.to_str().unwrap())
|
|
.stdout(std::process::Stdio::null())
|
|
.stderr(std::process::Stdio::piped());
|
|
|
|
// Hide the console window on Windows (CREATE_NO_WINDOW = 0x08000000)
|
|
#[cfg(target_os = "windows")]
|
|
cmd.creation_flags(0x08000000);
|
|
|
|
let status = cmd
|
|
.status()
|
|
.map_err(|e| format!("Failed to run ffmpeg: {e}"))?;
|
|
|
|
if !status.success() {
|
|
return Err(format!("ffmpeg exited with status {status}"));
|
|
}
|
|
|
|
if !output.exists() {
|
|
return Err("ffmpeg completed but output file not found".to_string());
|
|
}
|
|
|
|
eprintln!("[media] Audio extracted successfully");
|
|
Ok(output.to_string_lossy().to_string())
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn check_file_exists(path: String) -> bool {
|
|
std::path::Path::new(&path).exists()
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn copy_file(src: String, dst: String) -> Result<(), String> {
|
|
std::fs::copy(&src, &dst).map_err(|e| format!("Failed to copy file: {e}"))?;
|
|
Ok(())
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub fn create_dir(path: String) -> Result<(), String> {
|
|
std::fs::create_dir_all(&path).map_err(|e| format!("Failed to create directory: {e}"))?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Find ffmpeg binary — check sidecar directory first, then system PATH.
|
|
fn find_ffmpeg() -> Option<String> {
|
|
// Check sidecar extract dir (ffmpeg is bundled with the sidecar)
|
|
if let Some(data_dir) = crate::sidecar::DATA_DIR.get() {
|
|
// Read sidecar version to find the right directory
|
|
let version_file = data_dir.join("sidecar-version.txt");
|
|
if let Ok(version) = std::fs::read_to_string(&version_file) {
|
|
let version = version.trim();
|
|
let sidecar_dir = data_dir.join(format!("sidecar-{version}"));
|
|
let ffmpeg_name = if cfg!(target_os = "windows") {
|
|
"ffmpeg.exe"
|
|
} else {
|
|
"ffmpeg"
|
|
};
|
|
let ffmpeg_path = sidecar_dir.join(ffmpeg_name);
|
|
if ffmpeg_path.exists() {
|
|
return Some(ffmpeg_path.to_string_lossy().to_string());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fall back to system PATH
|
|
let ffmpeg_name = if cfg!(target_os = "windows") {
|
|
"ffmpeg.exe"
|
|
} else {
|
|
"ffmpeg"
|
|
};
|
|
if Command::new(ffmpeg_name)
|
|
.arg("-version")
|
|
.stdout(std::process::Stdio::null())
|
|
.stderr(std::process::Stdio::null())
|
|
.status()
|
|
.is_ok()
|
|
{
|
|
return Some(ffmpeg_name.to_string());
|
|
}
|
|
|
|
None
|
|
}
|