重构爱奇艺解析逻辑,优化tvid获取和视频信息请求

This commit is contained in:
xyysjd
2025-07-04 13:27:32 +08:00
parent 20f3a09cb1
commit 5e8c631406

View File

@@ -1,138 +1,134 @@
const axios = require("axios"); const axios = require("axios");
const pako = require("pako"); const pako = require("pako");
const { const {
time_to_second, time_to_second,
content_template, content_template,
} = require("./utils"); } = require("./utils");
const memory = require("../../utils/memory"); const memory = require("../../utils/memory");
//资源消耗大 256M内存扛不住
function Iqiyi() { function Iqiyi() {
this.name = "爱奇艺"; this.name = "爱奇艺";
this.domain = "iqiyi.com"; this.domain = "iqiyi.com";
this.example_urls = [ this.example_urls = [
"https://www.iqiyi.com/v_19rr1lm35o.html", //api lens 11 "https://www.iqiyi.com/v_bb6gsxzz78.html",
"http://www.iqiyi.com/v_1qzx9b00hs4.html?vfm=m_331_dbdy", //api lens 25 "https://www.iqiyi.com/v_19rr1lm35o.html",
"https://www.iqiyi.com/v_19rr1lm35o.html", ];
];
this.resolve = async (url) => { // 新的tvid获取方法
const res = await axios({ this.get_tvid = async (url) => {
url: url, const id = /v_(\w+)/.exec(url)[1];
method: "get", const api = `https://pcw-api.iq.com/api/decode/${id}?platformId=3&modeCode=intl&langCode=sg`;
headers: { const response = await axios.get(api);
"Accept-Encoding": "gzip,deflate,compress" return response.data.data.toString();
} };
});
const data = res.data;
const result = data.match(/<script id="__NEXT_DATA__" type="application\/json">(.*?)<\/script>/);
console.log(url)
let page_info = JSON.parse(result[1]);
// console.log('page_info:', page_info)
page_info = page_info.props.pageProps.videoInfo
const duration = time_to_second(page_info.duration);
this.title = page_info.tvName ? page_info.tvName : page_info.name;
const albumid = page_info.albumId;
const tvid = page_info.tvId.toString();
const categoryid = page_info.channelId;
const page = Math.round(duration / (60 * 5));
console.log("tvid", tvid);
let promises = [];
for (let i = 0; i < page; i++) {
const api_url = `https://cmts.iqiyi.com/bullet/${tvid.slice(-4, -2)}/${tvid.slice(-2)}/${tvid}_300_${i + 1}.z`;
const params = {
rn: "0.0123456789123456",
business: "danmu",
is_iqiyi: "true",
is_video_page: "true",
tvid: tvid,
albumid: albumid,
categoryid: categoryid,
qypid: "01010021010000000000"
};
promises.push(axios({
method: "get",
url: api_url,
params: params,
responseType: "arraybuffer"
}));
}
return promises;
};
function extract(xml, tag) { // 获取视频基础信息
const reg = new RegExp(`<${tag}>(.*?)</${tag}>`, "g"); this.get_video_info = async (tvid) => {
const res = xml.match(reg) const api = `https://pcw-api.iqiyi.com/video/video/baseinfo/${tvid}`;
?.map(x => x.substring(tag.length + 2, x.length - tag.length - 3)); const response = await axios.get(api);
return res || []; return response.data.data;
} };
this.xml2json = (xml, contents,length) => { this.resolve = async (url) => {
const danmaku = extract(xml, "content"); // 1. 获取tvid
const showTime = extract(xml, "showTime"); const tvid = await this.get_tvid(url);
const color = extract(xml, "color");
//const font = extract(xml, "font"); // 2. 获取视频基础信息
const videoInfo = await this.get_video_info(tvid);
this.title = videoInfo.name || videoInfo.tvName;
const duration = videoInfo.durationSec;
const albumid = videoInfo.albumId;
const categoryid = videoInfo.channelId || videoInfo.categoryId;
// 控制步长,减小内存占用 // 3. 计算需要请求的弹幕文件数量(每5分钟一个)
const step = Math.ceil(danmaku.length*length/10000); const page = Math.ceil(duration / (60 * 5));
// console.log(step) console.log("tvid:", tvid, "duration:", duration, "pages:", page);
for (let i = 0; i < danmaku.length; i+=step) {
// console.log(bulletInfo)
const content = JSON.parse(JSON.stringify(content_template));
content.timepoint = showTime[i];//showTime
content.color = parseInt(color[i], 16);//color
content.content = danmaku[i]; //content
content.size = 25;//font
contents.push(content);
}
};
this.parse = async (promises) => { // 4. 构建弹幕请求
memory(); let promises = [];
//筛选出成功的请求 for (let i = 0; i < page; i++) {
let datas = (await Promise.allSettled(promises)) const api_url = `https://cmts.iqiyi.com/bullet/${tvid.slice(-4, -2)}/${tvid.slice(-2)}/${tvid}_300_${i + 1}.z`;
.filter(x => x.status === "fulfilled") const params = {
.map(x => x.value.data); rn: "0.0123456789123456",
memory(); business: "danmu",
let contents = []; is_iqiyi: "true",
for (let i = 0; i < datas.length; i++) { is_video_page: "true",
const data = datas[i]; tvid: tvid,
let xml = pako.inflate(data, { to: "string" }); albumid: albumid,
this.xml2json(xml, contents,datas.length); categoryid: categoryid,
datas[i] = null; qypid: "01010021010000000000"
xml = null; };
if (global.gc) { promises.push(axios({
global.gc(); method: "get",
} url: api_url,
memory(); params: params,
} responseType: "arraybuffer"
// contents = make_response(contents); }));
memory(); }
return contents; return promises;
}; };
this.work = async (url) => { function extract(xml, tag) {
const promises = await this.resolve(url); const reg = new RegExp(`<${tag}>(.*?)</${tag}>`, "g");
console.log(this.name, "api lens:", promises.length); const res = xml.match(reg)
this.content = await this.parse(promises); ?.map(x => x.substring(tag.length + 2, x.length - tag.length - 3));
return { return res || [];
title: this.title, }
content: this.content,
msg: "ok"
};
};
this.xml2json = (xml, contents, length) => {
const danmaku = extract(xml, "content");
const showTime = extract(xml, "showTime");
const color = extract(xml, "color");
const step = Math.ceil(danmaku.length * length / 10000);
for (let i = 0; i < danmaku.length; i += step) {
const content = JSON.parse(JSON.stringify(content_template));
content.timepoint = showTime[i];
content.color = parseInt(color[i], 16);
content.content = danmaku[i];
content.size = 25;
contents.push(content);
}
};
this.parse = async (promises) => {
memory();
let datas = (await Promise.allSettled(promises))
.filter(x => x.status === "fulfilled")
.map(x => x.value.data);
memory();
let contents = [];
for (let i = 0; i < datas.length; i++) {
const data = datas[i];
let xml = pako.inflate(data, { to: "string" });
this.xml2json(xml, contents, datas.length);
datas[i] = null;
xml = null;
if (global.gc) global.gc();
memory();
}
return contents;
};
this.work = async (url) => {
const promises = await this.resolve(url);
console.log(this.name, "api lens:", promises.length);
this.content = await this.parse(promises);
return {
title: this.title,
content: this.content,
msg: "ok"
};
};
} }
module.exports = Iqiyi; module.exports = Iqiyi;
if (!module.parent) { if (!module.parent) {
const m = new Iqiyi(); const m = new Iqiyi();
m.work(m.example_urls[0])
m.work(m.example_urls[1]) .then(() => {
.then(() => { console.log(m.title);
// console.log(m.content); memory();
console.log(m.title); });
memory(); }
});
}