mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 07:27:15 +08:00
feat:支持指定剧集组识别和刮削
This commit is contained in:
@@ -150,6 +150,7 @@ class ChainBase(metaclass=ABCMeta):
|
||||
tmdbid: Optional[int] = None,
|
||||
doubanid: Optional[str] = None,
|
||||
bangumiid: Optional[int] = None,
|
||||
episode_group: Optional[str] = None,
|
||||
cache: bool = True) -> Optional[MediaInfo]:
|
||||
"""
|
||||
识别媒体信息,不含Fanart图片
|
||||
@@ -158,6 +159,7 @@ class ChainBase(metaclass=ABCMeta):
|
||||
:param tmdbid: tmdbid
|
||||
:param doubanid: 豆瓣ID
|
||||
:param bangumiid: BangumiID
|
||||
:param episode_group: 剧集组
|
||||
:param cache: 是否使用缓存
|
||||
:return: 识别的媒体信息,包括剧集信息
|
||||
"""
|
||||
@@ -173,7 +175,8 @@ class ChainBase(metaclass=ABCMeta):
|
||||
doubanid = None
|
||||
bangumiid = None
|
||||
return self.run_module("recognize_media", meta=meta, mtype=mtype,
|
||||
tmdbid=tmdbid, doubanid=doubanid, bangumiid=bangumiid, cache=cache)
|
||||
tmdbid=tmdbid, doubanid=doubanid, bangumiid=bangumiid,
|
||||
episode_group=episode_group, cache=cache)
|
||||
|
||||
def match_doubaninfo(self, name: str, imdbid: Optional[str] = None,
|
||||
mtype: Optional[MediaType] = None, year: Optional[str] = None, season: Optional[int] = None,
|
||||
|
||||
+14
-19
@@ -209,7 +209,6 @@ class DownloadChain(ChainBase):
|
||||
save_path: Optional[str] = None,
|
||||
userid: Union[str, int] = None,
|
||||
username: Optional[str] = None,
|
||||
media_category: Optional[str] = None,
|
||||
label: Optional[str] = None) -> Optional[str]:
|
||||
"""
|
||||
下载及发送通知
|
||||
@@ -222,9 +221,13 @@ class DownloadChain(ChainBase):
|
||||
:param save_path: 保存路径
|
||||
:param userid: 用户ID
|
||||
:param username: 调用下载的用户名/插件名
|
||||
:param media_category: 自定义媒体类别
|
||||
:param label: 自定义标签
|
||||
"""
|
||||
_torrent = context.torrent_info
|
||||
_media = context.media_info
|
||||
_meta = context.meta_info
|
||||
_site_downloader = _torrent.site_downloader
|
||||
|
||||
# 发送资源下载事件,允许外部拦截下载
|
||||
event_data = ResourceDownloadEventData(
|
||||
context=context,
|
||||
@@ -236,7 +239,7 @@ class DownloadChain(ChainBase):
|
||||
"save_path": save_path,
|
||||
"userid": userid,
|
||||
"username": username,
|
||||
"media_category": media_category
|
||||
"media_category": _media.category
|
||||
}
|
||||
)
|
||||
# 触发资源下载事件
|
||||
@@ -250,15 +253,11 @@ class DownloadChain(ChainBase):
|
||||
f"Reason: {event_data.reason}")
|
||||
return None
|
||||
|
||||
_torrent = context.torrent_info
|
||||
_media = context.media_info
|
||||
_meta = context.meta_info
|
||||
_site_downloader = _torrent.site_downloader
|
||||
|
||||
# 补充完整的media数据
|
||||
if not _media.genre_ids:
|
||||
new_media = self.recognize_media(mtype=_media.type, tmdbid=_media.tmdb_id,
|
||||
doubanid=_media.douban_id, bangumiid=_media.bangumi_id)
|
||||
doubanid=_media.douban_id, bangumiid=_media.bangumi_id,
|
||||
episode_group=_media.episode_group)
|
||||
if new_media:
|
||||
_media = new_media
|
||||
|
||||
@@ -355,7 +354,8 @@ class DownloadChain(ChainBase):
|
||||
username=username,
|
||||
channel=channel.value if channel else None,
|
||||
date=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
|
||||
media_category=media_category,
|
||||
media_category=_media.category,
|
||||
episode_group=_media.episode_group,
|
||||
note={"source": source}
|
||||
)
|
||||
|
||||
@@ -423,7 +423,6 @@ class DownloadChain(ChainBase):
|
||||
source: Optional[str] = None,
|
||||
userid: Optional[str] = None,
|
||||
username: Optional[str] = None,
|
||||
media_category: Optional[str] = None,
|
||||
downloader: Optional[str] = None
|
||||
) -> Tuple[List[Context], Dict[Union[int, str], Dict[int, NotExistMediaInfo]]]:
|
||||
"""
|
||||
@@ -435,7 +434,6 @@ class DownloadChain(ChainBase):
|
||||
:param source: 来源(消息通知、订阅、手工下载等)
|
||||
:param userid: 用户ID
|
||||
:param username: 调用下载的用户名/插件名
|
||||
:param media_category: 自定义媒体类别
|
||||
:param downloader: 下载器
|
||||
:return: 已经下载的资源列表、剩余未下载到的剧集 no_exists[tmdb_id/douban_id] = {season: NotExistMediaInfo}
|
||||
"""
|
||||
@@ -524,7 +522,7 @@ class DownloadChain(ChainBase):
|
||||
logger.info(f"开始下载电影 {context.torrent_info.title} ...")
|
||||
if self.download_single(context, save_path=save_path, channel=channel,
|
||||
source=source, userid=userid, username=username,
|
||||
media_category=media_category, downloader=downloader):
|
||||
downloader=downloader):
|
||||
# 下载成功
|
||||
logger.info(f"{context.torrent_info.title} 添加下载成功")
|
||||
downloaded_list.append(context)
|
||||
@@ -609,8 +607,7 @@ class DownloadChain(ChainBase):
|
||||
source=source,
|
||||
userid=userid,
|
||||
username=username,
|
||||
media_category=media_category,
|
||||
downloader=downloader,
|
||||
downloader=downloader
|
||||
)
|
||||
else:
|
||||
# 下载
|
||||
@@ -618,7 +615,6 @@ class DownloadChain(ChainBase):
|
||||
download_id = self.download_single(context, save_path=save_path,
|
||||
channel=channel, source=source,
|
||||
userid=userid, username=username,
|
||||
media_category=media_category,
|
||||
downloader=downloader)
|
||||
|
||||
if download_id:
|
||||
@@ -690,7 +686,6 @@ class DownloadChain(ChainBase):
|
||||
download_id = self.download_single(context, save_path=save_path,
|
||||
channel=channel, source=source,
|
||||
userid=userid, username=username,
|
||||
media_category=media_category,
|
||||
downloader=downloader)
|
||||
if download_id:
|
||||
# 下载成功
|
||||
@@ -780,7 +775,6 @@ class DownloadChain(ChainBase):
|
||||
source=source,
|
||||
userid=userid,
|
||||
username=username,
|
||||
media_category=media_category,
|
||||
downloader=downloader
|
||||
)
|
||||
if not download_id:
|
||||
@@ -866,7 +860,8 @@ class DownloadChain(ChainBase):
|
||||
# 补充媒体信息
|
||||
mediainfo: MediaInfo = self.recognize_media(mtype=mediainfo.type,
|
||||
tmdbid=mediainfo.tmdb_id,
|
||||
doubanid=mediainfo.douban_id)
|
||||
doubanid=mediainfo.douban_id,
|
||||
episode_group=mediainfo.episode_group)
|
||||
if not mediainfo:
|
||||
logger.error(f"媒体信息识别失败!")
|
||||
return False, {}
|
||||
|
||||
+8
-6
@@ -42,13 +42,13 @@ class MediaChain(ChainBase, metaclass=Singleton):
|
||||
"""
|
||||
return self.run_module("metadata_nfo", meta=meta, mediainfo=mediainfo, season=season, episode=episode)
|
||||
|
||||
def recognize_by_meta(self, metainfo: MetaBase) -> Optional[MediaInfo]:
|
||||
def recognize_by_meta(self, metainfo: MetaBase, episode_group: Optional[str] = None) -> Optional[MediaInfo]:
|
||||
"""
|
||||
根据主副标题识别媒体信息
|
||||
"""
|
||||
title = metainfo.title
|
||||
# 识别媒体信息
|
||||
mediainfo: MediaInfo = self.recognize_media(meta=metainfo)
|
||||
mediainfo: MediaInfo = self.recognize_media(meta=metainfo, episode_group=episode_group)
|
||||
if not mediainfo:
|
||||
# 尝试使用辅助识别,如果有注册响应事件的话
|
||||
if eventmanager.check(ChainEventType.NameRecognize):
|
||||
@@ -112,7 +112,7 @@ class MediaChain(ChainBase, metaclass=Singleton):
|
||||
# 重新识别
|
||||
return self.recognize_media(meta=org_meta)
|
||||
|
||||
def recognize_by_path(self, path: str) -> Optional[Context]:
|
||||
def recognize_by_path(self, path: str, episode_group: Optional[str] = None) -> Optional[Context]:
|
||||
"""
|
||||
根据文件路径识别媒体信息
|
||||
"""
|
||||
@@ -121,7 +121,7 @@ class MediaChain(ChainBase, metaclass=Singleton):
|
||||
# 元数据
|
||||
file_meta = MetaInfoPath(file_path)
|
||||
# 识别媒体信息
|
||||
mediainfo = self.recognize_media(meta=file_meta)
|
||||
mediainfo = self.recognize_media(meta=file_meta, episode_group=episode_group)
|
||||
if not mediainfo:
|
||||
# 尝试使用辅助识别,如果有注册响应事件的话
|
||||
if eventmanager.check(ChainEventType.NameRecognize):
|
||||
@@ -474,7 +474,8 @@ class MediaChain(ChainBase, metaclass=Singleton):
|
||||
if not file_meta.begin_episode:
|
||||
logger.warn(f"{filepath.name} 无法识别文件集数!")
|
||||
return
|
||||
file_mediainfo = self.recognize_media(meta=file_meta, tmdbid=mediainfo.tmdb_id)
|
||||
file_mediainfo = self.recognize_media(meta=file_meta, tmdbid=mediainfo.tmdb_id,
|
||||
episode_group=mediainfo.episode_group)
|
||||
if not file_mediainfo:
|
||||
logger.warn(f"{filepath.name} 无法识别文件媒体信息!")
|
||||
return
|
||||
@@ -483,7 +484,8 @@ class MediaChain(ChainBase, metaclass=Singleton):
|
||||
if overwrite or not self.storagechain.get_file_item(storage=fileitem.storage, path=nfo_path):
|
||||
# 获取集的nfo文件
|
||||
episode_nfo = self.metadata_nfo(meta=file_meta, mediainfo=file_mediainfo,
|
||||
season=file_meta.begin_season, episode=file_meta.begin_episode)
|
||||
season=file_meta.begin_season,
|
||||
episode=file_meta.begin_episode)
|
||||
if episode_nfo:
|
||||
# 保存或上传nfo文件到上级目录
|
||||
if not parent:
|
||||
|
||||
+23
-10
@@ -60,6 +60,7 @@ class SubscribeChain(ChainBase, metaclass=Singleton):
|
||||
doubanid: Optional[str] = None,
|
||||
bangumiid: Optional[int] = None,
|
||||
mediaid: Optional[str] = None,
|
||||
episode_group: Optional[str] = None,
|
||||
season: Optional[int] = None,
|
||||
channel: MessageChannel = None,
|
||||
source: Optional[str] = None,
|
||||
@@ -117,7 +118,8 @@ class SubscribeChain(ChainBase, metaclass=Singleton):
|
||||
mediainfo = __get_event_meida(mediaid, metainfo)
|
||||
else:
|
||||
# 使用TMDBID识别
|
||||
mediainfo = self.recognize_media(meta=metainfo, mtype=mtype, tmdbid=tmdbid, cache=False)
|
||||
mediainfo = self.recognize_media(meta=metainfo, mtype=mtype, tmdbid=tmdbid,
|
||||
episode_group=episode_group, cache=False)
|
||||
else:
|
||||
if doubanid:
|
||||
# 豆瓣识别模式,不使用缓存
|
||||
@@ -134,7 +136,7 @@ class SubscribeChain(ChainBase, metaclass=Singleton):
|
||||
|
||||
# 使用名称识别兜底
|
||||
if not mediainfo:
|
||||
mediainfo = self.recognize_media(meta=metainfo)
|
||||
mediainfo = self.recognize_media(meta=metainfo, episode_group=episode_group)
|
||||
|
||||
# 识别失败
|
||||
if not mediainfo:
|
||||
@@ -153,6 +155,7 @@ class SubscribeChain(ChainBase, metaclass=Singleton):
|
||||
tmdbid=mediainfo.tmdb_id,
|
||||
doubanid=mediainfo.douban_id,
|
||||
bangumiid=mediainfo.bangumi_id,
|
||||
episode_group=episode_group,
|
||||
cache=False)
|
||||
if not mediainfo:
|
||||
logger.error(f"媒体信息识别失败!")
|
||||
@@ -207,7 +210,7 @@ class SubscribeChain(ChainBase, metaclass=Singleton):
|
||||
'save_path': self.__get_default_subscribe_config(mediainfo.type, "save_path") if not kwargs.get(
|
||||
"save_path") else kwargs.get("save_path"),
|
||||
'filter_groups': self.__get_default_subscribe_config(mediainfo.type, "filter_groups") if not kwargs.get(
|
||||
"filter_groups") else kwargs.get("filter_groups"),
|
||||
"filter_groups") else kwargs.get("filter_groups")
|
||||
})
|
||||
sid, err_msg = self.subscribeoper.add(mediainfo=mediainfo, season=season, username=username, **kwargs)
|
||||
if not sid:
|
||||
@@ -383,6 +386,11 @@ class SubscribeChain(ChainBase, metaclass=Singleton):
|
||||
logger.info(
|
||||
f'{subscribe.name} 正在洗版,{torrent_info.title} 优先级低于或等于已下载优先级')
|
||||
continue
|
||||
# 更新订阅自定义属性
|
||||
if subscribe.media_category:
|
||||
torrent_mediainfo.category = subscribe.media_category
|
||||
if subscribe.episode_group:
|
||||
torrent_mediainfo.episode_group = subscribe.episode_group
|
||||
matched_contexts.append(context)
|
||||
|
||||
if not matched_contexts:
|
||||
@@ -398,7 +406,6 @@ class SubscribeChain(ChainBase, metaclass=Singleton):
|
||||
userid=subscribe.username,
|
||||
username=subscribe.username,
|
||||
save_path=subscribe.save_path,
|
||||
media_category=subscribe.media_category,
|
||||
downloader=subscribe.downloader,
|
||||
source=self.get_subscribe_source_keyword(subscribe)
|
||||
)
|
||||
@@ -603,9 +610,10 @@ class SubscribeChain(ChainBase, metaclass=Singleton):
|
||||
logger.debug(f'开始匹配站点:{domain},共缓存了 {len(contexts)} 个种子...')
|
||||
for context in contexts:
|
||||
# 提取信息
|
||||
torrent_meta = copy.deepcopy(context.meta_info)
|
||||
torrent_mediainfo = copy.deepcopy(context.media_info)
|
||||
torrent_info = context.torrent_info
|
||||
_context = copy.deepcopy(context)
|
||||
torrent_meta = _context.meta_info
|
||||
torrent_mediainfo = _context.media_info
|
||||
torrent_info = _context.torrent_info
|
||||
|
||||
# 不在订阅站点范围的不处理
|
||||
sub_sites = self.get_sub_sites(subscribe)
|
||||
@@ -736,7 +744,12 @@ class SubscribeChain(ChainBase, metaclass=Singleton):
|
||||
|
||||
# 匹配成功
|
||||
logger.info(f'{mediainfo.title_year} 匹配成功:{torrent_info.title}')
|
||||
_match_context.append(context)
|
||||
# 自定义属性
|
||||
if subscribe.media_category:
|
||||
torrent_mediainfo.category = subscribe.media_category
|
||||
if subscribe.episode_group:
|
||||
torrent_mediainfo.episode_group = subscribe.episode_group
|
||||
_match_context.append(_context)
|
||||
|
||||
if not _match_context:
|
||||
# 未匹配到资源
|
||||
@@ -752,7 +765,6 @@ class SubscribeChain(ChainBase, metaclass=Singleton):
|
||||
userid=subscribe.username,
|
||||
username=subscribe.username,
|
||||
save_path=subscribe.save_path,
|
||||
media_category=subscribe.media_category,
|
||||
downloader=subscribe.downloader,
|
||||
source=self.get_subscribe_source_keyword(subscribe)
|
||||
)
|
||||
@@ -1274,7 +1286,8 @@ class SubscribeChain(ChainBase, metaclass=Singleton):
|
||||
# 查询TMDB中的集信息
|
||||
tmdb_episodes = self.tmdbchain.tmdb_episodes(
|
||||
tmdbid=subscribe.tmdbid,
|
||||
season=subscribe.season
|
||||
season=subscribe.season,
|
||||
episode_group=subscribe.episode_group
|
||||
)
|
||||
if tmdb_episodes:
|
||||
for episode in tmdb_episodes:
|
||||
|
||||
+3
-2
@@ -70,13 +70,14 @@ class TmdbChain(ChainBase, metaclass=Singleton):
|
||||
"""
|
||||
return self.run_module("tmdb_seasons", tmdbid=tmdbid)
|
||||
|
||||
def tmdb_episodes(self, tmdbid: int, season: int) -> List[schemas.TmdbEpisode]:
|
||||
def tmdb_episodes(self, tmdbid: int, season: int, episode_group: Optional[str] = None) -> List[schemas.TmdbEpisode]:
|
||||
"""
|
||||
根据TMDBID查询某季的所有信信息
|
||||
:param tmdbid: TMDBID
|
||||
:param season: 季
|
||||
:param episode_group: 剧集组
|
||||
"""
|
||||
return self.run_module("tmdb_episodes", tmdbid=tmdbid, season=season)
|
||||
return self.run_module("tmdb_episodes", tmdbid=tmdbid, season=season, episode_group=episode_group)
|
||||
|
||||
def movie_similar(self, tmdbid: int) -> Optional[List[MediaInfo]]:
|
||||
"""
|
||||
|
||||
+12
-6
@@ -623,7 +623,8 @@ class TransferChain(ChainBase, metaclass=Singleton):
|
||||
# 下载记录中已存在识别信息
|
||||
mediainfo: Optional[MediaInfo] = self.recognize_media(mtype=MediaType(download_history.type),
|
||||
tmdbid=download_history.tmdbid,
|
||||
doubanid=download_history.doubanid)
|
||||
doubanid=download_history.doubanid,
|
||||
episode_group=download_history.episode_group)
|
||||
if mediainfo:
|
||||
# 更新自定义媒体类别
|
||||
if download_history.media_category:
|
||||
@@ -681,7 +682,8 @@ class TransferChain(ChainBase, metaclass=Singleton):
|
||||
season_num = 1
|
||||
task.episodes_info = self.tmdbchain.tmdb_episodes(
|
||||
tmdbid=task.mediainfo.tmdb_id,
|
||||
season=season_num
|
||||
season=season_num,
|
||||
episode_group=task.mediainfo.episode_group
|
||||
)
|
||||
|
||||
# 查询整理目标目录
|
||||
@@ -798,7 +800,8 @@ class TransferChain(ChainBase, metaclass=Singleton):
|
||||
# 按TMDBID识别
|
||||
mediainfo = self.recognize_media(mtype=mtype,
|
||||
tmdbid=downloadhis.tmdbid,
|
||||
doubanid=downloadhis.doubanid)
|
||||
doubanid=downloadhis.doubanid,
|
||||
episode_group=downloadhis.episode_group)
|
||||
if mediainfo:
|
||||
# 补充图片
|
||||
self.obtain_images(mediainfo)
|
||||
@@ -1214,12 +1217,12 @@ class TransferChain(ChainBase, metaclass=Singleton):
|
||||
# 查询媒体信息
|
||||
if mtype and mediaid:
|
||||
mediainfo = self.recognize_media(mtype=mtype, tmdbid=int(mediaid) if str(mediaid).isdigit() else None,
|
||||
doubanid=mediaid)
|
||||
doubanid=mediaid, episode_group=history.episode_group)
|
||||
if mediainfo:
|
||||
# 更新媒体图片
|
||||
self.obtain_images(mediainfo=mediainfo)
|
||||
else:
|
||||
mediainfo = self.mediachain.recognize_by_path(str(src_path))
|
||||
mediainfo = self.mediachain.recognize_by_path(str(src_path), episode_group=history.episode_group)
|
||||
if not mediainfo:
|
||||
return False, f"未识别到媒体信息,类型:{mtype.value},id:{mediaid}"
|
||||
# 重新执行整理
|
||||
@@ -1252,6 +1255,7 @@ class TransferChain(ChainBase, metaclass=Singleton):
|
||||
doubanid: Optional[str] = None,
|
||||
mtype: MediaType = None,
|
||||
season: Optional[int] = None,
|
||||
episode_group: Optional[str] = None,
|
||||
transfer_type: Optional[str] = None,
|
||||
epformat: EpisodeFormat = None,
|
||||
min_filesize: Optional[int] = 0,
|
||||
@@ -1269,6 +1273,7 @@ class TransferChain(ChainBase, metaclass=Singleton):
|
||||
:param doubanid: 豆瓣ID
|
||||
:param mtype: 媒体类型
|
||||
:param season: 季度
|
||||
:param episode_group: 剧集组
|
||||
:param transfer_type: 整理类型
|
||||
:param epformat: 剧集格式
|
||||
:param min_filesize: 最小文件大小(MB)
|
||||
@@ -1282,7 +1287,8 @@ class TransferChain(ChainBase, metaclass=Singleton):
|
||||
if tmdbid or doubanid:
|
||||
# 有输入TMDBID时单个识别
|
||||
# 识别媒体信息
|
||||
mediainfo: MediaInfo = self.mediachain.recognize_media(tmdbid=tmdbid, doubanid=doubanid, mtype=mtype)
|
||||
mediainfo: MediaInfo = self.mediachain.recognize_media(tmdbid=tmdbid, doubanid=doubanid,
|
||||
mtype=mtype, episode_group=episode_group)
|
||||
if not mediainfo:
|
||||
return False, f"媒体信息识别失败,tmdbid:{tmdbid},doubanid:{doubanid},type: {mtype.value}"
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user