fix: 优化TMDB搜索匹配优先级,title/original_title优先于别名匹配

将搜索结果匹配策略从"逐个结果完整匹配链"改为"两轮优先级匹配":
第一轮遍历所有结果只匹配title/original_title,第二轮再匹配别名译名。
避免排序靠前的无关影片因别名恰好匹配而抢先于正确结果。

Fixes #5719

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
jxxghp
2026-05-21 17:47:59 +08:00
parent 2bd4a41cbe
commit b6b5529d19

View File

@@ -200,55 +200,45 @@ class TmdbApi:
ret_info['media_type'] = MediaType.MOVIE if ret_info.get("media_type") == "movie" else MediaType.TV
return ret_info
def _match_multi_item(self, name: str, multi: dict, get_info_func) -> Optional[dict]:
@staticmethod
def _match_multi_title(name_compare_func, name: str, multi: dict) -> bool:
"""
匹配单个多媒体搜索结果项
:param name: 查询名称
:param multi: 搜索结果项
:param get_info_func: 获取详细信息的函数(同步或异步)
:return: 匹配的结果或None
匹配单个多媒体搜索结果项的标题/原标题
"""
if multi.get("media_type") == "movie":
return (name_compare_func(name, multi.get('title'))
or name_compare_func(name, multi.get('original_title')))
elif multi.get("media_type") == "tv":
return (name_compare_func(name, multi.get('name'))
or name_compare_func(name, multi.get('original_name')))
return False
def _match_multi_names(self, name: str, multi: dict, get_info_func) -> Optional[dict]:
"""
匹配单个多媒体搜索结果项的别名、译名
"""
if multi.get("media_type") == "movie":
if self.__compare_names(name, multi.get('title')) \
or self.__compare_names(name, multi.get('original_title')):
return multi
# 匹配别名、译名
if not multi.get("names"):
multi = get_info_func(mtype=MediaType.MOVIE, tmdbid=multi.get("id"))
if multi and self.__compare_names(name, multi.get("names")):
return multi
elif multi.get("media_type") == "tv":
if self.__compare_names(name, multi.get('name')) \
or self.__compare_names(name, multi.get('original_name')):
return multi
# 匹配别名、译名
if not multi.get("names"):
multi = get_info_func(mtype=MediaType.TV, tmdbid=multi.get("id"))
if multi and self.__compare_names(name, multi.get("names")):
return multi
return None
async def _async_match_multi_item(self, name: str, multi: dict) -> Optional[dict]:
async def _async_match_multi_names(self, name: str, multi: dict) -> Optional[dict]:
"""
匹配单个多媒体搜索结果项(异步版本)
:param name: 查询名称
:param multi: 搜索结果项
:return: 匹配的结果或None
匹配单个多媒体搜索结果项的别名、译名(异步版本)
"""
if multi.get("media_type") == "movie":
if self.__compare_names(name, multi.get('title')) \
or self.__compare_names(name, multi.get('original_title')):
return multi
# 匹配别名、译名
if not multi.get("names"):
multi = await self.async_get_info(mtype=MediaType.MOVIE, tmdbid=multi.get("id"))
if multi and self.__compare_names(name, multi.get("names")):
return multi
elif multi.get("media_type") == "tv":
if self.__compare_names(name, multi.get('name')) \
or self.__compare_names(name, multi.get('original_name')):
return multi
# 匹配别名、译名
if not multi.get("names"):
multi = await self.async_get_info(mtype=MediaType.TV, tmdbid=multi.get("id"))
if multi and self.__compare_names(name, multi.get("names")):
@@ -366,18 +356,18 @@ class TmdbApi:
key=lambda x: x.get('release_date') or '0000-00-00',
reverse=True
)
# 过滤年份
if year:
movies = [m for m in movies
if (m.get('release_date') or '')[0:4] == year]
# 第一轮:优先匹配标题、原标题
for movie in movies:
# 年份
movie_year = movie.get('release_date')[0:4] if movie.get('release_date') else None
if year and movie_year != year:
# 年份不匹配
continue
# 匹配标题、原标题
if self.__compare_names(name, movie.get('title')):
return movie
if self.__compare_names(name, movie.get('original_title')):
return movie
# 匹配别名、译名
# 第二轮:匹配别名、译名
for movie in movies:
if not movie.get("names"):
movie = self.get_info(mtype=MediaType.MOVIE, tmdbid=movie.get("id"))
if movie and self.__compare_names(name, movie.get("names")):
@@ -413,17 +403,18 @@ class TmdbApi:
key=lambda x: x.get('first_air_date') or '0000-00-00',
reverse=True
)
# 过滤年份
if year:
tvs = [t for t in tvs
if (t.get('first_air_date') or '')[0:4] == year]
# 第一轮:优先匹配标题、原标题
for tv in tvs:
tv_year = tv.get('first_air_date')[0:4] if tv.get('first_air_date') else None
if year and tv_year != year:
# 年份不匹配
continue
# 匹配标题、原标题
if self.__compare_names(name, tv.get('name')):
return tv
if self.__compare_names(name, tv.get('original_name')):
return tv
# 匹配别名、译名
# 第二轮:匹配别名、译名
for tv in tvs:
if not tv.get("names"):
tv = self.get_info(mtype=MediaType.TV, tmdbid=tv.get("id"))
if tv and self.__compare_names(name, tv.get("names")):
@@ -575,12 +566,19 @@ class TmdbApi:
# 按年份降序排列,电影在前面
multis = self._sort_multi_results(multis)
# 第一轮:优先匹配标题、原标题
ret_info = {}
for multi in multis:
matched = self._match_multi_item(name, multi, self.get_info)
if matched:
ret_info = matched
if self._match_multi_title(self.__compare_names, name, multi):
ret_info = multi
break
# 第二轮:匹配别名、译名
if not ret_info:
for multi in multis:
matched = self._match_multi_names(name, multi, self.get_info)
if matched:
ret_info = matched
break
# 类型变更
return self._convert_media_type(ret_info)
@@ -1521,18 +1519,18 @@ class TmdbApi:
key=lambda x: x.get('release_date') or '0000-00-00',
reverse=True
)
# 过滤年份
if year:
movies = [m for m in movies
if (m.get('release_date') or '')[0:4] == year]
# 第一轮:优先匹配标题、原标题
for movie in movies:
# 年份
movie_year = movie.get('release_date')[0:4] if movie.get('release_date') else None
if year and movie_year != year:
# 年份不匹配
continue
# 匹配标题、原标题
if self.__compare_names(name, movie.get('title')):
return movie
if self.__compare_names(name, movie.get('original_title')):
return movie
# 匹配别名、译名
# 第二轮:匹配别名、译名
for movie in movies:
if not movie.get("names"):
movie = await self.async_get_info(mtype=MediaType.MOVIE, tmdbid=movie.get("id"))
if movie and self.__compare_names(name, movie.get("names")):
@@ -1568,17 +1566,18 @@ class TmdbApi:
key=lambda x: x.get('first_air_date') or '0000-00-00',
reverse=True
)
# 过滤年份
if year:
tvs = [t for t in tvs
if (t.get('first_air_date') or '')[0:4] == year]
# 第一轮:优先匹配标题、原标题
for tv in tvs:
tv_year = tv.get('first_air_date')[0:4] if tv.get('first_air_date') else None
if year and tv_year != year:
# 年份不匹配
continue
# 匹配标题、原标题
if self.__compare_names(name, tv.get('name')):
return tv
if self.__compare_names(name, tv.get('original_name')):
return tv
# 匹配别名、译名
# 第二轮:匹配别名、译名
for tv in tvs:
if not tv.get("names"):
tv = await self.async_get_info(mtype=MediaType.TV, tmdbid=tv.get("id"))
if tv and self.__compare_names(name, tv.get("names")):
@@ -1897,12 +1896,19 @@ class TmdbApi:
# 按年份降序排列,电影在前面
multis = self._sort_multi_results(multis)
# 第一轮:优先匹配标题、原标题
ret_info = {}
for multi in multis:
matched = await self._async_match_multi_item(name, multi)
if matched:
ret_info = matched
if self._match_multi_title(self.__compare_names, name, multi):
ret_info = multi
break
# 第二轮:匹配别名、译名
if not ret_info:
for multi in multis:
matched = await self._async_match_multi_names(name, multi)
if matched:
ret_info = matched
break
# 类型变更
return self._convert_media_type(ret_info)