Merge pull request #5531 from WongWang/feat-plugin-priority

This commit is contained in:
jxxghp
2026-03-10 12:54:39 +08:00
committed by GitHub
3 changed files with 110 additions and 42 deletions

View File

@@ -5,6 +5,7 @@ from fastapi import APIRouter, Depends, Body
from app import schemas
from app.chain.download import DownloadChain
from app.chain.media import MediaChain
from app.core.config import settings
from app.core.context import MediaInfo, Context, TorrentInfo
from app.core.event import eventmanager
from app.core.metainfo import MetaInfo
@@ -77,13 +78,14 @@ def add(
# 元数据
metainfo = MetaInfo(title=torrent_in.title, subtitle=torrent_in.description)
# 媒体信息
mediainfo = MediaChain().recognize_media(meta=metainfo, tmdbid=tmdbid, doubanid=doubanid)
mediainfo = MediaChain().select_recognize_source(
log_name=torrent_in.title,
log_context=torrent_in.title,
native_fn=lambda: MediaChain().recognize_media(meta=metainfo, tmdbid=tmdbid, doubanid=doubanid),
plugin_fn=lambda: MediaChain().recognize_help(title=torrent_in.title, org_meta=metainfo)
)
if not mediainfo:
# 尝试使用辅助识别,如果有注册响应事件的话
if eventmanager.check(ChainEventType.NameRecognize):
mediainfo = MediaChain().recognize_help(title=torrent_in.title, org_meta=metainfo)
if not mediainfo:
return schemas.Response(success=False, message="无法识别媒体信息")
return schemas.Response(success=False, message="无法识别媒体信息")
# 种子信息
torrentinfo = TorrentInfo()
torrentinfo.from_dict(torrent_in.model_dump())

View File

@@ -85,21 +85,48 @@ class MediaChain(ChainBase):
"""
return self.run_module("metadata_nfo", meta=meta, mediainfo=mediainfo, season=season, episode=episode)
def select_recognize_source(self, log_name: str, log_context: str,
native_fn, plugin_fn) -> Optional[MediaInfo]:
"""
选择识别模式,插件优先或原生优先
:param log_name: 用于日志“标题:...”处的名称(如 file_path.name 或 title
:param log_context: 用于日志“未识别到...的媒体信息”处的上下文(如 path 或 title
:param native_fn: 原生识别函数
:param plugin_fn: 插件识别函数
"""
mediainfo = None
plugin_available = eventmanager.check(ChainEventType.NameRecognize)
if settings.RECOGNIZE_PLUGIN_FIRST and plugin_available:
# 插件优先
logger.info(f"插件优先模式已开启。请求辅助识别,标题:{log_name} ...")
mediainfo = plugin_fn()
if not mediainfo:
logger.info(f'辅助识别未识别到 {log_context} 的媒体信息,尝试使用原生识别')
mediainfo = native_fn()
else:
# 原生优先
logger.info(f"插件优先模式未开启。尝试原生识别,标题:{log_name} ...")
mediainfo = native_fn()
if not mediainfo and plugin_available:
logger.info(f'原生识别未识别到 {log_context} 的媒体信息,尝试使用辅助识别')
mediainfo = plugin_fn()
return 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, episode_group=episode_group)
# 按 config 中设置的识别顺序识别
mediainfo = self.select_recognize_source(
log_name=title,
log_context=title,
native_fn=lambda: self.recognize_media(meta=metainfo, episode_group=episode_group),
plugin_fn=lambda: self.recognize_help(title=title, org_meta=metainfo)
)
if not mediainfo:
# 尝试使用辅助识别,如果有注册响应事件的话
if eventmanager.check(ChainEventType.NameRecognize):
logger.info(f'请求辅助识别,标题:{title} ...')
mediainfo = self.recognize_help(title=title, org_meta=metainfo)
if not mediainfo:
logger.warn(f'{title} 未识别到媒体信息')
return None
logger.warn(f'{title} 未识别到媒体信息')
return None
# 识别成功
logger.info(f'{title} 识别到媒体信息:{mediainfo.type.value} {mediainfo.title_year}')
# 更新媒体图片
@@ -163,16 +190,16 @@ class MediaChain(ChainBase):
file_path = Path(path)
# 元数据
file_meta = MetaInfoPath(file_path)
# 识别媒体信息
mediainfo = self.recognize_media(meta=file_meta, episode_group=episode_group)
# 按 config 中设置的识别顺序识别
mediainfo = self.select_recognize_source(
log_name=file_path.name,
log_context=path,
native_fn=lambda: self.recognize_media(meta=file_meta, episode_group=episode_group),
plugin_fn=lambda: self.recognize_help(title=path, org_meta=file_meta)
)
if not mediainfo:
# 尝试使用辅助识别,如果有注册响应事件的话
if eventmanager.check(ChainEventType.NameRecognize):
logger.info(f'请求辅助识别,标题:{file_path.name} ...')
mediainfo = self.recognize_help(title=path, org_meta=file_meta)
if not mediainfo:
logger.warn(f'{path} 未识别到媒体信息')
return Context(meta_info=file_meta)
logger.warn(f'{path} 未识别到媒体信息')
return Context(meta_info=file_meta)
logger.info(f'{path} 识别到媒体信息:{mediainfo.type.value} {mediainfo.title_year}')
# 更新媒体图片
self.obtain_images(mediainfo=mediainfo)
@@ -820,22 +847,54 @@ class MediaChain(ChainBase):
logger.warn("无法识别元数据,跳过")
logger.info(f"{filepath.name} 刮削完成")
async def async_select_recognize_source(self, log_name: str, log_context: str,
native_fn, plugin_fn) -> Optional[MediaInfo]:
"""
选择识别模式,插件优先或原生优先(异步版本)
:param log_name: 用于日志“标题:...”处的名称(如 file_path.name 或 title
:param log_context: 用于日志“未识别到...的媒体信息”处的上下文(如 path 或 title
:param native_fn: 原生识别函数
:param plugin_fn: 插件识别函数
"""
mediainfo = None
plugin_available = eventmanager.check(ChainEventType.NameRecognize)
if settings.RECOGNIZE_PLUGIN_FIRST and plugin_available:
# 插件优先
logger.info(f"插件优先模式已开启。请求辅助识别,标题:{log_name} ...")
mediainfo = await plugin_fn()
if not mediainfo:
logger.info(f'辅助识别未识别到 {log_context} 的媒体信息,尝试使用原生识别')
mediainfo = await native_fn()
else:
# 原生优先
logger.info(f"插件优先模式未开启。尝试原生识别,标题:{log_name} ...")
mediainfo = await native_fn()
if not mediainfo and plugin_available:
logger.info(f'原生识别未识别到 {log_context} 的媒体信息,尝试使用辅助识别')
mediainfo = await plugin_fn()
return mediainfo
async def async_recognize_by_meta(self, metainfo: MetaBase,
episode_group: Optional[str] = None) -> Optional[MediaInfo]:
"""
根据主副标题识别媒体信息(异步版本)
"""
title = metainfo.title
# 识别媒体信息
mediainfo: MediaInfo = await self.async_recognize_media(meta=metainfo, episode_group=episode_group)
# 定义识别函数
async def native_recognize():
return await self.async_recognize_media(meta=metainfo, episode_group=episode_group)
async def plugin_recognize():
return await self.async_recognize_help(title=title, org_meta=metainfo)
# 按 config 中设置的识别顺序识别
mediainfo = await self.async_select_recognize_source(
log_name=title,
log_context=title,
native_fn=native_recognize,
plugin_fn=plugin_recognize
)
if not mediainfo:
# 尝试使用辅助识别,如果有注册响应事件的话
if eventmanager.check(ChainEventType.NameRecognize):
logger.info(f'请求辅助识别,标题:{title} ...')
mediainfo = await self.async_recognize_help(title=title, org_meta=metainfo)
if not mediainfo:
logger.warn(f'{title} 未识别到媒体信息')
return None
logger.warn(f'{title} 未识别到媒体信息')
return None
# 识别成功
logger.info(f'{title} 识别到媒体信息:{mediainfo.type.value} {mediainfo.title_year}')
# 更新媒体图片
@@ -899,16 +958,21 @@ class MediaChain(ChainBase):
file_path = Path(path)
# 元数据
file_meta = MetaInfoPath(file_path)
# 识别媒体信息
mediainfo = await self.async_recognize_media(meta=file_meta, episode_group=episode_group)
# 定义识别函数
async def native_recognize():
return await self.async_recognize_media(meta=file_meta, episode_group=episode_group)
async def plugin_recognize():
return await self.async_recognize_help(title=path, org_meta=file_meta)
# 按 config 中设置的识别顺序识别
mediainfo = await self.async_select_recognize_source(
log_name=file_path.name,
log_context=path,
native_fn=native_recognize,
plugin_fn=plugin_recognize
)
if not mediainfo:
# 尝试使用辅助识别,如果有注册响应事件的话
if eventmanager.check(ChainEventType.NameRecognize):
logger.info(f'请求辅助识别,标题:{file_path.name} ...')
mediainfo = await self.async_recognize_help(title=path, org_meta=file_meta)
if not mediainfo:
logger.warn(f'{path} 未识别到媒体信息')
return Context(meta_info=file_meta)
logger.warn(f'{path} 未识别到媒体信息')
return Context(meta_info=file_meta)
logger.info(f'{path} 识别到媒体信息:{mediainfo.type.value} {mediainfo.title_year}')
# 更新媒体图片
await self.async_obtain_images(mediainfo=mediainfo)

View File

@@ -322,6 +322,8 @@ class ConfigModel(BaseModel):
DEFAULT_SUB: Optional[str] = "zh-cn"
# 新增已入库媒体是否跟随TMDB信息变化
SCRAP_FOLLOW_TMDB: bool = True
# 优先使用辅助识别
RECOGNIZE_PLUGIN_FIRST: bool = False
# ==================== 服务地址配置 ====================
# 服务器地址,对应 https://github.com/jxxghp/MoviePilot-Server 项目