This commit is contained in:
jxxghp
2023-08-30 22:01:07 +08:00
parent 9326676bb6
commit 38eff64c95
6 changed files with 269 additions and 333 deletions

View File

@ -271,34 +271,31 @@ class ChainBase(metaclass=ABCMeta):
""" """
return self.run_module("list_torrents", status=status, hashs=hashs) return self.run_module("list_torrents", status=status, hashs=hashs)
def transfer(self, path: Path, mediainfo: MediaInfo, def transfer(self, path: Path, meta: MetaBase, mediainfo: MediaInfo,
transfer_type: str, transfer_type: str,
target: Path = None, target: Path = None,
meta: MetaBase = None, epformat: EpisodeFormat = None) -> Optional[TransferInfo]:
epformat: EpisodeFormat = None,
min_filesize: int = 0) -> Optional[TransferInfo]:
""" """
文件转移 文件转移
:param path: 文件路径 :param path: 文件路径
:param meta: 预识别的元数据
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息
:param transfer_type: 转移模式 :param transfer_type: 转移模式
:param target: 转移目标路径 :param target: 转移目标路径
:param meta: 预识别的元数据,仅单文件转移时传递
:param epformat: 自定义剧集识别格式 :param epformat: 自定义剧集识别格式
:param min_filesize: 最小文件大小
:return: {path, target_path, message} :return: {path, target_path, message}
""" """
return self.run_module("transfer", path=path, mediainfo=mediainfo, return self.run_module("transfer", path=path, meta=meta, mediainfo=mediainfo,
transfer_type=transfer_type, target=target, meta=meta, transfer_type=transfer_type, target=target,
epformat=epformat, min_filesize=min_filesize) epformat=epformat)
def transfer_completed(self, hashs: Union[str, list], transinfo: TransferInfo = None) -> None: def transfer_completed(self, hashs: Union[str, list], path: Path = None) -> None:
""" """
转移完成后的处理 转移完成后的处理
:param hashs: 种子Hash :param hashs: 种子Hash
:param transinfo: 转移信息 :param path: 源目录
""" """
return self.run_module("transfer_completed", hashs=hashs, transinfo=transinfo) return self.run_module("transfer_completed", hashs=hashs, path=path)
def remove_torrents(self, hashs: Union[str, list]) -> bool: def remove_torrents(self, hashs: Union[str, list]) -> bool:
""" """

View File

