修复芒果tv旧接口缺失导致最新剧集请求不到弹幕的问题及记住上次选择剧集有时不生效的问题 (#137)

* 修复芒果tv旧接口缺失导致最新剧集请求不到弹幕的问题

* 修复记住上次选择剧集有时不生效的问题
This commit is contained in:
huangxd- authored and GitHub committed 2026-01-07 00:13:15 +08:00
1 parent e4b763a2c8
commit 929080e7bc
4 files changed
+43 -21

No files matched your search

+13 -4
View File
@@ -421,8 +421,12 @@ async function matchAniAndEp(season, episode, year, searchData, title, req, plat
// 判断剧集
const normalizedTitle = normalizeSpaces(title);
for (const anime of searchData.animes) {
if (globals.rememberLastSelect && preferAnimeId && anime.bangumiId.toString() !== preferAnimeId.toString() &&
anime.animeId.toString() !== preferAnimeId.toString()) continue;
const animeIsPrefer =
globals.rememberLastSelect &&
preferAnimeId &&
String(anime.bangumiId) !== String(preferAnimeId) &&
String(anime.animeId) !== String(preferAnimeId);
if (animeIsPrefer) continue;
if (normalizeSpaces(anime.animeTitle).includes(normalizedTitle)) {
// 年份匹配优先于季匹配
if (!matchYear(anime, year)) {
@@ -445,7 +449,7 @@ async function matchAniAndEp(season, episode, year, searchData, title, req, plat
log("info", "过滤后的集标题", filteredEpisodes.map(episode => episode.episodeTitle));
// 年份匹配通过后,再判断season
if (matchSeason(anime, title, season)) {
if (matchSeason(anime, title, season) || !animeIsPrefer) {
// 使用新的集数匹配策略
const matchedEpisode = findEpisodeByNumber(filteredEpisodes, episode, platform);
if (matchedEpisode) {
@@ -459,7 +463,12 @@ async function matchAniAndEp(season, episode, year, searchData, title, req, plat
} else {
// 判断电影
for (const anime of searchData.animes) {
if (globals.rememberLastSelect && preferAnimeId && anime.bangumiId.toString() !== preferAnimeId.toString()) continue;
const animeIsPrefer =
globals.rememberLastSelect &&
preferAnimeId &&
String(anime.bangumiId) !== String(preferAnimeId) &&
String(anime.animeId) !== String(preferAnimeId);
if (animeIsPrefer) continue;
const animeTitle = anime.animeTitle.split("(")[0].trim();
if (animeTitle === title) {
// 年份匹配优先
+1 -1
View File
@@ -13,7 +13,7 @@ export const Globals = {
accessedEnvVars: {},
// 静态常量
VERSION: '1.11.0',
VERSION: '1.11.1',
MAX_LOGS: 500, // 日志存储,最多保存 500 行
MAX_ANIMES: 100,
+27 -15
View File
@@ -568,6 +568,7 @@ export default class MangoSource extends BaseSource {
// 弹幕和视频信息 API 基础地址
const api_video_info = "https://pcweb.api.mgtv.com/video/info";
const api_ctl_barrage = "https://galaxy.bz.mgtv.com/getctlbarrage";
const api_rd_barrage = "https://galaxy.bz.mgtv.com/rdbarrage";
// 解析 URL 获取 cid 和 vid
const regex = /^(https?:\/\/[^\/]+)(\/[^?#]*)/;
@@ -615,8 +616,9 @@ export default class MangoSource extends BaseSource {
const data = typeof res.data === "string" ? JSON.parse(res.data) : res.data;
const time = data.data.info.time;
// 尝试使用新API(支持彩色弹幕)获取分段列表
let useNewApi = true;
try {
// 尝试使用新API(支持彩色弹幕)获取分段列表
const ctlBarrageUrl = `${api_ctl_barrage}?version=8.1.39&abroad=0&uuid=&os=10.15.7&platform=0&mac=&vid=${vid}&pid=&cid=${cid}&ticket=`;
const res = await httpGet(ctlBarrageUrl, {
headers: {
@@ -629,25 +631,35 @@ export default class MangoSource extends BaseSource {
// 检查数据结构
if (!ctlBarrage.data || !ctlBarrage.data.cdn_list || !ctlBarrage.data.cdn_version) {
log("warn", `新API缺少必要字段,返回空分段列表`);
return new SegmentListResponse({
"type": "imgo",
"segmentList": []
});
useNewApi = false;
}
// 构建分段列表
const segmentList = [];
const totalSegments = Math.ceil(time_to_second(time) / 60); // 每1分钟一个分段
const cdnList = ctlBarrage.data.cdn_list.split(',')[0];
const cdnVersion = ctlBarrage.data.cdn_version;
if (!useNewApi) {
const step = 60; // 每60秒一个分段
const end_time = time_to_second(time);
for (let i = 0; i < end_time; i += step) {
segmentList.push({
"type": "imgo",
"segment_start": i, // 每段开始时间(秒)
"segment_end": Math.min((i + step), time_to_second(time)), // 每段结束时间(秒)
"url": `${api_rd_barrage}?vid=${vid}&cid=${cid}&time=${i * 1000}` // 每段弹幕URL
});
}
} else {
const totalSegments = Math.ceil(time_to_second(time) / 60); // 每1分钟一个分段
const cdnList = ctlBarrage.data.cdn_list.split(',')[0];
const cdnVersion = ctlBarrage.data.cdn_version;
for (let i = 0; i < totalSegments; i++) {
segmentList.push({
"type": "imgo",
"segment_start": i * 60, // 每段开始时间(秒)
"segment_end": Math.min((i + 1) * 60, time_to_second(time)), // 每段结束时间(秒)
"url": `https://${cdnList}/${cdnVersion}/${i}.json` // 每段弹幕URL
});
for (let i = 0; i < totalSegments; i++) {
segmentList.push({
"type": "imgo",
"segment_start": i * 60, // 每段开始时间(秒)
"segment_end": Math.min((i + 1) * 60, time_to_second(time)), // 每段结束时间(秒)
"url": `https://${cdnList}/${cdnVersion}/${i}.json` // 每段弹幕URL
});
}
}
return new SegmentListResponse({
+2 -1
View File
@@ -233,6 +233,7 @@ export function storeAnimeIdsToMap(curAnimes, key) {
// 保存旧的prefer值
const oldValue = globals.lastSelectMap.get(key);
const oldPrefer = oldValue?.prefer;
const oldSource = oldValue?.source;
// 如果key已存在,先删除它(为了更新顺序,保证 FIFO)
if (globals.lastSelectMap.has(key)) {
@@ -242,7 +243,7 @@ export function storeAnimeIdsToMap(curAnimes, key) {
// 添加新记录,保留prefer字段
globals.lastSelectMap.set(key, {
animeIds: [...uniqueAnimeIds],
...(oldPrefer !== undefined && { prefer: oldPrefer })
...(oldPrefer !== undefined && { prefer: oldPrefer, source: oldSource })
});
// 检查是否超过 MAX_LAST_SELECT_MAP,超过则删除最早的