need fix
This commit is contained in:
@ -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:
|
||||||
"""
|
"""
|
||||||
|
@ -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, "文件转移模块运行失败"
|
||||||
|
@ -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:
|
||||||
|
@ -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:
|
||||||
"""
|
"""
|
||||||
|
@ -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:
|
||||||
"""
|
"""
|
||||||
|
@ -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, {
|
||||||
|
Reference in New Issue
Block a user