mirror of
https://github.com/YaoFANGUK/video-subtitle-remover.git
synced 2026-04-19 13:27:34 +08:00
添加任务列表组件并优化视频加载逻辑 支持可视化显示字幕区域 整理所有模型, 分别为STTN智能擦除, STTN字幕检测, LAMA, ProPainter, OpenCV 提高处理性能 新增CPU运行模式并优化多语言支持 修复Propainter模式部分视频报错 本次提交新增了CPU运行模式,适用于无GPU加速的场景。同时,优化了多语言支持,新增了日语、韩语、越南语等语言配置文件,并更新了README文档以反映新的运行模式和多语言支持。此外,修复了部分代码逻辑,提升了系统的稳定性和兼容性。
248 lines
6.7 KiB
Python
248 lines
6.7 KiB
Python
from typing import List, Optional, Callable, Iterable, Sized, Tuple, Union
|
|
|
|
from PySide6.QtCore import QObject, Signal, QMutex, QSemaphore
|
|
|
|
|
|
class FutureError(BaseException):
|
|
pass
|
|
|
|
|
|
class FutureFailed(FutureError):
|
|
def __init__(self, _exception: Optional[BaseException]):
|
|
super().__init__()
|
|
self.exception = _exception
|
|
|
|
def __repr__(self):
|
|
return f"FutureFailed({self.exception})"
|
|
|
|
def __str__(self):
|
|
return f"FutureFailed({self.exception})"
|
|
|
|
|
|
class GatheredFutureFailed(FutureError):
|
|
def __init__(self, failures: List[Tuple['Future', BaseException]]):
|
|
super().__init__()
|
|
self.failures = failures
|
|
|
|
def __repr__(self):
|
|
return f"GatheredFutureFailed({self.failures})"
|
|
|
|
def __str__(self):
|
|
return f"GatheredFutureFailed({self.failures})"
|
|
|
|
def __iter__(self):
|
|
return iter(self.failures)
|
|
|
|
def __len__(self):
|
|
return len(self.failures)
|
|
|
|
|
|
class FutureCancelled(FutureError):
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def __repr__(self):
|
|
return f"FutureCanceled()"
|
|
|
|
def __str__(self):
|
|
return f"FutureCanceled()"
|
|
|
|
|
|
class Future(QObject):
|
|
result = Signal(object) # self
|
|
done = Signal(object) # self
|
|
failed = Signal(object) # self
|
|
partialDone = Signal(object) # child future
|
|
childrenDone = Signal(object) # self
|
|
|
|
def __init__(self, semaphore=0):
|
|
super().__init__()
|
|
self._taskID = None
|
|
self._failedCallback = lambda e: None
|
|
self._done = False
|
|
self._failed = False
|
|
self._result = None
|
|
self._exception = None
|
|
self._children = []
|
|
self._counter = 0
|
|
self._parent = None
|
|
self._callback = lambda _: None
|
|
self._mutex = QMutex()
|
|
self._extra = {}
|
|
self._semaphore = QSemaphore(semaphore)
|
|
|
|
def __onChildDone(self, childFuture: 'Future') -> None:
|
|
self._mutex.lock()
|
|
if childFuture.isFailed():
|
|
self._failed = True
|
|
self._counter += 1
|
|
self.partialDone.emit(childFuture)
|
|
try:
|
|
idx = getattr(childFuture, "_idx")
|
|
self._result[idx] = childFuture._result
|
|
self._mutex.unlock()
|
|
except AttributeError:
|
|
self._mutex.unlock()
|
|
raise RuntimeError(
|
|
"Invalid child future: please ensure that the child future is created by method 'Future.setChildren'")
|
|
|
|
if self._counter == len(self._children):
|
|
if self._failed: # set failed
|
|
l = []
|
|
|
|
for i, child in enumerate(self._children):
|
|
if isinstance(e := child.getException(), FutureError):
|
|
l.append((self._children[i], e))
|
|
|
|
self.setFailed(GatheredFutureFailed(l))
|
|
else:
|
|
self.setResult(self._result)
|
|
|
|
def __setChildren(self, children: List['Future']) -> None:
|
|
self._children = children
|
|
self._result = [None] * len(children)
|
|
|
|
for i, fut in enumerate(self._children):
|
|
setattr(fut, f"_idx", i)
|
|
fut.childrenDone.connect(self.__onChildDone)
|
|
fut._parent = self
|
|
|
|
for i, fut in enumerate(self._children): # check if child is done
|
|
if fut.isDone():
|
|
self.__onChildDone(fut)
|
|
|
|
def setResult(self, result) -> None:
|
|
"""
|
|
:param result: The result to set
|
|
:return: None
|
|
|
|
do not set result in thread pool,or it may not set correctly
|
|
please use in main thread,or use signal-slot to set result !!!
|
|
"""
|
|
if self._done:
|
|
raise RuntimeError("Future already done")
|
|
|
|
self._result = result
|
|
self._done = True
|
|
|
|
if self._parent:
|
|
self.childrenDone.emit(self)
|
|
|
|
if self._callback:
|
|
self._callback(result)
|
|
|
|
self.result.emit(result)
|
|
self.done.emit(self)
|
|
|
|
def setFailed(self, exception) -> None:
|
|
"""
|
|
:param exception: The exception to set
|
|
:return: None
|
|
"""
|
|
if self._done:
|
|
raise RuntimeError("Future already done")
|
|
|
|
self._exception = FutureFailed(exception)
|
|
self._done = True
|
|
self._failed = True
|
|
|
|
if self._parent:
|
|
self.childrenDone.emit(self)
|
|
|
|
if self._failedCallback:
|
|
self._failedCallback(self)
|
|
|
|
self.failed.emit(self._exception)
|
|
self.done.emit(self)
|
|
|
|
def setCallback(self, callback: Callable[[object, ], None]) -> None:
|
|
self._callback = callback
|
|
|
|
def setFailedCallback(self, callback: Callable[['Future', ], None]) -> None:
|
|
self._failedCallback = lambda e: callback(self)
|
|
|
|
def hasException(self) -> bool:
|
|
if self._children:
|
|
return any([fut.hasException() for fut in self._children])
|
|
else:
|
|
return self._exception is not None
|
|
|
|
def hasChildren(self) -> bool:
|
|
return bool(self._children)
|
|
|
|
def getException(self) -> Optional[BaseException]:
|
|
return self._exception
|
|
|
|
def setTaskID(self, _id: int) -> None:
|
|
self._taskID = _id
|
|
|
|
def getTaskID(self) -> int:
|
|
return self._taskID
|
|
|
|
def getChildren(self) -> List['Future']:
|
|
return self._children
|
|
|
|
@staticmethod
|
|
def gather(futures: {Iterable, Sized}) -> 'Future':
|
|
"""
|
|
:param futures: An iterable of Future objects
|
|
:return: A Future object that will be done when all futures are done
|
|
"""
|
|
future = Future()
|
|
future.__setChildren(futures)
|
|
return future
|
|
|
|
@property
|
|
def semaphore(self):
|
|
return self._semaphore
|
|
|
|
def wait(self):
|
|
if self.hasChildren():
|
|
for child in self.getChildren():
|
|
child.wait()
|
|
else:
|
|
self.semaphore.acquire(1)
|
|
|
|
def synchronize(self):
|
|
self.wait()
|
|
|
|
def isDone(self) -> bool:
|
|
return self._done
|
|
|
|
def isFailed(self) -> bool:
|
|
return self._failed
|
|
|
|
def getResult(self) -> Union[object, List[object]]:
|
|
return self._result
|
|
|
|
def setExtra(self, key, value):
|
|
self._extra[key] = value
|
|
|
|
def getExtra(self, key):
|
|
return self._extra.get(key, None)
|
|
|
|
def hasExtra(self, key):
|
|
return key in self._extra
|
|
|
|
def then(self, onSuccess: Callable, onFailed: Callable = None, onFinished : Callable = None):
|
|
self.result.connect(onSuccess)
|
|
|
|
if onFailed:
|
|
self.failed.connect(onFailed)
|
|
|
|
if onFinished:
|
|
self.done.connect(onFinished)
|
|
|
|
return self
|
|
|
|
def __getattr__(self, item):
|
|
return self.getExtra(item)
|
|
|
|
def __repr__(self):
|
|
return f"Future:({self._result})"
|
|
|
|
def __str__(self):
|
|
return f"Future({self._result})"
|
|
|
|
def __eq__(self, other):
|
|
return self._result == other._result |