@ -55,15 +55,14 @@ class TransferChain(ChainBase):
logger.info(f"获取到 {len(torrents)} 个已完成的下载任务") logger.info(f"获取到 {len(torrents)} 个已完成的下载任务")
for torrent in torrents: for torrent in torrents:
# 识别元数据 # 查询下载记录识别情况
downloadhis: DownloadHistory = self.downloadhis.get_by_hash(torrent.hash)
if downloadhis:
# MoviePilot下载的任务识别元数据
meta: MetaBase = MetaInfo(title=torrent.title) meta: MetaBase = MetaInfo(title=torrent.title)
if not meta.name: if not meta.name:
logger.error(f'未识别到元数据,标题:{torrent.title}') logger.error(f'未识别到元数据,标题:{torrent.title}')
continue continue
# 查询下载记录识别情况
downloadhis: DownloadHistory = self.downloadhis.get_by_hash(torrent.hash)
if downloadhis:
# 类型 # 类型
mtype = MediaType(downloadhis.type) mtype = MediaType(downloadhis.type)
# 补充剧集信息 # 补充剧集信息
@ -75,89 +74,153 @@ class TransferChain(ChainBase):
mediainfo = self.recognize_media(mtype=mtype, mediainfo = self.recognize_media(mtype=mtype,
tmdbid=downloadhis.tmdbid) tmdbid=downloadhis.tmdbid)
else: else:
mediainfo = self.recognize_media(meta=meta) # 非MoviePilot下载的任务按文件识别
meta = None
mediainfo = None
# 执行转移
self.do_transfer(path=torrent.path, meta=meta, mediainfo=mediainfo,
download_hash=torrent.hash)
# 设置下载任务状态
self.transfer_completed(hashs=torrent.hash, path=torrent.path)
# 结束
logger.info("下载器文件转移执行完成")
return True
def do_transfer(self, path: Path, meta: MetaBase,
mediainfo: MediaInfo, download_hash: str = None,
target: Path = None, epformat: EpisodeFormat = None) -> Tuple[bool, str]:
"""
执行一个复杂目录的转移操作
返回:成功标识,错误信息
"""
# 获取待转移路径清单
trans_paths = self.__get_trans_paths(path)
if not trans_paths:
logger.warn(f"{path.name} 没有找到可转移的媒体文件")
return False, f"{path.name} 没有找到可转移的媒体文件"
# 汇总错误信息
err_msgs = []
# 处理所有待转移目录或文件,默认一个转移路径或文件只有一个媒体信息
for trans_path in trans_paths:
# 如果是目录,获取所有文件并转移
if trans_path.is_dir():
# 遍历获取下载目录所有文件
file_paths = SystemUtils.list_files(directory=trans_path,
extensions=settings.RMT_MEDIAEXT)
else:
file_paths = [trans_path]
# 转移所有文件
for file_path in file_paths:
# 回收站及隐藏的文件不处理
file_path_str = str(file_path)
if file_path_str.find('/@Recycle/') != -1 \
or file_path_str.find('/#recycle/') != -1 \
or file_path_str.find('/.') != -1 \
or file_path_str.find('/@eaDir') != -1:
logger.debug(f"{file_path_str} 是回收站或隐藏的文件")
continue
if not meta:
# 上级目录元数据
dir_meta = MetaInfo(title=file_path.parent.name)
# 文件元数据,不包含后缀
file_meta = MetaInfo(title=file_path.stem)
# 合并元数据
file_meta.merge(dir_meta)
else:
file_meta = meta
if not file_meta:
logger.error(f"{file_path} 无法识别有效信息")
err_msgs.append(f"{file_path} 无法识别有效信息")
continue
if not mediainfo: if not mediainfo:
logger.warn(f'识别媒体信息,标题:{torrent.title}') # 识别媒体信息
file_mediainfo = self.recognize_media(meta=file_meta)
else:
file_mediainfo = mediainfo
if not file_mediainfo:
logger.warn(f'{file_path} 未识别到媒体信息')
# 新增转移失败历史记录 # 新增转移失败历史记录
his = self.__insert_fail_history( his = self.__insert_fail_history(
src_path=torrent.path, src_path=file_path,
download_hash=torrent.hash, download_hash=download_hash,
meta=meta meta=file_meta
) )
self.post_message(Notification( self.post_message(Notification(
mtype=NotificationType.Manual, mtype=NotificationType.Manual,
title=f"{torrent.title} 未识别到媒体信息,无法入库!\n" title=f"{file_path.name} 未识别到媒体信息,无法入库!\n"
f"回复:```\n/redo {his.id} [tmdbid]|[类型]\n``` 手动识别转移。" f"回复:```\n/redo {his.id} [tmdbid]|[类型]\n``` 手动识别转移。"
)) ))
# 设置种子状态,避免一直报错
self.transfer_completed(hashs=torrent.hash)
continue continue
logger.info(f"{torrent.title} 识别为:{mediainfo.type.value} {mediainfo.title_year}") logger.info(f"{file_path.name} 识别为:{file_mediainfo.type.value} {file_mediainfo.title_year}")
# 更新媒体图片 # 更新媒体图片
self.obtain_images(mediainfo=mediainfo) self.obtain_images(mediainfo=file_mediainfo)
# 执行转移
# 获取待转移路径清单 transferinfo: TransferInfo = self.transfer(meta=file_meta,
trans_paths = self.__get_trans_paths(torrent.path) mediainfo=file_mediainfo,
if not trans_paths: path=file_path,
logger.warn(f"{torrent.title} 对应目录没有找到媒体文件") transfer_type=settings.TRANSFER_TYPE,
continue target=target,
epformat=epformat)
# 转移所有文件
for trans_path in trans_paths:
transferinfo: TransferInfo = self.transfer(mediainfo=mediainfo,
path=trans_path,
transfer_type=settings.TRANSFER_TYPE)
if not transferinfo: if not transferinfo:
logger.error("文件转移模块运行失败") logger.error("文件转移模块运行失败")
continue return False, "文件转移模块运行失败"
if not transferinfo.target_path: if not transferinfo.target_path:
# 转移失败 # 转移失败
logger.warn(f"{torrent.title} 入库失败:{transferinfo.message}") logger.warn(f"{file_path.name} 入库失败:{transferinfo.message}")
err_msgs.append(f"{file_path.name} {transferinfo.message}")
# 新增转移失败历史记录 # 新增转移失败历史记录
self.__insert_fail_history( self.__insert_fail_history(
src_path=trans_path, src_path=file_path,
download_hash=torrent.hash, download_hash=download_hash,
meta=meta, meta=file_meta,
mediainfo=mediainfo, mediainfo=file_mediainfo,
transferinfo=transferinfo transferinfo=transferinfo
) )
# 发送消息 # 发送消息
self.post_message(Notification( self.post_message(Notification(
title=f"{mediainfo.title_year} {meta.season_episode} 入库失败!", title=f"{file_mediainfo.title_year} {file_meta.season_episode} 入库失败!",
text=f"原因:{transferinfo.message or '未知'}", text=f"原因:{transferinfo.message or '未知'}",
image=mediainfo.get_message_image() image=file_mediainfo.get_message_image()
)) ))
continue continue
# 新增转移成功历史记录 # 新增转移成功历史记录
self.__insert_sucess_history( self.__insert_sucess_history(
src_path=trans_path, src_path=file_path,
download_hash=torrent.hash, download_hash=download_hash,
meta=meta, meta=file_meta,
mediainfo=mediainfo, mediainfo=file_mediainfo,
transferinfo=transferinfo transferinfo=transferinfo
) )
# 刮削元数据
self.scrape_metadata(path=transferinfo.target_path, mediainfo=mediainfo)
# 刷新媒体库 # 刷新媒体库
self.refresh_mediaserver(mediainfo=mediainfo, file_path=transferinfo.target_path) self.refresh_mediaserver(mediainfo=file_mediainfo, file_path=transferinfo.target_path)
# 发送通知
self.send_transfer_message(meta=meta, mediainfo=mediainfo, transferinfo=transferinfo)
# 广播事件 # 广播事件
self.eventmanager.send_event(EventType.TransferComplete, { self.eventmanager.send_event(EventType.TransferComplete, {
'meta': meta, 'meta': file_meta,
'mediainfo': mediainfo, 'mediainfo': file_mediainfo,
'transferinfo': transferinfo 'transferinfo': transferinfo
}) })
# 转移完成 # 目录或文件转移完成
self.transfer_completed(hashs=torrent.hash, transinfo=transferinfo) # FIXME 汇总刮削元数据
# 结束 self.scrape_metadata(path=trans_path, mediainfo=file_mediainfo)
logger.info("下载器文件转移执行完成") # FIXME 汇总发送通知
return True self.send_transfer_message(meta=meta, mediainfo=mediainfo, transferinfo=transferinfo)
return True, "\n".join(err_msgs)
@staticmethod @staticmethod
def __get_trans_paths(directory: Path): def __get_trans_paths(directory: Path):
@ -267,50 +330,16 @@ class TransferChain(ChainBase):
self.obtain_images(mediainfo=mediainfo) self.obtain_images(mediainfo=mediainfo)
# 转移 # 转移
transferinfo: TransferInfo = self.transfer(mediainfo=mediainfo, state, errmsg = self.do_transfer(path=src_path,
path=src_path, meta=meta,
transfer_type=settings.TRANSFER_TYPE) mediainfo=mediainfo,
if not transferinfo: download_hash=history.download_hash)
logger.error("文件转移模块运行失败") if not state:
return False, "文件转移模块运行失败" return False, errmsg
# 删除旧历史记录 # 删除旧历史记录
self.transferhis.delete(logid) self.transferhis.delete(logid)
if not transferinfo.target_path:
# 转移失败
logger.warn(f"{src_path} 入库失败:{transferinfo.message}")
# 新增转移失败历史记录
self.__insert_fail_history(
src_path=src_path,
download_hash=history.download_hash,
meta=meta,
mediainfo=mediainfo,
transferinfo=transferinfo
)
return False, transferinfo.message
# 新增转移成功历史记录
self.__insert_sucess_history(
src_path=src_path,
download_hash=history.download_hash,
meta=meta,
mediainfo=mediainfo,
transferinfo=transferinfo
)
# 刮削元数据
self.scrape_metadata(path=transferinfo.target_path, mediainfo=mediainfo)
# 刷新媒体库
self.refresh_mediaserver(mediainfo=mediainfo, file_path=transferinfo.target_path)
# 发送通知
self.send_transfer_message(meta=meta, mediainfo=mediainfo, transferinfo=transferinfo)
# 广播事件
self.eventmanager.send_event(EventType.TransferComplete, {
'meta': meta,
'mediainfo': mediainfo,
'transferinfo': transferinfo
})
return True, "" return True, ""
def manual_transfer(self, in_path: Path, def manual_transfer(self, in_path: Path,
@ -322,7 +351,7 @@ class TransferChain(ChainBase):
epformat: EpisodeFormat = None, epformat: EpisodeFormat = None,
min_filesize: int = 0) -> Tuple[bool, Union[str, list]]: min_filesize: int = 0) -> Tuple[bool, Union[str, list]]:
""" """
手动转移 FIXME 手动转移
:param in_path: 源文件路径 :param in_path: 源文件路径
:param target: 目标路径 :param target: 目标路径
:param tmdbid: TMDB ID :param tmdbid: TMDB ID
@ -356,42 +385,23 @@ class TransferChain(ChainBase):
text=f"开始转移 {in_path} ...", text=f"开始转移 {in_path} ...",
key=ProgressKey.FileTransfer) key=ProgressKey.FileTransfer)
# 开始转移 # 开始转移
transferinfo: TransferInfo = self.transfer( # FIXME 查找下载记录 download_hash
state, errmsg = self.do_transfer(
path=in_path, path=in_path,
mediainfo=mediainfo,
transfer_type=transfer_type,
target=target,
epformat=epformat,
min_filesize=min_filesize
)
if not transferinfo:
return False, "文件转移模块运行失败"
if not transferinfo.target_path:
return False, transferinfo.message
# 新增转移成功历史记录
self.__insert_sucess_history(
src_path=in_path,
meta=meta, meta=meta,
mediainfo=mediainfo, mediainfo=mediainfo,
transferinfo=transferinfo target=target,
epformat=epformat,
download_hash=None
) )
# 刮削元数据 if not state:
self.scrape_metadata(path=transferinfo.target_path, mediainfo=mediainfo) return False, errmsg
# 刷新媒体库
self.refresh_mediaserver(mediainfo=mediainfo, file_path=transferinfo.target_path)
# 发送通知
self.send_transfer_message(meta=meta, mediainfo=mediainfo, transferinfo=transferinfo)
# 广播事件
self.eventmanager.send_event(EventType.TransferComplete, {
'meta': meta,
'mediainfo': mediainfo,
'transferinfo': transferinfo
})
self.progress.end(ProgressKey.FileTransfer) self.progress.end(ProgressKey.FileTransfer)
logger.info(f"{in_path} 转移完成") logger.info(f"{in_path} 转移完成")
return True, "" return True, ""
else: else:
# FIXME
# 错误信息 # 错误信息
errmsgs = [] errmsgs = []
# 自动识别所有文件 # 自动识别所有文件
@ -453,8 +463,7 @@ class TransferChain(ChainBase):
transfer_type=transfer_type, transfer_type=transfer_type,
target=target, target=target,
meta=file_meta, meta=file_meta,
epformat=epformat, epformat=epformat
min_filesize=min_filesize
) )
if not transferinfo: if not transferinfo:
return False, "文件转移模块运行失败" return False, "文件转移模块运行失败"

