Initial clean project import

This commit is contained in:
cat-shark
2026-06-19 18:41:41 +08:00
commit a13b804c7a
1306 changed files with 220568 additions and 0 deletions
@@ -0,0 +1,198 @@
import { exec, spawn, type ChildProcessWithoutNullStreams } from "child_process";
import path from "path";
import fs from "fs";
import { promisify } from "util";
import { VideoSubtitleCoverGeneratorModelConfig } from "../../src/types/VideoSubtitleCoverGenerator";
import { getPythonPath } from "../lib/python-util";
import { getPythonScriptPath, getFFmpegExecutablePath, getRuntimeBundleRoot, resourceExists } from "../lib/resource-path";
import { Log } from "../mapi/log/main";
import { buildRuntimeProcessEnv } from "../mapi/shell";
const execAsync = promisify(exec);
export class VideoSubtitleCoverGenerator {
type = "buildIn";
ServerApi: any;
ServerInfo: any;
private currentProcess: ChildProcessWithoutNullStreams | null = null;
private async stopCurrentProcess() {
if (!this.currentProcess?.pid) {
this.currentProcess = null;
return;
}
const currentPid = this.currentProcess.pid;
const processToStop = this.currentProcess;
this.currentProcess = null;
try {
if (process.platform === "win32") {
await execAsync(`taskkill /F /PID ${currentPid} /T`);
} else {
processToStop.kill("SIGKILL");
}
} catch (error: any) {
Log.warn("VideoSubtitleCoverGenerator", `Failed to stop python process ${currentPid}: ${error.message}`);
}
}
async init() {
// 初始化
}
async start() {
// 启动服务
return { code: 0, msg: "VideoSubtitleCoverGenerator服务启动成功" };
}
async ping() {
// 检查服务状态
return { code: 0, msg: "pong" };
}
async stop() {
await this.stopCurrentProcess();
return { code: 0, msg: "服务已停止" };
}
async cancel() {
await this.stopCurrentProcess();
return { code: 0, msg: "任务已取消" };
}
async config() {
// 返回配置信息
return {
code: 0,
config: {
name: "VideoSubtitleCoverGenerator",
displayName: "字幕封面生成器",
description: "一键生成带字幕的视频和封面,支持多种样式模板",
version: "1.0.0",
functions: ["VideoSubtitleCoverGenerator"],
models: []
}
};
}
async VideoSubtitleCoverGenerator(data: VideoSubtitleCoverGeneratorModelConfig, option: any = {}) {
try {
// 创建临时配置文件
const configPath = path.join(process.cwd(), "temp_config.json");
const config = {
modelConfig: data,
...option
};
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
// 调用Python脚本
// ⚠️ 只使用程序自带的 Python,不依赖系统环境
const pythonScript = getPythonScriptPath('video_subtitle_cover_generator.py');
const pythonPath = getPythonPath();
return new Promise((resolve, reject) => {
// 🔧 修复:传递APP_ROOT环境变量给Python进程,使其能正确识别打包环境
const env = buildRuntimeProcessEnv({
APP_ROOT: process.env.APP_ROOT || process.cwd(),
RESOURCE_BUNDLE_ROOT: getRuntimeBundleRoot()
});
// 🔧 修复:添加 FFmpeg 目录到 PATH,让 Python 脚本能找到 ffmpeg
const ffmpegPath = getFFmpegExecutablePath();
if (resourceExists(ffmpegPath)) {
const ffmpegDir = path.dirname(ffmpegPath);
const pathSep = process.platform === 'win32' ? ';' : ':';
env['PATH'] = ffmpegDir + pathSep + (env['PATH'] || process.env.PATH || '');
Log.info('VideoSubtitleCoverGenerator', `Added FFmpeg to PATH: ${ffmpegDir}`);
}
const pythonProcess = spawn(pythonPath, [pythonScript, configPath], {
cwd: process.env.APP_ROOT || process.cwd(),
env: env,
stdio: ["pipe", "pipe", "pipe"]
});
this.currentProcess = pythonProcess;
let stdout = "";
let stderr = "";
pythonProcess.stdout.on("data", (data) => {
stdout += data.toString();
console.log("Python stdout:", data.toString());
});
pythonProcess.stderr.on("data", (data) => {
stderr += data.toString();
console.error("Python stderr:", data.toString());
});
pythonProcess.on("close", (code) => {
if (this.currentProcess?.pid === pythonProcess.pid) {
this.currentProcess = null;
}
// 清理临时文件
try {
fs.unlinkSync(configPath);
} catch (e) {
console.warn("清理临时文件失败:", e);
}
if (code === 0) {
try {
const result = JSON.parse(stdout);
resolve(result);
} catch (e) {
resolve({
code: -1,
msg: `解析Python输出失败: ${e}`
});
}
} else {
resolve({
code: -1,
msg: `Python脚本执行失败 (退出码: ${code}): ${stderr}`
});
}
});
pythonProcess.on("error", (error) => {
if (this.currentProcess?.pid === pythonProcess.pid) {
this.currentProcess = null;
}
// 清理临时文件
try {
fs.unlinkSync(configPath);
} catch (e) {
console.warn("清理临时文件失败:", e);
}
resolve({
code: -1,
msg: `启动Python进程失败: ${error.message}`
});
});
// 设置超时
setTimeout(() => {
this.stopCurrentProcess().catch((error) => {
Log.warn("VideoSubtitleCoverGenerator", `Timeout stop failed: ${error}`);
});
resolve({
code: -1,
msg: "处理超时"
});
}, 300000); // 5分钟超时
});
} catch (error: any) {
return {
code: -1,
msg: `处理失败: ${error.message}`
};
}
}
}