From 3d656c2d8e7b35e9e37e2dfa2ae9d6b7abe2728c Mon Sep 17 00:00:00 2001 From: thzxx Date: Thu, 18 Jun 2026 11:08:59 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=89=93=E5=8C=85=20ffmpeg-static=20?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=20Windows=20=E6=97=A0=20ffmpeg=20=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 ffmpeg-static 依赖,自动解析 ffmpeg/ffprobe 路径 - 优先使用内置二进制,回退系统 PATH - ASAR 解包配置确保二进制可执行 --- package.json | 7 ++++++- src/main/ipc.ts | 20 ++++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 0820349..c0f5c5d 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,12 @@ "dist/**/*", "assets/**/*", "!node_modules/**/*", - "node_modules/sql.js/**/*" + "node_modules/sql.js/**/*", + "node_modules/ffmpeg-static/**/*" ], + "asar": { + "unpack": ["node_modules/ffmpeg-static/**"] + }, "extraResources": [ { "from": "node_modules/sql.js/dist/sql-wasm.wasm", @@ -67,6 +71,7 @@ "vite": "^5.4.0" }, "dependencies": { + "ffmpeg-static": "^5.2.0", "sql.js": "^1.11.0" } } diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 2bc8c90..828a40b 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -61,6 +61,22 @@ import { startProcess, killProcess, getWorkspaceDir, setWorkspaceDir, listWorksp import { setHTTPTimeout } from './tool-handlers-system.js'; import { execFile } from 'child_process'; import * as crypto from 'crypto'; +import ffmpegStatic from 'ffmpeg-static'; + +/** 获取 ffmpeg 可执行文件路径(优先打包内置,回退系统PATH) */ +function getFFmpegPath(): string { + if (ffmpegStatic) return ffmpegStatic; + return 'ffmpeg'; +} + +function getFFprobePath(): string { + const fmpeg = getFFmpegPath(); + if (fmpeg !== 'ffmpeg') { + const ext = process.platform === 'win32' ? '.exe' : ''; + return path.join(path.dirname(fmpeg), 'ffprobe' + ext); + } + return 'ffprobe'; +} /** 工具结果摘要(用于日志面板) */ function summarizeResult(toolName: string, result: Record): string { @@ -519,7 +535,7 @@ interface VideoInfo { function ffprobeVideo(filePath: string): Promise { return new Promise((resolve, reject) => { - execFile('ffprobe', [ + execFile(getFFprobePath(), [ '-v', 'quiet', '-print_format', 'json', '-show_format', '-show_streams', '-select_streams', 'v:0', filePath ], { timeout: 15_000 }, (err, stdout) => { @@ -561,7 +577,7 @@ function extractVideoFrames(filePath: string, maxFrames: number, maxWidth: numbe // 3. ffmpeg 提取帧:固定 1fps const outPattern = path.join(tmpDir, 'frame_%04d.jpg'); await new Promise((ffResolve, ffReject) => { - execFile('ffmpeg', [ + execFile(getFFmpegPath(), [ '-y', '-i', filePath, '-vf', `${scaleFilter},fps=1`,