View File

@ -30,20 +30,17 @@ class FileTransferModule(_ModuleBase):
def init_setting(self) -> Tuple[str, Union[str, bool]]: def init_setting(self) -> Tuple[str, Union[str, bool]]:
pass pass
def transfer(self, path: Path, mediainfo: MediaInfo, def transfer(self, path: Path, meta: MetaBase, mediainfo: MediaInfo,
transfer_type: str, target: Path = None, transfer_type: str, target: Path = None,
meta: MetaBase = None, epformat: EpisodeFormat = None) -> TransferInfo:
epformat: EpisodeFormat = None,
min_filesize: int = 0) -> TransferInfo:
""" """
文件转移 文件转移
:param path: 文件路径 :param path: 文件路径
:param meta: 预识别的元数据,仅单文件转移时传递
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息
:param transfer_type: 转移方式 :param transfer_type: 转移方式
:param target: 目标路径 :param target: 目标路径
:param meta: 预识别的元数据,仅单文件转移时传递
:param epformat: 集识别格式 :param epformat: 集识别格式
:param min_filesize: 最小文件大小(MB)
:return: {path, target_path, message} :return: {path, target_path, message}
""" """
# 获取目标路径 # 获取目标路径
@ -54,12 +51,11 @@ class FileTransferModule(_ModuleBase):
return TransferInfo(message="未找到媒体库目录,无法转移文件") return TransferInfo(message="未找到媒体库目录,无法转移文件")
# 转移 # 转移
return self.transfer_media(in_path=path, return self.transfer_media(in_path=path,
in_meta=meta,
mediainfo=mediainfo, mediainfo=mediainfo,
transfer_type=transfer_type, transfer_type=transfer_type,
target_dir=target, target_dir=target,
in_meta=meta, epformat=epformat)
epformat=epformat,
min_filesize=min_filesize)
@staticmethod @staticmethod
def __transfer_command(file_item: Path, target_file: Path, transfer_type: str) -> int: def __transfer_command(file_item: Path, target_file: Path, transfer_type: str) -> int:
@ -244,9 +240,9 @@ class FileTransferModule(_ModuleBase):
logger.error(f"音轨文件 {file_name} {transfer_type}失败:{reason}") logger.error(f"音轨文件 {file_name} {transfer_type}失败:{reason}")
return 0 return 0
def __transfer_bluray_dir(self, file_path: Path, new_path: Path, transfer_type: str) -> int: def __transfer_dir(self, file_path: Path, new_path: Path, transfer_type: str) -> int:
""" """
转移蓝光文件夹 转移整个文件夹
:param file_path: 原路径 :param file_path: 原路径
:param new_path: 新路径 :param new_path: 新路径
:param transfer_type: RmtMode转移方式 :param transfer_type: RmtMode转移方式
@ -265,7 +261,7 @@ class FileTransferModule(_ModuleBase):
def __transfer_dir_files(self, src_dir: Path, target_dir: Path, transfer_type: str) -> int: def __transfer_dir_files(self, src_dir: Path, target_dir: Path, transfer_type: str) -> int:
""" """
按目录结构转移所有文件 按目录结构转移目录下所有文件
:param src_dir: 原路径 :param src_dir: 原路径
:param target_dir: 新路径 :param target_dir: 新路径
:param transfer_type: RmtMode转移方式 :param transfer_type: RmtMode转移方式
@ -321,22 +317,20 @@ class FileTransferModule(_ModuleBase):
def transfer_media(self, def transfer_media(self,
in_path: Path, in_path: Path,
in_meta: MetaBase,
mediainfo: MediaInfo, mediainfo: MediaInfo,
transfer_type: str, transfer_type: str,
target_dir: Path = None, target_dir: Path,
in_meta: MetaBase = None,
epformat: EpisodeFormat = None, epformat: EpisodeFormat = None,
min_filesize: int = 0
) -> TransferInfo: ) -> TransferInfo:
""" """
识别并转移一个文件、多个文件或者目录 识别并转移一个文件或者一个目录下的所有文件
:param in_path: 转移的路径,可能是一个文件也可以是一个目录 :param in_path: 转移的路径,可能是一个文件也可以是一个目录
:param in_meta预识别元数据
:param mediainfo: 媒体信息 :param mediainfo: 媒体信息
:param target_dir: 目的文件夹,非空的转移到该文件夹,为空时则按类型转移到配置文件中的媒体库文件夹 :param target_dir: 目的文件夹,非空的转移到该文件夹,为空时则按类型转移到配置文件中的媒体库文件夹
:param transfer_type: 文件转移方式 :param transfer_type: 文件转移方式
:param in_meta预识别元数为空则重新识别
:param epformat: 识别的剧集格式 :param epformat: 识别的剧集格式
:param min_filesize: 最小文件大小MB小于该值的文件不转移
:return: TransferInfo、错误信息 :return: TransferInfo、错误信息
""" """
# 检查目录路径 # 检查目录路径
@ -372,160 +366,96 @@ class FileTransferModule(_ModuleBase):
rename_format = settings.TV_RENAME_FORMAT \ rename_format = settings.TV_RENAME_FORMAT \
if mediainfo.type == MediaType.TV else settings.MOVIE_RENAME_FORMAT if mediainfo.type == MediaType.TV else settings.MOVIE_RENAME_FORMAT
# 总大小 # 判断是否为文件夹
total_filesize = 0 if in_path.is_dir():
# 转移整个目录
# 处理文件清单 # 是否蓝光原盘
file_list = []
# 目标文件清单
file_list_new = []
# 失败文件清单
fail_list = []
# 错误信息
err_msgs = []
# 判断是否为蓝光原盘
bluray_flag = SystemUtils.is_bluray_dir(in_path) bluray_flag = SystemUtils.is_bluray_dir(in_path)
if bluray_flag:
# 识别目录名称,不包括后缀
meta = MetaInfo(in_path.stem)
# 目的路径 # 目的路径
new_path = self.get_rename_path( new_path = self.get_rename_path(
path=target_dir, path=target_dir,
template_string=rename_format, template_string=rename_format,
rename_dict=self.__get_naming_dict(meta=meta, rename_dict=self.__get_naming_dict(meta=in_meta,
mediainfo=mediainfo) mediainfo=mediainfo)
).parent ).parent
# 转移蓝光原盘 # 转移蓝光原盘
retcode = self.__transfer_bluray_dir(file_path=in_path, retcode = self.__transfer_dir(file_path=in_path,
new_path=new_path, new_path=new_path,
transfer_type=transfer_type) transfer_type=transfer_type)
if retcode != 0: if retcode != 0:
return TransferInfo(message=f"{retcode},蓝光原盘转移失败") logger.error(f"文件夹 {in_path} 转移失败,错误码:{retcode}")
else: return TransferInfo(message=f"文件夹 {in_path} 转移失败,错误码:{retcode}")
# 计算大小
total_filesize += in_path.stat().st_size logger.info(f"文件夹 {in_path} 转移成功")
# 返回转移后的路径 # 返回转移后的路径
return TransferInfo(path=in_path, return TransferInfo(path=in_path,
target_path=new_path, target_path=new_path,
total_size=total_filesize, total_size=in_path.stat().st_size,
is_bluray=bluray_flag, is_bluray=bluray_flag)
file_list=[],
file_list_new=[])
else: else:
# 获取文件清单 # 转移单个文件
transfer_files: List[Path] = SystemUtils.list_files( # 文件结束季为空
directory=in_path, in_meta.end_season = None
extensions=settings.RMT_MEDIAEXT, # 文件总季数为1
min_filesize=min_filesize if in_meta.total_season:
) in_meta.total_season = 1
if len(transfer_files) == 0: # 文件不可能有多集
return TransferInfo(message=f"{in_path} 目录下没有找到可转移的文件") if in_meta.total_episode > 2:
in_meta.total_episode = 1
in_meta.end_episode = None
# 有集自定义格式 # 有集自定义格式
formaterHandler = FormatParser(eformat=epformat.format, formaterHandler = FormatParser(eformat=epformat.format,
details=epformat.detail, details=epformat.detail,
part=epformat.part, part=epformat.part,
offset=epformat.offset) if epformat else None offset=epformat.offset) if epformat else None
# 过滤出符合自定义剧集格式的文件
if formaterHandler:
transfer_files = [x for x in transfer_files if formaterHandler.match(x.name)]
if len(transfer_files) == 0:
return TransferInfo(message=f"{in_path} 目录下没有找到符合自定义剧集格式的文件")
if not in_meta: # 自定义识别集数、PART
# 识别目录名称,不包括后缀
meta = MetaInfo(in_path.stem)
else:
meta = in_meta
# 目的路径
new_path = target_dir / (self.get_rename_path(
template_string=rename_format,
rename_dict=self.__get_naming_dict(meta=meta,
mediainfo=mediainfo)).parents[-2].name)
# 转移所有文件
for transfer_file in transfer_files:
try:
if not in_meta:
# 识别文件元数据,不包含后缀
file_meta = MetaInfo(transfer_file.stem)
# 合并元数据
file_meta.merge(meta)
else:
file_meta = in_meta
# 文件结束季为空
file_meta.end_season = None
# 文件总季数为1
if file_meta.total_season:
file_meta.total_season = 1
# 文件不可能有多集
if file_meta.total_episode > 2:
file_meta.total_episode = 1
file_meta.end_episode = None
# 自定义识别
if formaterHandler: if formaterHandler:
# 开始集、结束集、PART # 开始集、结束集、PART
begin_ep, end_ep, part = formaterHandler.split_episode(transfer_file.stem) begin_ep, end_ep, part = formaterHandler.split_episode(in_path.stem)
if begin_ep is not None: if begin_ep is not None:
file_meta.begin_episode = begin_ep in_meta.begin_episode = begin_ep
file_meta.part = part in_meta.part = part
if end_ep is not None: if end_ep is not None:
file_meta.end_episode = end_ep in_meta.end_episode = end_ep
# 目的文件名 # 目的文件名
new_file = self.get_rename_path( new_file = self.get_rename_path(
path=target_dir, path=target_dir,
template_string=rename_format, template_string=rename_format,
rename_dict=self.__get_naming_dict(meta=file_meta, rename_dict=self.__get_naming_dict(
meta=in_meta,
mediainfo=mediainfo, mediainfo=mediainfo,
file_ext=transfer_file.suffix) file_ext=in_path.suffix
)
) )
# 判断是否要覆盖 # 判断是否要覆盖
overflag = False overflag = False
if new_file.exists(): if new_file.exists():
if new_file.stat().st_size < transfer_file.stat().st_size: if new_file.stat().st_size < in_path.stat().st_size:
logger.info(f"目标文件已存在,但文件大小更小,将覆盖:{new_file}") logger.info(f"目标文件已存在,但文件大小更小,将覆盖:{new_file}")
overflag = True overflag = True
# 转移文件 # 转移文件
retcode = self.__transfer_file(file_item=transfer_file, retcode = self.__transfer_file(file_item=in_path,
new_file=new_file, new_file=new_file,
transfer_type=transfer_type, transfer_type=transfer_type,
over_flag=overflag) over_flag=overflag)
if retcode != 0: if retcode != 0:
logger.error(f"{transfer_file} 转移文件失败,错误码:{retcode}") logger.error(f"文件 {in_path} 转移失败,错误码:{retcode}")
err_msgs.append(f"{transfer_file.name}错误码 {retcode}") return TransferInfo(message=f"文件 {in_path.name} 转移失败,错误码{retcode}",
fail_list.append(transfer_file) fail_list=[in_path])
continue
# 源文件清单
file_list.append(str(transfer_file))
# 目的文件清单
file_list_new.append(str(new_file))
# 计算总大小
total_filesize += new_file.stat().st_size
except Exception as err:
err_msgs.append(f"{transfer_file.name}{err}")
logger.error(f"{transfer_file}转移失败:{err}")
fail_list.append(transfer_file)
if not file_list:
# 没有成功的
return TransferInfo(message="\n".join(err_msgs))
logger.info(f"文件 {in_path} 转移成功")
return TransferInfo(path=in_path, return TransferInfo(path=in_path,
target_path=new_path, target_path=new_file,
message="\n".join(err_msgs), file_count=1,
file_count=len(file_list), total_size=in_path.stat().st_size,
total_size=total_filesize, is_bluray=False,
fail_list=fail_list, file_list=[in_path],
is_bluray=bluray_flag, file_list_new=[new_file])
file_list=file_list,
file_list_new=file_list_new)
@staticmethod @staticmethod
def __get_naming_dict(meta: MetaBase, mediainfo: MediaInfo, file_ext: str = None) -> dict: def __get_naming_dict(meta: MetaBase, mediainfo: MediaInfo, file_ext: str = None) -> dict:

