mirror of
https://github.com/HiMeditator/auto-caption.git
synced 2026-02-13 19:23:26 +08:00
refactor: 重构项目后端
- 移除 .npmrc 中的镜像配置 - 移除 package.json 中未使用的依赖 - 大幅重构后端代码
This commit is contained in:
106
src/main/utils/AllConfig.ts
Normal file
106
src/main/utils/AllConfig.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { Styles, CaptionItem, Controls } from '../types'
|
||||
import { app, BrowserWindow } from 'electron'
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
|
||||
const defaultStyles: Styles = {
|
||||
fontFamily: 'sans-serif',
|
||||
fontSize: 24,
|
||||
fontColor: '#000000',
|
||||
background: '#dbe2ef',
|
||||
opacity: 80,
|
||||
transDisplay: true,
|
||||
transFontFamily: 'sans-serif',
|
||||
transFontSize: 24,
|
||||
transFontColor: '#000000'
|
||||
};
|
||||
|
||||
const defaultControls: Controls = {
|
||||
sourceLang: 'en',
|
||||
targetLang: 'zh',
|
||||
engine: 'gummy',
|
||||
audio: 0,
|
||||
engineEnabled: false,
|
||||
translation: true,
|
||||
customized: false,
|
||||
customizedApp: '',
|
||||
customizedCommand: ''
|
||||
};
|
||||
|
||||
|
||||
class AllConfig {
|
||||
styles: Styles = {...defaultStyles};
|
||||
controls: Controls = {...defaultControls};
|
||||
captionLog: CaptionItem[] = [];
|
||||
|
||||
constructor() {}
|
||||
|
||||
public readConfig() {
|
||||
const configPath = path.join(app.getPath('userData'), 'config.json')
|
||||
if(fs.existsSync(configPath)){
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
|
||||
this.setStyles(config.styles)
|
||||
this.setControls(config.controls)
|
||||
console.log('[INFO] Read Config from:', configPath)
|
||||
}
|
||||
}
|
||||
|
||||
public writeConfig() {
|
||||
const config = {
|
||||
controls: this.controls,
|
||||
styles: this.styles
|
||||
}
|
||||
const configPath = path.join(app.getPath('userData'), 'config.json')
|
||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 2))
|
||||
console.log('[INFO] Write Config to:', configPath)
|
||||
}
|
||||
|
||||
public setStyles(args: any) {
|
||||
this.styles = {...args}
|
||||
console.log('[INFO] Set Styles:', this.styles)
|
||||
}
|
||||
|
||||
public resetStyles() {
|
||||
this.setStyles(defaultStyles)
|
||||
}
|
||||
|
||||
public sendStyles(window: BrowserWindow) {
|
||||
window.webContents.send('caption.style.set', this.styles)
|
||||
console.log(`[INFO] Send Styles to #${window.id}:`, this.styles)
|
||||
}
|
||||
|
||||
public setControls(args: any) {
|
||||
const engineEnabled = args.engineEnabled
|
||||
this.controls = {...args}
|
||||
this.controls.engineEnabled = engineEnabled
|
||||
console.log('[INFO] Set Controls:', this.controls)
|
||||
}
|
||||
|
||||
public sendControls(window: BrowserWindow) {
|
||||
window.webContents.send('control.control.set', this.controls)
|
||||
console.log(`[INFO] Send Controls to #${window.id}:`, this.controls)
|
||||
}
|
||||
|
||||
public updateCaptionLog(log: CaptionItem) {
|
||||
if(this.captionLog.length && this.captionLog[this.captionLog.length - 1].index === log.index) {
|
||||
this.captionLog.splice(this.captionLog.length - 1, 1, log)
|
||||
}
|
||||
else {
|
||||
this.captionLog.push(log)
|
||||
}
|
||||
for(const window of BrowserWindow.getAllWindows()){
|
||||
this.sendCaptionLog(window, 'add')
|
||||
}
|
||||
}
|
||||
|
||||
public sendCaptionLog(window: BrowserWindow, command: 'add' | 'set') {
|
||||
if(command === 'add'){
|
||||
window.webContents.send(`both.log.add`, this.captionLog[this.captionLog.length - 1])
|
||||
}
|
||||
else if(command === 'set'){
|
||||
window.webContents.send(`both.log.${command}`, this.captionLog)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const allConfig = new AllConfig()
|
||||
@@ -1,22 +1,26 @@
|
||||
import { spawn, exec } from 'child_process'
|
||||
import { app, BrowserWindow } from 'electron'
|
||||
import { app } from 'electron'
|
||||
import { is } from '@electron-toolkit/utils'
|
||||
import path from 'path'
|
||||
import { addCaptionLog, controls, sendControls } from './config'
|
||||
import { controlWindow } from '../control'
|
||||
import { controlWindow } from '../ControlWindow'
|
||||
import { allConfig } from './AllConfig'
|
||||
|
||||
export class CaptionEngine {
|
||||
appPath: string = ''
|
||||
command: string[] = []
|
||||
process: any | undefined
|
||||
|
||||
private getApp() {
|
||||
if (controls.customized && controls.customizedApp) {
|
||||
this.appPath = controls.customizedApp
|
||||
this.command = [controls.customizedCommand]
|
||||
private getApp(): boolean {
|
||||
if (allConfig.controls.customized && allConfig.controls.customizedApp) {
|
||||
this.appPath = allConfig.controls.customizedApp
|
||||
this.command = [allConfig.controls.customizedCommand]
|
||||
}
|
||||
else if (controls.engine === 'gummy') {
|
||||
controls.customized = false
|
||||
else if (allConfig.controls.engine === 'gummy') {
|
||||
allConfig.controls.customized = false
|
||||
if(!process.env.DASHSCOPE_API_KEY) {
|
||||
controlWindow.sendErrorMessage('没有检测到 DASHSCOPE_API_KEY 环境变量,如果要使用 gummy 引擎,需要在阿里云百炼平台获取 API Key 并添加到本机环境变量')
|
||||
return false
|
||||
}
|
||||
let gummyName = ''
|
||||
if (process.platform === 'win32') {
|
||||
gummyName = 'main-gummy.exe'
|
||||
@@ -25,7 +29,7 @@ export class CaptionEngine {
|
||||
gummyName = 'main-gummy'
|
||||
}
|
||||
else {
|
||||
controlWindow.sendErrorMessage('不支持的操作系统平台:' + process.platform)
|
||||
controlWindow.sendErrorMessage('Unsupported platform: ' + process.platform)
|
||||
throw new Error('Unsupported platform')
|
||||
}
|
||||
if (is.dev) {
|
||||
@@ -41,20 +45,23 @@ export class CaptionEngine {
|
||||
)
|
||||
}
|
||||
this.command = []
|
||||
this.command.push('-s', controls.sourceLang)
|
||||
this.command.push('-t', controls.translation ? controls.targetLang : 'none')
|
||||
this.command.push('-a', controls.audio ? '1' : '0')
|
||||
this.command.push('-s', allConfig.controls.sourceLang)
|
||||
this.command.push(
|
||||
'-t', allConfig.controls.translation ?
|
||||
allConfig.controls.targetLang : 'none'
|
||||
)
|
||||
this.command.push('-a', allConfig.controls.audio ? '1' : '0')
|
||||
|
||||
console.log('[INFO] Engine Path:', this.appPath)
|
||||
console.log('[INFO] Engine Command:', this.command)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public start(window: BrowserWindow) {
|
||||
if (this.process) {
|
||||
this.stop();
|
||||
}
|
||||
this.getApp()
|
||||
public start() {
|
||||
if (this.process) { this.stop() }
|
||||
if(!this.getApp()){ return }
|
||||
|
||||
try {
|
||||
this.process = spawn(this.appPath, this.command)
|
||||
}
|
||||
@@ -64,14 +71,14 @@ export class CaptionEngine {
|
||||
return
|
||||
}
|
||||
|
||||
console.log('[INFO] Caption Engine Started: ', {
|
||||
appPath: this.appPath,
|
||||
command: this.command
|
||||
})
|
||||
console.log('[INFO] Caption Engine Started')
|
||||
|
||||
controls.engineEnabled = true
|
||||
sendControls(window)
|
||||
window.webContents.send('control.engine.started')
|
||||
allConfig.controls.engineEnabled = true
|
||||
|
||||
if(controlWindow.window){
|
||||
allConfig.sendControls(controlWindow.window)
|
||||
controlWindow.window.webContents.send('control.engine.started')
|
||||
}
|
||||
|
||||
this.process.stdout.on('data', (data) => {
|
||||
const lines = data.toString().split('\n');
|
||||
@@ -79,7 +86,7 @@ export class CaptionEngine {
|
||||
if (line.trim()) {
|
||||
try {
|
||||
const caption = JSON.parse(line);
|
||||
addCaptionLog(caption);
|
||||
allConfig.updateCaptionLog(caption);
|
||||
} catch (e) {
|
||||
controlWindow.sendErrorMessage('字幕引擎输出内容无法解析为 JSON 对象:' + e)
|
||||
console.error('[ERROR] Error parsing JSON:', e);
|
||||
@@ -96,8 +103,10 @@ export class CaptionEngine {
|
||||
this.process.on('close', (code: any) => {
|
||||
console.log(`[INFO] Subprocess exited with code ${code}`);
|
||||
this.process = undefined;
|
||||
controls.engineEnabled = false
|
||||
sendControls(window)
|
||||
allConfig.controls.engineEnabled = false
|
||||
if(controlWindow.window){
|
||||
allConfig.sendControls(controlWindow.window)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -107,7 +116,7 @@ export class CaptionEngine {
|
||||
exec(`taskkill /pid ${this.process.pid} /t /f`, (error) => {
|
||||
if (error) {
|
||||
controlWindow.sendErrorMessage('字幕引擎进程关闭失败:' + error)
|
||||
console.error(`[ERROR] Failed to kill process: ${error}`);
|
||||
console.error(`[ERROR] Failed to kill process: ${error}`)
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -115,8 +124,12 @@ export class CaptionEngine {
|
||||
}
|
||||
}
|
||||
this.process = undefined;
|
||||
controls.engineEnabled = false;
|
||||
console.log('[INFO] Caption engine process stopped');
|
||||
if(controlWindow.window) sendControls(controlWindow.window);
|
||||
allConfig.controls.engineEnabled = false;
|
||||
console.log('[INFO] Caption engine process stopped')
|
||||
if(controlWindow.window) {
|
||||
allConfig.sendControls(controlWindow.window)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const captionEngine = new CaptionEngine()
|
||||
@@ -1,123 +0,0 @@
|
||||
import { Styles, CaptionItem, Controls } from '../types'
|
||||
import { app, BrowserWindow } from 'electron'
|
||||
import { CaptionEngine } from './engine'
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
|
||||
export const captionEngine = new CaptionEngine()
|
||||
|
||||
export const styles: Styles = {
|
||||
fontFamily: 'sans-serif',
|
||||
fontSize: 24,
|
||||
fontColor: '#000000',
|
||||
background: '#dbe2ef',
|
||||
opacity: 80,
|
||||
transDisplay: true,
|
||||
transFontFamily: 'sans-serif',
|
||||
transFontSize: 24,
|
||||
transFontColor: '#000000'
|
||||
}
|
||||
|
||||
export const captionLog: CaptionItem[] = []
|
||||
|
||||
export const controls: Controls = {
|
||||
sourceLang: 'en',
|
||||
targetLang: 'zh',
|
||||
engine: 'gummy',
|
||||
audio: 0,
|
||||
engineEnabled: false,
|
||||
translation: true,
|
||||
customized: false,
|
||||
customizedApp: '',
|
||||
customizedCommand: ''
|
||||
}
|
||||
|
||||
export function setStyles(args: any) {
|
||||
styles.fontFamily = args.fontFamily
|
||||
styles.fontSize = args.fontSize
|
||||
styles.fontColor = args.fontColor
|
||||
styles.background = args.background
|
||||
styles.opacity = args.opacity
|
||||
styles.transDisplay = args.transDisplay
|
||||
styles.transFontFamily = args.transFontFamily
|
||||
styles.transFontSize = args.transFontSize
|
||||
styles.transFontColor = args.transFontColor
|
||||
console.log('[INFO] Set Styles:', styles)
|
||||
}
|
||||
|
||||
export function resetStyles() {
|
||||
setStyles({
|
||||
fontFamily: 'sans-serif',
|
||||
fontSize: 24,
|
||||
fontColor: '#000000',
|
||||
background: '#dbe2ef',
|
||||
opacity: 80,
|
||||
transDisplay: true,
|
||||
transFontFamily: 'sans-serif',
|
||||
transFontSize: 24,
|
||||
transFontColor: '#000000'
|
||||
})
|
||||
}
|
||||
|
||||
export function sendStyles(window: BrowserWindow) {
|
||||
window.webContents.send('caption.style.set', styles)
|
||||
console.log(`[INFO] Send Styles to #${window.id}:`, styles)
|
||||
}
|
||||
|
||||
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, log)
|
||||
}
|
||||
else {
|
||||
captionLog.push(log)
|
||||
}
|
||||
for(const window of BrowserWindow.getAllWindows()){
|
||||
sendCaptionLog(window, 'add')
|
||||
}
|
||||
}
|
||||
|
||||
export function setControls(args: any) {
|
||||
controls.sourceLang = args.sourceLang
|
||||
controls.targetLang = args.targetLang
|
||||
controls.engine = args.engine
|
||||
controls.audio = args.audio
|
||||
controls.translation = args.translation
|
||||
controls.customized = args.customized
|
||||
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)
|
||||
}
|
||||
|
||||
export function readConfig() {
|
||||
const configPath = path.join(app.getPath('userData'), 'config.json')
|
||||
if(fs.existsSync(configPath)){
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
|
||||
setStyles(config.styles)
|
||||
setControls(config.controls)
|
||||
console.log('[INFO] Read Config from:', configPath)
|
||||
}
|
||||
}
|
||||
|
||||
export function writeConfig() {
|
||||
const config = {
|
||||
controls: controls,
|
||||
styles: styles
|
||||
}
|
||||
const configPath = path.join(app.getPath('userData'), 'config.json')
|
||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 2))
|
||||
console.log('[INFO] Write Config to:', configPath)
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
class configSave {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user