Files
video-subtitle-remover/ui/advanced_setting_interface.py
Jason f78e985e1c 使用PySide6-Fluent-Widgets重构整套UI
添加任务列表组件并优化视频加载逻辑
支持可视化显示字幕区域
整理所有模型, 分别为STTN智能擦除, STTN字幕检测, LAMA, ProPainter, OpenCV
提高处理性能
新增CPU运行模式并优化多语言支持
修复Propainter模式部分视频报错

本次提交新增了CPU运行模式,适用于无GPU加速的场景。同时,优化了多语言支持,新增了日语、韩语、越南语等语言配置文件,并更新了README文档以反映新的运行模式和多语言支持。此外,修复了部分代码逻辑,提升了系统的稳定性和兼容性。
2025-05-22 08:41:59 +08:00

247 lines
10 KiB
Python

"""
@desc: 高级设置页面
"""
from PySide6 import QtWidgets, QtCore, QtGui
from qfluentwidgets import (ScrollArea, ExpandLayout, CardWidget, SubtitleLabel,
FluentIcon, NavigationWidget, NavigationItemPosition,
SettingCardGroup, RangeSettingCard, SwitchSettingCard,
HyperlinkCard, PrimaryPushSettingCard, ComboBoxSettingCard,
MessageBox)
from backend.config import config, tr, VERSION, PROJECT_HOME_URL, PROJECT_ISSUES_URL, PROJECT_RELEASES_URL
from backend.tools.version_service import VersionService
from backend.tools.concurrent import TaskExecutor
class AdvancedSettingInterface(ScrollArea):
"""高级设置页面"""
def __init__(self, parent=None):
super().__init__(parent)
self.parent = parent
self.version_manager = VersionService()
self.__initWidget()
def __initWidget(self):
# 创建滚动内容的容器
self.scrollWidget = QtWidgets.QWidget(self)
self.expandLayout = ExpandLayout(self.scrollWidget)
# 设置滚动区域属性
self.setWidget(self.scrollWidget)
self.enableTransparentBackground()
self.setWidgetResizable(True)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
# 设置滚动区域样式以适应主题
self.setAttribute(QtCore.Qt.WA_StyledBackground)
# 设置UI
self.setup_ui()
self.setup_layout()
def setup_layout(self):
self.subtitle_detection_group.addSettingCard(self.subtitle_yx_axis_difference_pixel)
self.subtitle_detection_group.addSettingCard(self.subtitle_area_deviation_pixel)
self.subtitle_detection_group.addSettingCard(self.subtitle_area_y_axis_difference_pixel)
self.subtitle_detection_group.addSettingCard(self.subtitle_area_pixel_tolerance_y_pixel)
self.subtitle_detection_group.addSettingCard(self.subtitle_area_pixel_tolerance_x_pixel)
self.subtitle_detection_group.addSettingCard(self.subtitle_timeline_backward_frame_count)
self.subtitle_detection_group.addSettingCard(self.subtitle_timeline_forward_frame_count)
self.expandLayout.addWidget(self.subtitle_detection_group)
self.sttn_group.addSettingCard(self.sttn_neighbor_stride)
self.sttn_group.addSettingCard(self.sttn_reference_length)
self.sttn_group.addSettingCard(self.sttn_max_load_num)
self.expandLayout.addWidget(self.sttn_group)
self.propainter_group.addSettingCard(self.propainter_max_load_num)
self.expandLayout.addWidget(self.propainter_group)
self.advanced_group.addSettingCard(self.check_update_on_startup)
self.expandLayout.addWidget(self.advanced_group)
self.about_group.addSettingCard(self.feedback)
self.about_group.addSettingCard(self.copyright)
self.about_group.addSettingCard(self.project_link)
self.expandLayout.addWidget(self.about_group)
self.expandLayout.setSpacing(16)
self.expandLayout.setContentsMargins(16, 16, 16, 48)
def setup_ui(self):
"""设置UI"""
# 字幕检测设置组
self.subtitle_detection_group = SettingCardGroup(tr["Setting"]["SubtitleDetectionSetting"], self.scrollWidget)
# STTN设置组
self.sttn_group = SettingCardGroup(tr["Setting"]["SttnSetting"], self.scrollWidget)
# Propainter设置组
self.propainter_group = SettingCardGroup(tr["Setting"]["ProPainterSetting"], self.scrollWidget)
# 高级设置组
self.advanced_group = SettingCardGroup(tr["Setting"]["AdvancedSetting"], self.scrollWidget)
# 关于设置组
self.about_group = SettingCardGroup(tr["Setting"]["AboutSetting"], self.scrollWidget)
self.subtitle_yx_axis_difference_pixel = RangeSettingCard(
configItem=config.subtitleYXAxisDifferencePixel,
icon=FluentIcon.ZOOM,
title=tr["Setting"]["SubtitleYXAxisDifferencePixel"],
content=tr["Setting"]["SubtitleYXAxisDifferencePixelDesc"],
parent=self.subtitle_detection_group
)
self.subtitle_area_deviation_pixel = RangeSettingCard(
configItem=config.subtitleAreaDeviationPixel,
icon=FluentIcon.ZOOM_IN,
title=tr["Setting"]["SubtitleAreaDeviationPixel"],
content=tr["Setting"]["SubtitleAreaDeviationPixelDesc"],
parent=self.subtitle_detection_group
)
self.subtitle_area_y_axis_difference_pixel = RangeSettingCard(
configItem=config.subtitleAreaYAxisDifferencePixel,
icon=FluentIcon.ALIGNMENT,
title=tr["Setting"]["SubtitleAreaYAxisDifferencePixel"],
content=tr["Setting"]["SubtitleAreaYAxisDifferencePixelDesc"],
parent=self.subtitle_detection_group
)
self.subtitle_area_pixel_tolerance_y_pixel = RangeSettingCard(
configItem=config.subtitleAreaPixelToleranceYPixel,
icon=FluentIcon.UP,
title=tr["Setting"]["SubtitleAreaPixelToleranceYPixel"],
content=tr["Setting"]["SubtitleAreaPixelToleranceYPixelDesc"],
parent=self.subtitle_detection_group
)
self.subtitle_area_pixel_tolerance_x_pixel = RangeSettingCard(
configItem=config.subtitleAreaPixelToleranceXPixel,
icon=FluentIcon.RIGHT_ARROW,
title=tr["Setting"]["SubtitleAreaPixelToleranceXPixel"],
content=tr["Setting"]["SubtitleAreaPixelToleranceXPixelDesc"],
parent=self.subtitle_detection_group
)
self.subtitle_timeline_backward_frame_count = RangeSettingCard(
configItem=config.subtitleTimelineBackwardFrameCount,
icon=FluentIcon.PAGE_LEFT,
title=tr["Setting"]["SubtitleTimelineBackwardFrameCount"],
content=tr["Setting"]["SubtitleTimelineBackwardFrameCountDesc"],
parent=self.subtitle_detection_group
)
self.subtitle_timeline_forward_frame_count = RangeSettingCard(
configItem=config.subtitleTimelineForwardFrameCount,
icon=FluentIcon.PAGE_RIGHT,
title=tr["Setting"]["subtitleTimelineForwardFrameCount"],
content=tr["Setting"]["subtitleTimelineForwardFrameCountDesc"],
parent=self.subtitle_detection_group
)
self.sttn_neighbor_stride = RangeSettingCard(
configItem=config.sttnNeighborStride,
icon=FluentIcon.UNIT,
title=tr["Setting"]["SttnNeighborStride"],
content=tr["Setting"]["SttnNeighborStrideDesc"],
parent=self.sttn_group
)
self.sttn_reference_length = RangeSettingCard(
configItem=config.sttnReferenceLength,
icon=FluentIcon.MORE,
title=tr["Setting"]["SttnReferenceLength"],
content=tr["Setting"]["SttnReferenceLengthDesc"],
parent=self.sttn_group
)
self.sttn_max_load_num = RangeSettingCard(
configItem=config.sttnMaxLoadNum,
icon=FluentIcon.DICTIONARY,
title=tr["Setting"]["SttnMaxLoadNum"],
content=tr["Setting"]["SttnMaxLoadNumDesc"],
parent=self.sttn_group
)
self.propainter_max_load_num = RangeSettingCard(
configItem=config.propainterMaxLoadNum,
icon=FluentIcon.DICTIONARY,
title=tr["Setting"]["PropainterMaxLoadNum"],
content=tr["Setting"]["PropainterMaxLoadNumDesc"],
parent=self.propainter_group
)
self.check_update_on_startup = SwitchSettingCard(
configItem=config.checkUpdateOnStartup,
icon=FluentIcon.UPDATE,
title=tr["Setting"]["CheckUpdateOnStartup"],
content=tr["Setting"]["CheckUpdateOnStartupDesc"],
parent=self.advanced_group
)
# 添加反馈链接
self.feedback = PrimaryPushSettingCard(
text=tr["Setting"]["FeedbackButton"],
icon=FluentIcon.MAIL,
title=tr["Setting"]["FeedbackTitle"],
content=tr["Setting"]["FeedbackDesc"],
parent=self.about_group
)
self.feedback.clicked.connect(lambda: QtGui.QDesktopServices.openUrl(
QtCore.QUrl(PROJECT_ISSUES_URL)
))
# 添加版权信息
self.copyright = PrimaryPushSettingCard(
text=tr["Setting"]["CopyrightButton"],
icon=FluentIcon.MAIL,
title=tr["Setting"]["CopyrightTitle"],
content=tr["Setting"]["CopyrightDesc"].format(VERSION),
parent=self.about_group
)
self.copyright.clicked.connect(lambda: self.check_update())
# 添加项目链接
self.project_link = HyperlinkCard(
url=PROJECT_HOME_URL,
text=PROJECT_HOME_URL,
icon=FluentIcon.GITHUB,
title=tr["Setting"]["ProjectLinkTitle"],
content=tr["Setting"]["ProjectLinkDesc"],
parent=self.about_group
)
def show_message_box(self, title: str, content: str, showYesButton=False, yesSlot=None):
""" show message box """
w = MessageBox(title, content, self)
if not showYesButton:
w.cancelButton.setText(self.tr('Close'))
w.yesButton.hide()
w.buttonLayout.insertStretch(0, 1)
if w.exec() and yesSlot is not None:
yesSlot()
def check_update(self, ignore=False):
""" check software update
Parameters
----------
ignore: bool
ignore message box when no updates are available
"""
TaskExecutor.runTask(self.version_manager.has_new_version).then(
lambda success: self.on_version_info_fetched(success, ignore))
def on_version_info_fetched(self, success, ignore=False):
if success:
self.show_message_box(
tr["Setting"]["UpdatesAvailableTitle"],
tr["Setting"]["UpdatesAvailableDesc"].format(self.version_manager.lastest_version),
True,
lambda: QtGui.QDesktopServices.openUrl(
QtCore.QUrl(PROJECT_RELEASES_URL)
)
)
elif not ignore:
self.show_message_box(
tr["Setting"]["NoUpdatesAvailableTitle"],
tr["Setting"]["NoUpdatesAvailableDesc"],
)