feat 重命名支持episode_title
集标题
This commit is contained in:
parent
21ecd1f708
commit
84d4c9cf73
@ -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`默认配置格式:
|
||||||
|
|
||||||
|
@ -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:
|
||||||
"""
|
"""
|
||||||
|
@ -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, "文件转移模块运行失败"
|
||||||
|
@ -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,17 +423,24 @@ class FileTransferModule(_ModuleBase):
|
|||||||
is_bluray=bluray_flag)
|
is_bluray=bluray_flag)
|
||||||
else:
|
else:
|
||||||
# 转移单个文件
|
# 转移单个文件
|
||||||
# 文件结束季为空
|
if mediainfo.type == MediaType.TV:
|
||||||
in_meta.end_season = None
|
# 电视剧
|
||||||
|
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.end_season = None
|
||||||
in_meta.total_season = 1
|
# 文件总季数为1
|
||||||
|
if in_meta.total_season:
|
||||||
# 文件不可能有多集
|
in_meta.total_season = 1
|
||||||
if in_meta.total_episode > 2:
|
# 文件不可能超过2集
|
||||||
in_meta.total_episode = 1
|
if in_meta.total_episode > 2:
|
||||||
in_meta.end_episode = None
|
in_meta.total_episode = 1
|
||||||
|
in_meta.end_episode = None
|
||||||
|
|
||||||
# 目的文件名
|
# 目的文件名
|
||||||
new_file = self.get_rename_path(
|
new_file = self.get_rename_path(
|
||||||
@ -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层目录
|
||||||
|
@ -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("文件转移模块运行失败")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user