refactor: 重构项目后端

- 移除 .npmrc 中的镜像配置
- 移除 package.json 中未使用的依赖
- 大幅重构后端代码
This commit is contained in:
himeditator
2025-07-01 21:50:33 +08:00
parent e30124cb87
commit e77779b72a
13 changed files with 222 additions and 234 deletions

4
.npmrc
View File

@@ -1,2 +1,2 @@
electron_mirror=https://npmmirror.com/mirrors/electron/ # electron_mirror=https://npmmirror.com/mirrors/electron/
electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/ # electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/

View File

@@ -19,4 +19,9 @@
### 新增文档 ### 新增文档
- 添加用户说明文档 - 添加用户说明文档
- 添加字幕引擎说明文档 - 添加字幕引擎说明文档
## v1.0.0
> 预计为稳定版,之后除非大改,否则版本号第一位不再改变。

View File

@@ -4,7 +4,7 @@
## 字幕引擎介绍 ## 字幕引擎介绍
所谓的字幕引擎实际上是一个子程序,它会实时获取系统音频输入(录音)或输出(播放声音)的流式数据,并调用音频转文字的模型生成对应音频的字幕。生成的字幕通过 IPC 输出为转换为 JSON 格式的字符串数据,并返回给主程序。主程序读取字幕数据,处理后显示在窗口上。 所谓的字幕引擎实际上是一个子程序,它会实时获取系统音频输入(录音)或输出(播放声音)的流式数据,并调用音频转文字的模型生成对应音频的字幕。生成的字幕转换为 JSON 格式的字符串数据,并通过 IPC 传递给主程序。主程序读取字幕数据,处理后显示在窗口上。
## 字幕引擎需要实现的功能 ## 字幕引擎需要实现的功能

View File

