feat 重命名支持episode_title集标题

This commit is contained in:
jxxghp 2023-09-28 10:58:31 +08:00
parent 21ecd1f708
commit 84d4c9cf73
5 changed files with 75 additions and 46 deletions

View File

@ -212,6 +212,7 @@ docker pull jxxghp/moviepilot:latest
> `season` 季号 > `season` 季号
> `episode` 集号 > `episode` 集号
> `season_episode` 季集 SxxExx > `season_episode` 季集 SxxExx
> `episode_title` 集标题
`TV_RENAME_FORMAT`默认配置格式: `TV_RENAME_FORMAT`默认配置格式:

View File

@ -18,7 +18,7 @@ from app.core.meta import MetaBase
from app.core.module import ModuleManager from app.core.module import ModuleManager
from app.log import logger from app.log import logger
from app.schemas import TransferInfo, TransferTorrent, ExistMediaInfo, DownloadingTorrent, CommingMessage, Notification, \ from app.schemas import TransferInfo, TransferTorrent, ExistMediaInfo, DownloadingTorrent, CommingMessage, Notification, \
WebhookEventInfo WebhookEventInfo, TmdbEpisode
from app.schemas.types import TorrentStatus, MediaType, MediaImageType, EventType from app.schemas.types import TorrentStatus, MediaType, MediaImageType, EventType
from app.utils.object import ObjectUtils from app.utils.object import ObjectUtils
@ -274,7 +274,8 @@ 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, meta: MetaBase, mediainfo: MediaInfo, 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: 文件路径 :param path: 文件路径
@ -282,10 +283,12 @@ class ChainBase(metaclass=ABCMeta):
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息
:param transfer_type: 转移模式 :param transfer_type: 转移模式
:param target: 转移目标路径 :param target: 转移目标路径
:param episodes_info: 当前季的全部集信息
:return: {path, target_path, message} :return: {path, target_path, message}
""" """
return self.run_module("transfer", path=path, meta=meta, mediainfo=mediainfo, 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: def transfer_completed(self, hashs: Union[str, list], path: Path = None) -> None:
""" """

View File

@ -9,6 +9,7 @@ from sqlalchemy.orm import Session
from app.chain import ChainBase from app.chain import ChainBase
from app.chain.media import MediaChain from app.chain.media import MediaChain
from app.chain.tmdb import TmdbChain
from app.core.config import settings from app.core.config import settings
from app.core.context import MediaInfo from app.core.context import MediaInfo
from app.core.meta import MetaBase from app.core.meta import MetaBase
@ -41,6 +42,7 @@ class TransferChain(ChainBase):
self.transferhis = TransferHistoryOper(self._db) self.transferhis = TransferHistoryOper(self._db)
self.progress = ProgressHelper() self.progress = ProgressHelper()
self.mediachain = MediaChain(self._db) self.mediachain = MediaChain(self._db)
self.tmdbchain = TmdbChain(self._db)
self.systemconfig = SystemConfigOper() self.systemconfig = SystemConfigOper()
def process(self) -> bool: 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}") 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) 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: if not download_hash:
download_file = self.downloadhis.get_file_by_fullpath(file_path_str) download_file = self.downloadhis.get_file_by_fullpath(file_path_str)
if download_file: if download_file:
@ -292,7 +280,8 @@ class TransferChain(ChainBase):
mediainfo=file_mediainfo, mediainfo=file_mediainfo,
path=file_path, path=file_path,
transfer_type=transfer_type, transfer_type=transfer_type,
target=target) target=target,
episodes_info=episodes_info)
if not transferinfo: if not transferinfo:
logger.error("文件转移模块运行失败") logger.error("文件转移模块运行失败")
return False, "文件转移模块运行失败" return False, "文件转移模块运行失败"

View File

