feat(renderer): 初步添加字幕显示窗口

This commit is contained in:
himeditator
2025-06-15 22:59:45 +08:00
parent 4ef62eed03
commit eb3711f6af
15 changed files with 147 additions and 101 deletions

22
package-lock.json generated
View File

@@ -13,6 +13,7 @@
"@electron-toolkit/utils": "^4.0.0",
"ant-design-vue": "^4.2.6",
"pinia": "^3.0.2",
"vue-router": "^4.5.1",
"ws": "^8.18.2"
},
"devDependencies": {
@@ -9429,6 +9430,27 @@
"node": ">=10"
}
},
"node_modules/vue-router": {
"version": "4.5.1",
"resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.1.tgz",
"integrity": "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==",
"license": "MIT",
"dependencies": {
"@vue/devtools-api": "^6.6.4"
},
"funding": {
"url": "https://github.com/sponsors/posva"
},
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/vue-router/node_modules/@vue/devtools-api": {
"version": "6.6.4",
"resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
"license": "MIT"
},
"node_modules/vue-tsc": {
"version": "2.2.10",
"resolved": "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-2.2.10.tgz",

View File

@@ -25,6 +25,7 @@
"@electron-toolkit/utils": "^4.0.0",
"ant-design-vue": "^4.2.6",
"pinia": "^3.0.2",
"vue-router": "^4.5.1",
"ws": "^8.18.2"
},
"devDependencies": {

View File

@@ -4,7 +4,7 @@ import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import icon from '../../resources/icon.png?asset'
let mainWindow: BrowserWindow | undefined
let captionWindow: BrowserWindow | undefined
function createMainWindow(): void {
mainWindow = new BrowserWindow({
icon: icon,
@@ -36,6 +36,39 @@ function createMainWindow(): void {
}
}
function createCaptionWindow(): void {
captionWindow = new BrowserWindow({
icon: icon,
width: 900,
height: 670,
show: false,
center: true,
autoHideMenuBar: true,
...(process.platform === 'linux' ? { icon } : {}),
webPreferences: {
preload: path.join(__dirname, '../preload/index.js'),
sandbox: false
}
})
captionWindow.on('ready-to-show', () => {
captionWindow?.show()
})
captionWindow.webContents.setWindowOpenHandler((details) => {
shell.openExternal(details.url)
return { action: 'deny' }
})
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
captionWindow.loadURL(`${process.env['ELECTRON_RENDERER_URL']}/#/caption`)
} else {
captionWindow.loadFile(path.join(__dirname, '../renderer/index.html'), {
hash: 'caption'
})
}
}
app.whenReady().then(() => {
electronApp.setAppUserModelId('com.himeditator.autocaption')
@@ -44,6 +77,7 @@ app.whenReady().then(() => {
})
createMainWindow()
createCaptionWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createMainWindow()

View File

@@ -1,17 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Auto Caption Player</title>
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:"
/>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@@ -1,6 +0,0 @@
<template>
<h1>Caption</h1>
</template>
<script setup lang="ts">
</script>

View File

@@ -1,5 +0,0 @@
body {
margin: 0;
padding: 0;
background-color: black;
}

View File

@@ -1 +0,0 @@
/// <reference types="vite/client" />

View File

@@ -1,8 +0,0 @@
import './assets/styles/reset.css'
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.use(createPinia())
app.mount('#app')

View File

@@ -1,9 +0,0 @@
import { ref } from 'vue'
import { defineStore } from 'pinia'
export const useCaptionStore = defineStore('caption', () => {
const captionFontFamily = ref<string>('sans-serif')
const captionFontSize = ref<number>(24)
const captionFontColor = ref<string>('#ffffff')
return { captionFontFamily, captionFontSize, captionFontColor }
})

View File

@@ -1,56 +1,6 @@
<template>
<div>
<a-row>
<a-col :span="controlSpan">
<div class="caption-control">
<a-card size="small" title="页面宽度">
<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>
</div>
<router-view></router-view>
</template>
<script setup lang="ts">
import CaptionStyle from './components/CaptionStyle.vue'
import CaptionControl from './components/CaptionControl.vue';
import CaptionData from './components/CaptionData.vue'
import { ref } from 'vue'
const controlSpan = ref(8)
</script>
<style scoped>
.caption-control {
height: 100vh;
border-right: 1px solid #7774;
padding: 20px;
overflow-y: auto;
scrollbar-width: thin;
}
.caption-data {
height: 100vh;
padding: 20px;
overflow-y: auto;
scrollbar-width: thin;
}
.span-input {
width: 100px;
}
</style>

View File

@@ -2,7 +2,8 @@
<div style="height: 20px;"></div>
<a-card size="small" title="字幕控制">
<template #extra>
<a @click="applyControl">应用</a>
<a @click="applyChange">更改设置</a> |
<a @click="cancelChange">取消更改</a>
</template>
<div class="control-item">
<span class="control-label">源语言</span>
@@ -71,13 +72,21 @@ const langList = computed(() => {
return []
})
function applyControl(){
function applyChange(){
captionControl.sourceLang = currentSourceLang.value
captionControl.targetLang = currentTargetLang.value
captionControl.engine = currentEngine.value
captionControl.port = currentPort.value
captionControl.translation = currentTranslation.value
}
function cancelChange(){
currentSourceLang.value = captionControl.sourceLang
currentTargetLang.value = captionControl.targetLang
currentEngine.value = captionControl.engine
currentPort.value = captionControl.port
currentTranslation.value = captionControl.translation
}
</script>
<style scoped>

View File

@@ -1,11 +1,14 @@
import './assets/styles/reset.css'
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/reset.css';
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(Antd)
app.mount('#app')

View File

@@ -0,0 +1,21 @@
import { createRouter, createWebHashHistory } from 'vue-router'
import HomePage from '../views/HomePage.vue'
import CaptionPage from '@renderer/views/CaptionPage.vue'
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: '/',
name: 'home',
component: HomePage
},
{
path: '/caption',
name: 'caption',
component: CaptionPage
}
]
})
export default router

View File

@@ -1,5 +1,5 @@
<template>
<h1>字幕测试 字幕测试 字幕测试</h1>
</template>
<script setup lang="ts">

View File

@@ -0,0 +1,52 @@
<template>
<div>
<a-row>
<a-col :span="controlSpan">
<div class="caption-control">
<a-card size="small" title="页面宽度">
<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>
</div>
</template>
<script setup lang="ts">
import CaptionStyle from '../components/CaptionStyle.vue'
import CaptionControl from '../components/CaptionControl.vue';
import CaptionData from '../components/CaptionData.vue'
import { ref } from 'vue'
const controlSpan = ref(8)
</script>
<style scoped>
.caption-control {
height: 100vh;
border-right: 1px solid #7774;
padding: 20px;
overflow-y: auto;
scrollbar-width: thin;
}
.caption-data {
height: 100vh;
padding: 20px;
overflow-y: auto;
scrollbar-width: thin;
}
.span-input {
width: 100px;
}
</style>