fix:优化transhandler线程安全

This commit is contained in:
jxxghp
2026-01-21 08:42:57 +08:00
parent 68402aadd7
commit a6ed0c0d00

View File

@@ -1,6 +1,5 @@
import re import re
from pathlib import Path from pathlib import Path
from threading import Lock
from typing import Optional, List, Tuple from typing import Optional, List, Tuple
from jinja2 import Template from jinja2 import Template
@@ -25,45 +24,37 @@ class TransHandler:
文件转移整理类 文件转移整理类
""" """
inner_lock: Lock = Lock()
def __init__(self): def __init__(self):
self.result = None pass
def __reset_result(self): @staticmethod
def __update_result(result: TransferInfo, **kwargs):
""" """
重置结果 更新结果
""" """
self.result = TransferInfo() # 设置值
for key, value in kwargs.items():
def __set_result(self, **kwargs): if hasattr(result, key):
""" current_value = getattr(result, key)
设置结果 if current_value is None:
""" current_value = value
with self.inner_lock: elif isinstance(current_value, list):
# 设置值 if isinstance(value, list):
for key, value in kwargs.items(): current_value.extend(value)
if hasattr(self.result, key):
current_value = getattr(self.result, key)
if current_value is None:
current_value = value
elif isinstance(current_value, list):
if isinstance(value, list):
current_value.extend(value)
else:
current_value.append(value)
elif isinstance(current_value, dict):
if isinstance(value, dict):
current_value.update(value)
else:
current_value[key] = value
elif isinstance(current_value, bool):
current_value = value
elif isinstance(current_value, int):
current_value += (value or 0)
else: else:
current_value = value current_value.append(value)
setattr(self.result, key, current_value) elif isinstance(current_value, dict):
if isinstance(value, dict):
current_value.update(value)
else:
current_value[key] = value
elif isinstance(current_value, bool):
current_value = value
elif isinstance(current_value, int):
current_value += (value or 0)
else:
current_value = value
setattr(result, key, current_value)
def transfer_media(self, def transfer_media(self,
fileitem: FileItem, fileitem: FileItem,
@@ -122,8 +113,8 @@ class TransHandler:
return True return True
return False return False
# 重置结果 # 整理结果
self.__reset_result() result = TransferInfo()
try: try:
@@ -144,14 +135,15 @@ class TransHandler:
rename_format, rename_path=new_path rename_format, rename_path=new_path
) )
if not new_path: if not new_path:
self.__set_result( self.__update_result(
result=result,
success=False, success=False,
message="重命名格式无效", message="重命名格式无效",
fileitem=fileitem, fileitem=fileitem,
transfer_type=transfer_type, transfer_type=transfer_type,
need_notify=need_notify, need_notify=need_notify,
) )
return self.result.model_copy() return result
else: else:
new_path = target_path / fileitem.name new_path = target_path / fileitem.name
# 原盘大小只计算STREAM目录内的文件大小 # 原盘大小只计算STREAM目录内的文件大小
@@ -169,39 +161,43 @@ class TransHandler:
target_oper=target_oper, target_oper=target_oper,
target_storage=target_storage, target_storage=target_storage,
target_path=new_path, target_path=new_path,
transfer_type=transfer_type) transfer_type=transfer_type,
result=result)
if not new_diritem: if not new_diritem:
logger.error(f"文件夹 {fileitem.path} 整理失败:{errmsg}") logger.error(f"文件夹 {fileitem.path} 整理失败:{errmsg}")
self.__set_result(success=False, self.__update_result(result=result,
message=errmsg, success=False,
fileitem=fileitem, message=errmsg,
transfer_type=transfer_type, fileitem=fileitem,
need_notify=need_notify) transfer_type=transfer_type,
return self.result.model_copy() need_notify=need_notify)
return result
logger.info(f"文件夹 {fileitem.path} 整理成功") logger.info(f"文件夹 {fileitem.path} 整理成功")
# 返回整理后的路径 # 返回整理后的路径
self.__set_result(success=True, self.__update_result(result=result,
fileitem=fileitem, success=True,
target_item=new_diritem, fileitem=fileitem,
target_diritem=new_diritem, target_item=new_diritem,
need_scrape=need_scrape, target_diritem=new_diritem,
need_notify=need_notify, need_scrape=need_scrape,
transfer_type=transfer_type) need_notify=need_notify,
return self.result.model_copy() transfer_type=transfer_type)
return result
else: else:
# 整理单个文件 # 整理单个文件
if mediainfo.type == MediaType.TV: if mediainfo.type == MediaType.TV:
# 电视剧 # 电视剧
if in_meta.begin_episode is None: if in_meta.begin_episode is None:
logger.warn(f"文件 {fileitem.path} 整理失败:未识别到文件集数") logger.warn(f"文件 {fileitem.path} 整理失败:未识别到文件集数")
self.__set_result(success=False, self.__update_result(result=result,
message="未识别到文件集数", success=False,
fileitem=fileitem, message="未识别到文件集数",
fail_list=[fileitem.path], fileitem=fileitem,
transfer_type=transfer_type, fail_list=[fileitem.path],
need_notify=need_notify) transfer_type=transfer_type,
return self.result.model_copy() need_notify=need_notify)
return result
# 文件结束季为空 # 文件结束季为空
in_meta.end_season = None in_meta.end_season = None
@@ -235,7 +231,8 @@ class TransHandler:
rename_format, rename_path=new_file rename_format, rename_path=new_file
) )
if not folder_path: if not folder_path:
self.__set_result( self.__update_result(
result=result,
success=False, success=False,
message="重命名格式无效", message="重命名格式无效",
fileitem=fileitem, fileitem=fileitem,
@@ -243,7 +240,7 @@ class TransHandler:
transfer_type=transfer_type, transfer_type=transfer_type,
need_notify=need_notify, need_notify=need_notify,
) )
return self.result.model_copy() return result
else: else:
new_file = target_path / fileitem.name new_file = target_path / fileitem.name
folder_path = target_path folder_path = target_path
@@ -252,13 +249,14 @@ class TransHandler:
target_diritem = target_oper.get_folder(folder_path) target_diritem = target_oper.get_folder(folder_path)
if not target_diritem: if not target_diritem:
logger.error(f"目标目录 {folder_path} 获取失败") logger.error(f"目标目录 {folder_path} 获取失败")
self.__set_result(success=False, self.__update_result(result=result,
message=f"目标目录 {folder_path} 获取失败", success=False,
fileitem=fileitem, message=f"目标目录 {folder_path} 获取失败",
fail_list=[fileitem.path], fileitem=fileitem,
transfer_type=transfer_type, fail_list=[fileitem.path],
need_notify=need_notify) transfer_type=transfer_type,
return self.result.model_copy() need_notify=need_notify)
return result
# 判断是否要覆盖,附加文件强制覆盖 # 判断是否要覆盖,附加文件强制覆盖
overflag = False overflag = False
@@ -285,26 +283,27 @@ class TransHandler:
logger.info(f"目标文件文件大小更小,将覆盖:{new_file}") logger.info(f"目标文件文件大小更小,将覆盖:{new_file}")
overflag = True overflag = True
else: else:
self.__set_result(success=False, self.__update_result(result=result,
message=f"媒体库存在同名文件,且质量更好", success=False,
fileitem=fileitem, message=f"媒体库存在同名文件,且质量更好",
target_item=target_item, fileitem=fileitem,
target_diritem=target_diritem, target_item=target_item,
fail_list=[fileitem.path], target_diritem=target_diritem,
transfer_type=transfer_type, fail_list=[fileitem.path],
need_notify=need_notify) transfer_type=transfer_type,
return self.result.model_copy() need_notify=need_notify)
return result
elif overwrite_mode == 'never': elif overwrite_mode == 'never':
# 存在不覆盖 # 存在不覆盖
self.__set_result(success=False, self.__update_result(result=result,
message=f"媒体库存在同名文件,当前覆盖模式为不覆盖", message=f"媒体库存在同名文件,当前覆盖模式为不覆盖",
fileitem=fileitem, fileitem=fileitem,
target_item=target_item, target_item=target_item,
target_diritem=target_diritem, target_diritem=target_diritem,
fail_list=[fileitem.path], fail_list=[fileitem.path],
transfer_type=transfer_type, transfer_type=transfer_type,
need_notify=need_notify) need_notify=need_notify)
return self.result.model_copy() return result
elif overwrite_mode == 'latest': elif overwrite_mode == 'latest':
# 仅保留最新版本 # 仅保留最新版本
logger.info(f"当前整理覆盖模式设置为仅保留最新版本,将覆盖:{new_file}") logger.info(f"当前整理覆盖模式设置为仅保留最新版本,将覆盖:{new_file}")
@@ -324,28 +323,32 @@ class TransHandler:
transfer_type=transfer_type, transfer_type=transfer_type,
over_flag=overflag, over_flag=overflag,
source_oper=source_oper, source_oper=source_oper,
target_oper=target_oper) target_oper=target_oper,
result=result)
if not new_item: if not new_item:
logger.error(f"文件 {fileitem.path} 整理失败:{err_msg}") logger.error(f"文件 {fileitem.path} 整理失败:{err_msg}")
self.__set_result(success=False, self.__update_result(result=result,
message=err_msg, success=False,
fileitem=fileitem, message=err_msg,
fail_list=[fileitem.path], fileitem=fileitem,
transfer_type=transfer_type, fail_list=[fileitem.path],
need_notify=need_notify) transfer_type=transfer_type,
return self.result.model_copy() need_notify=need_notify)
return result
logger.info(f"文件 {fileitem.path} 整理成功") logger.info(f"文件 {fileitem.path} 整理成功")
self.__set_result(success=True, self.__update_result(result=result,
fileitem=fileitem, success=True,
target_item=new_item, fileitem=fileitem,
target_diritem=target_diritem, target_item=new_item,
need_scrape=need_scrape, target_diritem=target_diritem,
transfer_type=transfer_type, need_scrape=need_scrape,
need_notify=need_notify) transfer_type=transfer_type,
return self.result.model_copy() need_notify=need_notify)
finally: return result
self.result = None except Exception as e:
logger.error(f"媒体整理出错:{e}")
return TransferInfo(success=False, message=str(e))
@staticmethod @staticmethod
def __transfer_command(fileitem: FileItem, target_storage: str, def __transfer_command(fileitem: FileItem, target_storage: str,
@@ -533,7 +536,8 @@ class TransHandler:
def __transfer_dir(self, fileitem: FileItem, mediainfo: MediaInfo, def __transfer_dir(self, fileitem: FileItem, mediainfo: MediaInfo,
source_oper: StorageBase, target_oper: StorageBase, source_oper: StorageBase, target_oper: StorageBase,
transfer_type: str, target_storage: str, target_path: Path) -> Tuple[Optional[FileItem], str]: transfer_type: str, target_storage: str, target_path: Path,
result: TransferInfo) -> Tuple[Optional[FileItem], str]:
""" """
整理整个文件夹 整理整个文件夹
:param fileitem: 源文件 :param fileitem: 源文件
@@ -570,7 +574,8 @@ class TransHandler:
source_oper=source_oper, source_oper=source_oper,
target_oper=target_oper, target_oper=target_oper,
target_path=target_path, target_path=target_path,
transfer_type=transfer_type) transfer_type=transfer_type,
result=result)
if state: if state:
return target_item, errmsg return target_item, errmsg
else: else:
@@ -578,7 +583,8 @@ class TransHandler:
def __transfer_dir_files(self, fileitem: FileItem, target_storage: str, def __transfer_dir_files(self, fileitem: FileItem, target_storage: str,
source_oper: StorageBase, target_oper: StorageBase, source_oper: StorageBase, target_oper: StorageBase,
transfer_type: str, target_path: Path) -> Tuple[bool, str]: transfer_type: str, target_path: Path,
result: TransferInfo) -> Tuple[bool, str]:
""" """
按目录结构整理目录下所有文件 按目录结构整理目录下所有文件
:param fileitem: 源文件 :param fileitem: 源文件
@@ -599,7 +605,8 @@ class TransHandler:
source_oper=source_oper, source_oper=source_oper,
target_oper=target_oper, target_oper=target_oper,
transfer_type=transfer_type, transfer_type=transfer_type,
target_path=new_path) target_path=new_path,
result=result)
if not state: if not state:
return False, errmsg return False, errmsg
else: else:
@@ -613,7 +620,8 @@ class TransHandler:
transfer_type=transfer_type) transfer_type=transfer_type)
if not new_item: if not new_item:
return False, errmsg return False, errmsg
self.__set_result( self.__update_result(
result=result,
file_list=[item.path], file_list=[item.path],
file_list_new=[new_item.path], file_list_new=[new_item.path],
) )
@@ -623,7 +631,8 @@ class TransHandler:
def __transfer_file(self, fileitem: FileItem, mediainfo: MediaInfo, def __transfer_file(self, fileitem: FileItem, mediainfo: MediaInfo,
source_oper: StorageBase, target_oper: StorageBase, source_oper: StorageBase, target_oper: StorageBase,
target_storage: str, target_file: Path, target_storage: str, target_file: Path,
transfer_type: str, over_flag: Optional[bool] = False) -> Tuple[Optional[FileItem], str]: transfer_type: str, result: TransferInfo,
over_flag: Optional[bool] = False) -> Tuple[Optional[FileItem], str]:
""" """
整理一个文件,同时处理其他相关文件 整理一个文件,同时处理其他相关文件
:param fileitem: 原文件 :param fileitem: 原文件
@@ -682,7 +691,8 @@ class TransHandler:
target_file=target_file, target_file=target_file,
transfer_type=transfer_type) transfer_type=transfer_type)
if new_item: if new_item:
self.__set_result( self.__update_result(
result=result,
file_list=[fileitem.path], file_list=[fileitem.path],
file_list_new=[new_item.path], file_list_new=[new_item.path],
file_count=1, file_count=1,