feat(renderer): 增加长字幕隐藏功能 (#1)

- 修复暗色主题部分内容的显示颜色
- 添加长字幕内容隐藏功能
- 优化字幕样式预览界面,支持动态显示最新字幕内容
This commit is contained in:
himeditator
2025-07-05 11:00:53 +08:00
parent f29e15cde5
commit 22cfb75d2c
19 changed files with 132 additions and 27 deletions

View File

@@ -6,4 +6,7 @@ indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
trim_trailing_whitespace = true
[*.py]
indent_size = 4

View File

@@ -12,7 +12,7 @@ import sys
import argparse
def convert_audio_to_text(s_lang, t_lang, audio_type):
sys.stdout.reconfigure(line_buffering=True)
sys.stdout.reconfigure(line_buffering=True) # type: ignore
stream = AudioStream(audio_type)
stream.openStream()
@@ -45,4 +45,3 @@ if __name__ == "__main__":
args.target_language,
0 if args.audio_type == '0' else 1
)

View File

@@ -15,6 +15,7 @@ export interface Controls {
}
export interface Styles {
lineBreak: number,
fontFamily: string,
fontSize: number,
fontColor: string,

View File

@@ -7,6 +7,7 @@ import * as path from 'path'
import * as fs from 'fs'
const defaultStyles: Styles = {
lineBreak: 1,
fontFamily: 'sans-serif',
fontSize: 24,
fontColor: '#000000',

View File

@@ -4,17 +4,13 @@
<script setup lang="ts">
import { onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { FullConfig } from './types'
import { useCaptionLogStore } from './stores/captionLog'
import { useCaptionStyleStore } from './stores/captionStyle'
import { useEngineControlStore } from './stores/engineControl'
import { useGeneralSettingStore } from './stores/generalSetting'
const router = useRouter()
onMounted(() => {
console.log('Current route:', router.currentRoute.value.fullPath)
window.electron.ipcRenderer.invoke('both.window.mounted').then((data: FullConfig) => {
useGeneralSettingStore().uiLanguage = data.uiLanguage
useGeneralSettingStore().uiTheme = data.uiTheme

View File

@@ -23,5 +23,5 @@
width: 80px;
text-align: right;
font-size: 12px;
color: #666
color: var(--tag-color)
}

View File

@@ -1,5 +1,7 @@
:root {
--control-background: #fff;
--tag-color: rgba(0, 0, 0, 0.45);
--icon-color: rgba(0, 0, 0, 0.88);
}
body {

View File

@@ -5,6 +5,16 @@
<a @click="backStyle">{{ $t('style.cancelChange') }}</a> |
<a @click="resetStyle">{{ $t('style.resetStyle') }}</a>
</template>
<div class="input-item">
<span class="input-label">{{ $t('style.longCaption') }}</span>
<a-select
class="input-area"
v-model:value="currentLineBreak"
:options="captionStyle.iBreakOptions"
></a-select>
</div>
<div class="input-item">
<span class="input-label">{{ $t('style.fontFamily') }}</span>
<a-input
@@ -105,21 +115,26 @@
backgroundColor: addOpicityToColor(currentBackground, currentOpacity)
}"
>
<p class="preview-caption"
<p :class="[captionStyle.lineBreak?'':'left-ellipsis']"
:style="{
fontFamily: currentFontFamily,
fontSize: currentFontSize + 'px',
color: currentFontColor
}">
{{ $t('example.original') }}
}">
<span v-if="captionData.length">{{ captionData[captionData.length-1].text }}</span>
<span v-else>{{ $t('example.original') }}</span>
</p>
<p class="preview-translation" v-if="currentTransDisplay"
<p :class="[captionStyle.lineBreak?'':'left-ellipsis']"
v-if="currentTransDisplay"
:style="{
fontFamily: currentTransFontFamily,
fontSize: currentTransFontSize + 'px',
color: currentTransFontColor
}"
>{{ $t('example.translation') }}</p>
>
<span v-if="captionData.length">{{ captionData[captionData.length-1].translation }}</span>
<span v-else>{{ $t('example.translation') }}</span>
</p>
</div>
</Teleport>
@@ -131,12 +146,17 @@ import { useCaptionStyleStore } from '@renderer/stores/captionStyle'
import { storeToRefs } from 'pinia'
import { notification } from 'ant-design-vue'
import { useI18n } from 'vue-i18n'
import { useCaptionLogStore } from '@renderer/stores/captionLog';
const captionLog = useCaptionLogStore();
const { captionData } = storeToRefs(captionLog);
const { t } = useI18n()
const captionStyle = useCaptionStyleStore()
const { changeSignal } = storeToRefs(captionStyle)
const currentLineBreak = ref<number>(0)
const currentFontFamily = ref<string>('sans-serif')
const currentFontSize = ref<number>(24)
const currentFontColor = ref<string>('#000000')
@@ -161,6 +181,7 @@ function useSameStyle(){
}
function applyStyle(){
captionStyle.lineBreak = currentLineBreak.value;
captionStyle.fontFamily = currentFontFamily.value;
captionStyle.fontSize = currentFontSize.value;
captionStyle.fontColor = currentFontColor.value;
@@ -175,12 +196,13 @@ function applyStyle(){
captionStyle.sendStylesChange();
notification.open({
message: t('noti.engineChange'),
description: t('noti.changeInfo')
message: t('noti.styleChange'),
description: t('noti.styleInfo')
});
}
function backStyle(){
currentLineBreak.value = captionStyle.lineBreak;
currentFontFamily.value = captionStyle.fontFamily;
currentFontSize.value = captionStyle.fontSize;
currentFontColor.value = captionStyle.fontColor;
@@ -221,7 +243,20 @@ watch(changeSignal, (val) => {
}
.preview-container p {
text-align: center;
margin: 0;
line-height: 1.5em;
}
.left-ellipsis {
white-space: nowrap;
overflow: hidden;
direction: rtl;
text-align: left;
}
.left-ellipsis > span {
direction: ltr;
display: inline-block;
}
</style>

View File

@@ -107,7 +107,7 @@ function stopEngine() {
<style scoped>
.about-tag {
color: rgba(0,0,0,0.45);
color: var(--tag-color);
margin-bottom: 16px;
}
@@ -115,7 +115,7 @@ function stopEngine() {
display: inline-block;
font-size: 24px;
cursor: pointer;
color: #1f2328;
color: var(--icon-color);
}
.about-modal-content {

View File

@@ -0,0 +1,32 @@
export const breakOptions = {
zh: [
{
value: 1,
label: '换行(可能造成字幕窗口高度增加)'
},
{
value: 0,
label: '不换行(省略掉超出字幕窗口宽度的内容)'
}
],
en: [
{
value: 1,
label: 'Wrap (may increase caption window height)'
},
{
value: 0,
label: 'Do not wrap (truncate content that exceeds caption window width)'
}
],
ja: [
{
value: 1,
label: '改行する(字幕ウィンドウの高さが増える可能性があります)'
},
{
value: 0,
label: '改行しない(字幕ウィンドウの幅を超える内容は省略します)'
}
]
}

View File

@@ -17,3 +17,4 @@ export const i18n = createI18n({
export * from './config/engine'
export * from './config/audio'
export * from './config/theme'
export * from './config/linebreak'

View File

@@ -20,14 +20,16 @@ export default {
"stoppedInfo": "The caption engine has stopped. You can click the 'Start Caption Engine' button to restart it.",
"error": "An error occurred",
"engineChange": "Cpation Engine Configuration Changed",
"changeInfo": "If the caption engine is already running, you need to restart it for the changes to take effect."
"changeInfo": "If the caption engine is already running, you need to restart it for the changes to take effect.",
"styleChange": "Caption Style Changed",
"styleInfo": "Caption style changes have been saved and applied."
},
general: {
"title": "General Settings",
"uiLanguage": "Language",
"barWidth": "Width",
"note": "General Settings take effect immediately. Please note that changes to the Caption Engine Settings and Caption Style Settings will only take effect after clicking Apply.",
"theme": "theme",
"theme": "Theme",
"light": "light",
"dark": "dark",
"system": "system"
@@ -57,6 +59,7 @@ export default {
"applyStyle": "Apply",
"cancelChange": "Cancel",
"resetStyle": "Reset",
"longCaption": "LongCaption",
"fontFamily": "Font Family",
"fontColor": "Font Color",
"fontSize": "Font Size",

View File

@@ -20,7 +20,9 @@ export default {
"stoppedInfo": "字幕エンジンが停止しました。再起動するには「字幕エンジンを開始」ボタンをクリックしてください。",
"error": "エラーが発生しました",
"engineChange": "字幕エンジンの設定が変更されました",
"changeInfo": "字幕エンジンがすでに起動している場合、変更を有効にするには再起動が必要です。"
"changeInfo": "字幕エンジンがすでに起動している場合、変更を有効にするには再起動が必要です。",
"styleChange": "字幕のスタイルが変更されました",
"styleInfo": "字幕のスタイル変更が保存され、適用されました"
},
general: {
"title": "一般設定",
@@ -57,6 +59,7 @@ export default {
"applyStyle": "適用",
"cancelChange": "キャンセル",
"resetStyle": "リセット",
"longCaption": "長い字幕",
"fontFamily": "フォント",
"fontColor": "カラー",
"fontSize": "サイズ",

View File

@@ -1,6 +1,6 @@
export default {
example: {
"original": "This is a preview of caption styles.",
"original": "This is a preview of caption styles. ",
"translation": "(翻译)这是字幕样式预览。"
},
noti: {
@@ -21,8 +21,8 @@ export default {
"error": "发生错误",
"engineChange": "字幕引擎配置已更改",
"changeInfo": "如果字幕引擎已经启动,需要重启字幕引擎修改才会生效",
"styleChange": "字幕样式修改已更改",
"styleInfo": "字幕样式修改已经生效"
"styleChange": "字幕样式修改",
"styleInfo": "字幕样式修改已经保存并生效"
},
general: {
"title": "通用设置",
@@ -59,6 +59,7 @@ export default {
"applyStyle": "应用样式",
"cancelChange": "取消更改",
"resetStyle": "恢复默认",
"longCaption": "长字幕",
"fontFamily": "字体族",
"fontColor": "字体颜色",
"fontSize": "字体大小",

View File

@@ -1,8 +1,10 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
import { Styles } from '@renderer/types'
import { breakOptions } from '@renderer/i18n'
export const useCaptionStyleStore = defineStore('captionStyle', () => {
const lineBreak = ref<number>(1)
const fontFamily = ref<string>('sans-serif')
const fontSize = ref<number>(24)
const fontColor = ref<string>('#000000')
@@ -14,6 +16,7 @@ export const useCaptionStyleStore = defineStore('captionStyle', () => {
const transFontSize = ref<number>(24)
const transFontColor = ref<string>('#000000')
const iBreakOptions = ref(breakOptions['zh'])
const changeSignal = ref<boolean>(false)
function addOpicityToColor(color: string, opicity: number) {
@@ -28,6 +31,7 @@ export const useCaptionStyleStore = defineStore('captionStyle', () => {
function sendStylesChange() {
const styles: Styles = {
lineBreak: lineBreak.value,
fontFamily: fontFamily.value,
fontSize: fontSize.value,
fontColor: fontColor.value,
@@ -47,6 +51,7 @@ export const useCaptionStyleStore = defineStore('captionStyle', () => {
}
function setStyles(args: Styles){
lineBreak.value = args.lineBreak
fontFamily.value = args.fontFamily
fontSize.value = args.fontSize
fontColor.value = args.fontColor
@@ -65,6 +70,7 @@ export const useCaptionStyleStore = defineStore('captionStyle', () => {
})
return {
lineBreak, // 换行方式
fontFamily, // 字体族
fontSize, // 字体大小
fontColor, // 字体颜色
@@ -79,6 +85,7 @@ export const useCaptionStyleStore = defineStore('captionStyle', () => {
setStyles, // 设置样式
sendStylesChange, // 发送样式改变
sendStylesReset, // 恢复默认样式
iBreakOptions, // 换行选项
changeSignal // 样式改变信号
}
})

View File

@@ -3,8 +3,9 @@ import { defineStore } from 'pinia'
import { i18n } from '../i18n'
import type { UILanguage, UITheme } from '../types'
import { engines, audioTypes, antDesignTheme } from '../i18n'
import { engines, audioTypes, antDesignTheme, breakOptions } from '../i18n'
import { useEngineControlStore } from './engineControl'
import { useCaptionStyleStore } from './captionStyle'
export const useGeneralSettingStore = defineStore('generalSetting', () => {
const uiLanguage = ref<UILanguage>('zh')
@@ -17,6 +18,7 @@ export const useGeneralSettingStore = defineStore('generalSetting', () => {
i18n.global.locale.value = newValue
useEngineControlStore().captionEngine = engines[newValue]
useEngineControlStore().audioType = audioTypes[newValue]
useCaptionStyleStore().iBreakOptions = breakOptions[newValue]
window.electron.ipcRenderer.send('control.uiLanguage.change', newValue)
})
@@ -49,12 +51,16 @@ export const useGeneralSettingStore = defineStore('generalSetting', () => {
antdTheme.value = antDesignTheme.light
const root = document.documentElement
root.style.setProperty('--control-background', '#fff')
root.style.setProperty('--tag-color', 'rgba(0, 0, 0, 0.45)')
root.style.setProperty('--icon-color', 'rgba(0, 0, 0, 0.88)')
}
function setDarkTheme(){
antdTheme.value = antDesignTheme.dark
const root = document.documentElement
root.style.setProperty('--control-background', '#000')
root.style.setProperty('--tag-color', 'rgba(255, 255, 255, 0.45)')
root.style.setProperty('--icon-color', 'rgba(255, 255, 255, 0.85)')
}
return {

View File

@@ -15,6 +15,7 @@ export interface Controls {
}
export interface Styles {
lineBreak: number,
fontFamily: string,
fontSize: number,
fontColor: string,

View File

@@ -20,7 +20,7 @@
</div>
</div>
<div class="caption-container">
<p class="preview-caption" :style="{
<p :class="[captionStyle.lineBreak?'':'left-ellipsis']" :style="{
fontFamily: captionStyle.fontFamily,
fontSize: captionStyle.fontSize + 'px',
color: captionStyle.fontColor
@@ -28,7 +28,9 @@
<span v-if="captionData.length">{{ captionData[captionData.length-1].text }}</span>
<span v-else>{{ $t('example.original') }}</span>
</p>
<p class="preview-translation" v-if="captionStyle.transDisplay" :style="{
<p :class="[captionStyle.lineBreak?'':'left-ellipsis']"
v-if="captionStyle.transDisplay"
:style="{
fontFamily: captionStyle.transFontFamily,
fontSize: captionStyle.transFontSize + 'px',
color: captionStyle.transFontColor
@@ -121,4 +123,16 @@ function closeCaptionWindow() {
line-height: 1.5em;
padding: 0 10px 10px 10px;
}
.left-ellipsis {
white-space: nowrap;
overflow: hidden;
direction: rtl;
text-align: left;
}
.left-ellipsis > span {
direction: ltr;
display: inline-block;
}
</style>

View File

@@ -39,7 +39,7 @@ const { leftBarWidth, antdTheme } = storeToRefs(generalSettingStore)
.caption-control {
height: 100vh;
border-right: 1px solid #7774;
border-right: 1px solid var(--tag-color);
padding: 20px;
overflow-y: auto;
}