perf: optimize media recognition internals

This commit is contained in:
jxxghp
2026-05-15 13:37:36 +08:00
parent b2a18f9ae4
commit 2831eecbeb
9 changed files with 396 additions and 254 deletions

View File

@@ -71,6 +71,42 @@ class DoubanModule(_ModuleBase):
"""
return 2
@staticmethod
def _prepare_search_names(meta: MetaBase) -> List[str]:
"""
准备搜索名称列表,保留中英文名称分别识别且按顺序去重的历史行为。
"""
# 简体名称
zh_name = zhconv.convert(meta.cn_name, "zh-hans") if meta.cn_name else None
# 使用中英文名分别识别,去重去空,但要保持顺序
return list(dict.fromkeys([k for k in [meta.cn_name, zh_name, meta.en_name] if k]))
@staticmethod
def _build_search_medias_result(meta: MetaBase, items: Optional[List[dict]]) -> List[MediaInfo]:
"""
构建豆瓣搜索结果,并沿用原有的类型、标题包含和季信息处理规则。
"""
if not items:
return []
ret_medias = []
for item_obj in items:
if meta.type and meta.type != MediaType.UNKNOWN and meta.type.value != item_obj.get("type_name"):
continue
if item_obj.get("type_name") not in (MediaType.TV.value, MediaType.MOVIE.value):
continue
if meta.name not in item_obj.get("target", {}).get("title"):
continue
ret_medias.append(MediaInfo(douban_info=item_obj.get("target")))
# 将搜索词中的季写入标题中
if ret_medias and meta.begin_season:
# 小写数据转大写
season_str = cn2an.an2cn(meta.begin_season, "low")
for media in ret_medias:
if media.type == MediaType.TV:
media.title = f"{media.title}{season_str}"
media.season = meta.begin_season
return ret_medias
def _recognize_media_core(self, meta: MetaBase = None,
mtype: MediaType = None,
doubanid: Optional[str] = None,
@@ -107,7 +143,7 @@ class DoubanModule(_ModuleBase):
meta.type = mtype
if doubanid:
meta.doubanid = doubanid
cache_info = self.cache.get(meta)
cache_info = self.cache.get(meta) if cache else {}
cache_hit = False
# 识别豆瓣信息
@@ -118,11 +154,7 @@ class DoubanModule(_ModuleBase):
info = douban_info_func(doubanid=doubanid, mtype=mtype or meta.type)
elif meta:
info = {}
# 简体名称
zh_name = zhconv.convert(meta.cn_name, "zh-hans") if meta.cn_name else None
# 使用中英文名分别识别,去重去空,但要保持顺序
names = list(dict.fromkeys([k for k in [meta.cn_name, zh_name, meta.en_name] if k]))
for name in names:
for name in self._prepare_search_names(meta):
if meta.begin_season:
logger.info(f"正在识别 {name}{meta.begin_season}季 ...")
else:
@@ -211,7 +243,7 @@ class DoubanModule(_ModuleBase):
meta.type = mtype
if doubanid:
meta.doubanid = doubanid
cache_info = self.cache.get(meta)
cache_info = self.cache.get(meta) if cache else {}
cache_hit = False
# 识别豆瓣信息
@@ -222,11 +254,7 @@ class DoubanModule(_ModuleBase):
info = await async_douban_info_func(doubanid=doubanid, mtype=mtype or meta.type)
elif meta:
info = {}
# 简体名称
zh_name = zhconv.convert(meta.cn_name, "zh-hans") if meta.cn_name else None
# 使用中英文名分别识别,去重去空,但要保持顺序
names = list(dict.fromkeys([k for k in [meta.cn_name, zh_name, meta.en_name] if k]))
for name in names:
for name in self._prepare_search_names(meta):
if meta.begin_season:
logger.info(f"正在识别 {name}{meta.begin_season}季 ...")
else:
@@ -913,24 +941,7 @@ class DoubanModule(_ModuleBase):
if not result or not result.get("items"):
return []
# 返回数据
ret_medias = []
for item_obj in result.get("items"):
if meta.type and meta.type != MediaType.UNKNOWN and meta.type.value != item_obj.get("type_name"):
continue
if item_obj.get("type_name") not in (MediaType.TV.value, MediaType.MOVIE.value):
continue
if meta.name not in item_obj.get("target", {}).get("title"):
continue
ret_medias.append(MediaInfo(douban_info=item_obj.get("target")))
# 将搜索词中的季写入标题中
if ret_medias and meta.begin_season:
# 小写数据转大写
season_str = cn2an.an2cn(meta.begin_season, "low")
for media in ret_medias:
if media.type == MediaType.TV:
media.title = f"{media.title}{season_str}"
media.season = meta.begin_season
return ret_medias
return self._build_search_medias_result(meta, result.get("items"))
async def async_search_medias(self, meta: MetaBase) -> Optional[List[MediaInfo]]:
"""
@@ -946,24 +957,7 @@ class DoubanModule(_ModuleBase):
if not result or not result.get("items"):
return []
# 返回数据
ret_medias = []
for item_obj in result.get("items"):
if meta.type and meta.type != MediaType.UNKNOWN and meta.type.value != item_obj.get("type_name"):
continue
if item_obj.get("type_name") not in (MediaType.TV.value, MediaType.MOVIE.value):
continue
if meta.name not in item_obj.get("target", {}).get("title"):
continue
ret_medias.append(MediaInfo(douban_info=item_obj.get("target")))
# 将搜索词中的季写入标题中
if ret_medias and meta.begin_season:
# 小写数据转大写
season_str = cn2an.an2cn(meta.begin_season, "low")
for media in ret_medias:
if media.type == MediaType.TV:
media.title = f"{media.title}{season_str}"
media.season = meta.begin_season
return ret_medias
return self._build_search_medias_result(meta, result.get("items"))
def search_persons(self, name: str) -> Optional[List[MediaPerson]]:
"""

View File

@@ -19,6 +19,8 @@ from app.schemas.types import MediaType, MediaImageType, ModuleType, MediaRecogn
from app.utils.http import RequestUtils
_DATE_RE = re.compile(r"^\d{4}-\d{2}-\d{2}$")
class TheMovieDbModule(_ModuleBase):
"""
@@ -118,6 +120,59 @@ class TheMovieDbModule(_ModuleBase):
# 使用中英文名分别识别,去重去空,但要保持顺序
return list(dict.fromkeys([k for k in [meta.cn_name, zh_name, meta.en_name] if k]))
@staticmethod
def _fill_group_season_info(mediainfo: MediaInfo, episode_group: Optional[str],
group_seasons: List[dict]) -> None:
"""
将指定剧集组的季、集、年份信息写入 MediaInfo。
"""
seasons = {}
season_info = []
season_years = {}
for group_season in group_seasons:
# 季
season = group_season.get("order")
# 集列表
episodes = group_season.get("episodes")
if not episodes:
continue
seasons[season] = [ep.get("episode_number") for ep in episodes]
season_info.append(group_season)
# 当前季第一集时间
first_date = episodes[0].get("air_date")
if first_date and _DATE_RE.match(first_date):
season_years[season] = str(first_date).split("-")[0]
# 每季集清单
if seasons:
mediainfo.seasons = seasons
mediainfo.number_of_seasons = len(seasons)
# 每季集详情
if season_info:
mediainfo.season_info = season_info
# 每季年份
if season_years:
mediainfo.season_years = season_years
# 所有剧集组
mediainfo.episode_group = episode_group
mediainfo.episode_groups = group_seasons
@staticmethod
def _build_search_medias_result(meta: MetaBase, results: Optional[List[dict]]) -> List[MediaInfo]:
"""
构建搜索结果,并沿用原有逻辑把搜索词中的季写入电视剧标题中。
"""
if not results:
return []
medias = [MediaInfo(tmdb_info=info) for info in results]
if meta.begin_season:
# 小写数据转大写
season_str = cn2an.an2cn(meta.begin_season, "low")
for media in medias:
if media.type == MediaType.TV:
media.title = f"{media.title}{season_str}"
media.season = meta.begin_season
return medias
def _get_info_by_tmdbid(self, tmdbid: int, mtype: Optional[MediaType],
meta: Optional[MetaBase]) -> Optional[dict]:
"""
@@ -289,36 +344,7 @@ class TheMovieDbModule(_ModuleBase):
"""
if mediainfo.type == MediaType.TV and mediainfo.episode_groups:
if group_seasons:
# 指定剧集组时
seasons = {}
season_info = []
season_years = {}
for group_season in group_seasons:
# 季
season = group_season.get("order")
# 集列表
episodes = group_season.get("episodes")
if not episodes:
continue
seasons[season] = [ep.get("episode_number") for ep in episodes]
season_info.append(group_season)
# 当前季第一季时间
first_date = episodes[0].get("air_date")
if re.match(r"^\d{4}-\d{2}-\d{2}$", first_date):
season_years[season] = str(first_date).split("-")[0]
# 每季集清单
if seasons:
mediainfo.seasons = seasons
mediainfo.number_of_seasons = len(seasons)
# 每季集详情
if season_info:
mediainfo.season_info = season_info
# 每季年份
if season_years:
mediainfo.season_years = season_years
# 所有剧集组
mediainfo.episode_group = episode_group
mediainfo.episode_groups = group_seasons
self._fill_group_season_info(mediainfo, episode_group, group_seasons)
else:
# 每季年份
season_years = {}
@@ -337,7 +363,7 @@ class TheMovieDbModule(_ModuleBase):
# 当前季第一季时间
first_date = episodes[0].get("air_date")
# 判断是不是日期格式
if first_date and re.match(r"^\d{4}-\d{2}-\d{2}$", first_date):
if first_date and _DATE_RE.match(first_date):
season_years[season] = str(first_date).split("-")[0]
if season_years:
mediainfo.season_years = season_years
@@ -350,36 +376,7 @@ class TheMovieDbModule(_ModuleBase):
"""
if mediainfo.type == MediaType.TV and mediainfo.episode_groups:
if group_seasons:
# 指定剧集组时
seasons = {}
season_info = []
season_years = {}
for group_season in group_seasons:
# 季
season = group_season.get("order")
# 集列表
episodes = group_season.get("episodes")
if not episodes:
continue
seasons[season] = [ep.get("episode_number") for ep in episodes]
season_info.append(group_season)
# 当前季第一季时间
first_date = episodes[0].get("air_date")
if re.match(r"^\d{4}-\d{2}-\d{2}$", first_date):
season_years[season] = str(first_date).split("-")[0]
# 每季集清单
if seasons:
mediainfo.seasons = seasons
mediainfo.number_of_seasons = len(seasons)
# 每季集详情
if season_info:
mediainfo.season_info = season_info
# 每季年份
if season_years:
mediainfo.season_years = season_years
# 所有剧集组
mediainfo.episode_group = episode_group
mediainfo.episode_groups = group_seasons
self._fill_group_season_info(mediainfo, episode_group, group_seasons)
else:
# 每季年份
season_years = {}
@@ -398,7 +395,7 @@ class TheMovieDbModule(_ModuleBase):
# 当前季第一季时间
first_date = episodes[0].get("air_date")
# 判断是不是日期格式
if first_date and re.match(r"^\d{4}-\d{2}-\d{2}$", first_date):
if first_date and _DATE_RE.match(first_date):
season_years[season] = str(first_date).split("-")[0]
if season_years:
mediainfo.season_years = season_years
@@ -484,7 +481,7 @@ class TheMovieDbModule(_ModuleBase):
meta.type = mtype
if tmdbid:
meta.tmdbid = tmdbid
cache_info = self.cache.get(meta)
cache_info = self.cache.get(meta) if cache else {}
# 查询剧集组
group_seasons = []
@@ -573,7 +570,7 @@ class TheMovieDbModule(_ModuleBase):
meta.type = mtype
if tmdbid:
meta.tmdbid = tmdbid
cache_info = self.cache.get(meta)
cache_info = self.cache.get(meta) if cache else {}
# 查询剧集组
group_seasons = []
@@ -764,17 +761,7 @@ class TheMovieDbModule(_ModuleBase):
else:
results = self.tmdb.search_tvs(meta.name, meta.year)
# 将搜索词中的季写入标题中
if results:
medias = [MediaInfo(tmdb_info=info) for info in results]
if meta.begin_season:
# 小写数据转大写
season_str = cn2an.an2cn(meta.begin_season, "low")
for media in medias:
if media.type == MediaType.TV:
media.title = f"{media.title}{season_str}"
media.season = meta.begin_season
return medias
return []
return self._build_search_medias_result(meta, results)
def search_persons(self, name: str) -> Optional[List[schemas.MediaPerson]]:
"""
@@ -1206,17 +1193,7 @@ class TheMovieDbModule(_ModuleBase):
else:
results = await self.tmdb.async_search_tvs(meta.name, meta.year)
# 将搜索词中的季写入标题中
if results:
medias = [MediaInfo(tmdb_info=info) for info in results]
if meta.begin_season:
# 小写数据转大写
season_str = cn2an.an2cn(meta.begin_season, "low")
for media in medias:
if media.type == MediaType.TV:
media.title = f"{media.title}{season_str}"
media.season = meta.begin_season
return medias
return []
return self._build_search_medias_result(meta, results)
async def async_tmdb_discover(self, mtype: MediaType, sort_by: str,
with_genres: str,