@@ -25,15 +25,13 @@
"@electron-toolkit/utils": "^4.0.0", "@electron-toolkit/utils": "^4.0.0",
"ant-design-vue": "^4.2.6", "ant-design-vue": "^4.2.6",
"pinia": "^3.0.2", "pinia": "^3.0.2",
"vue-router": "^4.5.1", "vue-router": "^4.5.1"
"ws": "^8.18.2"
}, },
"devDependencies": { "devDependencies": {
"@electron-toolkit/eslint-config-prettier": "3.0.0", "@electron-toolkit/eslint-config-prettier": "3.0.0",
"@electron-toolkit/eslint-config-ts": "^3.0.0", "@electron-toolkit/eslint-config-ts": "^3.0.0",
"@electron-toolkit/tsconfig": "^1.0.1", "@electron-toolkit/tsconfig": "^1.0.1",
"@types/node": "^22.14.1", "@types/node": "^22.14.1",
"@types/ws": "^8.18.1",
"@vitejs/plugin-vue": "^5.2.3", "@vitejs/plugin-vue": "^5.2.3",
"electron": "^35.1.5", "electron": "^35.1.5",
"electron-builder": "^25.1.8", "electron-builder": "^25.1.8",

Binary file not shown.

View File

@@ -2,13 +2,13 @@ import { shell, BrowserWindow, ipcMain } from 'electron'
import path from 'path' import path from 'path'
import { is } from '@electron-toolkit/utils' import { is } from '@electron-toolkit/utils'
import icon from '../../resources/icon.png?asset' import icon from '../../resources/icon.png?asset'
import { controlWindow } from './control' import { controlWindow } from './ControlWindow'
import { sendStyles, sendCaptionLog } from './utils/config' import { allConfig } from './utils/AllConfig'
class CaptionWindow { class CaptionWindow {
window: BrowserWindow | undefined; window: BrowserWindow | undefined;
public createWindow(): void { public createWindow(): void {
this.window = new BrowserWindow({ this.window = new BrowserWindow({
icon: icon, icon: icon,
width: 900, width: 900,
@@ -26,11 +26,11 @@ class CaptionWindow {
sandbox: false sandbox: false
} }
}) })
setTimeout(() => { setTimeout(() => {
if (this.window) { if (this.window) {
sendStyles(this.window); allConfig.sendStyles(this.window);
sendCaptionLog(this.window, 'set'); allConfig.sendCaptionLog(this.window, 'set');
} }
}, 1000); }, 1000);
@@ -46,7 +46,7 @@ class CaptionWindow {
shell.openExternal(details.url) shell.openExternal(details.url)
return { action: 'deny' } return { action: 'deny' }
}) })
if (is.dev && process.env['ELECTRON_RENDERER_URL']) { if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
this.window.loadURL(`${process.env['ELECTRON_RENDERER_URL']}/#/caption`) this.window.loadURL(`${process.env['ELECTRON_RENDERER_URL']}/#/caption`)
} else { } else {
@@ -57,7 +57,7 @@ class CaptionWindow {
} }
public handleMessage() { public handleMessage() {
// 字幕窗口请求创建控制窗口 // 激活控制窗口
ipcMain.on('caption.controlWindow.activate', () => { ipcMain.on('caption.controlWindow.activate', () => {
if(!controlWindow.window){ if(!controlWindow.window){
controlWindow.createWindow() controlWindow.createWindow()
@@ -66,18 +66,21 @@ class CaptionWindow {
controlWindow.window.show() controlWindow.window.show()
} }
}) })
// 字幕窗口高度发生变化 // 字幕窗口高度发生变化
ipcMain.on('caption.windowHeight.change', (_, height) => { ipcMain.on('caption.windowHeight.change', (_, height) => {
if(this.window){ if(this.window){
this.window.setSize(this.window.getSize()[0], height) this.window.setSize(this.window.getSize()[0], height)
} }
}) })
// 关闭字幕窗口 // 关闭字幕窗口
ipcMain.on('caption.window.close', () => { ipcMain.on('caption.window.close', () => {
if(this.window){ if(this.window){
this.window.close() this.window.close()
} }
}) })
// 是否固定在最前面 // 是否固定在最前面
ipcMain.on('caption.pin.set', (_, pinned) => { ipcMain.on('caption.pin.set', (_, pinned) => {
if(this.window){ if(this.window){

View File

@@ -2,20 +2,9 @@ import { shell, BrowserWindow, ipcMain } from 'electron'
import path from 'path' import path from 'path'
import { is } from '@electron-toolkit/utils' import { is } from '@electron-toolkit/utils'
import icon from '../../resources/icon.png?asset' import icon from '../../resources/icon.png?asset'
import { captionWindow } from './caption' import { captionWindow } from './CaptionWindow'
import { import { allConfig } from './utils/AllConfig'
captionEngine, import { captionEngine } from './utils/CaptionEngine'
captionLog,
controls,
setStyles,
resetStyles,
sendStyles,
sendCaptionLog,
setControls,
sendControls,
readConfig,
writeConfig
} from './utils/config'
class ControlWindow { class ControlWindow {
window: BrowserWindow | undefined; window: BrowserWindow | undefined;
@@ -25,8 +14,8 @@ class ControlWindow {
icon: icon, icon: icon,
width: 1200, width: 1200,
height: 800, height: 800,
minWidth: 900, minWidth: 600,
minHeight: 600, minHeight: 400,
show: false, show: false,
center: true, center: true,
autoHideMenuBar: true, autoHideMenuBar: true,
@@ -37,30 +26,30 @@ class ControlWindow {
} }
}) })
allConfig.readConfig()
setTimeout(() => { setTimeout(() => {
if (this.window) { if (this.window) {
readConfig() allConfig.sendStyles(this.window)
sendStyles(this.window) // 配置初始样式 allConfig.sendControls(this.window)
sendCaptionLog(this.window, 'set') // 配置当前字幕记录 allConfig.sendCaptionLog(this.window, 'set')
sendControls(this.window) // 配置字幕引擎配置
} }
}, 1000); }, 1000);
this.window.on('ready-to-show', () => { this.window.on('ready-to-show', () => {
this.window?.show() this.window?.show()
}) })
this.window.on('closed', () => { this.window.on('closed', () => {
this.window = undefined this.window = undefined
writeConfig() allConfig.writeConfig()
}) })
this.window.webContents.setWindowOpenHandler((details) => { this.window.webContents.setWindowOpenHandler((details) => {
shell.openExternal(details.url) shell.openExternal(details.url)
return { action: 'deny' } return { action: 'deny' }
}) })
if (is.dev && process.env['ELECTRON_RENDERER_URL']) { if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
this.window.loadURL(process.env['ELECTRON_RENDERER_URL']) this.window.loadURL(process.env['ELECTRON_RENDERER_URL'])
} else { } else {
@@ -69,23 +58,26 @@ class ControlWindow {
} }
public handleMessage() { public handleMessage() {
// 控制窗口样式更新 // 样式变更
ipcMain.on('control.style.change', (_, args) => { ipcMain.on('control.style.change', (_, args) => {
setStyles(args) allConfig.setStyles(args)
if(captionWindow.window){ if(captionWindow.window){
sendStyles(captionWindow.window) allConfig.sendStyles(captionWindow.window)
} }
}) })
// 样式重置
ipcMain.on('control.style.reset', () => { ipcMain.on('control.style.reset', () => {
resetStyles() allConfig.resetStyles()
if(captionWindow.window){
sendStyles(captionWindow.window)
}
if(this.window){ if(this.window){
sendStyles(this.window) allConfig.sendStyles(this.window)
}
if(captionWindow.window){
allConfig.sendStyles(captionWindow.window)
} }
}) })
// 控制窗口请求创建字幕窗口
// 激活字幕窗口
ipcMain.on('control.captionWindow.activate', () => { ipcMain.on('control.captionWindow.activate', () => {
if(!captionWindow.window){ if(!captionWindow.window){
captionWindow.createWindow() captionWindow.createWindow()
@@ -94,37 +86,31 @@ class ControlWindow {
captionWindow.window.show() captionWindow.window.show()
} }
}) })
// 字幕引擎控制配置更新并启动引擎
// 字幕引擎配置更新
ipcMain.on('control.control.change', (_, args) => { ipcMain.on('control.control.change', (_, args) => {
setControls(args) allConfig.setControls(args)
}) })
// 启动字幕引擎 // 启动字幕引擎
ipcMain.on('control.engine.start', () => { ipcMain.on('control.engine.start', () => {
if(controls.engineEnabled){ if(allConfig.controls.engineEnabled){
this.window?.webContents.send('control.engine.already') this.window?.webContents.send('control.engine.already')
} }
else { else {
if( captionEngine.start()
process.env.DASHSCOPE_API_KEY ||
(controls.customized && controls.customizedApp)
) {
if(this.window){
captionEngine.start(this.window)
}
}
else {
this.sendErrorMessage('没有检测到 DASHSCOPE_API_KEY 环境变量,如果要使用 gummy 引擎,需要在阿里云百炼平台获取 API Key 并添加到本机环境变量')
}
} }
}) })
// 停止字幕引擎 // 停止字幕引擎
ipcMain.on('control.engine.stop', () => { ipcMain.on('control.engine.stop', () => {
captionEngine.stop() captionEngine.stop()
this.window?.webContents.send('control.engine.stopped') this.window?.webContents.send('control.engine.stopped')
}) })
// 清空字幕记录 // 清空字幕记录
ipcMain.on('control.caption.clear', () => { ipcMain.on('control.caption.clear', () => {
captionLog.splice(0) allConfig.captionLog.splice(0)
}) })
} }
@@ -133,4 +119,4 @@ class ControlWindow {
} }
} }
export const controlWindow = new ControlWindow() export const controlWindow = new ControlWindow()

View File

@@ -1,8 +1,9 @@
import { app, BrowserWindow } from 'electron' import { app, BrowserWindow } from 'electron'
import { electronApp, optimizer } from '@electron-toolkit/utils' import { electronApp, optimizer } from '@electron-toolkit/utils'
import { controlWindow } from './control' import { controlWindow } from './ControlWindow'
import { captionWindow } from './caption' import { captionWindow } from './CaptionWindow'
import { captionEngine, writeConfig } from './utils/config' import { allConfig } from './utils/AllConfig'
import { captionEngine } from './utils/CaptionEngine'
app.whenReady().then(() => { app.whenReady().then(() => {
electronApp.setAppUserModelId('com.himeditator.autocaption') electronApp.setAppUserModelId('com.himeditator.autocaption')
@@ -23,9 +24,9 @@ app.whenReady().then(() => {
}) })
}) })
app.on('will-quit', async () => { app.on('will-quit', async () => {
captionEngine.stop() captionEngine.stop()
writeConfig() allConfig.writeConfig()
}); });
app.on('window-all-closed', () => { app.on('window-all-closed', () => {

View File

@@ -1,3 +1,5 @@
export type UILanguage = "zh" | "en" | "ja"
export interface Styles { export interface Styles {
fontFamily: string, fontFamily: string,
fontSize: number, fontSize: number,
@@ -22,10 +24,10 @@ export interface Controls {
engineEnabled: boolean, engineEnabled: boolean,
sourceLang: string, sourceLang: string,
targetLang: string, targetLang: string,
engine: string, engine: 'gummy',
audio: 0 | 1, audio: 0 | 1,
translation: boolean, translation: boolean,
customized: boolean, customized: boolean,
customizedApp: string, customizedApp: string,
customizedCommand: string customizedCommand: string
} }

106
src/main/utils/AllConfig.ts Normal file
View 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()

View File

@@ -1,22 +1,26 @@
import { spawn, exec } from 'child_process' import { spawn, exec } from 'child_process'
import { app, BrowserWindow } from 'electron' import { app } from 'electron'
import { is } from '@electron-toolkit/utils' import { is } from '@electron-toolkit/utils'
import path from 'path' import path from 'path'
import { addCaptionLog, controls, sendControls } from './config' import { controlWindow } from '../ControlWindow'
import { controlWindow } from '../control' import { allConfig } from './AllConfig'
export class CaptionEngine { export class CaptionEngine {
appPath: string = '' appPath: string = ''
command: string[] = [] command: string[] = []
process: any | undefined process: any | undefined
private getApp() { private getApp(): boolean {
if (controls.customized && controls.customizedApp) { if (allConfig.controls.customized && allConfig.controls.customizedApp) {
this.appPath = controls.customizedApp this.appPath = allConfig.controls.customizedApp
this.command = [controls.customizedCommand] this.command = [allConfig.controls.customizedCommand]
} }
else if (controls.engine === 'gummy') { else if (allConfig.controls.engine === 'gummy') {
controls.customized = false allConfig.controls.customized = false
if(!process.env.DASHSCOPE_API_KEY) {
controlWindow.sendErrorMessage('没有检测到 DASHSCOPE_API_KEY 环境变量,如果要使用 gummy 引擎,需要在阿里云百炼平台获取 API Key 并添加到本机环境变量')
return false
}
let gummyName = '' let gummyName = ''
if (process.platform === 'win32') { if (process.platform === 'win32') {
gummyName = 'main-gummy.exe' gummyName = 'main-gummy.exe'
@@ -25,7 +29,7 @@ export class CaptionEngine {
gummyName = 'main-gummy' gummyName = 'main-gummy'
} }
else { else {
controlWindow.sendErrorMessage('不支持的操作系统平台:' + process.platform) controlWindow.sendErrorMessage('Unsupported platform: ' + process.platform)
throw new Error('Unsupported platform') throw new Error('Unsupported platform')
} }
if (is.dev) { if (is.dev) {
@@ -41,20 +45,23 @@ export class CaptionEngine {
) )
} }
this.command = [] this.command = []
this.command.push('-s', controls.sourceLang) this.command.push('-s', allConfig.controls.sourceLang)
this.command.push('-t', controls.translation ? controls.targetLang : 'none') this.command.push(
this.command.push('-a', controls.audio ? '1' : '0') '-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 Path:', this.appPath)
console.log('[INFO] Engine Command:', this.command) console.log('[INFO] Engine Command:', this.command)
} }
return true
} }
public start(window: BrowserWindow) { public start() {
if (this.process) { if (this.process) { this.stop() }
this.stop(); if(!this.getApp()){ return }
}
this.getApp()
try { try {
this.process = spawn(this.appPath, this.command) this.process = spawn(this.appPath, this.command)
} }
@@ -64,14 +71,14 @@ export class CaptionEngine {
return return
} }
console.log('[INFO] Caption Engine Started: ', { console.log('[INFO] Caption Engine Started')
appPath: this.appPath,
command: this.command
})
controls.engineEnabled = true allConfig.controls.engineEnabled = true
sendControls(window)
window.webContents.send('control.engine.started') if(controlWindow.window){
allConfig.sendControls(controlWindow.window)
controlWindow.window.webContents.send('control.engine.started')
}
this.process.stdout.on('data', (data) => { this.process.stdout.on('data', (data) => {
const lines = data.toString().split('\n'); const lines = data.toString().split('\n');
@@ -79,7 +86,7 @@ export class CaptionEngine {
if (line.trim()) { if (line.trim()) {
try { try {
const caption = JSON.parse(line); const caption = JSON.parse(line);
addCaptionLog(caption); allConfig.updateCaptionLog(caption);
} catch (e) { } catch (e) {
controlWindow.sendErrorMessage('字幕引擎输出内容无法解析为 JSON 对象:' + e) controlWindow.sendErrorMessage('字幕引擎输出内容无法解析为 JSON 对象:' + e)
console.error('[ERROR] Error parsing JSON:', e); console.error('[ERROR] Error parsing JSON:', e);
@@ -96,8 +103,10 @@ export class CaptionEngine {
this.process.on('close', (code: any) => { this.process.on('close', (code: any) => {
console.log(`[INFO] Subprocess exited with code ${code}`); console.log(`[INFO] Subprocess exited with code ${code}`);
this.process = undefined; this.process = undefined;
controls.engineEnabled = false allConfig.controls.engineEnabled = false
sendControls(window) if(controlWindow.window){
allConfig.sendControls(controlWindow.window)
}
}); });
} }
@@ -107,7 +116,7 @@ export class CaptionEngine {
exec(`taskkill /pid ${this.process.pid} /t /f`, (error) => { exec(`taskkill /pid ${this.process.pid} /t /f`, (error) => {
if (error) { if (error) {
controlWindow.sendErrorMessage('字幕引擎进程关闭失败:' + error) controlWindow.sendErrorMessage('字幕引擎进程关闭失败:' + error)
console.error(`[ERROR] Failed to kill process: ${error}`); console.error(`[ERROR] Failed to kill process: ${error}`)
} }
}); });
} else { } else {
@@ -115,8 +124,12 @@ export class CaptionEngine {
} }
} }
this.process = undefined; this.process = undefined;
controls.engineEnabled = false; allConfig.controls.engineEnabled = false;
console.log('[INFO] Caption engine process stopped'); console.log('[INFO] Caption engine process stopped')
if(controlWindow.window) sendControls(controlWindow.window); if(controlWindow.window) {
allConfig.sendControls(controlWindow.window)
}
} }
} }
export const captionEngine = new CaptionEngine()

View File

@@ -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)
}

View File

@@ -1,3 +0,0 @@
class configSave {
}