@ -11,7 +11,7 @@ from app.core.meta import MetaBase
from app.core.metainfo import MetaInfo 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.schemas import TransferInfo, ExistMediaInfo from app.schemas import TransferInfo, ExistMediaInfo, TmdbEpisode
from app.schemas.types import MediaType from app.schemas.types import MediaType
from app.utils.system import SystemUtils from app.utils.system import SystemUtils
@ -30,7 +30,8 @@ class FileTransferModule(_ModuleBase):
pass pass
def transfer(self, path: Path, meta: MetaBase, mediainfo: MediaInfo, 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: 文件路径 :param path: 文件路径
@ -38,6 +39,7 @@ class FileTransferModule(_ModuleBase):
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息
:param transfer_type: 转移方式 :param transfer_type: 转移方式
:param target: 目标路径 :param target: 目标路径
:param episodes_info: 当前季的全部集信息
:return: {path, target_path, message} :return: {path, target_path, message}
""" """
# 获取目标路径 # 获取目标路径
@ -49,13 +51,14 @@ class FileTransferModule(_ModuleBase):
logger.error("未找到媒体库目录,无法转移文件") logger.error("未找到媒体库目录,无法转移文件")
return TransferInfo(success=False, return TransferInfo(success=False,
path=path, path=path,
message="未找到媒体库目录,无法转移文件") message="未找到媒体库目录")
# 转移 # 转移
return self.transfer_media(in_path=path, return self.transfer_media(in_path=path,
in_meta=meta, in_meta=meta,
mediainfo=mediainfo, mediainfo=mediainfo,
transfer_type=transfer_type, transfer_type=transfer_type,
target_dir=target) target_dir=target,
episodes_info=episodes_info)
@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:
@ -355,6 +358,7 @@ class FileTransferModule(_ModuleBase):
mediainfo: MediaInfo, mediainfo: MediaInfo,
transfer_type: str, transfer_type: str,
target_dir: Path, target_dir: Path,
episodes_info: List[TmdbEpisode] = None
) -> TransferInfo: ) -> TransferInfo:
""" """
识别并转移一个文件或者一个目录下的所有文件 识别并转移一个文件或者一个目录下的所有文件
@ -363,6 +367,7 @@ class FileTransferModule(_ModuleBase):
:param mediainfo: 媒体信息 :param mediainfo: 媒体信息
:param target_dir: 媒体库根目录 :param target_dir: 媒体库根目录
:param transfer_type: 文件转移方式 :param transfer_type: 文件转移方式
:param episodes_info: 当前季的全部集信息
:return: TransferInfo错误信息 :return: TransferInfo错误信息
""" """
# 检查目录路径 # 检查目录路径
@ -404,7 +409,7 @@ class FileTransferModule(_ModuleBase):
if retcode != 0: if retcode != 0:
logger.error(f"文件夹 {in_path} 转移失败,错误码:{retcode}") logger.error(f"文件夹 {in_path} 转移失败,错误码:{retcode}")
return TransferInfo(success=False, return TransferInfo(success=False,
message=f"文件夹 {in_path} 转移失败,错误码:{retcode}", message=f"错误码:{retcode}",
path=in_path, path=in_path,
target_path=new_path, target_path=new_path,
is_bluray=bluray_flag) is_bluray=bluray_flag)
@ -418,14 +423,21 @@ class FileTransferModule(_ModuleBase):
is_bluray=bluray_flag) is_bluray=bluray_flag)
else: else:
# 转移单个文件 # 转移单个文件
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)])
# 文件结束季为空 # 文件结束季为空
in_meta.end_season = None in_meta.end_season = None
# 文件总季数为1 # 文件总季数为1
if in_meta.total_season: if in_meta.total_season:
in_meta.total_season = 1 in_meta.total_season = 1
# 文件不可能超过2集
# 文件不可能有多集
if in_meta.total_episode > 2: if in_meta.total_episode > 2:
in_meta.total_episode = 1 in_meta.total_episode = 1
in_meta.end_episode = None in_meta.end_episode = None
@ -437,6 +449,7 @@ class FileTransferModule(_ModuleBase):
rename_dict=self.__get_naming_dict( rename_dict=self.__get_naming_dict(
meta=in_meta, meta=in_meta,
mediainfo=mediainfo, mediainfo=mediainfo,
episodes_info=episodes_info,
file_ext=in_path.suffix file_ext=in_path.suffix
) )
) )
@ -456,7 +469,7 @@ class FileTransferModule(_ModuleBase):
if retcode != 0: if retcode != 0:
logger.error(f"文件 {in_path} 转移失败,错误码:{retcode}") logger.error(f"文件 {in_path} 转移失败,错误码:{retcode}")
return TransferInfo(success=False, return TransferInfo(success=False,
message=f"文件 {in_path.name} 转移失败,错误码:{retcode}", message=f"错误码:{retcode}",
path=in_path, path=in_path,
target_path=new_file, target_path=new_file,
fail_list=[str(in_path)]) fail_list=[str(in_path)])
@ -472,13 +485,23 @@ class FileTransferModule(_ModuleBase):
file_list_new=[str(new_file)]) file_list_new=[str(new_file)])
@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,
episodes_info: List[TmdbEpisode] = None) -> dict:
""" """
根据媒体信息返回Format字典 根据媒体信息返回Format字典
:param meta: 文件元数据 :param meta: 文件元数据
:param mediainfo: 识别的媒体信息 :param mediainfo: 识别的媒体信息
:param file_ext: 文件扩展名 :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 { return {
# 标题 # 标题
"title": mediainfo.title, "title": mediainfo.title,
@ -514,6 +537,8 @@ class FileTransferModule(_ModuleBase):
"season_episode": "%s%s" % (meta.season, meta.episodes), "season_episode": "%s%s" % (meta.season, meta.episodes),
# 段/节 # 段/节
"part": meta.part, "part": meta.part,
# 剧集标题
"episode_title": episode_title,
# 文件后缀 # 文件后缀
"fileExt": file_ext "fileExt": file_ext
} }
@ -613,9 +638,10 @@ 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
# 相对路径 # 相对路径
meta = MetaInfo(mediainfo.title)
rel_path = self.get_rename_path( rel_path = self.get_rename_path(
template_string=rename_format, template_string=rename_format,
rename_dict=self.__get_naming_dict(meta=MetaInfo(mediainfo.title), rename_dict=self.__get_naming_dict(meta=meta,
mediainfo=mediainfo) mediainfo=mediainfo)
) )
# 取相对路径的第1层目录 # 取相对路径的第1层目录