View File

@ -10,7 +10,7 @@ from app.core.metainfo import MetaInfo
from app.log import logger from app.log import logger
from app.modules import _ModuleBase from app.modules import _ModuleBase
from app.modules.qbittorrent.qbittorrent import Qbittorrent from app.modules.qbittorrent.qbittorrent import Qbittorrent
from app.schemas import TransferInfo, TransferTorrent, DownloadingTorrent from app.schemas import TransferTorrent, DownloadingTorrent
from app.schemas.types import TorrentStatus from app.schemas.types import TorrentStatus
from app.utils.string import StringUtils from app.utils.string import StringUtils
from app.utils.system import SystemUtils from app.utils.system import SystemUtils
@ -156,11 +156,11 @@ class QbittorrentModule(_ModuleBase):
return ret_torrents return ret_torrents
def transfer_completed(self, hashs: Union[str, list], def transfer_completed(self, hashs: Union[str, list],
transinfo: TransferInfo = None) -> None: path: Path = None) -> None:
""" """
转移完成后的处理 转移完成后的处理
:param hashs: 种子Hash :param hashs: 种子Hash
:param transinfo: 转移信息 :param path: 源目录
""" """
self.qbittorrent.set_torrents_tag(ids=hashs, tags=['已整理']) self.qbittorrent.set_torrents_tag(ids=hashs, tags=['已整理'])
# 移动模式删除种子 # 移动模式删除种子
@ -168,11 +168,11 @@ class QbittorrentModule(_ModuleBase):
if self.remove_torrents(hashs): if self.remove_torrents(hashs):
logger.info(f"移动模式删除种子成功:{hashs} ") logger.info(f"移动模式删除种子成功:{hashs} ")
# 删除残留文件 # 删除残留文件
if transinfo and transinfo.path and transinfo.path.exists(): if path and path.exists():
files = SystemUtils.list_files(transinfo.path, settings.RMT_MEDIAEXT) files = SystemUtils.list_files(path, settings.RMT_MEDIAEXT)
if not files: if not files:
logger.warn(f"删除残留文件夹:{transinfo.path}") logger.warn(f"删除残留文件夹:{path}")
shutil.rmtree(transinfo.path, ignore_errors=True) shutil.rmtree(path, ignore_errors=True)
def remove_torrents(self, hashs: Union[str, list]) -> bool: def remove_torrents(self, hashs: Union[str, list]) -> bool:
""" """

