mirror of
https://github.com/YaoFANGUK/video-subtitle-remover.git
synced 2026-04-13 16:07:32 +08:00
添加任务列表组件并优化视频加载逻辑 支持可视化显示字幕区域 整理所有模型, 分别为STTN智能擦除, STTN字幕检测, LAMA, ProPainter, OpenCV 提高处理性能 新增CPU运行模式并优化多语言支持 修复Propainter模式部分视频报错 本次提交新增了CPU运行模式,适用于无GPU加速的场景。同时,优化了多语言支持,新增了日语、韩语、越南语等语言配置文件,并更新了README文档以反映新的运行模式和多语言支持。此外,修复了部分代码逻辑,提升了系统的稳定性和兼容性。
128 lines
4.2 KiB
Python
128 lines
4.2 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
@desc: 进程管理器,用于管理和终止子进程
|
||
"""
|
||
import weakref
|
||
import signal
|
||
import os
|
||
import platform
|
||
import logging
|
||
import atexit
|
||
import subprocess
|
||
import concurrent.futures
|
||
|
||
class ProcessManager:
|
||
"""
|
||
进程管理器类,用于管理子进程的生命周期
|
||
使用弱引用避免内存泄漏
|
||
"""
|
||
_instance = None
|
||
|
||
@classmethod
|
||
def instance(cls):
|
||
"""单例模式获取实例"""
|
||
if cls._instance is None:
|
||
cls._instance = ProcessManager()
|
||
return cls._instance
|
||
|
||
def __init__(self):
|
||
"""初始化进程管理器"""
|
||
self.processes = {}
|
||
self.logger = logging.getLogger(__name__)
|
||
|
||
# 注册退出处理函数
|
||
atexit.register(self.terminate_all)
|
||
|
||
def add_process(self, process, name=None):
|
||
"""
|
||
添加进程到管理器
|
||
|
||
Args:
|
||
process: 要添加的进程对象 (subprocess.Popen实例)
|
||
name: 进程名称,如果不提供则使用进程ID
|
||
"""
|
||
if process is None:
|
||
return
|
||
|
||
process_id = name or f"Process:{id(process)}"
|
||
self.processes[process_id] = process
|
||
print(f"Added process: {process_id}, PID: {process.pid if hasattr(process, 'pid') else 'unknown'}")
|
||
return process_id
|
||
|
||
def add_pid(self, pid, name=None):
|
||
process_id = name or f"Pid:{pid}"
|
||
self.processes[process_id] = pid
|
||
print(f"Added process: {process_id}, PID: {pid}")
|
||
return process_id
|
||
|
||
def remove_process(self, process_id):
|
||
"""
|
||
从管理器中移除进程
|
||
|
||
Args:
|
||
process_id: 进程ID或名称
|
||
"""
|
||
if process_id in self.processes:
|
||
del self.processes[process_id]
|
||
print(f"Removed process: {process_id}")
|
||
return True
|
||
return False
|
||
|
||
def terminate_all(self):
|
||
"""并发终止所有管理的进程"""
|
||
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||
futures = []
|
||
for process_id, process in list(self.processes.items()):
|
||
if isinstance(process, int):
|
||
futures.append(executor.submit(self.terminate_by_pid, process))
|
||
else:
|
||
futures.append(executor.submit(self.terminate_by_process, process))
|
||
|
||
# 等待所有终止操作完成
|
||
concurrent.futures.wait(futures)
|
||
|
||
# 清空进程字典
|
||
self.processes.clear()
|
||
|
||
def terminate_by_process(self, process):
|
||
if process is None:
|
||
return
|
||
try:
|
||
print(f"Terminating process: pid: {process.pid}")
|
||
if hasattr(process, 'poll') and process.poll() is not None:
|
||
# 进程已经结束,直接返回
|
||
return
|
||
|
||
# 进程还在运行
|
||
process.terminate()
|
||
if hasattr(process, 'join'):
|
||
try:
|
||
process.join(timeout=3)
|
||
except:
|
||
pass
|
||
if hasattr(process, 'wait'):
|
||
try:
|
||
process.wait(timeout=3)
|
||
except:
|
||
pass
|
||
# 进程未能正常终止,尝试强制终止
|
||
if hasattr(process, 'kill'):
|
||
process.kill()
|
||
except Exception as e:
|
||
# print(f"Error terminating process: {str(e)}")
|
||
pass
|
||
self.terminate_by_pid(process.pid)
|
||
|
||
def terminate_by_pid(self, pid):
|
||
try:
|
||
# 使用系统命令强制终止进程
|
||
if platform.system() == 'Windows':
|
||
subprocess.run(['taskkill', '/F', '/T', '/PID', str(pid)],
|
||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3)
|
||
else:
|
||
subprocess.run(['pkill', '-9', '-P', str(pid)],
|
||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=2)
|
||
subprocess.run(['kill', '-9', str(pid)],
|
||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3)
|
||
except Exception as e:
|
||
print(f"Error forcibly terminating process with PID {pid}: {str(e)}") |