Skip to content

Commit 304da00

Browse files
committed
upd: add config file
1 parent 36abb65 commit 304da00

14 files changed

Lines changed: 680 additions & 132 deletions

File tree

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,58 @@
1+
export interface VideoConfig {
2+
id: string;
3+
name: string;
4+
width: number;
5+
height: number;
6+
frameRate: number;
7+
sampleRate: number;
8+
}
9+
10+
export interface AudioConfig {
11+
id: string;
12+
name: string;
13+
sampleRate: number;
14+
channelCount: number;
15+
}
16+
117
export interface AppConfigInterface {
2-
rlToken: string;
3-
userId: string;
4-
competitionId: string;
18+
version: string;
19+
appConfig: {
20+
autoOpenOnLogin?: boolean; // 开机自启动
21+
autoStartStreaming?: boolean; // 启动时自动开始推流
22+
autoHiddenOnStart?: boolean; // 启动时自动隐藏主窗口
23+
videoCachePath: string; // 视频缓存路径
24+
};
25+
userConfig: {
26+
rlToken?: string;
27+
userId?: string;
28+
competitionId?: string;
29+
};
30+
devicesConfig: {
31+
screens?: Array<VideoConfig>;
32+
cameras?: Array<VideoConfig>;
33+
microphones?: Array<AudioConfig>;
34+
};
35+
}
36+
37+
export interface UpdateVideoConfigDTO {
38+
id: string;
39+
name: string;
40+
width: number;
41+
height: number;
42+
frameRate: number;
43+
sampleRate: number;
44+
}
545

6-
devicesConfig: {
7-
8-
}
46+
export interface UpdateAudioConfigDTO {
47+
id: string;
48+
name: string;
49+
sampleRate: number;
50+
channelCount: number;
51+
}
952

10-
}
53+
export interface UpdateAppConfigDTO {
54+
autoOpenOnLogin: boolean;
55+
autoStartStreaming: boolean;
56+
autoHiddenOnStart: boolean;
57+
videoCachePath: string;
58+
}

src/electron/main.ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { WebSocketService } from './services/websocket-service';
66
import { VideoRecordingService } from './services/video-recording-service';
77
import { createTray } from './utils/tray';
88
import fs from 'fs';
9+
import { ConfigManager } from './services/config-manager';
910

1011
app.setName('Kessoku the Broadcaster');
1112

@@ -14,6 +15,7 @@ let mainWindow: BrowserWindow;
1415
let webSocketService: WebSocketService;
1516
let videoRecordingService: VideoRecordingService;
1617
const SERVICE_URL: string = 'http://localhost:3001';
18+
let configManager: ConfigManager = new ConfigManager();
1719

1820
app.setAboutPanelOptions({
1921
applicationName: app.getName(),
@@ -130,7 +132,7 @@ function createSettingsWindow() {
130132
resizable: false,
131133
show: false,
132134
titleBarStyle: 'hiddenInset',
133-
})
135+
});
134136

135137
if (isDevelopment()) {
136138
settingsWindow.loadURL('http://localhost:5123/#settings');
@@ -182,9 +184,9 @@ function setupIpcHandlers() {
182184
}
183185
});
184186

185-
ipcMainOn("openSettingsWindow", () => {
187+
ipcMainOn('openSettingsWindow', () => {
186188
createSettingsWindow();
187-
})
189+
});
188190

189191
// 获取连接状态
190192
ipcMainHandle('get-connection-status', () => {
@@ -270,6 +272,33 @@ function setupIpcHandlers() {
270272
throw error;
271273
}
272274
});
275+
276+
ipcMainHandle('getAppConfig', async () => {
277+
return configManager.getConfigData;
278+
});
279+
280+
ipcMainHandle('getDevicesConfig', async () => {
281+
return configManager.getDevicesConfig;
282+
});
283+
284+
ipcMainHandle('hasDevicesConfig', async () => {
285+
return configManager.hasDevicesConfig();
286+
});
287+
288+
ipcMainHandle('updateAppConfig', async (data: UpdateAppConfigDTO) => {
289+
configManager.updateAppConfig(data);
290+
});
291+
292+
ipcMainHandle('updateAudioConfig', async (data: UpdateAudioConfigDTO[]) => {
293+
configManager.updateAudioConfig(data);
294+
});
295+
296+
ipcMainHandle(
297+
'updateVideoConfig',
298+
async ({ data, type }: { data: UpdateVideoConfigDTO[]; type: 'camera' | 'screen' }) => {
299+
configManager.updateVideoConfig(data, type);
300+
},
301+
);
273302
}
274303

