支持设置视频保存路径

This commit is contained in:
Jason
2025-05-22 09:30:24 +08:00
parent 70488eb290
commit afcc93b9cc
12 changed files with 89 additions and 16 deletions

View File

@@ -2,7 +2,7 @@
import os
from pathlib import Path
from qfluentwidgets import (qconfig, ConfigItem, QConfig, OptionsValidator, BoolValidator, OptionsConfigItem,
EnumSerializer, RangeValidator, RangeConfigItem)
EnumSerializer, RangeValidator, RangeConfigItem, ConfigValidator)
from backend.tools.constant import InpaintMode, SubtitleDetectMode
import configparser
@@ -105,6 +105,9 @@ class Config(QConfig):
# 启动时检查应用更新
checkUpdateOnStartup = ConfigItem("Main", "CheckUpdateOnStartup", True, BoolValidator())
# 视频保存目录
saveDirectory = ConfigItem("Main", "SaveDirectory", "", ConfigValidator())
CONFIG_FILE = 'config/config.json'
config = Config()
qconfig.load(CONFIG_FILE, config)

View File

@@ -43,6 +43,9 @@ UpdatesAvailableTitle = 有可用更新
UpdatesAvailableDesc = 发现新版本 {}, 是否更新?
NoUpdatesAvailableTitle = 无可用更新
NoUpdatesAvailableDesc = 软件已是最新版本
ChooseDirectory = 选择文件夹
SaveDirectory = 视频保存目录
SaveDirectoryDefault = 默认保存到输入视频当前目录
[SubtitleExtractorGUI]
Title = 字幕去除器

View File

@@ -43,6 +43,9 @@ UpdatesAvailableTitle = 有可用更新
UpdatesAvailableDesc = 發現新版本 {},是否更新?
NoUpdatesAvailableTitle = 無可用更新
NoUpdatesAvailableDesc = 軟體已是最新版本
ChooseDirectory = 選擇資料夾
SaveDirectory = 影片保存目錄
SaveDirectoryDefault = 預設保存到輸入影片的當前目錄
[SubtitleExtractorGUI]
Title = 字幕去除器

View File

