mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-06 07:56:52 +08:00
fix #4581
This commit is contained in:
+3
-3
@@ -367,12 +367,12 @@ class MediaChain(ChainBase):
|
|||||||
overwrite=overwrite)
|
overwrite=overwrite)
|
||||||
else:
|
else:
|
||||||
# 检查目的目录下是否已经有nfo刮削文件
|
# 检查目的目录下是否已经有nfo刮削文件
|
||||||
sub_files = storagechain.list_files(fileitem)
|
has_nfo_file = storagechain.any_files(fileitem, extensions=['.nfo'])
|
||||||
if any(f.name.endswith('.nfo') for f in sub_files):
|
if has_nfo_file and file_list:
|
||||||
logger.info(f"目录 {fileitem.path} 已有NFO文件,开始增量刮削...")
|
logger.info(f"目录 {fileitem.path} 已有NFO文件,开始增量刮削...")
|
||||||
for file_path in file_list:
|
for file_path in file_list:
|
||||||
file_item = storagechain.get_file_item(storage=fileitem.storage,
|
file_item = storagechain.get_file_item(storage=fileitem.storage,
|
||||||
path=Path(file_path))
|
path=Path(file_path))
|
||||||
if file_item:
|
if file_item:
|
||||||
# 对于电视剧文件,应该保存到与视频文件相同的目录
|
# 对于电视剧文件,应该保存到与视频文件相同的目录
|
||||||
# 而不是电视剧根目录
|
# 而不是电视剧根目录
|
||||||
|
|||||||
+16
-5
@@ -372,6 +372,8 @@ class TransferChain(ChainBase, metaclass=Singleton):
|
|||||||
self._transfer_interval = 15
|
self._transfer_interval = 15
|
||||||
# 事件管理器
|
# 事件管理器
|
||||||
self.jobview = JobManager()
|
self.jobview = JobManager()
|
||||||
|
# 车移成功的文件清单
|
||||||
|
self._success_target_files: Dict[str, List[str]] = {}
|
||||||
# 启动整理任务
|
# 启动整理任务
|
||||||
self.__init()
|
self.__init()
|
||||||
|
|
||||||
@@ -441,6 +443,13 @@ class TransferChain(ChainBase, metaclass=Singleton):
|
|||||||
})
|
})
|
||||||
|
|
||||||
with task_lock:
|
with task_lock:
|
||||||
|
# 登记转移成功文件清单
|
||||||
|
target_dir_path = transferinfo.target_diritem.path
|
||||||
|
target_files = transferinfo.file_list_new
|
||||||
|
if self._success_target_files.get(target_dir_path):
|
||||||
|
self._success_target_files[target_dir_path].extend(target_files)
|
||||||
|
else:
|
||||||
|
self._success_target_files[target_dir_path] = target_files
|
||||||
# 全部整理成功时
|
# 全部整理成功时
|
||||||
if self.jobview.is_success(task):
|
if self.jobview.is_success(task):
|
||||||
# 移动模式删除空目录
|
# 移动模式删除空目录
|
||||||
@@ -461,6 +470,13 @@ class TransferChain(ChainBase, metaclass=Singleton):
|
|||||||
storagechain.delete_media_file(t.fileitem, delete_self=False)
|
storagechain.delete_media_file(t.fileitem, delete_self=False)
|
||||||
# 整理完成且有成功的任务时
|
# 整理完成且有成功的任务时
|
||||||
if self.jobview.is_finished(task):
|
if self.jobview.is_finished(task):
|
||||||
|
# 更新文件数量
|
||||||
|
transferinfo.file_count = self.jobview.count(task.mediainfo, task.meta.begin_season) or 1
|
||||||
|
# 更新文件大小
|
||||||
|
transferinfo.total_size = self.jobview.size(task.mediainfo,
|
||||||
|
task.meta.begin_season) or task.fileitem.size
|
||||||
|
# 更新文件清单
|
||||||
|
transferinfo.file_list_new = self._success_target_files.pop(transferinfo.target_diritem.path, [])
|
||||||
# 发送通知,实时手动整理时不发
|
# 发送通知,实时手动整理时不发
|
||||||
if transferinfo.need_notify and (task.background or not task.manual):
|
if transferinfo.need_notify and (task.background or not task.manual):
|
||||||
se_str = None
|
se_str = None
|
||||||
@@ -470,11 +486,6 @@ class TransferChain(ChainBase, metaclass=Singleton):
|
|||||||
se_str = f"{task.meta.season} {StringUtils.format_ep(season_episodes)}"
|
se_str = f"{task.meta.season} {StringUtils.format_ep(season_episodes)}"
|
||||||
else:
|
else:
|
||||||
se_str = f"{task.meta.season}"
|
se_str = f"{task.meta.season}"
|
||||||
# 更新文件数量
|
|
||||||
transferinfo.file_count = self.jobview.count(task.mediainfo, task.meta.begin_season) or 1
|
|
||||||
# 更新文件大小
|
|
||||||
transferinfo.total_size = self.jobview.size(task.mediainfo,
|
|
||||||
task.meta.begin_season) or task.fileitem.size
|
|
||||||
self.send_transfer_message(meta=task.meta,
|
self.send_transfer_message(meta=task.meta,
|
||||||
mediainfo=task.mediainfo,
|
mediainfo=task.mediainfo,
|
||||||
transferinfo=transferinfo,
|
transferinfo=transferinfo,
|
||||||
|
|||||||
@@ -27,11 +27,10 @@ class TransHandler:
|
|||||||
文件转移整理类
|
文件转移整理类
|
||||||
"""
|
"""
|
||||||
|
|
||||||
result: Optional[TransferInfo] = None
|
|
||||||
inner_lock: Lock = Lock()
|
inner_lock: Lock = Lock()
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.__reset_result()
|
self.result = None
|
||||||
|
|
||||||
def __reset_result(self):
|
def __reset_result(self):
|
||||||
"""
|
"""
|
||||||
@@ -104,208 +103,215 @@ class TransHandler:
|
|||||||
# 重置结果
|
# 重置结果
|
||||||
self.__reset_result()
|
self.__reset_result()
|
||||||
|
|
||||||
# 重命名格式
|
try:
|
||||||
rename_format = settings.TV_RENAME_FORMAT \
|
|
||||||
if mediainfo.type == MediaType.TV else settings.MOVIE_RENAME_FORMAT
|
|
||||||
|
|
||||||
# 判断是否为文件夹
|
# 重命名格式
|
||||||
if fileitem.type == "dir":
|
rename_format = settings.TV_RENAME_FORMAT \
|
||||||
# 整理整个目录,一般为蓝光原盘
|
if mediainfo.type == MediaType.TV else settings.MOVIE_RENAME_FORMAT
|
||||||
if need_rename:
|
|
||||||
new_path = self.get_rename_path(
|
# 判断是否为文件夹
|
||||||
path=target_path,
|
if fileitem.type == "dir":
|
||||||
template_string=rename_format,
|
# 整理整个目录,一般为蓝光原盘
|
||||||
rename_dict=self.get_naming_dict(meta=in_meta,
|
if need_rename:
|
||||||
mediainfo=mediainfo)
|
new_path = self.get_rename_path(
|
||||||
)
|
path=target_path,
|
||||||
new_path = DirectoryHelper.get_media_root_path(
|
template_string=rename_format,
|
||||||
rename_format, rename_path=new_path
|
rename_dict=self.get_naming_dict(meta=in_meta,
|
||||||
)
|
mediainfo=mediainfo)
|
||||||
if not new_path:
|
|
||||||
self.__set_result(
|
|
||||||
success=False,
|
|
||||||
message="重命名格式无效",
|
|
||||||
fileitem=fileitem,
|
|
||||||
transfer_type=transfer_type,
|
|
||||||
need_notify=need_notify,
|
|
||||||
)
|
)
|
||||||
return self.result
|
new_path = DirectoryHelper.get_media_root_path(
|
||||||
else:
|
rename_format, rename_path=new_path
|
||||||
new_path = target_path / fileitem.name
|
)
|
||||||
# 整理目录
|
if not new_path:
|
||||||
new_diritem, errmsg = self.__transfer_dir(fileitem=fileitem,
|
self.__set_result(
|
||||||
mediainfo=mediainfo,
|
success=False,
|
||||||
source_oper=source_oper,
|
message="重命名格式无效",
|
||||||
target_oper=target_oper,
|
fileitem=fileitem,
|
||||||
target_storage=target_storage,
|
transfer_type=transfer_type,
|
||||||
target_path=new_path,
|
need_notify=need_notify,
|
||||||
transfer_type=transfer_type)
|
)
|
||||||
if not new_diritem:
|
return self.result.copy()
|
||||||
logger.error(f"文件夹 {fileitem.path} 整理失败:{errmsg}")
|
else:
|
||||||
self.__set_result(success=False,
|
new_path = target_path / fileitem.name
|
||||||
message=errmsg,
|
# 整理目录
|
||||||
fileitem=fileitem,
|
new_diritem, errmsg = self.__transfer_dir(fileitem=fileitem,
|
||||||
transfer_type=transfer_type,
|
mediainfo=mediainfo,
|
||||||
need_notify=need_notify)
|
source_oper=source_oper,
|
||||||
return self.result
|
target_oper=target_oper,
|
||||||
|
target_storage=target_storage,
|
||||||
logger.info(f"文件夹 {fileitem.path} 整理成功")
|
target_path=new_path,
|
||||||
# 计算目录下所有文件大小
|
transfer_type=transfer_type)
|
||||||
total_size = sum(file.stat().st_size for file in Path(fileitem.path).rglob('*') if file.is_file())
|
if not new_diritem:
|
||||||
# 返回整理后的路径
|
logger.error(f"文件夹 {fileitem.path} 整理失败:{errmsg}")
|
||||||
self.__set_result(success=True,
|
|
||||||
fileitem=fileitem,
|
|
||||||
target_item=new_diritem,
|
|
||||||
target_diritem=new_diritem,
|
|
||||||
total_size=total_size,
|
|
||||||
need_scrape=need_scrape,
|
|
||||||
need_notify=need_notify,
|
|
||||||
transfer_type=transfer_type)
|
|
||||||
return self.result
|
|
||||||
else:
|
|
||||||
# 整理单个文件
|
|
||||||
if mediainfo.type == MediaType.TV:
|
|
||||||
# 电视剧
|
|
||||||
if in_meta.begin_episode is None:
|
|
||||||
logger.warn(f"文件 {fileitem.path} 整理失败:未识别到文件集数")
|
|
||||||
self.__set_result(success=False,
|
self.__set_result(success=False,
|
||||||
message="未识别到文件集数",
|
message=errmsg,
|
||||||
|
fileitem=fileitem,
|
||||||
|
transfer_type=transfer_type,
|
||||||
|
need_notify=need_notify)
|
||||||
|
return self.result.copy()
|
||||||
|
|
||||||
|
logger.info(f"文件夹 {fileitem.path} 整理成功")
|
||||||
|
# 计算目录下所有文件大小
|
||||||
|
total_size = sum(file.stat().st_size for file in Path(fileitem.path).rglob('*') if file.is_file())
|
||||||
|
# 返回整理后的路径
|
||||||
|
self.__set_result(success=True,
|
||||||
|
fileitem=fileitem,
|
||||||
|
target_item=new_diritem,
|
||||||
|
target_diritem=new_diritem,
|
||||||
|
total_size=total_size,
|
||||||
|
need_scrape=need_scrape,
|
||||||
|
need_notify=need_notify,
|
||||||
|
transfer_type=transfer_type)
|
||||||
|
return self.result.copy()
|
||||||
|
else:
|
||||||
|
# 整理单个文件
|
||||||
|
if mediainfo.type == MediaType.TV:
|
||||||
|
# 电视剧
|
||||||
|
if in_meta.begin_episode is None:
|
||||||
|
logger.warn(f"文件 {fileitem.path} 整理失败:未识别到文件集数")
|
||||||
|
self.__set_result(success=False,
|
||||||
|
message="未识别到文件集数",
|
||||||
|
fileitem=fileitem,
|
||||||
|
fail_list=[fileitem.path],
|
||||||
|
transfer_type=transfer_type,
|
||||||
|
need_notify=need_notify)
|
||||||
|
return self.result.copy()
|
||||||
|
|
||||||
|
# 文件结束季为空
|
||||||
|
in_meta.end_season = None
|
||||||
|
# 文件总季数为1
|
||||||
|
if in_meta.total_season:
|
||||||
|
in_meta.total_season = 1
|
||||||
|
# 文件不可能超过2集
|
||||||
|
if in_meta.total_episode > 2:
|
||||||
|
in_meta.total_episode = 1
|
||||||
|
in_meta.end_episode = None
|
||||||
|
|
||||||
|
# 目的文件名
|
||||||
|
if need_rename:
|
||||||
|
new_file = self.get_rename_path(
|
||||||
|
path=target_path,
|
||||||
|
template_string=rename_format,
|
||||||
|
rename_dict=self.get_naming_dict(
|
||||||
|
meta=in_meta,
|
||||||
|
mediainfo=mediainfo,
|
||||||
|
episodes_info=episodes_info,
|
||||||
|
file_ext=f".{fileitem.extension}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
folder_path = DirectoryHelper.get_media_root_path(
|
||||||
|
rename_format, rename_path=new_file
|
||||||
|
)
|
||||||
|
if not folder_path:
|
||||||
|
self.__set_result(
|
||||||
|
success=False,
|
||||||
|
message="重命名格式无效",
|
||||||
|
fileitem=fileitem,
|
||||||
|
fail_list=[fileitem.path],
|
||||||
|
transfer_type=transfer_type,
|
||||||
|
need_notify=need_notify,
|
||||||
|
)
|
||||||
|
return self.result.copy()
|
||||||
|
else:
|
||||||
|
new_file = target_path / fileitem.name
|
||||||
|
folder_path = target_path
|
||||||
|
|
||||||
|
# 判断是否要覆盖
|
||||||
|
overflag = False
|
||||||
|
# 目标目录
|
||||||
|
target_diritem = target_oper.get_folder(folder_path)
|
||||||
|
if not target_diritem:
|
||||||
|
logger.error(f"目标目录 {folder_path} 获取失败")
|
||||||
|
self.__set_result(success=False,
|
||||||
|
message=f"目标目录 {folder_path} 获取失败",
|
||||||
fileitem=fileitem,
|
fileitem=fileitem,
|
||||||
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
|
return self.result.copy()
|
||||||
|
# 目标文件
|
||||||
# 文件结束季为空
|
target_item = target_oper.get_item(new_file)
|
||||||
in_meta.end_season = None
|
if target_item:
|
||||||
# 文件总季数为1
|
|
||||||
if in_meta.total_season:
|
|
||||||
in_meta.total_season = 1
|
|
||||||
# 文件不可能超过2集
|
|
||||||
if in_meta.total_episode > 2:
|
|
||||||
in_meta.total_episode = 1
|
|
||||||
in_meta.end_episode = None
|
|
||||||
|
|
||||||
# 目的文件名
|
|
||||||
if need_rename:
|
|
||||||
new_file = self.get_rename_path(
|
|
||||||
path=target_path,
|
|
||||||
template_string=rename_format,
|
|
||||||
rename_dict=self.get_naming_dict(
|
|
||||||
meta=in_meta,
|
|
||||||
mediainfo=mediainfo,
|
|
||||||
episodes_info=episodes_info,
|
|
||||||
file_ext=f".{fileitem.extension}"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
folder_path = DirectoryHelper.get_media_root_path(
|
|
||||||
rename_format, rename_path=new_file
|
|
||||||
)
|
|
||||||
if not folder_path:
|
|
||||||
self.__set_result(
|
|
||||||
success=False,
|
|
||||||
message="重命名格式无效",
|
|
||||||
fileitem=fileitem,
|
|
||||||
fail_list=[fileitem.path],
|
|
||||||
transfer_type=transfer_type,
|
|
||||||
need_notify=need_notify,
|
|
||||||
)
|
|
||||||
return self.result
|
|
||||||
else:
|
|
||||||
new_file = target_path / fileitem.name
|
|
||||||
folder_path = target_path
|
|
||||||
|
|
||||||
# 判断是否要覆盖
|
|
||||||
overflag = False
|
|
||||||
# 目标目录
|
|
||||||
target_diritem = target_oper.get_folder(folder_path)
|
|
||||||
if not target_diritem:
|
|
||||||
logger.error(f"目标目录 {folder_path} 获取失败")
|
|
||||||
self.__set_result(success=False,
|
|
||||||
message=f"目标目录 {folder_path} 获取失败",
|
|
||||||
fileitem=fileitem,
|
|
||||||
fail_list=[fileitem.path],
|
|
||||||
transfer_type=transfer_type,
|
|
||||||
need_notify=need_notify)
|
|
||||||
return self.result
|
|
||||||
# 目标文件
|
|
||||||
target_item = target_oper.get_item(new_file)
|
|
||||||
if target_item:
|
|
||||||
# 目标文件已存在
|
|
||||||
target_file = new_file
|
|
||||||
if target_storage == "local" and new_file.is_symlink():
|
|
||||||
target_file = new_file.readlink()
|
|
||||||
if not target_file.exists():
|
|
||||||
overflag = True
|
|
||||||
if not overflag:
|
|
||||||
# 目标文件已存在
|
# 目标文件已存在
|
||||||
logger.info(f"目的文件系统中已经存在同名文件 {target_file},当前整理覆盖模式设置为 {overwrite_mode}")
|
target_file = new_file
|
||||||
if overwrite_mode == 'always':
|
if target_storage == "local" and new_file.is_symlink():
|
||||||
# 总是覆盖同名文件
|
target_file = new_file.readlink()
|
||||||
overflag = True
|
if not target_file.exists():
|
||||||
elif overwrite_mode == 'size':
|
|
||||||
# 存在时大覆盖小
|
|
||||||
if target_item.size < fileitem.size:
|
|
||||||
logger.info(f"目标文件文件大小更小,将覆盖:{new_file}")
|
|
||||||
overflag = True
|
overflag = True
|
||||||
else:
|
if not overflag:
|
||||||
|
# 目标文件已存在
|
||||||
|
logger.info(f"目的文件系统中已经存在同名文件 {target_file},当前整理覆盖模式设置为 {overwrite_mode}")
|
||||||
|
if overwrite_mode == 'always':
|
||||||
|
# 总是覆盖同名文件
|
||||||
|
overflag = True
|
||||||
|
elif overwrite_mode == 'size':
|
||||||
|
# 存在时大覆盖小
|
||||||
|
if target_item.size < fileitem.size:
|
||||||
|
logger.info(f"目标文件文件大小更小,将覆盖:{new_file}")
|
||||||
|
overflag = True
|
||||||
|
else:
|
||||||
|
self.__set_result(success=False,
|
||||||
|
message=f"媒体库存在同名文件,且质量更好",
|
||||||
|
fileitem=fileitem,
|
||||||
|
target_item=target_item,
|
||||||
|
target_diritem=target_diritem,
|
||||||
|
fail_list=[fileitem.path],
|
||||||
|
transfer_type=transfer_type,
|
||||||
|
need_notify=need_notify)
|
||||||
|
return self.result.copy()
|
||||||
|
elif overwrite_mode == 'never':
|
||||||
|
# 存在不覆盖
|
||||||
self.__set_result(success=False,
|
self.__set_result(success=False,
|
||||||
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
|
return self.result.copy()
|
||||||
elif overwrite_mode == 'never':
|
elif overwrite_mode == 'latest':
|
||||||
# 存在不覆盖
|
# 仅保留最新版本
|
||||||
self.__set_result(success=False,
|
logger.info(f"当前整理覆盖模式设置为仅保留最新版本,将覆盖:{new_file}")
|
||||||
message=f"媒体库存在同名文件,当前覆盖模式为不覆盖",
|
overflag = True
|
||||||
fileitem=fileitem,
|
else:
|
||||||
target_item=target_item,
|
if overwrite_mode == 'latest':
|
||||||
target_diritem=target_diritem,
|
# 文件不存在,但仅保留最新版本
|
||||||
fail_list=[fileitem.path],
|
logger.info(f"当前整理覆盖模式设置为 {overwrite_mode},仅保留最新版本,正在删除已有版本文件 ...")
|
||||||
transfer_type=transfer_type,
|
self.__delete_version_files(target_oper, new_file)
|
||||||
need_notify=need_notify)
|
# 整理文件
|
||||||
return self.result
|
new_item, err_msg = self.__transfer_file(fileitem=fileitem,
|
||||||
elif overwrite_mode == 'latest':
|
mediainfo=mediainfo,
|
||||||
# 仅保留最新版本
|
target_storage=target_storage,
|
||||||
logger.info(f"当前整理覆盖模式设置为仅保留最新版本,将覆盖:{new_file}")
|
target_file=new_file,
|
||||||
overflag = True
|
transfer_type=transfer_type,
|
||||||
else:
|
over_flag=overflag,
|
||||||
if overwrite_mode == 'latest':
|
source_oper=source_oper,
|
||||||
# 文件不存在,但仅保留最新版本
|
target_oper=target_oper)
|
||||||
logger.info(f"当前整理覆盖模式设置为 {overwrite_mode},仅保留最新版本,正在删除已有版本文件 ...")
|
if not new_item:
|
||||||
self.__delete_version_files(target_oper, new_file)
|
logger.error(f"文件 {fileitem.path} 整理失败:{err_msg}")
|
||||||
# 整理文件
|
self.__set_result(success=False,
|
||||||
new_item, err_msg = self.__transfer_file(fileitem=fileitem,
|
message=err_msg,
|
||||||
mediainfo=mediainfo,
|
fileitem=fileitem,
|
||||||
target_storage=target_storage,
|
fail_list=[fileitem.path],
|
||||||
target_file=new_file,
|
transfer_type=transfer_type,
|
||||||
transfer_type=transfer_type,
|
need_notify=need_notify)
|
||||||
over_flag=overflag,
|
return self.result.copy()
|
||||||
source_oper=source_oper,
|
|
||||||
target_oper=target_oper)
|
logger.info(f"文件 {fileitem.path} 整理成功")
|
||||||
if not new_item:
|
self.__set_result(success=True,
|
||||||
logger.error(f"文件 {fileitem.path} 整理失败:{err_msg}")
|
|
||||||
self.__set_result(success=False,
|
|
||||||
message=err_msg,
|
|
||||||
fileitem=fileitem,
|
fileitem=fileitem,
|
||||||
fail_list=[fileitem.path],
|
target_item=new_item,
|
||||||
|
target_diritem=target_diritem,
|
||||||
|
file_count=1,
|
||||||
|
file_list_new=[new_item.path],
|
||||||
|
total_size=new_item.size,
|
||||||
|
need_scrape=need_scrape,
|
||||||
transfer_type=transfer_type,
|
transfer_type=transfer_type,
|
||||||
need_notify=need_notify)
|
need_notify=need_notify)
|
||||||
return self.result
|
return self.result.copy()
|
||||||
|
finally:
|
||||||
logger.info(f"文件 {fileitem.path} 整理成功")
|
self.result = None
|
||||||
self.__set_result(success=True,
|
|
||||||
fileitem=fileitem,
|
|
||||||
target_item=new_item,
|
|
||||||
target_diritem=target_diritem,
|
|
||||||
need_scrape=need_scrape,
|
|
||||||
transfer_type=transfer_type,
|
|
||||||
need_notify=need_notify)
|
|
||||||
return self.result
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __transfer_command(fileitem: FileItem, target_storage: str,
|
def __transfer_command(fileitem: FileItem, target_storage: str,
|
||||||
|
|||||||
Reference in New Issue
Block a user