mirror of
https://github.com/HiMeditator/auto-caption.git
synced 2026-02-14 20:02:03 +08:00
feat(main): 实现字幕引擎控制功能
- 新增字幕引擎启动和停止功能 - 实现控制窗口的字幕引擎状态显示 - 优化字幕日志的发送逻辑 - 重构子进程相关代码
This commit is contained in:
@@ -30,7 +30,7 @@ class CaptionWindow {
|
||||
setTimeout(() => {
|
||||
if (this.window) {
|
||||
sendStyles(this.window);
|
||||
sendCaptionLog(this.window);
|
||||
sendCaptionLog(this.window, 'set');
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
|
||||
@@ -4,15 +4,18 @@ import { is } from '@electron-toolkit/utils'
|
||||
import icon from '../../resources/icon.png?asset'
|
||||
import { captionWindow } from './caption'
|
||||
import {
|
||||
captionEngine,
|
||||
controls,
|
||||
setStyles,
|
||||
sendStyles,
|
||||
sendCaptionLog,
|
||||
setControls
|
||||
setControls,
|
||||
sendControls
|
||||
} from './utils/config'
|
||||
|
||||
class ControlWindow {
|
||||
window: BrowserWindow | undefined;
|
||||
|
||||
|
||||
public createWindow(): void {
|
||||
this.window = new BrowserWindow({
|
||||
icon: icon,
|
||||
@@ -32,8 +35,9 @@ class ControlWindow {
|
||||
|
||||
setTimeout(() => {
|
||||
if (this.window) {
|
||||
sendStyles(this.window);
|
||||
sendCaptionLog(this.window);
|
||||
sendStyles(this.window) // 配置初始样式
|
||||
sendCaptionLog(this.window, 'set') // 配置当前字幕记录
|
||||
sendControls(this.window) // 配置字幕引擎配置
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
@@ -75,10 +79,25 @@ class ControlWindow {
|
||||
captionWindow.window.show()
|
||||
}
|
||||
})
|
||||
// 字幕引擎控制配置更新
|
||||
// 字幕引擎控制配置更新并启动引擎
|
||||
ipcMain.on('control.control.change', (_, args) => {
|
||||
setControls(args)
|
||||
})
|
||||
// 启动字幕引擎
|
||||
ipcMain.on('control.engine.start', () => {
|
||||
if(controls.engineEnabled){
|
||||
this.window?.webContents.send('control.engine.already')
|
||||
}
|
||||
else {
|
||||
captionEngine.start()
|
||||
this.window?.webContents.send('control.engine.started')
|
||||
}
|
||||
})
|
||||
// 停止字幕引擎
|
||||
ipcMain.on('control.engine.stop', () => {
|
||||
captionEngine.stop()
|
||||
this.window?.webContents.send('control.engine.stopped')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,6 @@ import { electronApp, optimizer } from '@electron-toolkit/utils'
|
||||
import { controlWindow } from './control'
|
||||
import { captionWindow } from './caption'
|
||||
|
||||
import { PythonProcess } from './utils/pythonProcess'
|
||||
const pySubProcess = new PythonProcess()
|
||||
|
||||
app.whenReady().then(() => {
|
||||
electronApp.setAppUserModelId('com.himeditator.autocaption')
|
||||
|
||||
@@ -18,8 +15,6 @@ app.whenReady().then(() => {
|
||||
|
||||
controlWindow.createWindow()
|
||||
|
||||
// pySubProcess.start()
|
||||
|
||||
app.on('activate', function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0){
|
||||
controlWindow.createWindow()
|
||||
|
||||
@@ -19,6 +19,7 @@ export interface CaptionItem {
|
||||
}
|
||||
|
||||
export interface Controls {
|
||||
engineEnabled: boolean,
|
||||
sourceLang: string,
|
||||
targetLang: string,
|
||||
engine: string,
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { Styles, CaptionItem, Controls } from '../types'
|
||||
import { BrowserWindow } from 'electron'
|
||||
import { CaptionEngine } from './engine'
|
||||
|
||||
export const captionEngine = new CaptionEngine()
|
||||
|
||||
export const styles: Styles = {
|
||||
fontFamily: 'sans-serif',
|
||||
@@ -19,12 +22,15 @@ export const controls: Controls = {
|
||||
sourceLang: 'en',
|
||||
targetLang: 'zh',
|
||||
engine: 'gummy',
|
||||
engineEnabled: false,
|
||||
translation: true,
|
||||
customized: false,
|
||||
customizedApp: '',
|
||||
customizedCommand: ''
|
||||
}
|
||||
|
||||
export let engineRunning: boolean = false
|
||||
|
||||
export function setStyles(args: any) {
|
||||
styles.fontFamily = args.fontFamily
|
||||
styles.fontSize = args.fontSize
|
||||
@@ -40,23 +46,27 @@ export function setStyles(args: any) {
|
||||
|
||||
export function sendStyles(window: BrowserWindow) {
|
||||
window.webContents.send('caption.style.set', styles)
|
||||
console.log('[INFO] Send Styles:', styles)
|
||||
console.log(`[INFO] Send Styles to #${window.id}:`, styles)
|
||||
}
|
||||
|
||||
export function sendCaptionLog(window: BrowserWindow) {
|
||||
window.webContents.send('both.log.set', captionLog)
|
||||
export function sendCaptionLog(window: BrowserWindow, command: string) {
|
||||
if(command === 'add'){
|
||||
window.webContents.send(`both.log.add`, captionLog[captionLog.length - 1])
|
||||
}
|
||||
else if(command === 'set'){
|
||||
window.webContents.send(`both.log.${command}`, captionLog)
|
||||
}
|
||||
}
|
||||
|
||||
export function addCaptionLog(log: CaptionItem) {
|
||||
if(captionLog.length && captionLog[captionLog.length - 1].index === log.index) {
|
||||
captionLog.splice(captionLog.length - 1, 1)
|
||||
captionLog.push(log)
|
||||
captionLog.splice(captionLog.length - 1, 1, log)
|
||||
}
|
||||
else {
|
||||
captionLog.push(log)
|
||||
}
|
||||
for(const window of BrowserWindow.getAllWindows()){
|
||||
sendCaptionLog(window)
|
||||
sendCaptionLog(window, 'add')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,4 +79,9 @@ export function setControls(args: any) {
|
||||
controls.customizedApp = args.customizedApp
|
||||
controls.customizedCommand = args.customizedCommand
|
||||
console.log('[INFO] Set Controls:', controls)
|
||||
}
|
||||
|
||||
export function sendControls(window: BrowserWindow) {
|
||||
window.webContents.send('control.control.set', controls)
|
||||
console.log(`[INFO] Send Controls to #${window.id}:`, controls)
|
||||
}
|
||||
79
src/main/utils/engine.ts
Normal file
79
src/main/utils/engine.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { spawn } from 'child_process'
|
||||
import { app } from 'electron'
|
||||
import path from 'path'
|
||||
import { addCaptionLog, controls } from './config'
|
||||
|
||||
export class CaptionEngine {
|
||||
appPath: string = ''
|
||||
command: string[] = []
|
||||
process: any | undefined
|
||||
|
||||
private getApp() {
|
||||
if(controls.customized && controls.customizedCommand && controls.customizedApp){
|
||||
this.appPath = controls.customizedApp
|
||||
this.command = [ controls.customizedCommand ]
|
||||
}
|
||||
else if(controls.engine === 'gummy'){
|
||||
this.appPath = path.join(
|
||||
app.getAppPath(),
|
||||
'python-subprocess', 'subenv', 'Scripts', 'python.exe'
|
||||
)
|
||||
this.command = []
|
||||
this.command.push(path.join(
|
||||
app.getAppPath(),
|
||||
'python-subprocess', 'main.py'
|
||||
))
|
||||
this.command.push('-s', controls.sourceLang)
|
||||
this.command.push('-t', controls.targetLang)
|
||||
|
||||
console.log(this.appPath)
|
||||
console.log(this.command)
|
||||
}
|
||||
}
|
||||
|
||||
public start() {
|
||||
if (this.process) {
|
||||
this.stop();
|
||||
}
|
||||
this.getApp()
|
||||
this.process = spawn(this.appPath, this.command)
|
||||
controls.engineEnabled = true
|
||||
|
||||
console.log('[INFO] Caption Engine Started: ', {
|
||||
appPath: this.appPath,
|
||||
command: this.command
|
||||
})
|
||||
|
||||
this.process.stdout.on('data', (data) => {
|
||||
const lines = data.toString().split('\n');
|
||||
lines.forEach( (line: string) => {
|
||||
if (line.trim()) {
|
||||
try {
|
||||
const caption = JSON.parse(line);
|
||||
addCaptionLog(caption);
|
||||
} catch (e) {
|
||||
console.error('Error parsing JSON:', e);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.process.stderr.on('data', (data) => {
|
||||
console.error(`Python Error: ${data}`);
|
||||
});
|
||||
|
||||
this.process.on('close', (code: any) => {
|
||||
console.log(`Python process exited with code ${code}`);
|
||||
this.process = undefined;
|
||||
});
|
||||
}
|
||||
|
||||
public stop() {
|
||||
if (this.process) {
|
||||
this.process.kill();
|
||||
this.process = undefined;
|
||||
controls.engineEnabled = false;
|
||||
console.log('[INFO] Caption engine process stopped');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import { spawn } from 'child_process'
|
||||
import { app } from 'electron'
|
||||
import path from 'path'
|
||||
import { addCaptionLog } from './config'
|
||||
|
||||
export class PythonProcess {
|
||||
public start() {
|
||||
const basePath = app.getAppPath()
|
||||
const pythonPath = path.join(
|
||||
basePath,
|
||||
'python-subprocess', 'subenv', 'Scripts', 'python.exe'
|
||||
)
|
||||
const targetPath = path.join(basePath, 'python-subprocess', 'main.py')
|
||||
|
||||
console.log(pythonPath)
|
||||
console.log(targetPath)
|
||||
|
||||
const pythonProcess = spawn(pythonPath, [targetPath])
|
||||
|
||||
pythonProcess.stdout.on('data', (data) => {
|
||||
const lines = data.toString().split('\n');
|
||||
lines.forEach( (line: string) => {
|
||||
if (line.trim()) {
|
||||
try {
|
||||
const caption = JSON.parse(line);
|
||||
addCaptionLog(caption);
|
||||
} catch (e) {
|
||||
console.error('Error parsing JSON:', e);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
pythonProcess.stderr.on('data', (data) => {
|
||||
console.error(`Python Error: ${data}`);
|
||||
});
|
||||
|
||||
pythonProcess.on('close', (code) => {
|
||||
console.log(`Python process exited with code ${code}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user