fix: 打包 ffmpeg-static 解决 Windows 无 ffmpeg 问题
- 新增 ffmpeg-static 依赖,自动解析 ffmpeg/ffprobe 路径 - 优先使用内置二进制,回退系统 PATH - ASAR 解包配置确保二进制可执行
This commit is contained in:
+6
-1
@@ -27,8 +27,12 @@
|
|||||||
"dist/**/*",
|
"dist/**/*",
|
||||||
"assets/**/*",
|
"assets/**/*",
|
||||||
"!node_modules/**/*",
|
"!node_modules/**/*",
|
||||||
"node_modules/sql.js/**/*"
|
"node_modules/sql.js/**/*",
|
||||||
|
"node_modules/ffmpeg-static/**/*"
|
||||||
],
|
],
|
||||||
|
"asar": {
|
||||||
|
"unpack": ["node_modules/ffmpeg-static/**"]
|
||||||
|
},
|
||||||
"extraResources": [
|
"extraResources": [
|
||||||
{
|
{
|
||||||
"from": "node_modules/sql.js/dist/sql-wasm.wasm",
|
"from": "node_modules/sql.js/dist/sql-wasm.wasm",
|
||||||
@@ -67,6 +71,7 @@
|
|||||||
"vite": "^5.4.0"
|
"vite": "^5.4.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"ffmpeg-static": "^5.2.0",
|
||||||
"sql.js": "^1.11.0"
|
"sql.js": "^1.11.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-2
@@ -61,6 +61,22 @@ import { startProcess, killProcess, getWorkspaceDir, setWorkspaceDir, listWorksp
|
|||||||
import { setHTTPTimeout } from './tool-handlers-system.js';
|
import { setHTTPTimeout } from './tool-handlers-system.js';
|
||||||
import { execFile } from 'child_process';
|
import { execFile } from 'child_process';
|
||||||
import * as crypto from 'crypto';
|
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, unknown>): string {
|
function summarizeResult(toolName: string, result: Record<string, unknown>): string {
|
||||||
@@ -519,7 +535,7 @@ interface VideoInfo {
|
|||||||
|
|
||||||
function ffprobeVideo(filePath: string): Promise<VideoInfo> {
|
function ffprobeVideo(filePath: string): Promise<VideoInfo> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
execFile('ffprobe', [
|
execFile(getFFprobePath(), [
|
||||||
'-v', 'quiet', '-print_format', 'json', '-show_format', '-show_streams',
|
'-v', 'quiet', '-print_format', 'json', '-show_format', '-show_streams',
|
||||||
'-select_streams', 'v:0', filePath
|
'-select_streams', 'v:0', filePath
|
||||||
], { timeout: 15_000 }, (err, stdout) => {
|
], { timeout: 15_000 }, (err, stdout) => {
|
||||||
@@ -561,7 +577,7 @@ function extractVideoFrames(filePath: string, maxFrames: number, maxWidth: numbe
|
|||||||
// 3. ffmpeg 提取帧:固定 1fps
|
// 3. ffmpeg 提取帧:固定 1fps
|
||||||
const outPattern = path.join(tmpDir, 'frame_%04d.jpg');
|
const outPattern = path.join(tmpDir, 'frame_%04d.jpg');
|
||||||
await new Promise<void>((ffResolve, ffReject) => {
|
await new Promise<void>((ffResolve, ffReject) => {
|
||||||
execFile('ffmpeg', [
|
execFile(getFFmpegPath(), [
|
||||||
'-y',
|
'-y',
|
||||||
'-i', filePath,
|
'-i', filePath,
|
||||||
'-vf', `${scaleFilter},fps=1`,
|
'-vf', `${scaleFilter},fps=1`,
|
||||||
|
|||||||
Reference in New Issue
Block a user