View File

@ -12,6 +12,7 @@ from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer from watchdog.observers import Observer
from watchdog.observers.polling import PollingObserver from watchdog.observers.polling import PollingObserver
from app.chain.tmdb import TmdbChain
from app.chain.transfer import TransferChain from app.chain.transfer import TransferChain
from app.core.config import settings from app.core.config import settings
from app.core.context import MediaInfo from app.core.context import MediaInfo
@ -74,6 +75,7 @@ class DirMonitor(_PluginBase):
transferhis = None transferhis = None
downloadhis = None downloadhis = None
transferchian = None transferchian = None
tmdbchain = None
_observer = [] _observer = []
_enabled = False _enabled = False
_notify = False _notify = False
@ -93,7 +95,7 @@ class DirMonitor(_PluginBase):
self.transferhis = TransferHistoryOper(self.db) self.transferhis = TransferHistoryOper(self.db)
self.downloadhis = DownloadHistoryOper(self.db) self.downloadhis = DownloadHistoryOper(self.db)
self.transferchian = TransferChain(self.db) self.transferchian = TransferChain(self.db)
self.tmdbchain = TmdbChain(self.db)
# 清空配置 # 清空配置
self._dirconf = {} self._dirconf = {}
@ -274,6 +276,13 @@ class DirMonitor(_PluginBase):
# 更新媒体图片 # 更新媒体图片
self.chain.obtain_images(mediainfo=mediainfo) 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 # 获取downloadhash
download_hash = self.get_download_hash(src=str(file_path)) download_hash = self.get_download_hash(src=str(file_path))
@ -282,7 +291,8 @@ class DirMonitor(_PluginBase):
path=file_path, path=file_path,
transfer_type=self._transfer_type, transfer_type=self._transfer_type,
target=target, target=target,
meta=file_meta) meta=file_meta,
episodes_info=episodes_info)
if not transferinfo: if not transferinfo:
logger.error("文件转移模块运行失败") logger.error("文件转移模块运行失败")