diff --git a/README.md b/README.md index 7b075dce..eba89926 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,7 @@ docker pull jxxghp/moviepilot:latest > `season`: 季号 > `episode`: 集号 > `season_episode`: 季集 SxxExx +> `episode_title`: 集标题 `TV_RENAME_FORMAT`默认配置格式: diff --git a/app/chain/__init__.py b/app/chain/__init__.py index 25af7083..cd281904 100644 --- a/app/chain/__init__.py +++ b/app/chain/__init__.py @@ -18,7 +18,7 @@ from app.core.meta import MetaBase from app.core.module import ModuleManager from app.log import logger from app.schemas import TransferInfo, TransferTorrent, ExistMediaInfo, DownloadingTorrent, CommingMessage, Notification, \ - WebhookEventInfo + WebhookEventInfo, TmdbEpisode from app.schemas.types import TorrentStatus, MediaType, MediaImageType, EventType from app.utils.object import ObjectUtils @@ -274,7 +274,8 @@ class ChainBase(metaclass=ABCMeta): return self.run_module("list_torrents", status=status, hashs=hashs) def transfer(self, path: Path, meta: MetaBase, mediainfo: MediaInfo, - transfer_type: str, target: Path = None) -> Optional[TransferInfo]: + transfer_type: str, target: Path = None, + episodes_info: List[TmdbEpisode] = None) -> Optional[TransferInfo]: """ 文件转移 :param path: 文件路径 @@ -282,10 +283,12 @@ class ChainBase(metaclass=ABCMeta): :param mediainfo: 识别的媒体信息 :param transfer_type: 转移模式 :param target: 转移目标路径 + :param episodes_info: 当前季的全部集信息 :return: {path, target_path, message} """ return self.run_module("transfer", path=path, meta=meta, mediainfo=mediainfo, - transfer_type=transfer_type, target=target) + transfer_type=transfer_type, target=target, + episodes_info=episodes_info) def transfer_completed(self, hashs: Union[str, list], path: Path = None) -> None: """ diff --git a/app/chain/transfer.py b/app/chain/transfer.py index 124e966b..ad4c6bfd 100644 --- a/app/chain/transfer.py +++ b/app/chain/transfer.py @@ -9,6 +9,7 @@ from sqlalchemy.orm import Session from app.chain import ChainBase from app.chain.media import MediaChain +from app.chain.tmdb import TmdbChain from app.core.config import settings from app.core.context import MediaInfo from app.core.meta import MetaBase @@ -41,6 +42,7 @@ class TransferChain(ChainBase): self.transferhis = TransferHistoryOper(self._db) self.progress = ProgressHelper() self.mediachain = MediaChain(self._db) + self.tmdbchain = TmdbChain(self._db) self.systemconfig = SystemConfigOper() def process(self) -> bool: @@ -257,31 +259,17 @@ class TransferChain(ChainBase): logger.info(f"{file_path.name} 识别为:{file_mediainfo.type.value} {file_mediainfo.title_year}") - # 电视剧没有集无法转移 - if file_mediainfo.type == MediaType.TV and not file_meta.episode: - # 转移失败 - logger.warn(f"{file_path.name} 入库失败:未识别到集数") - err_msgs.append(f"{file_path.name} 未识别到集数") - # 新增转移失败历史记录 - self.transferhis.add_fail( - src_path=file_path, - mode=settings.TRANSFER_TYPE, - download_hash=download_hash, - meta=file_meta, - mediainfo=file_mediainfo - ) - # 发送消息 - self.post_message(Notification( - mtype=NotificationType.Manual, - title=f"{file_path.name} 入库失败!", - text=f"原因:未识别到集数", - image=file_mediainfo.get_message_image() - )) - continue - # 更新媒体图片 self.obtain_images(mediainfo=file_mediainfo) + # 获取集数据 + if mediainfo.type == MediaType.TV: + episodes_info = self.tmdbchain.tmdb_episodes(tmdbid=mediainfo.tmdb_id, + season=file_meta.begin_season or 1) + else: + episodes_info = None + + # 获取下载hash if not download_hash: download_file = self.downloadhis.get_file_by_fullpath(file_path_str) if download_file: @@ -292,7 +280,8 @@ class TransferChain(ChainBase): mediainfo=file_mediainfo, path=file_path, transfer_type=transfer_type, - target=target) + target=target, + episodes_info=episodes_info) if not transferinfo: logger.error("文件转移模块运行失败") return False, "文件转移模块运行失败" diff --git a/app/modules/filetransfer/__init__.py b/app/modules/filetransfer/__init__.py index 64d34ad9..d58f4b90 100644 --- a/app/modules/filetransfer/__init__.py +++ b/app/modules/filetransfer/__init__.py @@ -11,7 +11,7 @@ from app.core.meta import MetaBase from app.core.metainfo import MetaInfo from app.log import logger from app.modules import _ModuleBase -from app.schemas import TransferInfo, ExistMediaInfo +from app.schemas import TransferInfo, ExistMediaInfo, TmdbEpisode from app.schemas.types import MediaType from app.utils.system import SystemUtils @@ -30,7 +30,8 @@ class FileTransferModule(_ModuleBase): pass def transfer(self, path: Path, meta: MetaBase, mediainfo: MediaInfo, - transfer_type: str, target: Path = None) -> TransferInfo: + transfer_type: str, target: Path = None, + episodes_info: List[TmdbEpisode] = None) -> TransferInfo: """ 文件转移 :param path: 文件路径 @@ -38,6 +39,7 @@ class FileTransferModule(_ModuleBase): :param mediainfo: 识别的媒体信息 :param transfer_type: 转移方式 :param target: 目标路径 + :param episodes_info: 当前季的全部集信息 :return: {path, target_path, message} """ # 获取目标路径 @@ -49,13 +51,14 @@ class FileTransferModule(_ModuleBase): logger.error("未找到媒体库目录,无法转移文件") return TransferInfo(success=False, path=path, - message="未找到媒体库目录,无法转移文件") + message="未找到媒体库目录") # 转移 return self.transfer_media(in_path=path, in_meta=meta, mediainfo=mediainfo, transfer_type=transfer_type, - target_dir=target) + target_dir=target, + episodes_info=episodes_info) @staticmethod def __transfer_command(file_item: Path, target_file: Path, transfer_type: str) -> int: @@ -355,6 +358,7 @@ class FileTransferModule(_ModuleBase): mediainfo: MediaInfo, transfer_type: str, target_dir: Path, + episodes_info: List[TmdbEpisode] = None ) -> TransferInfo: """ 识别并转移一个文件或者一个目录下的所有文件 @@ -363,6 +367,7 @@ class FileTransferModule(_ModuleBase): :param mediainfo: 媒体信息 :param target_dir: 媒体库根目录 :param transfer_type: 文件转移方式 + :param episodes_info: 当前季的全部集信息 :return: TransferInfo、错误信息 """ # 检查目录路径 @@ -404,7 +409,7 @@ class FileTransferModule(_ModuleBase): if retcode != 0: logger.error(f"文件夹 {in_path} 转移失败,错误码:{retcode}") return TransferInfo(success=False, - message=f"文件夹 {in_path} 转移失败,错误码:{retcode}", + message=f"错误码:{retcode}", path=in_path, target_path=new_path, is_bluray=bluray_flag) @@ -418,17 +423,24 @@ class FileTransferModule(_ModuleBase): is_bluray=bluray_flag) else: # 转移单个文件 - # 文件结束季为空 - in_meta.end_season = None + if mediainfo.type == MediaType.TV: + # 电视剧 + if in_meta.begin_episode is None: + logger.warn(f"文件 {in_path} 转移失败:未识别到文件集数") + return TransferInfo(success=False, + message=f"未识别到文件集数", + path=in_path, + fail_list=[str(in_path)]) - # 文件总季数为1 - if in_meta.total_season: - in_meta.total_season = 1 - - # 文件不可能有多集 - if in_meta.total_episode > 2: - in_meta.total_episode = 1 - in_meta.end_episode = None + # 文件结束季为空 + 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 # 目的文件名 new_file = self.get_rename_path( @@ -437,6 +449,7 @@ class FileTransferModule(_ModuleBase): rename_dict=self.__get_naming_dict( meta=in_meta, mediainfo=mediainfo, + episodes_info=episodes_info, file_ext=in_path.suffix ) ) @@ -456,7 +469,7 @@ class FileTransferModule(_ModuleBase): if retcode != 0: logger.error(f"文件 {in_path} 转移失败,错误码:{retcode}") return TransferInfo(success=False, - message=f"文件 {in_path.name} 转移失败,错误码:{retcode}", + message=f"错误码:{retcode}", path=in_path, target_path=new_file, fail_list=[str(in_path)]) @@ -472,13 +485,23 @@ class FileTransferModule(_ModuleBase): file_list_new=[str(new_file)]) @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, + episodes_info: List[TmdbEpisode] = None) -> dict: """ 根据媒体信息,返回Format字典 :param meta: 文件元数据 :param mediainfo: 识别的媒体信息 :param file_ext: 文件扩展名 + :param episodes_info: 当前季的全部集信息 """ + # 获取集标题 + episode_title = None + if meta.begin_episode and episodes_info: + for episode in episodes_info: + if episode.episode_number == meta.begin_episode: + episode_title = episode.name + break + return { # 标题 "title": mediainfo.title, @@ -514,6 +537,8 @@ class FileTransferModule(_ModuleBase): "season_episode": "%s%s" % (meta.season, meta.episodes), # 段/节 "part": meta.part, + # 剧集标题 + "episode_title": episode_title, # 文件后缀 "fileExt": file_ext } @@ -613,9 +638,10 @@ class FileTransferModule(_ModuleBase): rename_format = settings.TV_RENAME_FORMAT \ if mediainfo.type == MediaType.TV else settings.MOVIE_RENAME_FORMAT # 相对路径 + meta = MetaInfo(mediainfo.title) rel_path = self.get_rename_path( template_string=rename_format, - rename_dict=self.__get_naming_dict(meta=MetaInfo(mediainfo.title), + rename_dict=self.__get_naming_dict(meta=meta, mediainfo=mediainfo) ) # 取相对路径的第1层目录 diff --git a/app/plugins/dirmonitor/__init__.py b/app/plugins/dirmonitor/__init__.py index 0264b8fb..377b00ec 100644 --- a/app/plugins/dirmonitor/__init__.py +++ b/app/plugins/dirmonitor/__init__.py @@ -12,6 +12,7 @@ from watchdog.events import FileSystemEventHandler from watchdog.observers import Observer from watchdog.observers.polling import PollingObserver +from app.chain.tmdb import TmdbChain from app.chain.transfer import TransferChain from app.core.config import settings from app.core.context import MediaInfo @@ -74,6 +75,7 @@ class DirMonitor(_PluginBase): transferhis = None downloadhis = None transferchian = None + tmdbchain = None _observer = [] _enabled = False _notify = False @@ -93,7 +95,7 @@ class DirMonitor(_PluginBase): self.transferhis = TransferHistoryOper(self.db) self.downloadhis = DownloadHistoryOper(self.db) self.transferchian = TransferChain(self.db) - + self.tmdbchain = TmdbChain(self.db) # 清空配置 self._dirconf = {} @@ -274,6 +276,13 @@ class DirMonitor(_PluginBase): # 更新媒体图片 self.chain.obtain_images(mediainfo=mediainfo) + # 获取集数据 + if mediainfo.type == MediaType.TV: + episodes_info = self.tmdbchain.tmdb_episodes(tmdbid=mediainfo.tmdb_id, + season=file_meta.begin_season or 1) + else: + episodes_info = None + # 获取downloadhash download_hash = self.get_download_hash(src=str(file_path)) @@ -282,7 +291,8 @@ class DirMonitor(_PluginBase): path=file_path, transfer_type=self._transfer_type, target=target, - meta=file_meta) + meta=file_meta, + episodes_info=episodes_info) if not transferinfo: logger.error("文件转移模块运行失败")