feat 下载器监控支持转移合集

This commit is contained in:
jxxghp 2023-08-23 08:47:03 +08:00
parent e5e33d4486
commit 66a1f25465
10 changed files with 155 additions and 75 deletions

View File

@ -60,6 +60,7 @@ class TransferChain(ChainBase):
self.progress.update(value=0, self.progress.update(value=0,
text=f"开始转移下载任务文件,共 {total_num} 个任务 ...", text=f"开始转移下载任务文件,共 {total_num} 个任务 ...",
key=ProgressKey.FileTransfer) key=ProgressKey.FileTransfer)
for torrent in torrents: for torrent in torrents:
# 更新进度 # 更新进度
self.progress.update(value=processed_num / total_num * 100, self.progress.update(value=processed_num / total_num * 100,
@ -105,12 +106,20 @@ class TransferChain(ChainBase):
continue continue
logger.info(f"{torrent.title} 识别为:{mediainfo.type.value} {mediainfo.title_year}") logger.info(f"{torrent.title} 识别为:{mediainfo.type.value} {mediainfo.title_year}")
# 更新媒体图片 # 更新媒体图片
self.obtain_images(mediainfo=mediainfo) self.obtain_images(mediainfo=mediainfo)
# 转移 # 获取待转移路径清单
trans_paths = self.__get_trans_paths(torrent.path)
if not trans_paths:
logger.warn(f"{torrent.title} 对应目录没有找到媒体文件")
continue
# 转移所有文件
for trans_path in trans_paths:
transferinfo: TransferInfo = self.transfer(mediainfo=mediainfo, transferinfo: TransferInfo = self.transfer(mediainfo=mediainfo,
path=torrent.path, path=trans_path,
transfer_type=settings.TRANSFER_TYPE) transfer_type=settings.TRANSFER_TYPE)
if not transferinfo: if not transferinfo:
logger.error("文件转移模块运行失败") logger.error("文件转移模块运行失败")
@ -120,7 +129,7 @@ class TransferChain(ChainBase):
logger.warn(f"{torrent.title} 入库失败:{transferinfo.message}") logger.warn(f"{torrent.title} 入库失败:{transferinfo.message}")
# 新增转移失败历史记录 # 新增转移失败历史记录
self.__insert_fail_history( self.__insert_fail_history(
src_path=torrent.path, src_path=trans_path,
download_hash=torrent.hash, download_hash=torrent.hash,
meta=meta, meta=meta,
mediainfo=mediainfo, mediainfo=mediainfo,
@ -132,20 +141,16 @@ class TransferChain(ChainBase):
text=f"原因:{transferinfo.message or '未知'}", text=f"原因:{transferinfo.message or '未知'}",
image=mediainfo.get_message_image() image=mediainfo.get_message_image()
)) ))
# 设置种子状态,避免一直报错
self.transfer_completed(hashs=torrent.hash, transinfo=transferinfo)
continue continue
# 新增转移成功历史记录 # 新增转移成功历史记录
self.__insert_sucess_history( self.__insert_sucess_history(
src_path=torrent.path, src_path=trans_path,
download_hash=torrent.hash, download_hash=torrent.hash,
meta=meta, meta=meta,
mediainfo=mediainfo, mediainfo=mediainfo,
transferinfo=transferinfo transferinfo=transferinfo
) )
# 转移完成
self.transfer_completed(hashs=torrent.hash, transinfo=transferinfo)
# 刮削元数据 # 刮削元数据
self.scrape_metadata(path=transferinfo.target_path, mediainfo=mediainfo) self.scrape_metadata(path=transferinfo.target_path, mediainfo=mediainfo)
# 刷新媒体库 # 刷新媒体库
@ -158,6 +163,10 @@ class TransferChain(ChainBase):
'mediainfo': mediainfo, 'mediainfo': mediainfo,
'transferinfo': transferinfo 'transferinfo': transferinfo
}) })
# 转移完成
self.transfer_completed(hashs=torrent.hash, transinfo=transferinfo)
# 计数 # 计数
processed_num += 1 processed_num += 1
# 更新进度 # 更新进度
@ -169,6 +178,38 @@ class TransferChain(ChainBase):
logger.info("下载器文件转移执行完成") logger.info("下载器文件转移执行完成")
return True return True
@staticmethod
def __get_trans_paths(directory: Path):
"""
获取转移目录列表
"""
if not directory.exists():
logger.warn(f"目录不存在:{directory}")
return []
if directory.is_file():
return [directory]
# 需要转移的路径列表
trans_paths = []
# 先检查当前目录的下级目录,以支持合集的情况
for sub_dir in SystemUtils.list_sub_directory(directory):
# 没有媒体文件的目录跳过
if not SystemUtils.list_files(sub_dir, extensions=settings.RMT_MEDIAEXT):
continue
trans_paths.append(sub_dir)
if not trans_paths:
# 没有有效子目录,直接转移当前目录
trans_paths.append(directory)
else:
# 有子目录时,把当前目录的文件添加到转移任务中
trans_paths.extend(
SystemUtils.list_sub_files(directory, extensions=settings.RMT_MEDIAEXT)
)
def remote_transfer(self, arg_str: str, channel: MessageChannel, userid: Union[str, int] = None): def remote_transfer(self, arg_str: str, channel: MessageChannel, userid: Union[str, int] = None):
""" """
远程重新转移参数 历史记录ID TMDBID|类型 远程重新转移参数 历史记录ID TMDBID|类型
@ -210,7 +251,7 @@ class TransferChain(ChainBase):
def re_transfer(self, logid: int, mtype: MediaType, tmdbid: int) -> Tuple[bool, str]: def re_transfer(self, logid: int, mtype: MediaType, tmdbid: int) -> Tuple[bool, str]:
""" """
根据历史记录重新识别转移 根据历史记录重新识别转移只处理对应的src目录
:param logid: 历史记录ID :param logid: 历史记录ID
:param mtype: 媒体类型 :param mtype: 媒体类型
:param tmdbid: TMDB ID :param tmdbid: TMDB ID
@ -220,14 +261,6 @@ class TransferChain(ChainBase):
if not history: if not history:
logger.error(f"历史记录不存在ID{logid}") logger.error(f"历史记录不存在ID{logid}")
return False, "历史记录不存在" return False, "历史记录不存在"
if history.download_hash:
# 有下载记录,按下载记录重新转移
torrents: Optional[List[TransferTorrent]] = self.list_torrents(hashs=history.download_hash)
if not torrents:
return False, f"没有获取到种子hash{history.download_hash}"
# 源目录
src_path = Path(torrents[0].path)
else:
# 没有下载记录,按源目录路径重新转移 # 没有下载记录,按源目录路径重新转移
src_path = Path(history.src) src_path = Path(history.src)
if not src_path.exists(): if not src_path.exists():
@ -252,9 +285,13 @@ class TransferChain(ChainBase):
if not transferinfo: if not transferinfo:
logger.error("文件转移模块运行失败") logger.error("文件转移模块运行失败")
return False, "文件转移模块运行失败" return False, "文件转移模块运行失败"
# 删除旧历史记录
self.transferhis.delete(logid)
if not transferinfo.target_path: if not transferinfo.target_path:
# 转移失败 # 转移失败
logger.warn(f"{src_path.name} 入库失败:{transferinfo.message}") logger.warn(f"{src_path} 入库失败:{transferinfo.message}")
# 新增转移失败历史记录 # 新增转移失败历史记录
self.__insert_fail_history( self.__insert_fail_history(
src_path=src_path, src_path=src_path,
@ -273,8 +310,6 @@ class TransferChain(ChainBase):
mediainfo=mediainfo, mediainfo=mediainfo,
transferinfo=transferinfo transferinfo=transferinfo
) )
# 删除旧历史记录
self.transferhis.delete(logid)
# 刮削元数据 # 刮削元数据
self.scrape_metadata(path=transferinfo.target_path, mediainfo=mediainfo) self.scrape_metadata(path=transferinfo.target_path, mediainfo=mediainfo)
# 刷新媒体库 # 刷新媒体库
@ -287,6 +322,7 @@ class TransferChain(ChainBase):
'mediainfo': mediainfo, 'mediainfo': mediainfo,
'transferinfo': transferinfo 'transferinfo': transferinfo
}) })
return True, "" return True, ""
def __insert_sucess_history(self, src_path: Path, download_hash: str, meta: MetaBase, def __insert_sucess_history(self, src_path: Path, download_hash: str, meta: MetaBase,
@ -294,7 +330,7 @@ class TransferChain(ChainBase):
""" """
新增转移成功历史记录 新增转移成功历史记录
""" """
self.transferhis.add( self.transferhis.add_force(
src=str(src_path), src=str(src_path),
dest=str(transferinfo.target_path), dest=str(transferinfo.target_path),
mode=settings.TRANSFER_TYPE, mode=settings.TRANSFER_TYPE,
@ -317,10 +353,10 @@ class TransferChain(ChainBase):
def __insert_fail_history(self, src_path: Path, download_hash: str, meta: MetaBase, def __insert_fail_history(self, src_path: Path, download_hash: str, meta: MetaBase,
transferinfo: TransferInfo = None, mediainfo: MediaInfo = None): transferinfo: TransferInfo = None, mediainfo: MediaInfo = None):
""" """
新增转移失败历史记录 新增转移失败历史记录不能按download_hash判重
""" """
if mediainfo and transferinfo: if mediainfo and transferinfo:
his = self.transferhis.add( his = self.transferhis.add_force(
src=str(src_path), src=str(src_path),
dest=str(transferinfo.target_path), dest=str(transferinfo.target_path),
mode=settings.TRANSFER_TYPE, mode=settings.TRANSFER_TYPE,
@ -341,7 +377,7 @@ class TransferChain(ChainBase):
files=json.dumps(transferinfo.file_list) files=json.dumps(transferinfo.file_list)
) )
else: else:
his = self.transferhis.add( his = self.transferhis.add_force(
src=str(src_path), src=str(src_path),
mode=settings.TRANSFER_TYPE, mode=settings.TRANSFER_TYPE,
seasons=meta.season, seasons=meta.season,
@ -389,8 +425,8 @@ class TransferChain(ChainBase):
logger.warn(f"文件 {path} 已删除") logger.warn(f"文件 {path} 已删除")
# 判断目录是否为空, 为空则删除 # 判断目录是否为空, 为空则删除
if str(path.parent.parent) != str(path.root): if str(path.parent.parent) != str(path.root):
# 父目录非根目录,才删除父目录 # 父目录非根目录,才删除父目录
files = SystemUtils.list_files_with_extensions(path.parent, settings.RMT_MEDIAEXT) files = SystemUtils.list_files(path.parent, settings.RMT_MEDIAEXT)
if not files: if not files:
shutil.rmtree(path.parent) shutil.rmtree(path.parent)
logger.warn(f"目录 {path.parent} 已删除") logger.warn(f"目录 {path.parent} 已删除")

View File

@ -167,7 +167,7 @@ class DoubanModule(_ModuleBase):
if settings.SCRAP_SOURCE != "douban": if settings.SCRAP_SOURCE != "douban":
return None return None
# 目录下的所有文件 # 目录下的所有文件
for file in SystemUtils.list_files_with_extensions(path, settings.RMT_MEDIAEXT): for file in SystemUtils.list_files(path, settings.RMT_MEDIAEXT):
if not file: if not file:
continue continue
logger.info(f"开始刮削媒体库文件:{file} ...") logger.info(f"开始刮削媒体库文件:{file} ...")

View File

@ -121,7 +121,7 @@ class FileTransferModule(_ModuleBase):
# 比对文件名并转移字幕 # 比对文件名并转移字幕
org_dir: Path = org_path.parent org_dir: Path = org_path.parent
file_list: List[Path] = SystemUtils.list_files_with_extensions(org_dir, settings.RMT_SUBEXT) file_list: List[Path] = SystemUtils.list_files(org_dir, settings.RMT_SUBEXT)
if len(file_list) == 0: if len(file_list) == 0:
logger.debug(f"{org_dir} 目录下没有找到字幕文件...") logger.debug(f"{org_dir} 目录下没有找到字幕文件...")
else: else:
@ -207,7 +207,7 @@ class FileTransferModule(_ModuleBase):
""" """
dir_name = org_path.parent dir_name = org_path.parent
file_name = org_path.name file_name = org_path.name
file_list: List[Path] = SystemUtils.list_files_with_extensions(dir_name, ['.mka']) file_list: List[Path] = SystemUtils.list_files(dir_name, ['.mka'])
pending_file_list: List[Path] = [file for file in file_list if org_path.stem == file.stem] pending_file_list: List[Path] = [file for file in file_list if org_path.stem == file.stem]
if len(pending_file_list) == 0: if len(pending_file_list) == 0:
logger.debug(f"{dir_name} 目录下没有找到匹配的音轨文件") logger.debug(f"{dir_name} 目录下没有找到匹配的音轨文件")
@ -409,7 +409,7 @@ class FileTransferModule(_ModuleBase):
file_list_new=[]) file_list_new=[])
else: else:
# 获取文件清单 # 获取文件清单
transfer_files: List[Path] = SystemUtils.list_files_with_extensions(in_path, settings.RMT_MEDIAEXT) transfer_files: List[Path] = SystemUtils.list_files(in_path, settings.RMT_MEDIAEXT)
if len(transfer_files) == 0: if len(transfer_files) == 0:
return TransferInfo(message=f"{in_path} 目录下没有找到可转移的文件") return TransferInfo(message=f"{in_path} 目录下没有找到可转移的文件")
if not in_meta: if not in_meta:

View File

@ -168,7 +168,7 @@ class QbittorrentModule(_ModuleBase):
logger.info(f"移动模式删除种子成功:{hashs} ") logger.info(f"移动模式删除种子成功:{hashs} ")
# 删除残留文件 # 删除残留文件
if transinfo.path and transinfo.path.exists(): if transinfo.path and transinfo.path.exists():
files = SystemUtils.list_files_with_extensions(transinfo.path, settings.RMT_MEDIAEXT) files = SystemUtils.list_files(transinfo.path, settings.RMT_MEDIAEXT)
if not files: if not files:
logger.warn(f"删除残留文件夹:{transinfo.path}") logger.warn(f"删除残留文件夹:{transinfo.path}")
shutil.rmtree(transinfo.path, ignore_errors=True) shutil.rmtree(transinfo.path, ignore_errors=True)

View File

@ -108,7 +108,7 @@ class SubtitleModule(_ModuleBase):
# 解压文件 # 解压文件
shutil.unpack_archive(zip_file, zip_path, format='zip') shutil.unpack_archive(zip_file, zip_path, format='zip')
# 遍历转移文件 # 遍历转移文件
for sub_file in SystemUtils.list_files_with_extensions(zip_path, settings.RMT_SUBEXT): for sub_file in SystemUtils.list_files(zip_path, settings.RMT_SUBEXT):
target_sub_file = download_dir / sub_file.name target_sub_file = download_dir / sub_file.name
if target_sub_file.exists(): if target_sub_file.exists():
logger.info(f"字幕文件已存在:{target_sub_file}") logger.info(f"字幕文件已存在:{target_sub_file}")

View File

@ -190,7 +190,7 @@ class TheMovieDbModule(_ModuleBase):
if settings.SCRAP_SOURCE != "themoviedb": if settings.SCRAP_SOURCE != "themoviedb":
return None return None
# 目录下的所有文件 # 目录下的所有文件
for file in SystemUtils.list_files_with_extensions(path, settings.RMT_MEDIAEXT): for file in SystemUtils.list_files(path, settings.RMT_MEDIAEXT):
if not file: if not file:
continue continue
logger.info(f"开始刮削媒体库文件:{file} ...") logger.info(f"开始刮削媒体库文件:{file} ...")

View File

@ -152,7 +152,7 @@ class TransmissionModule(_ModuleBase):
logger.info(f"移动模式删除种子成功:{hashs} ") logger.info(f"移动模式删除种子成功:{hashs} ")
# 删除残留文件 # 删除残留文件
if transinfo.path and transinfo.path.exists(): if transinfo.path and transinfo.path.exists():
files = SystemUtils.list_files_with_extensions(transinfo.path, settings.RMT_MEDIAEXT) files = SystemUtils.list_files(transinfo.path, settings.RMT_MEDIAEXT)
if not files: if not files:
logger.warn(f"删除残留文件夹:{transinfo.path}") logger.warn(f"删除残留文件夹:{transinfo.path}")
shutil.rmtree(transinfo.path, ignore_errors=True) shutil.rmtree(transinfo.path, ignore_errors=True)

View File

@ -309,7 +309,7 @@ class DirMonitor(_PluginBase):
if len(str(file_dir)) <= len(str(Path(mon_path))): if len(str(file_dir)) <= len(str(Path(mon_path))):
# 重要,删除到监控目录为止 # 重要,删除到监控目录为止
break break
files = SystemUtils.list_files_with_extensions(file_dir, settings.RMT_MEDIAEXT) files = SystemUtils.list_files(file_dir, settings.RMT_MEDIAEXT)
if not files: if not files:
logger.warn(f"移动模式,删除空目录:{file_dir}") logger.warn(f"移动模式,删除空目录:{file_dir}")
shutil.rmtree(file_dir, ignore_errors=True) shutil.rmtree(file_dir, ignore_errors=True)

View File

@ -258,7 +258,7 @@ class LibraryScraper(_PluginBase):
""" """
exclude_paths = self._exclude_paths.split("\n") exclude_paths = self._exclude_paths.split("\n")
# 查找目录下所有的文件 # 查找目录下所有的文件
files = SystemUtils.list_files_with_extensions(path, settings.RMT_MEDIAEXT) files = SystemUtils.list_files(path, settings.RMT_MEDIAEXT)
for file in files: for file in files:
if self._event.is_set(): if self._event.is_set():
logger.info(f"媒体库刮削服务停止") logger.info(f"媒体库刮削服务停止")

View File

@ -91,10 +91,13 @@ class SystemUtils:
return -1, str(err) return -1, str(err)
@staticmethod @staticmethod
def list_files_with_extensions(directory: Path, extensions: list) -> List[Path]: def list_files(directory: Path, extensions: list) -> List[Path]:
""" """
获取目录下所有指定扩展名的文件 获取目录下所有指定扩展名的文件包括子目录
""" """
if not directory.exists():
return []
if directory.is_file(): if directory.is_file():
return [directory] return [directory]
@ -108,6 +111,47 @@ class SystemUtils:
return files return files
@staticmethod
def list_sub_files(directory: Path, extensions: list) -> List[Path]:
"""
列出当前目录下的所有指定扩展名的文件(不包括子目录)
"""
if not directory.exists():
return []
if directory.is_file():
return [directory]
files = []
pattern = r".*(" + "|".join(extensions) + ")$"
# 遍历目录
for path in directory.iterdir():
if path.is_file() and re.match(pattern, path.name, re.IGNORECASE):
files.append(path)
return files
@staticmethod
def list_sub_directory(directory: Path) -> List[Path]:
"""
列出当前目录下的所有子目录不递归
"""
if not directory.exists():
return []
if directory.is_file():
return []
dirs = []
# 遍历目录
for path in directory.iterdir():
if path.is_dir():
dirs.append(path)
return dirs
@staticmethod @staticmethod
def get_directory_size(path: Path) -> float: def get_directory_size(path: Path) -> float:
""" """