diff --git a/README.md b/README.md index 73586fe..0e8b1d8 100644 --- a/README.md +++ b/README.md @@ -492,7 +492,7 @@ API 支持返回 Bilibili 标准 XML 格式的弹幕数据,通过查询参数 ```plain # TITLE_NOISE_FILTER 默认值 -[((](?:臻彩|真彩|高清|标清|超清|国配|中配|日配|粤语|原声|台配|无修|未删减|完整版)[))] +[((\\[](?:臻彩|真彩|高清|标清|超清|国配|中配|日配|粤语|原声|台配|无修|未删减|完整版|日语版|国语版|英语版|中字|字幕|助听|原版)[\\]))] ``` ```regex diff --git a/config/.env.example b/config/.env.example index 846c0c0..0f45fda 100644 --- a/config/.env.example +++ b/config/.env.example @@ -401,7 +401,7 @@ ANIME_TITLE_FILTER= # 示例:只清理括号臻彩和真彩 # TITLE_NOISE_FILTER=[((](?:臻彩|真彩)[))] # 设为空值可禁用 -TITLE_NOISE_FILTER=[((](?:臻彩|真彩|高清|标清|超清|国配|中配|日配|粤语|原声|台配|无修|未删减|完整版)[))] +TITLE_NOISE_FILTER=[((\\[](?:臻彩|真彩|高清|标清|超清|国配|中配|日配|粤语|原声|台配|无修|未删减|完整版|日语版|国语版|英语版|中字|字幕|助听|原版)[\\]))] # ==================== AI 配置 ==================== diff --git a/danmu_api/apis/dandan-api.js b/danmu_api/apis/dandan-api.js index 37d6c94..3a621b2 100644 --- a/danmu_api/apis/dandan-api.js +++ b/danmu_api/apis/dandan-api.js @@ -1291,13 +1291,6 @@ async function matchAniAndEp(season, episode, year, searchData, title, req, plat // 遍历所有搜索结果,寻找最佳匹配 for (const anime of searchData.animes) { - // 偏好过滤 - const animeIsNotPrefer = - globals.rememberLastSelect && - preferAnimeId && - String(anime.bangumiId) !== String(preferAnimeId) && - String(anime.animeId) !== String(preferAnimeId); - if (animeIsNotPrefer) continue; let isMatch = false; @@ -1330,7 +1323,8 @@ async function matchAniAndEp(season, episode, year, searchData, title, req, plat // 构造一个虚拟的 anime 对象传入 matchSeason,这样当命中别名时,matchSeason 才能正确判断后缀 const tempAnime = { ...anime, animeTitle: candTitle }; - if (matchSeason(tempAnime, title, season) || animeIsPrefer) { + const seasonOk = matchSeason(tempAnime, title, season); + if (seasonOk || animeIsPrefer) { isMatch = true; break; // 别名命中跳出 } @@ -1449,8 +1443,8 @@ async function matchAniAndEp(season, episode, year, searchData, title, req, plat }; } - // 如果没有指定平台偏好 (platform 为空) 或已命中最高优先级的手动优选,立刻跳出查找 - if (!platform || isPreferredAnime) { + // 已命中最高优先级的手动优选,或不存在平台偏好且无待匹配的优选条目时立刻跳出查找 + if (isPreferredAnime || (!platform && !preferAnimeId)) { break; } @@ -2400,11 +2394,12 @@ export async function getComment(path, queryFormat, segmentFlag, clientIp, inclu } } - log("info", `[system] [LogVar-API] animeTitle:${animeTitle}; lastTitle:${lastTitle}; titleMatches:${titleMatches(animeTitle, lastTitle)}`); + log("info", `[system] [LogVar-API] animeTitle:${animeTitle}; lastTitle:${lastTitle}; titleMatches:${titleMatches(animeTitle, lastTitle, null, true)}`); // 校验番剧标题或别名是否匹配最新搜索/匹配上下文,别名检查用于兼容不同源对同一番剧的标题命名差异 - const titleOrAliasMatches = titleMatches(animeTitle, lastTitle) || - (Array.isArray(animeAliases) && animeAliases.some(alias => titleMatches(alias, lastTitle))); + // 偏好记录使用非严格匹配(forceNonStrict=true),因为用户手动选择不应受严格标题匹配限制 + const titleOrAliasMatches = titleMatches(animeTitle, lastTitle, null, true) || + (Array.isArray(animeAliases) && animeAliases.some(alias => titleMatches(alias, lastTitle, null, true))); if (titleOrAliasMatches) { log("info", `[system] [LogVar-API] excute setPreferByAnimeId`); diff --git a/danmu_api/configs/envs.js b/danmu_api/configs/envs.js index cbaa505..c5e49a4 100644 --- a/danmu_api/configs/envs.js +++ b/danmu_api/configs/envs.js @@ -542,7 +542,7 @@ export class Envs { * @returns {RegExp|null} 全局正则,显式设为空时返回 null(禁用) */ static resolveTitleNoiseFilter() { - const defaultPattern = '[((](?:臻彩|真彩|高清|标清|超清|国配|中配|日配|粤语|原声|台配|无修|未删减|完整版)[))]'; + const defaultPattern = '[((\\[](?:臻彩|真彩|高清|标清|超清|国配|中配|日配|粤语|原声|台配|无修|未删减|完整版|日语版|国语版|英语版|中字|字幕|助听|原版)[\\]))]'; const raw = this.get('TITLE_NOISE_FILTER', '', 'string').trim(); const hasKey = (this.env && 'TITLE_NOISE_FILTER' in this.env) || (typeof process !== 'undefined' && 'TITLE_NOISE_FILTER' in process.env); @@ -638,7 +638,7 @@ export class Envs { 'TITLE_TO_CHINESE': { category: 'match', type: 'boolean', description: '外语标题转换中文开关' }, 'ANIME_TITLE_SIMPLIFIED': { category: 'match', type: 'boolean', description: '搜索的剧名标题自动繁转简' }, 'TITLE_MAPPING_TABLE': { category: 'match', type: 'map', description: '剧名映射表,用于自动匹配时替换标题进行搜索,格式:原始标题->映射标题;原始标题->映射标题;... ,例如:"唐朝诡事录->唐朝诡事录之西行;国色芳华->锦绣芳华"' }, - 'TITLE_NOISE_FILTER': { category: 'match', type: 'text', description: '剧名杂音清理规则,按正则表达式清理搜索与匹配阶段的剧名杂音词(如`百花杀(真彩)`→`百花杀`)。默认值:[((](?:臻彩|真彩|高清|标清|超清|国配|中配|日配|粤语|原声|台配|无修|未删减|完整版)[))],中英文括号均匹配。设为空值可禁用' }, + 'TITLE_NOISE_FILTER': { category: 'match', type: 'text', description: '剧名杂音清理规则,按正则表达式清理搜索与匹配阶段的剧名杂音词(如`百花杀(真彩)`→`百花杀`)。默认值:[((\\[](?:臻彩|真彩|高清|标清|超清|国配|中配|日配|粤语|原声|台配|无修|未删减|完整版|日语版|国语版|英语版|中字|字幕|助听|原版)[\\]))],中英文圆方括号均匹配。设为空值可禁用' }, 'AI_BASE_URL': { category: 'match', type: 'text', description: 'AI服务基础URL,不填默认为https://api.openai.com/v1' }, 'AI_MODEL': { category: 'match', type: 'text', description: 'AI模型名称,不填默认为gpt-4o' }, 'AI_API_KEY': { category: 'match', type: 'text', description: 'AI服务API密钥,默认为空,需手动填写' }, diff --git a/danmu_api/utils/common-util.js b/danmu_api/utils/common-util.js index e0b93ab..98b3166 100644 --- a/danmu_api/utils/common-util.js +++ b/danmu_api/utils/common-util.js @@ -269,15 +269,15 @@ export function getExplicitSeasonNumber(text) { * @param {number|null} parsedSeason - 解析出的目标季度 * @returns {boolean} 是否匹配 */ -export function titleMatches(title, query, parsedSeason = null) { +export function titleMatches(title, query, parsedSeason = null, forceNonStrict = false) { if (title == null || query == null) return false; const titleText = String(title); const queryText = String(query); if (!titleText || !queryText) return false; - // 策略1:严格模式仅允许头部或完全匹配 - if (globals.strictTitleMatch) return strictTitleMatch(titleText, queryText); + // 策略1:严格模式仅允许头部或完全匹配(forceNonStrict 为 true 时跳过,用于偏好记录等场景) + if (!forceNonStrict && globals.strictTitleMatch) return strictTitleMatch(titleText, queryText); // 剧名杂音清理:移除画质/配音/版本等杂音词,避免阻塞匹配 const tagFilter = globals.titleNoiseFilter || null;