@@ -42,7 +42,10 @@ CheckUpdateOnStartupDesc = New versions offer improved stability and features (r
UpdatesAvailableTitle = Update Available
UpdatesAvailableDesc = New version {} found. Update now?
NoUpdatesAvailableTitle = No Updates Available
NoUpdatesAvailableDesc = Software is up-to-date.
NoUpdatesAvailableDesc = Software is up-to-date.
ChooseDirectory = Choose Folder
SaveDirectory = Video save directory
SaveDirectoryDefault = Default save to the current directory of the input video
[SubtitleExtractorGUI]
Title = Subtitle Remover

View File

@@ -43,6 +43,9 @@ UpdatesAvailableTitle = Actualización disponible
UpdatesAvailableDesc = Nueva versión {} disponible. ¿Actualizar ahora?
NoUpdatesAvailableTitle = Sin actualizaciones
NoUpdatesAvailableDesc = El software está actualizado.
ChooseDirectory = Seleccionar Carpeta
SaveDirectory = Directorio de guardado de video
SaveDirectoryDefault = Guardar por defecto en el directorio actual del video de entrada
[SubtitleExtractorGUI]
Title = Eliminador de subtítulos

View File

@@ -43,6 +43,9 @@ UpdatesAvailableTitle = 利用可能なアップデート
UpdatesAvailableDesc = 新バージョン {} を発見。更新しますか?
NoUpdatesAvailableTitle = 利用可能なアップデートなし
NoUpdatesAvailableDesc = 最新バージョンです
ChooseDirectory = フォルダを選択
SaveDirectory = 動画保存ディレクトリ
SaveDirectoryDefault = 入力動画の現在ディレクトリにデフォルトで保存
[SubtitleExtractorGUI]
Title = 字幕除去ツール

View File

@@ -43,6 +43,9 @@ UpdatesAvailableTitle = 업데이트 가능
UpdatesAvailableDesc = 새 버전 {} 발견. 업데이트할까요?
NoUpdatesAvailableTitle = 사용 가능한 업데이트 없음
NoUpdatesAvailableDesc = 최신 버전입니다.
ChooseDirectory = 폴더 선택
SaveDirectory = 동영상 저장 디렉터리
SaveDirectoryDefault = 입력 동영상의 현재 디렉터리에 기본 저장
[SubtitleExtractorGUI]
Title = 자막 제거 도구

View File

@@ -43,6 +43,9 @@ UpdatesAvailableTitle = Có bản cập nhật
UpdatesAvailableDesc = Phát hiện phiên bản mới {}, cập nhật?
NoUpdatesAvailableTitle = Không có cập nhật
NoUpdatesAvailableDesc = Đang dùng phiên bản mới nhất
ChooseDirectory = Chọn Thư Mục
SaveDirectory = Thư mục lưu video
SaveDirectoryDefault = Mặc định lưu vào thư mục hiện tại của video đầu vào
[SubtitleExtractorGUI]
Title = Công cụ xóa phụ đề

View File

@@ -337,6 +337,7 @@ class SubtitleRemover:
self.append_output(tr['Main']['SubtitleDetectionAcceleratorON'].format(accelerator_name))
if accelerator_name == 'DirectML' and config.inpaintMode.value not in [InpaintMode.STTN_AUTO, InpaintMode.STTN_DET]:
self.append_output(tr['Main']['DirectMLWarning'])
os.makedirs(os.path.dirname(self.video_out_path), exist_ok=True)
# 重置进度条
self.progress_total = 0
tbar = tqdm(total=int(self.frame_count), unit='frame', position=0, file=sys.__stdout__,

View File

@@ -3,10 +3,11 @@
"""
from PySide6 import QtWidgets, QtCore, QtGui
from PySide6.QtWidgets import QFileDialog
from qfluentwidgets import (ScrollArea, ExpandLayout, CardWidget, SubtitleLabel,
FluentIcon, NavigationWidget, NavigationItemPosition,
SettingCardGroup, RangeSettingCard, SwitchSettingCard,
HyperlinkCard, PrimaryPushSettingCard, ComboBoxSettingCard,
HyperlinkCard, PrimaryPushSettingCard, PushSettingCard,
MessageBox)
from backend.config import config, tr, VERSION, PROJECT_HOME_URL, PROJECT_ISSUES_URL, PROJECT_RELEASES_URL
from backend.tools.version_service import VersionService
@@ -58,6 +59,7 @@ class AdvancedSettingInterface(ScrollArea):
self.propainter_group.addSettingCard(self.propainter_max_load_num)
self.expandLayout.addWidget(self.propainter_group)
self.advanced_group.addSettingCard(self.save_directory)
self.advanced_group.addSettingCard(self.check_update_on_startup)
self.expandLayout.addWidget(self.advanced_group)
@@ -170,6 +172,16 @@ class AdvancedSettingInterface(ScrollArea):
parent=self.propainter_group
)
# 视频保存路径
self.save_directory = PushSettingCard(
text=tr["Setting"]["ChooseDirectory"],
icon=FluentIcon.DOWNLOAD,
title=tr["Setting"]["SaveDirectory"],
content=tr["Setting"]["SaveDirectoryDefault"] if not config.saveDirectory.value else config.saveDirectory.value,
parent=self.advanced_group
)
self.save_directory.clicked.connect(self.choose_save_directory)
self.check_update_on_startup = SwitchSettingCard(
configItem=config.checkUpdateOnStartup,
icon=FluentIcon.UPDATE,
@@ -244,4 +256,15 @@ class AdvancedSettingInterface(ScrollArea):
self.show_message_box(
tr["Setting"]["NoUpdatesAvailableTitle"],
tr["Setting"]["NoUpdatesAvailableDesc"],
)
)
def choose_save_directory(self):
"""选择保存目录"""
last_save_directory = "./" if not config.saveDirectory.value else config.saveDirectory.value
folder = QFileDialog.getExistingDirectory(
self, tr['Setting']['ChooseDirectory'], last_save_directory)
if not folder:
folder = ""
config.set(config.saveDirectory, folder)
self.save_directory.setContent(tr["Setting"]["SaveDirectoryDefault"] if not config.saveDirectory.value else config.saveDirectory.value)

View File

@@ -1,13 +1,17 @@
import os
from pathlib import Path
from enum import Enum, unique
from dataclasses import dataclass
from functools import cached_property
from PySide6.QtWidgets import QWidget, QVBoxLayout, QMenu, QAbstractItemView, QTableWidgetItem, QHeaderView
from PySide6.QtCore import Qt, Signal, QModelIndex, QUrl
from qfluentwidgets import TableWidget, BodyLabel, FluentIcon, InfoBar, InfoBarPosition
from PySide6.QtGui import QAction, QColor, QBrush
from showinfm import show_in_file_manager
from backend.config import tr
from backend.config import config, tr
from backend.tools.common_tools import is_image_file
@unique
class TaskStatus(Enum):
@@ -28,8 +32,30 @@ class Task:
name: str
progress: int
status: TaskStatus
output_path: str
options: dict
# 用于储存只读的输出路径, 在任务完成后设置
_output_path: str = None
@property
def output_path(self):
"""获取输出路径"""
if self._output_path is not None:
return self._output_path
save_directory = os.path.dirname(self.path) if not config.saveDirectory.value else config.saveDirectory.value
if self.is_image:
output_path = os.path.abspath(os.path.join(save_directory, f'{Path(self.path).stem}_no_sub.png'))
else:
output_path = os.path.abspath(os.path.join(save_directory, f'{Path(self.path).stem}_no_sub.mp4'))
return output_path
@output_path.setter
def output_path(self, value):
self._output_path = value
@cached_property
def is_image(self):
"""判断是否是图片文件"""
return is_image_file(self.path)
class TaskListComponent(QWidget):
"""任务列表组件"""
@@ -81,7 +107,7 @@ class TaskListComponent(QWidget):
layout.addWidget(self.table)
def add_task(self, video_path, output_path):
def add_task(self, video_path):
"""添加任务到列表
Args:
@@ -102,7 +128,6 @@ class TaskListComponent(QWidget):
name=file_name,
progress=0,
status=TaskStatus.PENDING,
output_path=output_path,
options={},
)
self.tasks.append(task)

View File

@@ -4,7 +4,6 @@ import threading
import multiprocessing
import time
import traceback
from pathlib import Path
from PySide6.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout
from PySide6.QtCore import Slot, QRect, Signal
from PySide6 import QtWidgets
@@ -13,7 +12,7 @@ from ui.setting_interface import SettingInterface
from ui.component.video_display_component import VideoDisplayComponent
from ui.component.task_list_component import TaskListComponent, TaskStatus, TaskOptions
from ui.icon.my_fluent_icon import MyFluentIcon
from backend.config import tr
from backend.config import config, tr
from backend.tools.subtitle_remover_remote_call import SubtitleRemoverRemoteCall
from backend.tools.process_manager import ProcessManager
from backend.tools.common_tools import get_readable_path, is_image_file, read_image
@@ -344,12 +343,17 @@ class HomeInterface(QWidget):
if key == TaskOptions.SUB_AREAS.value:
value = self.video_display_component.preview_coordinates_to_video_coordinates(value)
options[key] = value
process = self.run_subtitle_remover_process(task.path, task.output_path, options)
# 清理缓存, 使用动态路径
task.output_path = None
output_path = task.output_path
process = self.run_subtitle_remover_process(task.path, output_path, options)
# 更新任务状态为已完成
task = self.task_list_component.get_task(self.current_processing_task_index)
if process.exitcode == 0 and task and task.status == TaskStatus.PROCESSING:
self.progress_signal.emit(100, True)
# 任务完成, 更新输出路径为只读
task.output_path = output_path
self.task_list_component.update_task_status(self.current_processing_task_index, TaskStatus.COMPLETED)
else:
self.task_list_component.update_task_status(self.current_processing_task_index, TaskStatus.FAILED)
@@ -584,11 +588,7 @@ class HomeInterface(QWidget):
# 正序添加, 确保任务列表顺序一致
for path in reversed(files_loaded):
# 添加到任务列表
if is_image_file(path):
output_path = os.path.abspath(os.path.join(os.path.dirname(path), f'{Path(path).stem}_no_sub.png'))
else:
output_path = os.path.abspath(os.path.join(os.path.dirname(path), f'{Path(path).stem}_no_sub.mp4'))
self.task_list_component.add_task(path, output_path)
self.task_list_component.add_task(path)
index = max(0, self.task_list_component.find_task_index_by_path(path))
self.task_list_component.select_task(index)