fix 统一文件识别处理逻辑

This commit is contained in:
jxxghp
2023-08-17 11:56:21 +08:00
parent 8828447367
commit 7b9249894b
5 changed files with 140 additions and 106 deletions

View File

@@ -269,15 +269,19 @@ 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, transfer_type: str) -> Optional[TransferInfo]: def transfer(self, path: Path, mediainfo: MediaInfo,
transfer_type: str,
meta: MetaBase = None) -> Optional[TransferInfo]:
""" """
文件转移 文件转移
:param path: 文件路径 :param path: 文件路径
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息
:param transfer_type: 转移模式 :param transfer_type: 转移模式
:param meta: 预识别的元数据,仅单文件转移时传递
:return: {path, target_path, message} :return: {path, target_path, message}
""" """
return self.run_module("transfer", path=path, mediainfo=mediainfo, transfer_type=transfer_type) return self.run_module("transfer", path=path, mediainfo=mediainfo,
transfer_type=transfer_type, meta=meta)
def transfer_completed(self, hashs: Union[str, list], transinfo: TransferInfo) -> None: def transfer_completed(self, hashs: Union[str, list], transinfo: TransferInfo) -> None:
""" """

View File

@@ -36,7 +36,8 @@ class TransferChain(ChainBase):
self.transferhis = TransferHistoryOper(self._db) self.transferhis = TransferHistoryOper(self._db)
self.progress = ProgressHelper() self.progress = ProgressHelper()
def process(self, arg_str: str = None, channel: MessageChannel = None, userid: Union[str, int] = None) -> bool: def process(self, arg_str: str = None,
channel: MessageChannel = None, userid: Union[str, int] = None) -> bool:
""" """
获取下载器中的种子列表,并执行转移 获取下载器中的种子列表,并执行转移
:param arg_str: 传入的参数 (种子hash和TMDBID|类型) :param arg_str: 传入的参数 (种子hash和TMDBID|类型)
@@ -154,13 +155,16 @@ class TransferChain(ChainBase):
transferinfo: TransferInfo = self.transfer(mediainfo=mediainfo, transferinfo: TransferInfo = self.transfer(mediainfo=mediainfo,
path=torrent.path, path=torrent.path,
transfer_type=settings.TRANSFER_TYPE) transfer_type=settings.TRANSFER_TYPE)
if not transferinfo or not transferinfo.target_path: if not transferinfo:
logger.error("文件转移模块运行失败")
continue
if not transferinfo.target_path:
# 转移失败 # 转移失败
logger.warn(f"{torrent.title} 入库失败") logger.warn(f"{torrent.title} 入库失败{transferinfo.message}")
self.post_message(Notification( self.post_message(Notification(
channel=channel, channel=channel,
title=f"{mediainfo.title_year}{meta.season_episode} 入库失败!", title=f"{mediainfo.title_year}{meta.season_episode} 入库失败!",
text=f"原因:{transferinfo.message if transferinfo else '未知'}", text=f"原因:{transferinfo.message or '未知'}",
image=mediainfo.get_message_image(), image=mediainfo.get_message_image(),
userid=userid userid=userid
)) ))
@@ -189,7 +193,7 @@ class TransferChain(ChainBase):
# 新增转移成功历史记录 # 新增转移成功历史记录
self.transferhis.add( self.transferhis.add(
src=str(torrent.path), src=str(torrent.path),
dest=str(transferinfo.target_path) if transferinfo else None, dest=str(transferinfo.target_path),
mode=settings.TRANSFER_TYPE, mode=settings.TRANSFER_TYPE,
type=mediainfo.type.value, type=mediainfo.type.value,
category=mediainfo.category, category=mediainfo.category,

View File

@@ -1,5 +1,5 @@
from dataclasses import dataclass, asdict from dataclasses import dataclass, asdict
from typing import Union, Optional, List from typing import Union, Optional, List, Self
import cn2an import cn2an
import regex as re import regex as re
@@ -443,6 +443,61 @@ class MetaBase(object):
elif str(ep).isdigit(): elif str(ep).isdigit():
self.begin_episode = int(ep) self.begin_episode = int(ep)
self.end_episode = None self.end_episode = None
def merge(self, meta: Self):
"""
全并Meta信息
"""
# 类型
if self.type == MediaType.UNKNOWN \
and meta.type != MediaType.UNKNOWN:
self.type = meta.type
# 名称
if not self.name:
self.cn_name = meta.cn_name
self.en_name = meta.en_name
# 年份
if not self.year:
self.year = meta.year
# 开始季
if not self.begin_season:
self.begin_season = meta.begin_season
# 结束季
if not self.end_season:
self.end_season = meta.end_season
# 总季数
if self.begin_season:
self.total_seasons = meta.total_seasons
# 开始集
if not self.begin_episode:
self.begin_episode = meta.begin_episode
# 结束集
if not self.end_episode:
self.end_episode = meta.end_episode
# 总集数
if not self.total_episode:
self.total_episode = meta.total_episode
# 版本
if not self.resource_type:
self.resource_type = meta.resource_type
# 分辨率
if not self.resource_pix:
self.resource_pix = meta.resource_pix
# 制作组/字幕组
if not self.resource_team:
self.resource_team = meta.resource_team
# 特效
if not self.resource_effect:
self.resource_effect = meta.resource_effect
# 视频编码
if not self.video_encode:
self.video_encode = meta.video_encode
# 音频编码
if not self.audio_encode:
self.audio_encode = meta.audio_encode
# Part
if not self.part:
self.part = meta.part
def to_dict(self): def to_dict(self):
""" """

View File

@@ -29,12 +29,14 @@ 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, transfer_type: str) -> Optional[TransferInfo]: def transfer(self, path: Path, mediainfo: MediaInfo,
transfer_type: str, meta: MetaBase = None) -> TransferInfo:
""" """
文件转移 文件转移
:param path: 文件路径 :param path: 文件路径
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息
:param transfer_type: 转移方式 :param transfer_type: 转移方式
:param meta: 预识别的元数据,仅单文件转移时传递
:return: {path, target_path, message} :return: {path, target_path, message}
""" """
# 获取目标路径 # 获取目标路径
@@ -43,26 +45,11 @@ class FileTransferModule(_ModuleBase):
logger.error("未找到媒体库目录,无法转移文件") logger.error("未找到媒体库目录,无法转移文件")
return TransferInfo(message="未找到媒体库目录,无法转移文件") return TransferInfo(message="未找到媒体库目录,无法转移文件")
# 转移 # 转移
result = self.transfer_media(in_path=path, return self.transfer_media(in_path=path,
mediainfo=mediainfo, mediainfo=mediainfo,
transfer_type=transfer_type, transfer_type=transfer_type,
target_dir=target_path) target_dir=target_path,
if not result: file_meta=meta)
return TransferInfo()
if isinstance(result, str):
return TransferInfo(message=result)
# 解包结果
is_bluray, target_path, file_list, file_list_new, file_size, fail_list, msg = result
# 返回
return TransferInfo(path=path,
target_path=target_path,
message=msg,
file_count=len(file_list),
total_size=file_size,
fail_list=fail_list,
is_bluray=is_bluray,
file_list=file_list,
file_list_new=file_list_new)
@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:
@@ -338,22 +325,24 @@ class FileTransferModule(_ModuleBase):
in_path: Path, in_path: Path,
mediainfo: MediaInfo, mediainfo: MediaInfo,
transfer_type: str, transfer_type: str,
target_dir: Path = None target_dir: Path = None,
) -> Union[str, Tuple[bool, Path, list, list, int, List[Path], str]]: file_meta: MetaBase = None
) -> TransferInfo:
""" """
识别并转移一个文件、多个文件或者目录 识别并转移一个文件、多个文件或者目录
:param in_path: 转移的路径,可能是一个文件也可以是一个目录 :param in_path: 转移的路径,可能是一个文件也可以是一个目录
:param mediainfo: 媒体信息
:param target_dir: 目的文件夹,非空的转移到该文件夹,为空时则按类型转移到配置文件中的媒体库文件夹 :param target_dir: 目的文件夹,非空的转移到该文件夹,为空时则按类型转移到配置文件中的媒体库文件夹
:param transfer_type: 文件转移方式 :param transfer_type: 文件转移方式
:param mediainfo: 媒体信息 :param file_meta预识别元数为空则重新识别
:return: 是否蓝光原盘、目的路径、处理文件清单、总大小、失败文件列表、错误信息 :return: TransferInfo、错误信息
""" """
# 检查目录路径 # 检查目录路径
if not in_path.exists(): if not in_path.exists():
return f"{in_path} 路径不存在" return TransferInfo(message=f"{in_path} 路径不存在")
if not target_dir.exists(): if not target_dir.exists():
return f"{target_dir} 目标路径不存在" return TransferInfo(message=f"{target_dir} 目标路径不存在")
if mediainfo.type == MediaType.MOVIE: if mediainfo.type == MediaType.MOVIE:
if settings.LIBRARY_MOVIE_NAME: if settings.LIBRARY_MOVIE_NAME:
@@ -405,17 +394,22 @@ class FileTransferModule(_ModuleBase):
new_path=new_path, new_path=new_path,
transfer_type=transfer_type) transfer_type=transfer_type)
if retcode != 0: if retcode != 0:
return f"{retcode},蓝光原盘转移失败" return TransferInfo(message=f"{retcode},蓝光原盘转移失败")
else: else:
# 计算大小 # 计算大小
total_filesize += in_path.stat().st_size total_filesize += in_path.stat().st_size
# 返回转移后的路径 # 返回转移后的路径
return bluray_flag, new_path, [], [], total_filesize, [], "" return TransferInfo(path=in_path,
target_path=new_path,
total_size=total_filesize,
is_bluray=bluray_flag,
file_list=[],
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_with_extensions(in_path, settings.RMT_MEDIAEXT)
if len(transfer_files) == 0: if len(transfer_files) == 0:
return f"{in_path} 目录下没有找到可转移的文件" return TransferInfo(message=f"{in_path} 目录下没有找到可转移的文件")
# 识别目录名称,不包括后缀 # 识别目录名称,不包括后缀
meta = MetaInfo(in_path.stem) meta = MetaInfo(in_path.stem)
# 目的路径 # 目的路径
@@ -427,46 +421,16 @@ class FileTransferModule(_ModuleBase):
# 转移所有文件 # 转移所有文件
for transfer_file in transfer_files: for transfer_file in transfer_files:
try: try:
# 识别文件元数据,不包含后缀 if not file_meta:
file_meta = MetaInfo(transfer_file.stem) # 识别文件元数据,不包含后缀
# 开始季 file_meta = MetaInfo(transfer_file.stem)
if not file_meta.begin_season: # 合并元数据
file_meta.begin_season = meta.begin_season file_meta.merge(meta)
# 结束季为空 # 结束季为空
file_meta.end_season = None file_meta.end_season = None
# 总季数 # 总季数为1
if file_meta.begin_season: if file_meta.begin_season:
file_meta.total_seasons = 1 file_meta.total_seasons = 1
# 开始集
if not file_meta.begin_episode:
file_meta.begin_episode = meta.begin_episode
# 结束集
if not file_meta.end_episode:
file_meta.end_episode = meta.end_episode
# 总集数
if not file_meta.total_episode:
file_meta.total_episode = meta.total_episode
# 版本
if not file_meta.resource_type:
file_meta.resource_type = meta.resource_type
# 分辨率
if not file_meta.resource_pix:
file_meta.resource_pix = meta.resource_pix
# 制作组/字幕组
if not file_meta.resource_team:
file_meta.resource_team = meta.resource_team
# 特效
if not file_meta.resource_effect:
file_meta.resource_effect = meta.resource_effect
# 视频编码
if not file_meta.video_encode:
file_meta.video_encode = meta.video_encode
# 音频编码
if not file_meta.audio_encode:
file_meta.audio_encode = meta.audio_encode
# Part
if not file_meta.part:
file_meta.part = meta.part
# 目的文件名 # 目的文件名
new_file = self.get_rename_path( new_file = self.get_rename_path(
path=target_dir, path=target_dir,
@@ -475,6 +439,8 @@ class FileTransferModule(_ModuleBase):
mediainfo=mediainfo, mediainfo=mediainfo,
file_ext=transfer_file.suffix) file_ext=transfer_file.suffix)
) )
# 重新修正目的路径
new_path = new_path.parents[-2].name
# 判断是否要覆盖 # 判断是否要覆盖
overflag = False overflag = False
if new_file.exists(): if new_file.exists():
@@ -491,10 +457,11 @@ class FileTransferModule(_ModuleBase):
err_msgs.append(f"{transfer_file.name}:错误码 {retcode}") err_msgs.append(f"{transfer_file.name}:错误码 {retcode}")
fail_list.append(transfer_file) fail_list.append(transfer_file)
continue continue
# 计算文件数 # 源文件清单
file_list.append(str(transfer_file)) file_list.append(str(transfer_file))
# 目的文件清单
file_list_new.append(str(new_file)) file_list_new.append(str(new_file))
# 计算大小 # 计算大小
total_filesize += transfer_file.stat().st_size total_filesize += transfer_file.stat().st_size
except Exception as err: except Exception as err:
err_msgs.append(f"{transfer_file.name}{err}") err_msgs.append(f"{transfer_file.name}{err}")
@@ -503,10 +470,17 @@ class FileTransferModule(_ModuleBase):
if not file_list: if not file_list:
# 没有成功的 # 没有成功的
return "\n".join(err_msgs) return TransferInfo(message="\n".join(err_msgs))
# 蓝光原盘、新路径、处理文件清单、总大小、失败文件列表、错误信息 return TransferInfo(path=in_path,
return bluray_flag, new_path, file_list, file_list_new, total_filesize, fail_list, "\n".join(err_msgs) target_path=new_path,
message="\n".join(err_msgs),
file_count=len(file_list),
total_size=total_filesize,
fail_list=fail_list,
is_bluray=bluray_flag,
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

