动画源细节优化 (#216)

* animeko.js:提高搜索接口结果数量,并支持翻页

* bahamut.js:支持解析正确的类型
This commit is contained in:
Elegy233 authored and GitHub committed 2026-03-02 23:50:07 +08:00
1 parent 0c2d44408a
commit c01df2f483
2 files changed
+67 -31

No files matched your search

+55 -30
View File
@@ -29,7 +29,7 @@ export default class AnimekoSource extends BaseSource {
/**
* 搜索动画条目
* 使用 Bangumi V0 POST 接口进行搜索,并进行后置过滤和关系检测
* 使用 Bangumi V0 POST 接口进行搜索,支持偏移翻页、结果过滤及关系检测
* @param {string} keyword 搜索关键词
* @returns {Promise<Array>} 转换后的搜索结果列表
*/
@@ -37,49 +37,74 @@ export default class AnimekoSource extends BaseSource {
try {
// 标准化函数
const searchKeyword = keyword.replace(/[._]/g, ' ').replace(/\s+/g, ' ').trim();
log("info", `[Animeko] 开始搜索 (V0): ${searchKeyword}`);
const searchUrl = `https://api.bgm.tv/v0/search/subjects?limit=5`;
const payload = {
keyword: searchKeyword,
filter: {
type: [2] // 2 代表动画类型
let allFilteredResults = [];
let offset = 0;
const limit = 20;
while (true) {
const searchUrl = `https://api.bgm.tv/v0/search/subjects?limit=${limit}&offset=${offset}`;
const payload = {
keyword: searchKeyword,
filter: {
type: [2] // 2 代表动画类型
}
};
const resp = await httpPost(searchUrl, JSON.stringify(payload), {
headers: this.headers
});
if (!resp || !resp.data) {
log("info", `[Animeko] 搜索请求失败或无数据返回 (offset: ${offset})`);
break;
}
};
const resp = await httpPost(searchUrl, JSON.stringify(payload), {
headers: this.headers
});
const currentBatch = resp.data.data || [];
if (!resp || !resp.data) {
log("info", "[Animeko] 搜索请求失败或无数据返回");
return [];
if (currentBatch.length === 0) {
break;
}
// 执行结果相关度过滤 (剔除强大的模糊搜索带来的杂项)
const filteredBatch = this.filterSearchResults(currentBatch, keyword);
if (filteredBatch.length > 0) {
allFilteredResults = allFilteredResults.concat(filteredBatch);
}
// 核心分页判断逻辑
if (filteredBatch.length < limit) {
log("info", `[Animeko] 过滤后当前批次剩 ${filteredBatch.length} 个结果,停止翻页`);
break;
}
offset += limit;
// 安全熔断:限制最大翻页次数(例如获取前 60 条)防止特殊情况下的无意义消耗
if (offset >= 60) {
log("warn", `[Animeko] 搜索翻页达到安全上限(60),强制停止`);
break;
}
}
let resultsList = resp.data.data || [];
if (resultsList.length === 0) {
log("info", "[Animeko] 未找到相关条目");
return [];
}
// 执行结果相关度过滤
resultsList = this.filterSearchResults(resultsList, keyword);
if (resultsList.length === 0) {
if (allFilteredResults.length === 0) {
log("info", "[Animeko] 过滤后无匹配结果");
return [];
}
// 跨页合并后,为了防止多页触发同样的“智能季度匹配兜底”导致重复,这里做一次 ID 去重
let uniqueResults = Array.from(new Map(allFilteredResults.map(item => [item.id, item])).values());
// 检测条目间关系 (如处理续篇、剧场版等层级关系)
if (resultsList.length > 1) {
resultsList = await this.checkRelationsAndModifyTitles(resultsList);
if (uniqueResults.length > 1) {
uniqueResults = await this.checkRelationsAndModifyTitles(uniqueResults);
}
log("info", `[Animeko] 搜索完成,找到 ${resultsList.length} 个有效结果`);
return this.transformResults(resultsList);
log("info", `[Animeko] 搜索完成,共找到 ${uniqueResults.length} 个有效结果`);
return this.transformResults(uniqueResults);
} catch (error) {
log("error", "[Animeko] Search error:", {
message: error.message,
+12 -1
View File
@@ -317,10 +317,21 @@ export default class BahamutSource extends BaseSource {
// 优先使用tmdb智能标题替换的标题,否则简转繁处理原标题
const displayTitle = anime._displayTitle || simplized(anime.title);
// 解析剧集类型
let itemType = "动漫"; // 默认类型
// 从 epData 中获取完整标题 (优先使用 anime.title)
const fullTitle = (epData.anime && epData.anime.title) || (detail && detail.title) || "";
if (fullTitle.includes("[電影]")) {
itemType = "剧场版";
} else if (fullTitle.includes("[特別篇]")) {
itemType = "OVA";
}
let transformedAnime = {
animeId: anime.video_sn,
bangumiId: String(anime.video_sn),
animeTitle: `${displayTitle}(${(anime.info.match(/(\d{4})/) || [null])[0]})【动漫】from bahamut`,
animeTitle: `${displayTitle}(${(anime.info.match(/(\d{4})/) || [null])[0]})【${itemType}】from bahamut`,
type: "动漫",
typeDescription: "动漫",
imageUrl: anime.cover,