为弹弹源添加别名替换相关逻辑,使不同译名的结果能够参与match匹配 (#270)
* tmdb-util.js:将关键词清理函数提取为公共函数 * dandan.js:调用tmdb智能别名替换,并增加内部别名智能替换功能 使不同译名的结果能够参与match匹配
This commit is contained in:
1 parent
d89ba7a1c2
commit
b6926712f5
2 files changed
+51
-10
No files matched your search
@@ -5,7 +5,7 @@ import { httpGet } from "../utils/http-util.js";
|
||||
import { addAnime, removeEarliestAnime } from "../utils/cache-util.js";
|
||||
import { simplized } from "../utils/zh-util.js";
|
||||
import { SegmentListResponse } from '../models/dandan-model.js';
|
||||
import { getTmdbJaOriginalTitle } from "../utils/tmdb-util.js";
|
||||
import { getTmdbJaOriginalTitle, smartTitleReplace, cleanSearchQuery } from "../utils/tmdb-util.js";
|
||||
import TencentSource from "./tencent.js";
|
||||
import IqiyiSource from "./iqiyi.js";
|
||||
import MangoSource from "./mango.js";
|
||||
@@ -86,7 +86,7 @@ export default class DandanSource extends BaseSource {
|
||||
// 延迟100毫秒,避免与原始搜索争抢同一连接池
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
// 获取 TMDB 日语原名
|
||||
// 获取 TMDB 日语原名及中文别名
|
||||
const tmdbResult = await getTmdbJaOriginalTitle(keyword, tmdbAbortController.signal, "Dandan");
|
||||
|
||||
// 如果没有结果或者没有标题,则停止
|
||||
@@ -95,7 +95,7 @@ export default class DandanSource extends BaseSource {
|
||||
return { success: false, source: 'tmdb' };
|
||||
}
|
||||
|
||||
const { title: tmdbTitle } = tmdbResult;
|
||||
const { title: tmdbTitle, cnAlias } = tmdbResult;
|
||||
log("info", `[Dandan] 使用日语原名通过 episodes 接口进行搜索: ${tmdbTitle}`);
|
||||
|
||||
// episodes 接口对日语原名的支持更好,使用其进行 TMDB 原名搜索
|
||||
@@ -121,9 +121,10 @@ export default class DandanSource extends BaseSource {
|
||||
|
||||
const animes = resp.data.animes;
|
||||
|
||||
// 标记 TMDB 来源,供后续处理环节识别以跳过常规标题匹配
|
||||
// 标记 TMDB 来源并注入别名,供后续处理环节识别与替换
|
||||
for (const anime of animes) {
|
||||
anime.isTmdbSource = true;
|
||||
anime._tmdbCnAlias = cnAlias;
|
||||
}
|
||||
|
||||
log("info", `dandanSearchresp (tmdb): ${JSON.stringify(animes)}`);
|
||||
@@ -273,6 +274,15 @@ export default class DandanSource extends BaseSource {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 提取并映射 title 字段以适配 smartTitleReplace 工具
|
||||
sourceAnimes.forEach(anime => {
|
||||
anime.title = anime.animeTitle;
|
||||
});
|
||||
|
||||
// 应用 TMDB 智能标题替换
|
||||
const cnAlias = sourceAnimes.length > 0 ? sourceAnimes[0]._tmdbCnAlias : null;
|
||||
smartTitleReplace(sourceAnimes, cnAlias);
|
||||
|
||||
// 初始搜索结果数量,用于判断是否展开相关作品搜索
|
||||
const initialCount = sourceAnimes.length;
|
||||
const existingIds = new Set();
|
||||
@@ -288,12 +298,19 @@ export default class DandanSource extends BaseSource {
|
||||
while (queue.length > 0) {
|
||||
const currentBatch = queue.splice(0, queue.length);
|
||||
|
||||
// 使动态加入的相关作品调用 TMDB 智能替换
|
||||
const newlyAddedRelateds = currentBatch.filter(a => a.isRelated && !a._displayTitle);
|
||||
if (newlyAddedRelateds.length > 0) {
|
||||
newlyAddedRelateds.forEach(a => a.title = a.animeTitle);
|
||||
smartTitleReplace(newlyAddedRelateds, cnAlias);
|
||||
}
|
||||
|
||||
await Promise.all(currentBatch.map(async (anime) => {
|
||||
try {
|
||||
// 获取详情数据(包含剧集、别名和相关作品)
|
||||
const details = await this.getEpisodes(anime.animeId);
|
||||
const eps = details.episodes; // 提取剧集列表
|
||||
const aliases = details.titles; // 提取别名列表
|
||||
const apiAliases = details.titles || []; // 提取 API 返回的别名列表
|
||||
|
||||
// 计算当前作品标题与用户原始搜索词的相似度
|
||||
const similarity = this.calculateSimilarity(queryTitle, anime.animeTitle);
|
||||
@@ -317,11 +334,11 @@ export default class DandanSource extends BaseSource {
|
||||
}
|
||||
|
||||
// 区分初始搜索结果与动态相关作品的结果过滤逻辑
|
||||
const allTitles = [anime.animeTitle, ...aliases];
|
||||
const allTitles = [anime.animeTitle, ...apiAliases];
|
||||
let isMatch = false;
|
||||
|
||||
if (anime.isRelated || anime.isTmdbSource) {
|
||||
// 相关作品及TMDB原名搜索结果逻辑:仅执行单纯的季度过滤,跳过常规标题匹配,防止标题语言差异导致误判
|
||||
// 相关作品及TMDB原名搜索结果逻辑:仅执行单纯的季度过滤,跳过常规标题匹配,防止标题差异导致误判
|
||||
const querySeason = getExplicitSeasonNumber(queryTitle);
|
||||
if (querySeason !== null) {
|
||||
let titleSeason = null;
|
||||
@@ -363,6 +380,30 @@ export default class DandanSource extends BaseSource {
|
||||
}
|
||||
|
||||
if (links.length > 0) {
|
||||
// 复用 TMDB 工具清洗用户搜索词剥离季度/Part等后缀
|
||||
const baseQueryTitle = cleanSearchQuery(queryTitle);
|
||||
|
||||
// 在官方别名池中寻找与纯净主标题精确匹配的别名(忽略大小写)
|
||||
const matchedApiAlias = apiAliases.find(alias => {
|
||||
if (!alias) return false;
|
||||
return alias.toLowerCase() === baseQueryTitle.toLowerCase();
|
||||
});
|
||||
|
||||
// 如果详情接口中存在完全匹配的官方别名,强制复用智能拼接替换
|
||||
if (matchedApiAlias) {
|
||||
smartTitleReplace([anime], matchedApiAlias);
|
||||
log("info", `[Dandan] 命中 API 官方别名: 搜索词 "${baseQueryTitle}" 匹配到 "${matchedApiAlias}", 已将原标题 "${anime.animeTitle}" 替换展示`);
|
||||
}
|
||||
|
||||
// 优先使用 智能标题替换后的标题,如果没有则直接使用原标题
|
||||
const displayTitle = anime._displayTitle || anime.animeTitle;
|
||||
|
||||
// 合并别名池:API返回的别名 + 原始标题(供合并工具对齐使用)
|
||||
const finalAliases = [...apiAliases];
|
||||
if (anime.animeTitle && anime.animeTitle !== displayTitle && !finalAliases.includes(anime.animeTitle)) {
|
||||
finalAliases.push(anime.animeTitle);
|
||||
}
|
||||
|
||||
// 构造标准番剧对象
|
||||
// 类型统一从 bangumi 详情接口读取,确保相关作品不会错误继承主作品类型
|
||||
const resolvedType = details.type || anime.type || "tvseries";
|
||||
@@ -373,8 +414,8 @@ export default class DandanSource extends BaseSource {
|
||||
let transformedAnime = {
|
||||
animeId: anime.animeId,
|
||||
bangumiId: String(anime.animeId),
|
||||
animeTitle: `${anime.animeTitle}(${yearStr})【${resolvedTypeDescription}】from dandan`,
|
||||
aliases: aliases,
|
||||
animeTitle: `${displayTitle}(${yearStr})【${resolvedTypeDescription}】from dandan`,
|
||||
aliases: finalAliases,
|
||||
type: resolvedType,
|
||||
typeDescription: resolvedTypeDescription,
|
||||
imageUrl: details.imageUrl || anime.imageUrl,
|
||||
|
||||
@@ -663,7 +663,7 @@ function detectSuffixStart(title) {
|
||||
* @param {string} title 原始标题
|
||||
* @returns {string} 清洗后的标题主体
|
||||
*/
|
||||
function cleanSearchQuery(title) {
|
||||
export function cleanSearchQuery(title) {
|
||||
const limit = detectSuffixStart(title);
|
||||
if (limit < title.length) {
|
||||
return title.substring(0, limit).trim();
|
||||
|
||||
Reference in new issue
Block a user