@@ -15,7 +15,7 @@ from app.core.metainfo import MetaInfo
from app.db.transferhistory_oper import TransferHistoryOper from app.db.transferhistory_oper import TransferHistoryOper
from app.log import logger from app.log import logger
from app.plugins import _PluginBase from app.plugins import _PluginBase
from app.schemas import MediaType, Notification, NotificationType, TransferInfo from app.schemas import Notification, NotificationType, TransferInfo
from app.schemas.types import EventType from app.schemas.types import EventType
lock = threading.Lock() lock = threading.Lock()
@@ -180,24 +180,17 @@ class DirMonitor(_PluginBase):
logger.info(f"{event_path} 已整理过") logger.info(f"{event_path} 已整理过")
return return
# 文件元数据
file_meta = MetaInfo(title=file_path.name)
# 上级目录元数据 # 上级目录元数据
dir_meta = MetaInfo(title=file_path.parent.name) meta = MetaInfo(title=file_path.parent.name)
# 整合元数据 # 文件元数据,不包含后缀
if not file_meta.cn_name and dir_meta.cn_name: file_meta = MetaInfo(title=file_path.stem)
file_meta.cn_name = dir_meta.cn_name # 合并元数据
if not file_meta.en_name and dir_meta.en_name: file_meta.merge(meta)
file_meta.en_name = dir_meta.en_name # 结束季为空
if file_meta.type != MediaType.TV and dir_meta.type == MediaType.TV: file_meta.end_season = None
file_meta.type = MediaType.TV # 总季数为1
if not file_meta.year and dir_meta.year: if file_meta.begin_season:
file_meta.year = dir_meta.year file_meta.total_seasons = 1
if not file_meta.begin_season and dir_meta.begin_season:
file_meta.begin_season = dir_meta.begin_season
if not file_meta.episode_list and dir_meta.episode_list:
file_meta.begin_episode = dir_meta.begin_episode
file_meta.end_episode = dir_meta.end_episode
if not file_meta.name: if not file_meta.name:
logger.warn(f"{file_path.name} 无法识别有效信息") logger.warn(f"{file_path.name} 无法识别有效信息")
@@ -221,15 +214,19 @@ class DirMonitor(_PluginBase):
# 转移 # 转移
transferinfo: TransferInfo = self.chain.transfer(mediainfo=mediainfo, transferinfo: TransferInfo = self.chain.transfer(mediainfo=mediainfo,
path=file_path, path=file_path,
transfer_type=self._transfer_type) transfer_type=self._transfer_type,
meta=file_meta)
if not transferinfo or not transferinfo.target_path: if not transferinfo:
logger.error("文件转移模块运行失败")
return
if not transferinfo.target_path:
# 转移失败 # 转移失败
logger.warn(f"{file_path.name} 入库失败") logger.warn(f"{file_path.name} 入库失败{transferinfo.message}")
if self._notify: if self._notify:
self.chain.post_message(Notification( self.chain.post_message(Notification(
title=f"{mediainfo.title_year}{file_meta.season_episode} 入库失败!", title=f"{mediainfo.title_year}{file_meta.season_episode} 入库失败!",
text=f"原因:{transferinfo.message if transferinfo else '未知'}", text=f"原因:{transferinfo.message or '未知'}",
image=mediainfo.get_message_image() image=mediainfo.get_message_image()
)) ))
return return
@@ -237,7 +234,7 @@ class DirMonitor(_PluginBase):
# 新增转移成功历史记录 # 新增转移成功历史记录
self.transferhis.add( self.transferhis.add(
src=event_path, src=event_path,
dest=str(transferinfo.target_path) if transferinfo else None, dest=str(transferinfo.target_path),
mode=settings.TRANSFER_TYPE, mode=settings.TRANSFER_TYPE,
type=mediainfo.type.value, type=mediainfo.type.value,
category=mediainfo.category, category=mediainfo.category,