View File

@ -10,7 +10,7 @@ from app.core.metainfo import MetaInfo
from app.log import logger from app.log import logger
from app.modules import _ModuleBase from app.modules import _ModuleBase
from app.modules.transmission.transmission import Transmission from app.modules.transmission.transmission import Transmission
from app.schemas import TransferInfo, TransferTorrent, DownloadingTorrent from app.schemas import TransferTorrent, DownloadingTorrent
from app.schemas.types import TorrentStatus from app.schemas.types import TorrentStatus
from app.utils.string import StringUtils from app.utils.string import StringUtils
from app.utils.system import SystemUtils from app.utils.system import SystemUtils
@ -141,11 +141,11 @@ class TransmissionModule(_ModuleBase):
return ret_torrents return ret_torrents
def transfer_completed(self, hashs: Union[str, list], def transfer_completed(self, hashs: Union[str, list],
transinfo: TransferInfo = None) -> None: path: Path = None) -> None:
""" """
转移完成后的处理 转移完成后的处理
:param hashs: 种子Hash :param hashs: 种子Hash
:param transinfo: 转移信息 :param path: 源目录
:return: None :return: None
""" """
self.transmission.set_torrent_tag(ids=hashs, tags=['已整理']) self.transmission.set_torrent_tag(ids=hashs, tags=['已整理'])
@ -154,11 +154,11 @@ class TransmissionModule(_ModuleBase):
if self.remove_torrents(hashs): if self.remove_torrents(hashs):
logger.info(f"移动模式删除种子成功:{hashs} ") logger.info(f"移动模式删除种子成功:{hashs} ")
# 删除残留文件 # 删除残留文件
if transinfo and transinfo.path and transinfo.path.exists(): if path and path.exists():
files = SystemUtils.list_files(transinfo.path, settings.RMT_MEDIAEXT) files = SystemUtils.list_files(path, settings.RMT_MEDIAEXT)
if not files: if not files:
logger.warn(f"删除残留文件夹:{transinfo.path}") logger.warn(f"删除残留文件夹:{path}")
shutil.rmtree(transinfo.path, ignore_errors=True) shutil.rmtree(path, ignore_errors=True)
def remove_torrents(self, hashs: Union[str, list]) -> bool: def remove_torrents(self, hashs: Union[str, list]) -> bool:
""" """

View File

@ -383,7 +383,7 @@ class DirMonitor(_PluginBase):
} }
self._medias[mediainfo.title_year + " " + meta.season] = media_list self._medias[mediainfo.title_year + " " + meta.season] = media_list
# 刷新媒体库 # 汇总刷新媒体库
self.chain.refresh_mediaserver(mediainfo=mediainfo, file_path=target_path) self.chain.refresh_mediaserver(mediainfo=mediainfo, file_path=target_path)
# 广播事件 # 广播事件
self.eventmanager.send_event(EventType.TransferComplete, { self.eventmanager.send_event(EventType.TransferComplete, {