mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-03-20 03:57:30 +08:00
fix:优化transhandler线程安全
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user