275304
const handleCloseEvents = (mainWindow: BrowserWindow) => {

src/electron/preload.cts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,25 @@ electron.contextBridge.exposeInMainWorld('electron', {
9191
},
9292
openSettingsWindow: () => {
9393
ipcSend('openSettingsWindow');
94-
}
94+
},
95+
getAppConfig: () => {
96+
return ipcInvoke('getAppConfig');
97+
},
98+
getDevicesConfig: () => {
99+
return ipcInvoke('getDevicesConfig');
100+
},
101+
hasDevicesConfig: () => {
102+
return ipcInvoke('hasDevicesConfig');
103+
},
104+
updateVideoConfig: (data: UpdateVideoConfigDTO[], type: 'camera' | 'screen') => {
105+
return ipcInvoke('updateVideoConfig', { data, type });
106+
},
107+
updateAudioConfig: (data: UpdateAudioConfigDTO[]) => {
108+
return ipcInvoke('updateAudioConfig', data);
109+
},
110+
updateAppConfig: (data: UpdateAppConfigDTO) => {
111+
return ipcInvoke('updateAppConfig', data);
112+
},
95113
} satisfies Window['electron']);
96114

97115
function ipcInvoke<Key extends keyof EventPayloadMapping>(
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import {
2+
AppConfigInterface,
3+
UpdateAppConfigDTO,
4+
UpdateAudioConfigDTO,
5+
UpdateVideoConfigDTO,
6+
} from 'common/interface/config.interface';
7+
import fs from 'fs';
8+
import path from 'path';
9+
import os from 'os';
10+
import { app } from 'electron';
11+
12+
export class ConfigManager {
13+
protected configPath: string = os.homedir() + '/.Kessoku-the-Broadcaster/config.json';
14+
private configData: AppConfigInterface;
15+
16+
constructor() {
17+
this.loadingConfig();
18+
}
19+
20+
private loadingConfig() {
21+
if (fs.existsSync(this.configPath)) {
22+
const rawData = fs.readFileSync(this.configPath, 'utf-8');
23+
this.configData = JSON.parse(rawData) as AppConfigInterface;
24+
} else {
25+
// 确保配置目录存在
26+
const configDir = path.dirname(this.configPath);
27+
if (!fs.existsSync(configDir)) {
28+
fs.mkdirSync(configDir, { recursive: true });
29+
}
30+
31+
fs.writeFileSync(
32+
this.configPath,
33+
JSON.stringify(
34+
{
35+
version: app.getVersion(),
36+
appConfig: {},
37+
userConfig: {},
38+
devicesConfig: {},
39+
} as AppConfigInterface,
40+
null,
41+
2,
42+
),
43+
);
44+
this.configData = JSON.parse(fs.readFileSync(this.configPath, 'utf-8')) as AppConfigInterface;
45+
}
46+
}
47+
48+
get getConfigPath() {
49+
return this.configPath;
50+
}
51+
52+
get getConfigData() {
53+
return this.configData;
54+
}
55+
56+
get getDevicesConfig() {
57+
return this.configData.devicesConfig || {};
58+
}
59+
60+
hasDevicesConfig(): boolean {
61+
const dc = this.configData.devicesConfig;
62+
return !!(
63+
(dc.screens && dc.screens.length > 0) ||
64+
(dc.cameras && dc.cameras.length > 0) ||
65+
(dc.microphones && dc.microphones.length > 0)
66+
);
67+
}
68+
69+
private saveConfig() {
70+
fs.writeFileSync(this.configPath, JSON.stringify(this.configData, null, 2));
71+
}
72+
73+
updateAppConfig(data: UpdateAppConfigDTO) {
74+
this.configData.appConfig = {
75+
...this.configData.appConfig,
76+
...data,
77+
};
78+
this.saveConfig();
79+
}
80+
81+
updateVideoConfig(data: UpdateVideoConfigDTO[], type: 'camera' | 'screen') {
82+
if (type === 'camera') {
83+
this.configData.devicesConfig.cameras = data;
84+
} else if (type === 'screen') {
85+
this.configData.devicesConfig.screens = data;
86+
}
87+
this.saveConfig();
88+
}
89+
90+
updateAudioConfig(data: UpdateAudioConfigDTO[]) {
91+
this.configData.devicesConfig.microphones = data;
92+
this.saveConfig();
93+
}
94+
}

src/ui/app.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
<script lang="ts">
22
import { Vue, Options } from 'vue-class-component';
3+
import { Provide } from 'vue-property-decorator';
34
45
import LoginView from './modules/login/login.view.vue';
56
import HomeView from './modules/home/home.view.vue';
67
import Tools from './components/tools.vue';
8+
import { AppConfigInterface } from 'common/interface/config.interface';
79
810
@Options({
911
components: {
@@ -13,15 +15,15 @@ import Tools from './components/tools.vue';
1315
},
1416
})
1517
export default class App extends Vue {
16-
async mounted() {
18+
mounted() {
1719
window.addEventListener('keydown', (e) => {
1820
if ((e.ctrlKey || e.metaKey) && ['=', '-', '0'].includes(e.key)) {
1921
e.preventDefault();
2022
}
2123
2224
if (e.metaKey && e.key == ',') {
2325
e.preventDefault();
24-
window.electron.openSettingsWindow()
26+
window.electron.openSettingsWindow();
2527
}
2628
});
2729
}

src/ui/components/config-dialog.vue

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,16 @@ export default class ConfigDialog extends Vue {
9090
<div class="resolution-inputs">
9191
<el-input-number
9292
v-model="deviceManager.configForm.width"
93-
:min="deviceManager.currentConfigDevice?.capabilities?.width?.min"
94-
:max="deviceManager.currentConfigDevice?.capabilities?.width?.max"
93+
:min="deviceManager.currentConfigDevice.capabilities.width.min"
94+
:max="deviceManager.currentConfigDevice.capabilities.width.max"
9595
:step="1"
9696
controls-position="right"
9797
/>
9898
<span class="resolution-separator">×</span>
9999
<el-input-number
100100
v-model="deviceManager.configForm.height"
101-
:min="deviceManager.currentConfigDevice?.capabilities?.height?.min"
102-
:max="deviceManager.currentConfigDevice?.capabilities?.height?.max"
101+
:min="deviceManager.currentConfigDevice.capabilities.height.min"
102+
:max="deviceManager.currentConfigDevice.capabilities.height.max"
103103
:step="1"
104104
controls-position="right"
105105
/>
@@ -142,8 +142,8 @@ export default class ConfigDialog extends Vue {
142142
<el-form-item label="帧率">
143143
<el-input-number
144144
v-model="deviceManager.configForm.frameRate"
145-
:min="deviceManager.currentConfigDevice?.capabilities?.frameRate?.min"
146-
:max="60"
145+
:min="deviceManager.currentConfigDevice.capabilities.frameRate.min"
146+
:max="deviceManager.currentConfigDevice.capabilities.frameRate.max"
147147
:step="1"
148148
controls-position="right"
149149
/>
@@ -152,16 +152,16 @@ export default class ConfigDialog extends Vue {
152152

153153
<el-form-item label="支持范围">
154154
<div class="capabilities-info">
155-
<p v-if="deviceManager.currentConfigDevice?.capabilities">
155+
<p v-if="deviceManager.currentConfigDevice.capabilities">
156156
宽度:
157-
{{ Math.round(deviceManager.currentConfigDevice.capabilities.width?.min) }} -
158-
{{ Math.round(deviceManager.currentConfigDevice.capabilities.width?.max) }}<br />
157+
{{ Math.round(deviceManager.currentConfigDevice.capabilities.width.min) }} -
158+
{{ Math.round(deviceManager.currentConfigDevice.capabilities.width.max) }}<br />
159159
高度:
160-
{{ Math.round(deviceManager.currentConfigDevice.capabilities.height?.min) }} -
161-
{{ Math.round(deviceManager.currentConfigDevice.capabilities.height?.max) }}<br />
160+
{{ Math.round(deviceManager.currentConfigDevice.capabilities.height.min) }} -
161+
{{ Math.round(deviceManager.currentConfigDevice.capabilities.height.max) }}<br />
162162
帧率:
163-
{{ Math.round(deviceManager.currentConfigDevice.capabilities.frameRate?.min) }} -
164-
{{ 60 }}
163+
{{ Math.round(deviceManager.currentConfigDevice.capabilities.frameRate.min) }} -
164+
{{ Math.round(deviceManager.currentConfigDevice.capabilities.frameRate.max) }}
165165
fps
166166
</p>
167167
<p v-else>待获取设备参数信息</p>

src/ui/components/device-card.vue

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,12 @@ export default class DeviceCard extends Vue {
4646
@Inject()
4747
updateVideoElement!: (device: Device) => void;
4848
49-
// 使用本地响应式数据
5049
private localFormatSetting: string = '';
5150
5251
mounted() {
5352
this.updateFormatSetting();
5453
}
5554
56-
// 公共方法:更新 formatSetting 显示
5755
public updateFormatSetting() {
5856
this.localFormatSetting = this.device?.formatSetting || '未获取当前设备参数';
5957
}

0 commit comments

Comments
 (0)