mirror of
https://github.com/HiMeditator/auto-caption.git
synced 2026-02-22 01:14:41 +08:00
refactor(renderer): 重构项目前端
- 拆分了 CaptionData 和 ControlPage 组件 - 对部分页面和变量进行了重命名 - 重构优化了状态管理,新增状态管理
This commit is contained in:
@@ -23,5 +23,7 @@
|
|||||||
|
|
||||||
## v1.0.0
|
## v1.0.0
|
||||||
|
|
||||||
|
2025-07-
|
||||||
|
|
||||||
> 预计为稳定版,之后除非大改,否则版本号第一位不再改变。
|
> 预计为稳定版,之后除非大改,否则版本号第一位不再改变。
|
||||||
|
|
||||||
|
|||||||
11
assets/technical-docs/api-doc.md
Normal file
11
assets/technical-docs/api-doc.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# api-doc
|
||||||
|
|
||||||
|
本文档主要记录主进程和渲染进程的通信约定。
|
||||||
|
|
||||||
|
## 背景知识
|
||||||
|
|
||||||
|
本项目渲染进程包含两个:字幕窗口和控制窗口。主进程需要分别和两者进行通信,通信命令一般有三个关键词组成,由点号隔开。
|
||||||
|
|
||||||
|
第一个词表示发送/接收处理对象,`config` 表示配置对象,`engine` 表示字幕引擎对象,`both` 表示两者同时。
|
||||||
|
|
||||||
|
比如 ``
|
||||||
@@ -1,34 +1,4 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="caption-stat">
|
|
||||||
<a-row>
|
|
||||||
<a-col :span="6">
|
|
||||||
<a-statistic title="字幕引擎" :value="(customized && customizedApp)?'自定义':engine" />
|
|
||||||
</a-col>
|
|
||||||
<a-col :span="6">
|
|
||||||
<a-statistic title="字幕引擎状态" :value="engineEnabled?'已启动':'未启动'" />
|
|
||||||
</a-col>
|
|
||||||
<a-col :span="6">
|
|
||||||
<a-statistic title="已记录字幕" :value="captionData.length" />
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="caption-control">
|
|
||||||
<a-button
|
|
||||||
type="primary"
|
|
||||||
class="control-button"
|
|
||||||
@click="openCaptionWindow"
|
|
||||||
>打开字幕窗口</a-button>
|
|
||||||
<a-button
|
|
||||||
class="control-button"
|
|
||||||
@click="captionControl.startEngine"
|
|
||||||
>启动字幕引擎</a-button>
|
|
||||||
<a-button
|
|
||||||
danger class="control-button"
|
|
||||||
@click="captionControl.stopEngine"
|
|
||||||
>关闭字幕引擎</a-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="caption-list">
|
<div class="caption-list">
|
||||||
<div class="caption-title">
|
<div class="caption-title">
|
||||||
<span style="margin-right: 30px;">字幕记录</span>
|
<span style="margin-right: 30px;">字幕记录</span>
|
||||||
@@ -77,11 +47,8 @@
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { useCaptionLogStore } from '@renderer/stores/captionLog'
|
import { useCaptionLogStore } from '@renderer/stores/captionLog'
|
||||||
import { useCaptionControlStore } from '@renderer/stores/captionControl'
|
|
||||||
const captionLog = useCaptionLogStore()
|
const captionLog = useCaptionLogStore()
|
||||||
const { captionData } = storeToRefs(captionLog)
|
const { captionData } = storeToRefs(captionLog)
|
||||||
const captionControl = useCaptionControlStore()
|
|
||||||
const { engineEnabled, engine, customized, customizedApp } = storeToRefs(captionControl)
|
|
||||||
const pagination = ref({
|
const pagination = ref({
|
||||||
current: 1,
|
current: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@@ -118,10 +85,6 @@ const columns = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
function openCaptionWindow() {
|
|
||||||
window.electron.ipcRenderer.send('control.captionWindow.activate')
|
|
||||||
}
|
|
||||||
|
|
||||||
function exportCaptions() {
|
function exportCaptions() {
|
||||||
const jsonData = JSON.stringify(captionData.value, null, 2)
|
const jsonData = JSON.stringify(captionData.value, null, 2)
|
||||||
const blob = new Blob([jsonData], { type: 'application/json' })
|
const blob = new Blob([jsonData], { type: 'application/json' })
|
||||||
@@ -142,19 +105,6 @@ function clearCaptions() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.caption-control {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: center;
|
|
||||||
margin: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.control-button {
|
|
||||||
height: 40px;
|
|
||||||
margin: 20px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.caption-list {
|
.caption-list {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
@@ -199,4 +149,4 @@ function clearCaptions() {
|
|||||||
padding-left: 16px;
|
padding-left: 16px;
|
||||||
border-left: 3px solid #1890ff;
|
border-left: 3px solid #1890ff;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -69,15 +69,15 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, watch } from 'vue'
|
import { ref, computed, watch } from 'vue'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { useCaptionControlStore } from '@renderer/stores/captionControl'
|
import { useEngineControlStore } from '@renderer/stores/engineControl'
|
||||||
import { notification } from 'ant-design-vue'
|
import { notification } from 'ant-design-vue'
|
||||||
|
|
||||||
const captionControl = useCaptionControlStore()
|
const engineControl = useEngineControlStore()
|
||||||
const { captionEngine, audioType, changeSignal } = storeToRefs(captionControl)
|
const { captionEngine, audioType, changeSignal } = storeToRefs(engineControl)
|
||||||
|
|
||||||
const currentSourceLang = ref('auto')
|
const currentSourceLang = ref('auto')
|
||||||
const currentTargetLang = ref('zh')
|
const currentTargetLang = ref('zh')
|
||||||
const currentEngine = ref('gummy')
|
const currentEngine = ref<'gummy'>('gummy')
|
||||||
const currentAudio = ref<0 | 1>(0)
|
const currentAudio = ref<0 | 1>(0)
|
||||||
const currentTranslation = ref<boolean>(false)
|
const currentTranslation = ref<boolean>(false)
|
||||||
|
|
||||||
@@ -95,17 +95,17 @@ const langList = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
function applyChange(){
|
function applyChange(){
|
||||||
captionControl.sourceLang = currentSourceLang.value
|
engineControl.sourceLang = currentSourceLang.value
|
||||||
captionControl.targetLang = currentTargetLang.value
|
engineControl.targetLang = currentTargetLang.value
|
||||||
captionControl.engine = currentEngine.value
|
engineControl.engine = currentEngine.value
|
||||||
captionControl.audio = currentAudio.value
|
engineControl.audio = currentAudio.value
|
||||||
captionControl.translation = currentTranslation.value
|
engineControl.translation = currentTranslation.value
|
||||||
|
|
||||||
captionControl.customized = currentCustomized.value
|
engineControl.customized = currentCustomized.value
|
||||||
captionControl.customizedApp = currentCustomizedApp.value
|
engineControl.customizedApp = currentCustomizedApp.value
|
||||||
captionControl.customizedCommand = currentCustomizedCommand.value
|
engineControl.customizedCommand = currentCustomizedCommand.value
|
||||||
|
|
||||||
captionControl.sendControlChange()
|
engineControl.sendControlChange()
|
||||||
|
|
||||||
notification.open({
|
notification.open({
|
||||||
message: '字幕控制已更改',
|
message: '字幕控制已更改',
|
||||||
@@ -114,21 +114,21 @@ function applyChange(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function cancelChange(){
|
function cancelChange(){
|
||||||
currentSourceLang.value = captionControl.sourceLang
|
currentSourceLang.value = engineControl.sourceLang
|
||||||
currentTargetLang.value = captionControl.targetLang
|
currentTargetLang.value = engineControl.targetLang
|
||||||
currentEngine.value = captionControl.engine
|
currentEngine.value = engineControl.engine
|
||||||
currentAudio.value = captionControl.audio
|
currentAudio.value = engineControl.audio
|
||||||
currentTranslation.value = captionControl.translation
|
currentTranslation.value = engineControl.translation
|
||||||
|
|
||||||
currentCustomized.value = captionControl.customized
|
currentCustomized.value = engineControl.customized
|
||||||
currentCustomizedApp.value = captionControl.customizedApp
|
currentCustomizedApp.value = engineControl.customizedApp
|
||||||
currentCustomizedCommand.value = captionControl.customizedCommand
|
currentCustomizedCommand.value = engineControl.customizedCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(changeSignal, (val) => {
|
watch(changeSignal, (val) => {
|
||||||
if(val == true) {
|
if(val == true) {
|
||||||
cancelChange();
|
cancelChange();
|
||||||
captionControl.changeSignal = false;
|
engineControl.changeSignal = false;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -162,4 +162,4 @@ watch(changeSignal, (val) => {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #666
|
color: #666
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
68
src/renderer/src/components/EngineStatus.vue
Normal file
68
src/renderer/src/components/EngineStatus.vue
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<template>
|
||||||
|
<div class="caption-stat">
|
||||||
|
<a-row>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-statistic title="字幕引擎" :value="(customized && customizedApp)?'自定义':engine" />
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-statistic title="字幕引擎状态" :value="engineEnabled?'已启动':'未启动'" />
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-statistic title="已记录字幕" :value="captionData.length" />
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="caption-control">
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
class="control-button"
|
||||||
|
@click="openCaptionWindow"
|
||||||
|
>打开字幕窗口</a-button>
|
||||||
|
<a-button
|
||||||
|
class="control-button"
|
||||||
|
@click="startEngine"
|
||||||
|
>启动字幕引擎</a-button>
|
||||||
|
<a-button
|
||||||
|
danger class="control-button"
|
||||||
|
@click="stopEngine"
|
||||||
|
>关闭字幕引擎</a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { useCaptionLogStore } from '@renderer/stores/captionLog'
|
||||||
|
import { useEngineControlStore } from '@renderer/stores/engineControl'
|
||||||
|
const captionLog = useCaptionLogStore()
|
||||||
|
const { captionData } = storeToRefs(captionLog)
|
||||||
|
const engineControl = useEngineControlStore()
|
||||||
|
const { engineEnabled, engine, customized, customizedApp } = storeToRefs(engineControl)
|
||||||
|
|
||||||
|
function openCaptionWindow() {
|
||||||
|
window.electron.ipcRenderer.send('control.captionWindow.activate')
|
||||||
|
}
|
||||||
|
|
||||||
|
function startEngine() {
|
||||||
|
window.electron.ipcRenderer.send('control.engine.start')
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopEngine() {
|
||||||
|
window.electron.ipcRenderer.send('control.engine.stop')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.caption-control {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-button {
|
||||||
|
height: 40px;
|
||||||
|
margin: 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
54
src/renderer/src/components/GeneralSetting.vue
Normal file
54
src/renderer/src/components/GeneralSetting.vue
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<a-card size="small" title="页面宽度">
|
||||||
|
<template #extra>
|
||||||
|
<a-button type="link" @click="showAbout = true">关于本项目</a-button>
|
||||||
|
</template>
|
||||||
|
<div>
|
||||||
|
<a-input type="range" class="span-input" min="6" max="18" v-model:value="leftBarWidth" />
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
|
||||||
|
<a-modal v-model:open="showAbout" title="关于本项目" :footer="null">
|
||||||
|
<div class="about-modal-content">
|
||||||
|
<h2 class="about-title">Auto Caption 项目</h2>
|
||||||
|
<p class="about-desc">一个跨平台的实时字幕显示软件。</p>
|
||||||
|
<a-divider />
|
||||||
|
<div class="about-info">
|
||||||
|
<p><b>作者:</b>HiMeditator</p>
|
||||||
|
<p><b>版本:</b>v0.1.0</p>
|
||||||
|
<p>
|
||||||
|
<b>项目地址:</b>
|
||||||
|
<a href="https://github.com/HiMeditator/auto-caption" target="_blank">
|
||||||
|
GitHub | auto-caption
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>用户手册:</b>
|
||||||
|
<a
|
||||||
|
href="https://github.com/HiMeditator/auto-caption/blob/main/assets/user-manual_zh.md"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
GitHub | user-manual_zh.md
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="about-date">2026 年 6 月 26 日</div>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { useGeneralSettingStore } from '@renderer/stores/generalSetting'
|
||||||
|
|
||||||
|
const generalSettingStore = useGeneralSettingStore()
|
||||||
|
const { leftBarWidth } = storeToRefs(generalSettingStore)
|
||||||
|
const showAbout = ref(false)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.span-input {
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import './assets/reset.css'
|
import './assets/reset.css'
|
||||||
import { createPinia } from 'pinia'
|
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
|
import { createPinia } from 'pinia'
|
||||||
|
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
@@ -11,4 +11,5 @@ const app = createApp(App)
|
|||||||
app.use(createPinia())
|
app.use(createPinia())
|
||||||
app.use(router)
|
app.use(router)
|
||||||
app.use(Antd)
|
app.use(Antd)
|
||||||
app.mount('#app')
|
|
||||||
|
app.mount('#app')
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
import { CaptionItem } from '../types'
|
||||||
interface CaptionItem {
|
|
||||||
index: number,
|
|
||||||
time_s: string,
|
|
||||||
time_t: string,
|
|
||||||
text: string,
|
|
||||||
translation: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useCaptionLogStore = defineStore('captionLog', () => {
|
export const useCaptionLogStore = defineStore('captionLog', () => {
|
||||||
const captionData = ref<CaptionItem[]>([])
|
const captionData = ref<CaptionItem[]>([])
|
||||||
@@ -34,4 +27,4 @@ export const useCaptionLogStore = defineStore('captionLog', () => {
|
|||||||
captionData,
|
captionData,
|
||||||
clear
|
clear
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
import { Styles } from '@renderer/types'
|
||||||
|
|
||||||
export const useCaptionStyleStore = defineStore('captionStyle', () => {
|
export const useCaptionStyleStore = defineStore('captionStyle', () => {
|
||||||
const fontFamily = ref<string>('sans-serif')
|
const fontFamily = ref<string>('sans-serif')
|
||||||
@@ -7,7 +8,7 @@ export const useCaptionStyleStore = defineStore('captionStyle', () => {
|
|||||||
const fontColor = ref<string>('#000000')
|
const fontColor = ref<string>('#000000')
|
||||||
const background = ref<string>('#dbe2ef')
|
const background = ref<string>('#dbe2ef')
|
||||||
const opacity = ref<number>(80)
|
const opacity = ref<number>(80)
|
||||||
|
|
||||||
const transDisplay = ref<boolean>(true)
|
const transDisplay = ref<boolean>(true)
|
||||||
const transFontFamily = ref<string>('sans-serif')
|
const transFontFamily = ref<string>('sans-serif')
|
||||||
const transFontSize = ref<number>(24)
|
const transFontSize = ref<number>(24)
|
||||||
@@ -26,7 +27,7 @@ export const useCaptionStyleStore = defineStore('captionStyle', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
function sendStyleChange() {
|
function sendStyleChange() {
|
||||||
const styles = {
|
const styles: Styles = {
|
||||||
fontFamily: fontFamily.value,
|
fontFamily: fontFamily.value,
|
||||||
fontSize: fontSize.value,
|
fontSize: fontSize.value,
|
||||||
fontColor: fontColor.value,
|
fontColor: fontColor.value,
|
||||||
@@ -69,7 +70,7 @@ export const useCaptionStyleStore = defineStore('captionStyle', () => {
|
|||||||
transFontColor, // 翻译字体颜色
|
transFontColor, // 翻译字体颜色
|
||||||
backgroundRGBA, // 带透明度的背景颜色
|
backgroundRGBA, // 带透明度的背景颜色
|
||||||
sendStyleChange, // 发送样式改变
|
sendStyleChange, // 发送样式改变
|
||||||
sendStyleReset, // 恢复默认样式
|
sendStyleReset, // 恢复默认样式
|
||||||
changeSignal // 样式改变信号
|
changeSignal // 样式改变信号
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ import { notification } from 'ant-design-vue'
|
|||||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
|
import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
|
||||||
import { h } from 'vue'
|
import { h } from 'vue'
|
||||||
|
|
||||||
export const useCaptionControlStore = defineStore('captionControl', () => {
|
import { Controls } from '@renderer/types'
|
||||||
|
|
||||||
|
export const useEngineControlStore = defineStore('engineControl', () => {
|
||||||
const captionEngine = ref([
|
const captionEngine = ref([
|
||||||
{
|
{
|
||||||
value: 'gummy',
|
value: 'gummy',
|
||||||
@@ -39,7 +41,7 @@ export const useCaptionControlStore = defineStore('captionControl', () => {
|
|||||||
|
|
||||||
const sourceLang = ref<string>('en')
|
const sourceLang = ref<string>('en')
|
||||||
const targetLang = ref<string>('zh')
|
const targetLang = ref<string>('zh')
|
||||||
const engine = ref<string>('gummy')
|
const engine = ref<'gummy'>('gummy')
|
||||||
const audio = ref<0 | 1>(0)
|
const audio = ref<0 | 1>(0)
|
||||||
const translation = ref<boolean>(true)
|
const translation = ref<boolean>(true)
|
||||||
const customized = ref<boolean>(false)
|
const customized = ref<boolean>(false)
|
||||||
@@ -49,7 +51,7 @@ export const useCaptionControlStore = defineStore('captionControl', () => {
|
|||||||
const changeSignal = ref<boolean>(false)
|
const changeSignal = ref<boolean>(false)
|
||||||
|
|
||||||
function sendControlChange() {
|
function sendControlChange() {
|
||||||
const controls = {
|
const controls: Controls = {
|
||||||
engineEnabled: engineEnabled.value,
|
engineEnabled: engineEnabled.value,
|
||||||
sourceLang: sourceLang.value,
|
sourceLang: sourceLang.value,
|
||||||
targetLang: targetLang.value,
|
targetLang: targetLang.value,
|
||||||
@@ -63,14 +65,6 @@ export const useCaptionControlStore = defineStore('captionControl', () => {
|
|||||||
window.electron.ipcRenderer.send('control.control.change', controls)
|
window.electron.ipcRenderer.send('control.control.change', controls)
|
||||||
}
|
}
|
||||||
|
|
||||||
function startEngine() {
|
|
||||||
window.electron.ipcRenderer.send('control.engine.start')
|
|
||||||
}
|
|
||||||
|
|
||||||
function stopEngine() {
|
|
||||||
window.electron.ipcRenderer.send('control.engine.stop')
|
|
||||||
}
|
|
||||||
|
|
||||||
window.electron.ipcRenderer.on('control.control.set', (_, controls) => {
|
window.electron.ipcRenderer.on('control.control.set', (_, controls) => {
|
||||||
sourceLang.value = controls.sourceLang
|
sourceLang.value = controls.sourceLang
|
||||||
targetLang.value = controls.targetLang
|
targetLang.value = controls.targetLang
|
||||||
@@ -84,16 +78,16 @@ export const useCaptionControlStore = defineStore('captionControl', () => {
|
|||||||
changeSignal.value = true
|
changeSignal.value = true
|
||||||
})
|
})
|
||||||
|
|
||||||
window.electron.ipcRenderer.on('control.engine.already', () => {
|
window.electron.ipcRenderer.on('control.engine.already', () => {
|
||||||
notification.open({
|
notification.open({
|
||||||
message: '字幕引擎已经启动',
|
message: '字幕引擎已经启动',
|
||||||
description: '字幕引擎已经启动,请勿重复启动'
|
description: '字幕引擎已经启动,请勿重复启动'
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
window.electron.ipcRenderer.on('control.engine.started', () => {
|
window.electron.ipcRenderer.on('control.engine.started', () => {
|
||||||
const str0 =
|
const str0 =
|
||||||
`原语言:${sourceLang.value},是否翻译:${translation.value?'是':'否'},` +
|
`原语言:${sourceLang.value},是否翻译:${translation.value?'是':'否'},` +
|
||||||
`字幕引擎:${engine.value},音频类型:${audio.value ? '输入音频' : '输出音频'}` +
|
`字幕引擎:${engine.value},音频类型:${audio.value ? '输入音频' : '输出音频'}` +
|
||||||
(translation.value ? `,翻译语言:${targetLang.value}` : '');
|
(translation.value ? `,翻译语言:${targetLang.value}` : '');
|
||||||
const str1 = `类型:自定义引擎,引擎路径:${customizedApp.value},命令参数:${customizedCommand.value}`;
|
const str1 = `类型:自定义引擎,引擎路径:${customizedApp.value},命令参数:${customizedCommand.value}`;
|
||||||
@@ -103,14 +97,14 @@ export const useCaptionControlStore = defineStore('captionControl', () => {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
window.electron.ipcRenderer.on('control.engine.stopped', () => {
|
window.electron.ipcRenderer.on('control.engine.stopped', () => {
|
||||||
notification.open({
|
notification.open({
|
||||||
message: '字幕引擎停止',
|
message: '字幕引擎停止',
|
||||||
description: '可点击“启动字幕引擎”按钮重新启动'
|
description: '可点击“启动字幕引擎”按钮重新启动'
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
window.electron.ipcRenderer.on('control.error.send', (_, message) => {
|
window.electron.ipcRenderer.on('control.error.send', (_, message) => {
|
||||||
notification.open({
|
notification.open({
|
||||||
message: '发生错误',
|
message: '发生错误',
|
||||||
description: message,
|
description: message,
|
||||||
@@ -133,8 +127,6 @@ export const useCaptionControlStore = defineStore('captionControl', () => {
|
|||||||
customizedApp, // 自定义字幕引擎的应用程序
|
customizedApp, // 自定义字幕引擎的应用程序
|
||||||
customizedCommand, // 自定义字幕引擎的命令
|
customizedCommand, // 自定义字幕引擎的命令
|
||||||
sendControlChange, // 发送最新控制消息到后端
|
sendControlChange, // 发送最新控制消息到后端
|
||||||
startEngine, // 启动字幕引擎
|
|
||||||
stopEngine, // 停止字幕引擎
|
|
||||||
changeSignal, // 配置改变信号
|
changeSignal, // 配置改变信号
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
9
src/renderer/src/stores/generalSetting.ts
Normal file
9
src/renderer/src/stores/generalSetting.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { ref } from 'vue'
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
export const useGeneralSettingStore = defineStore('generalSetting', () => {
|
||||||
|
const leftBarWidth = ref<number>(8)
|
||||||
|
return {
|
||||||
|
leftBarWidth
|
||||||
|
}
|
||||||
|
})
|
||||||
33
src/renderer/src/types/index.ts
Normal file
33
src/renderer/src/types/index.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
export type UILanguage = "zh" | "en" | "ja"
|
||||||
|
|
||||||
|
export interface Styles {
|
||||||
|
fontFamily: string,
|
||||||
|
fontSize: number,
|
||||||
|
fontColor: string,
|
||||||
|
background: string,
|
||||||
|
opacity: number,
|
||||||
|
transDisplay: boolean,
|
||||||
|
transFontFamily: string,
|
||||||
|
transFontSize: number,
|
||||||
|
transFontColor: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CaptionItem {
|
||||||
|
index: number,
|
||||||
|
time_s: string,
|
||||||
|
time_t: string,
|
||||||
|
text: string,
|
||||||
|
translation: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Controls {
|
||||||
|
engineEnabled: boolean,
|
||||||
|
sourceLang: string,
|
||||||
|
targetLang: string,
|
||||||
|
engine: 'gummy',
|
||||||
|
audio: 0 | 1,
|
||||||
|
translation: boolean,
|
||||||
|
customized: boolean,
|
||||||
|
customizedApp: string,
|
||||||
|
customizedCommand: string
|
||||||
|
}
|
||||||
@@ -111,7 +111,7 @@ function closeCaptionWindow() {
|
|||||||
background-color: #2221;
|
background-color: #2221;
|
||||||
}
|
}
|
||||||
|
|
||||||
.caption-container {
|
.caption-container {
|
||||||
-webkit-app-region: drag;
|
-webkit-app-region: drag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,4 +121,4 @@ function closeCaptionWindow() {
|
|||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
padding: 0 10px 10px 10px;
|
padding: 0 10px 10px 10px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,63 +1,32 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<a-row>
|
||||||
<a-row>
|
<a-col :span="leftBarWidth">
|
||||||
<a-col :span="controlSpan">
|
<div class="caption-control">
|
||||||
<div class="caption-control">
|
<GeneralSetting />
|
||||||
<a-card size="small" title="页面宽度">
|
<EngineControl />
|
||||||
<template #extra>
|
<CaptionStyle />
|
||||||
<a-button type="link" @click="showAbout = true">关于本项目</a-button>
|
|
||||||
</template>
|
|
||||||
<div>
|
|
||||||
<a-input type="range" class="span-input" min="6" max="18" v-model:value="controlSpan" />
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
<CaptionControl />
|
|
||||||
<CaptionStyle />
|
|
||||||
</div>
|
|
||||||
</a-col>
|
|
||||||
<a-col :span="24 - controlSpan">
|
|
||||||
<div class="caption-data">
|
|
||||||
<CaptionData />
|
|
||||||
</div>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
<a-modal v-model:open="showAbout" title="关于本项目" :footer="null">
|
|
||||||
<div class="about-modal-content">
|
|
||||||
<h2 class="about-title">Auto Caption 项目</h2>
|
|
||||||
<p class="about-desc">一个跨平台的实时字幕显示软件。</p>
|
|
||||||
<a-divider />
|
|
||||||
<div class="about-info">
|
|
||||||
<p><b>作者:</b>HiMeditator</p>
|
|
||||||
<p><b>版本:</b>v0.1.0</p>
|
|
||||||
<p>
|
|
||||||
<b>项目地址:</b>
|
|
||||||
<a href="https://github.com/HiMeditator/auto-caption" target="_blank">
|
|
||||||
GitHub | auto-caption
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<b>用户手册:</b>
|
|
||||||
<a
|
|
||||||
href="https://github.com/HiMeditator/auto-caption/blob/main/assets/user-manual_zh.md"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
GitHub | user-manual_zh.md
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="about-date">2026 年 6 月 26 日</div>
|
|
||||||
</div>
|
</div>
|
||||||
</a-modal>
|
</a-col>
|
||||||
</div>
|
<a-col :span="24 - leftBarWidth">
|
||||||
|
<div class="caption-data">
|
||||||
|
<EngineStatus />
|
||||||
|
<CaptionLog />
|
||||||
|
</div>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import GeneralSetting from '../components/GeneralSetting.vue'
|
||||||
import CaptionStyle from '../components/CaptionStyle.vue'
|
import CaptionStyle from '../components/CaptionStyle.vue'
|
||||||
import CaptionControl from '../components/CaptionControl.vue';
|
import EngineControl from '../components/EngineControl.vue'
|
||||||
import CaptionData from '../components/CaptionData.vue'
|
import EngineStatus from '@renderer/components/EngineStatus.vue'
|
||||||
import { ref } from 'vue'
|
import CaptionLog from '../components/CaptionLog.vue'
|
||||||
const controlSpan = ref(8)
|
import { storeToRefs } from 'pinia'
|
||||||
const showAbout = ref(false)
|
import { useGeneralSettingStore } from '@renderer/stores/generalSetting'
|
||||||
|
|
||||||
|
const generalSettingStore = useGeneralSettingStore()
|
||||||
|
const { leftBarWidth } = storeToRefs(generalSettingStore)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -76,10 +45,6 @@ const showAbout = ref(false)
|
|||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
}
|
}
|
||||||
|
|
||||||
.span-input {
|
|
||||||
width: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.about-modal-content {
|
.about-modal-content {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 8px 0 0 0;
|
padding: 8px 0 0 0;
|
||||||
@@ -109,4 +74,4 @@ const showAbout = ref(false)
|
|||||||
font-size: 0.95em;
|
font-size: 0.95em;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user