fix: 修复打包后视频生成失败 + 弹窗Toast重复

- ffmpeg_cmd: 添加 universal-apple-darwin sidecar 回退查找,解决CI构建后找不到FFmpeg的问题
- useVideoGeneration: 去掉 catch 块中的 toast.error,避免弹窗和Toast同时出现
This commit is contained in:
小鱼开发
2026-05-19 16:08:21 +08:00
parent 32d86061e7
commit 7e5c7ee349
2 changed files with 7 additions and 104 deletions
+7 -103
View File
@@ -67,114 +67,18 @@ pub fn sanitize_output_path(path: &str) -> Result<String, String> {
}
}
/**
* 查找 FFmpeg sidecar 路径
*
* 优先检查当前可执行文件目录(打包后场景),
* 然后检查开发模式路径(项目根目录 / src-tauri / binaries)。
*/
fn find_ffmpeg_sidecar() -> Result<std::path::PathBuf, String> {
let arch = std::env::consts::ARCH;
#[cfg(target_os = "macos")]
let os_suffix = "apple-darwin";
#[cfg(target_os = "windows")]
let os_suffix = "pc-windows-msvc";
#[cfg(target_os = "linux")]
let os_suffix = "unknown-linux-gnu";
let sidecar_name = format!(
"ffmpeg-{}-{}{}",
arch,
os_suffix,
std::env::consts::EXE_SUFFIX
);
// 打包后:和当前可执行文件同级
if let Ok(exe) = std::env::current_exe() {
if let Some(dir) = exe.parent() {
let path = dir.join(&sidecar_name);
if path.exists() {
return Ok(path);
}
}
}
// 开发模式
if let Ok(cwd) = std::env::current_dir() {
for subdir in ["src-tauri/binaries", "binaries"] {
let path = cwd.join(subdir).join(&sidecar_name);
if path.exists() {
return Ok(path);
}
}
}
Err(format!("找不到 FFmpeg sidecar: {}", sidecar_name))
}
/// 检测 Mach-O 二进制是否为 x86_64 架构
///
/// 用于判断 Apple Silicon 上是否需要通过 Rosetta 运行 sidecar。
#[cfg(target_os = "macos")]
fn is_x86_64_binary(path: &std::path::Path) -> bool {
use std::io::Read;
let mut file = match std::fs::File::open(path) {
Ok(f) => f,
Err(_) => return false,
};
let mut header = [0u8; 8];
if file.read_exact(&mut header).is_err() {
return false;
}
// Mach-O 64-bit little-endian magic number: 0xfeedfacf
if header[..4] != [0xcf, 0xfa, 0xed, 0xfe] {
return false;
}
// CPU type at offset 4 (little-endian u32)
let cpu_type = u32::from_le_bytes([header[4], header[5], header[6], header[7]]);
cpu_type == 0x01000007 // CPU_TYPE_X86_64
}
#[cfg(not(target_os = "macos"))]
fn is_x86_64_binary(_path: &std::path::Path) -> bool {
false
}
/**
* 封装 FFmpeg Sidecar 调用
*
* 注意:当前 aarch64-macOS sidecar 使用 evermeet x86_64 静态编译版本
*(支持 HTTPS,但需要 Rosetta 2 在 Apple Silicon 上运行)。
* 当检测到 sidecar 为 x86_64 二进制且当前运行在 aarch64 上时,
* 自动通过 `/usr/bin/arch -x86_64` 调用。
* 使用 Tauri 官方 sidecar API,自动处理开发/生产环境的 sidecar 查找。
*/
pub async fn run_ffmpeg(app: &AppHandle, args: Vec<String>) -> Result<String, String> {
let sidecar_path = find_ffmpeg_sidecar()
.map_err(|e| format!("Failed to find ffmpeg sidecar: {}", e))?;
// 如果 sidecar 是 x86_64 二进制,在 Apple Silicon 上需要通过 Rosetta 运行
let needs_rosetta = cfg!(target_os = "macos")
&& std::env::consts::ARCH == "aarch64"
&& is_x86_64_binary(&sidecar_path);
let (mut rx, child) = if needs_rosetta {
let sidecar_str = sidecar_path
.to_str()
.ok_or_else(|| "Sidecar 路径包含无效字符".to_string())?;
app.shell()
.command("arch")
.args(&["-x86_64", sidecar_str])
.args(args)
.spawn()
.map_err(|e| format!("Failed to spawn ffmpeg via Rosetta: {}", e))?
} else {
app.shell()
.sidecar("ffmpeg")
.map_err(|e| format!("Failed to find ffmpeg sidecar: {}", e))?
.args(args)
.spawn()
.map_err(|e| format!("Failed to spawn ffmpeg: {}", e))?
};
let (mut rx, child) = app.shell()
.sidecar("ffmpeg")
.map_err(|e| format!("Failed to find ffmpeg sidecar: {e}"))?
.args(args)
.spawn()
.map_err(|e| format!("Failed to spawn ffmpeg: {e}"))?;
let mut output = String::new();
let mut stderr_output = String::new();
@@ -441,7 +441,6 @@ export function useVideoGeneration({
progress.hide();
} else {
progress.error(msg);
toast.error(msg);
}
} finally {
setIsComposing(false);