fix: 芒果TV搜索API改用新版v2接口+seqId签名 (#374)

* fix: 芒果TV搜索API改用新版v2接口+seqId签名

旧版 /msite/search/v2 已返回403,改用 /aphone/search/rebirth/v2
新增 seqId=md5(deviceId + "." + timestamp) 签名
适配新版响应格式 mediaRebirthV2

* 使用纯JS md5替代Node crypto模块以兼容fw播放器
This commit is contained in:
lilixu3 authored and GitHub committed 2026-07-17 07:27:47 +08:00
1 parent 50e84818e3
commit 64f885c98d
1 file changed
+23 -15
+23 -15
View File
@@ -5,7 +5,7 @@ import { httpGet} from "../utils/http-util.js";
import { printFirst200Chars, titleMatches, getExplicitSeasonNumber, extractSeasonNumberFromAnimeTitle } from "../utils/common-util.js";
import { time_to_second, generateValidStartDate } from "../utils/time-util.js";
import { rgbToInt } from "../utils/danmu-util.js";
import { convertToAsciiSum } from "../utils/codec-util.js";
import { md5, convertToAsciiSum } from "../utils/codec-util.js";
import { addAnime, removeEarliestAnime } from "../utils/cache-util.js";
import { SegmentListResponse } from '../models/dandan-model.js';
@@ -82,14 +82,22 @@ export default class MangoSource extends BaseSource {
try {
log("info", `[Mango] 开始搜索: ${keyword}`);
// 生成设备ID(session内持久化)
if (!this._deviceId) {
this._deviceId = md5(`danmu-api-mango-${Date.now()}`);
}
// 生成签名 seqId = md5(deviceId + "." + timestamp)
const timestamp = Date.now();
const seqId = md5(this._deviceId + "." + timestamp);
const encodedKeyword = encodeURIComponent(keyword);
const searchUrl = `https://mobileso.bz.mgtv.com/msite/search/v2?q=${encodedKeyword}&pc=30&pn=1&sort=-99&ty=0&du=0&pt=0&corr=1&abroad=0&_support=10000000000000000`;
const searchUrl = `https://mobileso.bz.mgtv.com/aphone/search/rebirth/v2?q=${encodedKeyword}&_support=10100001&device=23127PN0CC&osVersion=16&appVersion=9.3.3&did=${this._deviceId}&mac=${this._deviceId}&seqId=${seqId}&ticket=&userId=0&osType=android&type=10&abroad=0`;
const response = await httpGet(searchUrl, {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 16; 23127PN0CC Build/AP1A.240505.003)',
'Accept': 'application/json',
'Referer': 'https://www.mgtv.com/'
}
});
@@ -108,33 +116,33 @@ export default class MangoSource extends BaseSource {
// 处理搜索结果
const results = [];
for (const content of data.data.contents) {
if (content.type !== "media") {
if (content.type !== "mediaRebirthV2") {
continue;
}
for (const item of content.data) {
// 只处理芒果TV自有内容 (source为'imgo')
if (item.source !== "imgo") {
// 只处理芒果TV自有内容 (新版API中source为空或'imgo')
if (item.source && item.source !== "imgo") {
continue;
}
// 从URL中提取 collection_id
const urlMatch = item.url ? item.url.match(/\/b\/(\d+)/) : null;
if (!urlMatch) {
// 新版API使用clipId作为媒体ID
if (!item.clipId) {
continue;
}
const mediaId = urlMatch[1];
const mediaId = String(item.clipId);
// 清理标题 (移除HTML标签)
const cleanedTitle = item.title ? item.title.replace(/<[^>]+>/g, '').replace(/:/g, ':') : '';
// 提取年份
const yearMatch = item.desc && item.desc[0] ? item.desc[0].match(/[12][890][0-9][0-9]/) : null;
// 提取年份 (desc始终为数组)
const descText = Array.isArray(item.desc) ? (item.desc[0] || '') : (item.desc || '');
const yearMatch = descText.match(/[12][890][0-9][0-9]/);
const year = yearMatch ? parseInt(yearMatch[0]) : null;
// 提取媒体类型(参考优化后的 youku.js 和 bilibili.js)
const typeMatch = item.desc && item.desc[0] ? item.desc[0].split('/')[0].replace("类型:", "").trim() : '';
// 提取媒体类型
const typeMatch = descText.split('/')[0].replace("类型:", "").trim();
const mediaType = this._extractMediaType(typeMatch);
results.push({