🐞 fix: V1.3.3 修复bili音乐逻辑 (现在即可使用命令:bili音乐+链接,下载音乐啦!)

1. 将m4s发送转换为mp3发送格式
2. 提升了bili解析的扩展性
3. 整理了path获取的方式
This commit is contained in:
zhiyu 2024-02-08 00:23:47 +08:00
parent 9e44ced5f5
commit 2f794fd80b
5 changed files with 246 additions and 134 deletions

View File

@ -6,35 +6,54 @@ import { Buffer } from 'node:buffer';
import axios from "axios"; import axios from "axios";
import _ from "lodash"; import _ from "lodash";
import tunnel from "tunnel"; import tunnel from "tunnel";
import HttpProxyAgent, { HttpsProxyAgent } from "https-proxy-agent"; import HttpProxyAgent from "https-proxy-agent";
import { mkdirIfNotExists, checkAndRemoveFile, deleteFolderRecursive } from "../utils/file.js"; import { checkAndRemoveFile, deleteFolderRecursive, mkdirIfNotExists } from "../utils/file.js";
import { downloadBFile, getAudioUrl, getDownloadUrl, mergeFileToMp4 } from "../utils/bilibili.js"; import {
import { parseUrl, parseM3u8, downloadM3u8Videos, mergeAcFileToMp4 } from "../utils/acfun.js"; downloadBFile,
getBiliAudio,
getDownloadUrl,
getDynamic,
getVideoInfo,
m4sToMp3,
mergeFileToMp4
} from "../utils/bilibili.js";
import { downloadM3u8Videos, mergeAcFileToMp4, parseM3u8, parseUrl } from "../utils/acfun.js";
import { import {
transMap,
douyinTypeMap,
DIVIDING_LINE, DIVIDING_LINE,
XHS_NO_WATERMARK_HEADER, douyinTypeMap,
REDIS_YUNZAI_ISOVERSEA, REDIS_YUNZAI_ISOVERSEA,
transMap,
TWITTER_BEARER_TOKEN, TWITTER_BEARER_TOKEN,
XHS_NO_WATERMARK_HEADER,
} from "../constants/constant.js"; } from "../constants/constant.js";
import { containsChinese, formatBiliInfo, getIdVideo, secondsToTime } from "../utils/common.js"; import { containsChinese, formatBiliInfo, getIdVideo, secondsToTime } from "../utils/common.js";
import config from "../model/index.js"; import config from "../model/index.js";
import Translate from "../utils/trans-strategy.js"; import Translate from "../utils/trans-strategy.js";
import * as xBogus from "../utils/x-bogus.cjs"; import * as xBogus from "../utils/x-bogus.cjs";
import { getVideoInfo, getDynamic } from "../utils/biliInfo.js"; import { getBodianAudio, getBodianMusicInfo, getBodianMv } from "../utils/bodian.js";
import { getBodianAudio, getBodianMv, getBodianMusicInfo } from "../utils/bodian.js";
import { av2BV } from "../utils/bilibili-bv-av-convert.js"; import { av2BV } from "../utils/bilibili-bv-av-convert.js";
import querystring from "querystring"; import querystring from "querystring";
import TokenBucket from "../utils/token-bucket.js"; import TokenBucket from "../utils/token-bucket.js";
import { getWbi } from "../utils/biliWbi.js"; import { getWbi } from "../utils/biliWbi.js";
import { BILI_SUMMARY, DY_INFO, TIKTOK_INFO, TWITTER_TWEET_INFO, XHS_REQ_LINK } from "../constants/tools.js"; import { BILI_SUMMARY, DY_INFO, TIKTOK_INFO, TWITTER_TWEET_INFO, XHS_REQ_LINK, XHS_VIDEO } from "../constants/tools.js";
import { XHS_VIDEO } from "../constants/tools.js";
import child_process from 'node:child_process' import child_process from 'node:child_process'
import { getAudio, getVideo } from "../utils/y2b.js"; import { getAudio, getVideo } from "../utils/y2b.js";
import { processTikTokUrl } from "../utils/tiktok.js"; import { processTikTokUrl } from "../utils/tiktok.js";
export class tools extends plugin { export class tools extends plugin {
/**
* 构造安全的命令
* @type {{existsPromptKey: string, existsTransKey: string}}
*/
static Constants = {
existsTransKey: Object.keys(transMap).join("|"),
};
/**
* 构造令牌桶防止解析致使服务器宕机默认限制5s调用一次
* @type {TokenBucket}
*/
static #tokenBucket = new TokenBucket(1, 1, 5);
constructor() { constructor() {
super({ super({
name: "R插件工具和学习类", name: "R插件工具和学习类",
@ -197,9 +216,7 @@ export class tools extends plugin {
"http", "http",
"https", "https",
); );
const path = `${ this.defaultPath }${ const path = `${ this.getCurDownloadPath(e) }/temp.mp4`;
this.e.group_id || this.e.user_id
}/temp.mp4`;
await this.downloadVideo(resUrl).then(() => { await this.downloadVideo(resUrl).then(() => {
e.reply(segment.video(path)); e.reply(segment.video(path));
}); });
@ -257,7 +274,7 @@ export class tools extends plugin {
this.downloadVideo(data.video.play_addr.url_list[0], !isOversea).then(video => { this.downloadVideo(data.video.play_addr.url_list[0], !isOversea).then(video => {
e.reply( e.reply(
segment.video( segment.video(
`${ this.defaultPath }${ this.e.group_id || this.e.user_id }/temp.mp4`, `${ this.getCurDownloadPath(e) }/temp.mp4`,
), ),
); );
}); });
@ -296,7 +313,7 @@ export class tools extends plugin {
} }
// 只提取音乐处理 // 只提取音乐处理
if (e.msg !== undefined && e.msg.includes("bili音乐")) { if (e.msg !== undefined && e.msg.includes("bili音乐")) {
await this.biliMusic(url, e); await this.biliMusic(e, url);
return true; return true;
} }
// 动态处理 // 动态处理
@ -346,7 +363,7 @@ export class tools extends plugin {
} }
// 创建文件,如果不存在 // 创建文件,如果不存在
const path = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }/`; const path = `${ this.getCurDownloadPath(e) }/`;
await mkdirIfNotExists(path); await mkdirIfNotExists(path);
// 下载文件 // 下载文件
getDownloadUrl(url) getDownloadUrl(url)
@ -367,9 +384,13 @@ export class tools extends plugin {
return true; return true;
} }
async biliMusic(url, e) { // 下载哔哩哔哩音乐
const { audioUrl } = await getAudioUrl(url); async biliMusic(e, url) {
e.reply(segment.record(audioUrl)) const videoId = /video\/[^\?\/ ]+/.exec(url)[0].split("/")[1];
getBiliAudio(videoId, "").then(async audioUrl => {
const path = this.getCurDownloadPath(e);
e.reply(segment.record(await m4sToMp3(audioUrl, path)));
})
return true return true
} }
@ -399,6 +420,8 @@ export class tools extends plugin {
return url; return url;
} }
// 小蓝鸟解析:停止更新
/** /**
* 哔哩哔哩总结 * 哔哩哔哩总结
* @author zhiyu1998 * @author zhiyu1998
@ -492,7 +515,6 @@ export class tools extends plugin {
return true; return true;
} }
// 小蓝鸟解析:停止更新
// 例子https://twitter.com/chonkyanimalx/status/1595834168000204800 // 例子https://twitter.com/chonkyanimalx/status/1595834168000204800
async twitter(e) { async twitter(e) {
// 配置参数及解析 // 配置参数及解析
@ -512,14 +534,14 @@ export class tools extends plugin {
await fetch(TWITTER_TWEET_INFO.replace("{}", id), { await fetch(TWITTER_TWEET_INFO.replace("{}", id), {
headers: { headers: {
"User-Agent": "v2TweetLookupJS", "User-Agent": "v2TweetLookupJS",
"authorization": `Bearer ${Buffer.from(TWITTER_BEARER_TOKEN, "base64").toString()}` "authorization": `Bearer ${ Buffer.from(TWITTER_BEARER_TOKEN, "base64").toString() }`
}, },
...params, ...params,
agent: !isOversea ? '' : new HttpProxyAgent(this.myProxy), agent: !isOversea ? '' : new HttpProxyAgent(this.myProxy),
}).then(async resp => { }).then(async resp => {
logger.info(resp) logger.info(resp)
e.reply(`识别:小蓝鸟学习版,${ resp.data.text }`); e.reply(`识别:小蓝鸟学习版,${ resp.data.text }`);
const downloadPath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`; const downloadPath = `${ this.getCurDownloadPath(e) }`;
// 创建文件夹(如果没有过这个群) // 创建文件夹(如果没有过这个群)
if (!fs.existsSync(downloadPath)) { if (!fs.existsSync(downloadPath)) {
mkdirsSync(downloadPath); mkdirsSync(downloadPath);
@ -569,7 +591,7 @@ export class tools extends plugin {
// acfun解析 // acfun解析
async acfun(e) { async acfun(e) {
const path = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }/temp/`; const path = `${ this.getCurDownloadPath(e) }/temp/`;
await mkdirIfNotExists(path); await mkdirIfNotExists(path);
let inputMsg = e.msg; let inputMsg = e.msg;
@ -619,9 +641,9 @@ export class tools extends plugin {
} else { } else {
id = /explore\/(\w+)/.exec(msgUrl)?.[1] || /discovery\/item\/(\w+)/.exec(msgUrl)?.[1]; id = /explore\/(\w+)/.exec(msgUrl)?.[1] || /discovery\/item\/(\w+)/.exec(msgUrl)?.[1];
} }
const downloadPath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`; const downloadPath = `${ this.getCurDownloadPath(e) }`;
// 获取信息 // 获取信息
fetch(`${XHS_REQ_LINK}${ id }`, { fetch(`${ XHS_REQ_LINK }${ id }`, {
headers: XHS_NO_WATERMARK_HEADER, headers: XHS_NO_WATERMARK_HEADER,
}).then(async resp => { }).then(async resp => {
const xhsHtml = await resp.text(); const xhsHtml = await resp.text();
@ -641,7 +663,7 @@ export class tools extends plugin {
this.downloadVideo(xhsVideoUrl).then(path => { this.downloadVideo(xhsVideoUrl).then(path => {
if (path === undefined) { if (path === undefined) {
// 创建文件,如果不存在 // 创建文件,如果不存在
path = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }/`; path = `${ this.getCurDownloadPath(e) }/`;
} }
e.reply(segment.video(path + "/temp.mp4")); e.reply(segment.video(path + "/temp.mp4"));
}); });
@ -730,7 +752,7 @@ export class tools extends plugin {
const API = `https://imginn.com/${ suffix }`; const API = `https://imginn.com/${ suffix }`;
// logger.info(API); // logger.info(API);
let imgPromise = []; let imgPromise = [];
const downloadPath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`; const downloadPath = `${ this.getCurDownloadPath(e) }`;
// 判断是否是海外服务器 // 判断是否是海外服务器
const isOversea = await this.isOverseasServer(); const isOversea = await this.isOverseasServer();
// 简单封装图片下载 // 简单封装图片下载
@ -813,7 +835,7 @@ export class tools extends plugin {
segment.image(albumPic120), segment.image(albumPic120),
]); ]);
if (e.msg.includes("musicId")) { if (e.msg.includes("musicId")) {
const path = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`; const path = `${ this.getCurDownloadPath(e) }`;
await getBodianAudio(id, path).then(_ => { await getBodianAudio(id, path).then(_ => {
Bot.acquireGfs(e.group_id).upload( Bot.acquireGfs(e.group_id).upload(
fs.readFileSync(path + "/temp.mp3"), fs.readFileSync(path + "/temp.mp3"),
@ -968,12 +990,12 @@ export class tools extends plugin {
const format = `${ bestVideo.id }x${ bestAudio.id }` const format = `${ bestVideo.id }x${ bestAudio.id }`
// 下载地址格式化 // 下载地址格式化
const path = `${ v }${ p ? `/p${ p }` : '' }`; const path = `${ v }${ p ? `/p${ p }` : '' }`;
const fullpath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }/${ path }`; const fullpath = `${ this.getCurDownloadPath(e) }/${ path }`;
// 创建下载文件夹 // 创建下载文件夹
await mkdirIfNotExists(fullpath); await mkdirIfNotExists(fullpath);
// yt-dlp下载 // yt-dlp下载
let cmd = //`cd '${__dirname}' && (cd tmp > /dev/null || (mkdir tmp && cd tmp)) &&` + let cmd = //`cd '${__dirname}' && (cd tmp > /dev/null || (mkdir tmp && cd tmp)) &&` +
`yt-dlp ${ this.y2bCk !== undefined ? `--cookies ${ this.y2bCk }` : '' } ${url} -f ${ format.replace('x', '+') } ` + `yt-dlp ${ this.y2bCk !== undefined ? `--cookies ${ this.y2bCk }` : '' } ${ url } -f ${ format.replace('x', '+') } ` +
`-o '${ fullpath }/${ v }.%(ext)s' ${ isProxy ? `--proxy ${ this.proxyAddr }:${ this.proxyPort }` : '' } -k --write-info-json`; `-o '${ fullpath }/${ v }.%(ext)s' ${ isProxy ? `--proxy ${ this.proxyAddr }:${ this.proxyPort }` : '' } -k --write-info-json`;
logger.mark(cmd) logger.mark(cmd)
try { try {
@ -1099,6 +1121,15 @@ export class tools extends plugin {
} }
} }
/**
* 获取当前发送人/群的下载路径
* @param e Yunzai 机器人事件
* @returns {string}
*/
getCurDownloadPath(e) {
return `${ this.defaultPath }${ e.group_id || e.user_id }`
}
/** /**
* 提取视频下载位置 * 提取视频下载位置
* @returns {{groupPath: string, target: string}} * @returns {{groupPath: string, target: string}}
@ -1208,18 +1239,4 @@ export class tools extends plugin {
logger.warn(`解析被限制使用`); logger.warn(`解析被限制使用`);
} }
} }
/**
* 构造安全的命令
* @type {{existsPromptKey: string, existsTransKey: string}}
*/
static Constants = {
existsTransKey: Object.keys(transMap).join("|"),
};
/**
* 构造令牌桶防止解析致使服务器宕机默认限制5s调用一次
* @type {TokenBucket}
*/
static #tokenBucket = new TokenBucket(1, 1, 5);
} }

View File

@ -1,5 +1,5 @@
- { - {
version: 1.3.2, version: 1.3.3,
data: data:
[ [
新增<span class="cmd">油管解析</span>功能, 新增<span class="cmd">油管解析</span>功能,

View File

@ -5,6 +5,27 @@
*/ */
export const BILI_SUMMARY = "https://api.bilibili.com/x/web-interface/view/conclusion/get" export const BILI_SUMMARY = "https://api.bilibili.com/x/web-interface/view/conclusion/get"
/**
* 视频流URL
* https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/video/videostream_url.md
* @type {string}
*/
export const BILI_PLAY_STREAM = "https://api.bilibili.com/x/player/playurl?cid={cid}&bvid={bvid}&qn=64&fnval=16"
/**
* 动态信息
* https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/dynamic/content.md
* @type {string}
*/
export const BILI_DYNAMIC = "https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail?dynamic_id={}"
/**
* BVID -> CID
* https://github.com/SocialSisterYi/bilibili-API-collect/blob/33bde6f6afcac2ff8c6f7069f08ce84065a6cff6/docs/video/info.md?plain=1#L4352
* @type {string}
*/
export const BILI_BVID_TO_CID = "https://api.bilibili.com/x/player/pagelist?bvid={bvid}&jsonp=jsonp"
/** /**
* 视频基本信息API * 视频基本信息API
* https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/video/info.md * https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/video/info.md

View File

@ -1,57 +0,0 @@
import fetch from "node-fetch";
import axios from "axios";
import { BILI_VIDEO_INFO } from "../constants/tools.js";
async function getVideoInfo(url) {
// const baseVideoInfo = "http://api.bilibili.com/x/web-interface/view";
const videoId = /video\/[^\?\/ ]+/.exec(url)[0].split("/")[1];
// 获取视频信息,然后发送
return fetch(`${BILI_VIDEO_INFO}?bvid=${videoId}`)
.then(async resp => {
const respJson = await resp.json();
const respData = respJson.data;
return {
title: respData.title,
pic: respData.pic,
desc: respData.desc,
duration: respData.duration,
dynamic: respJson.data.dynamic,
stat: respData.stat,
bvid: respData.bvid,
aid: respData.aid,
cid: respData.pages?.[0].cid,
owner: respData.owner,
pages: respData?.pages,
};
});
}
async function getDynamic(dynamicId) {
const dynamicApi = `https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail?dynamic_id=${dynamicId}`
return axios.get(dynamicApi, {
headers: {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36',
'referer': 'https://www.bilibili.com',
}
}).then(resp => {
const dynamicData = resp.data.data.card
const card = JSON.parse(dynamicData.card)
const dynamicOrigin = card.item
const dynamicDesc = dynamicOrigin.description
const pictures = dynamicOrigin.pictures
let dynamicSrc = []
for (let pic of pictures) {
const img_src = pic.img_src
dynamicSrc.push(img_src)
}
// console.log(dynamic_src)
return {
dynamicSrc,
dynamicDesc
}
})
}
export { getVideoInfo, getDynamic };

View File

@ -2,8 +2,17 @@ import fs from "node:fs";
import axios from 'axios' import axios from 'axios'
import child_process from 'node:child_process' import child_process from 'node:child_process'
import util from "util"; import util from "util";
import { BILI_BVID_TO_CID, BILI_DYNAMIC, BILI_PLAY_STREAM, BILI_VIDEO_INFO } from "../constants/tools.js";
import { mkdirIfNotExists } from "./file.js";
async function downloadBFile (url, fullFileName, progressCallback) { /**
* 下载单个bili文件
* @param url
* @param fullFileName
* @param progressCallback
* @returns {Promise<any>}
*/
export async function downloadBFile(url, fullFileName, progressCallback) {
return axios return axios
.get(url, { .get(url, {
responseType: 'stream', responseType: 'stream',
@ -35,7 +44,12 @@ async function downloadBFile (url, fullFileName, progressCallback) {
}); });
} }
async function getDownloadUrl (url) { /**
* 获取下载链接
* @param url
* @returns {Promise<any>}
*/
export async function getDownloadUrl(url) {
return axios return axios
.get(url, { .get(url, {
headers: { headers: {
@ -65,34 +79,15 @@ async function getDownloadUrl (url) {
}); });
} }
async function getAudioUrl (url) { /**
return axios * 合并视频和音频
.get(url, { * @param vFullFileName
headers: { * @param aFullFileName
'User-Agent': * @param outputFileName
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36', * @param shouldDelete
referer: 'https://www.bilibili.com', * @returns {Promise<{outputFileName}>}
}, */
}) export async function mergeFileToMp4(vFullFileName, aFullFileName, outputFileName, shouldDelete = true) {
.then(({ data }) => {
const info = JSON.parse(
data.match(/<script>window\.__playinfo__=({.*})<\/script><script>/)?.[1],
);
// 获取音频
const audioUrl =
info?.data?.dash?.audio?.[0]?.baseUrl ?? info?.data?.dash?.audio?.[0]?.backupUrl?.[0];
const title = data.match(/title="(.*?)"/)?.[1]?.replaceAll?.(/\\|\/|:|\*|\?|"|<|>|\|/g, '');
if (audioUrl) {
return { audioUrl, title };
}
return Promise.reject('获取下载地址失败');
});
}
async function mergeFileToMp4 (vFullFileName, aFullFileName, outputFileName, shouldDelete = true) {
// 判断当前环境 // 判断当前环境
let env; let env;
if (process.platform === "win32") { if (process.platform === "win32") {
@ -122,4 +117,140 @@ async function mergeFileToMp4 (vFullFileName, aFullFileName, outputFileName, sho
} }
} }
export { downloadBFile, getDownloadUrl, getAudioUrl, mergeFileToMp4 } /**
* 下载m4s文件通过ffmpeg转换成mp3
* @param m4sUrl
* @returns {Promise<void>}
*/
export async function m4sToMp3(m4sUrl, path) {
return axios
.get(m4sUrl, {
responseType: 'stream',
headers: {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36',
referer: 'https://www.bilibili.com',
},
}).then(async res => {
// 如果没有目录就创建一个
await mkdirIfNotExists(path)
// 补充保存文件名
path += "/temp.m4s";
if (fs.existsSync(path)) {
fs.unlinkSync(path);
}
// 开始下载
const fileStream = fs.createWriteStream(path);
res.data.pipe(fileStream);
// 下载完成
return new Promise((resolve, reject) => {
fileStream.on("finish", () => {
fileStream.close(() => {
const transformCmd = `ffmpeg -i ${ path } ${ path.replace(".m4s", ".mp3") } -y -loglevel quiet`;
child_process.execSync(transformCmd)
logger.mark("bili: mp3下载完成")
resolve(path);
});
});
fileStream.on("error", err => {
fs.unlink(path, () => {
reject(err);
});
});
});
});
}
/**
* 哔哩哔哩音乐下载
* @param bvid BVID
* @param cid 选项CID
* @returns {Promise<any>}
*/
export async function getBiliAudio(bvid, cid) {
// 转换cid
if (!cid)
cid = await fetchCID(bvid).catch((err) => console.log(err))
// 返回一个fetch的promise
return (new Promise((resolve, reject) => {
fetch(BILI_PLAY_STREAM.replace("{bvid}", bvid).replace("{cid}", cid))
.then(res => res.json())
.then(json => resolve(json.data.dash.audio[0].baseUrl));
}))
}
/**
* bvid转换成cid
* @param bvid
* @returns {Promise<*>}
*/
export const fetchCID = async (bvid) => {
//console.log('Data.js Calling fetchCID:' + URL_BVID_TO_CID.replace("{bvid}", bvid))
const res = await fetch(BILI_BVID_TO_CID.replace("{bvid}", bvid))
const json = await res.json()
const cid = json.data[0].cid
return cid
}
/**
* 获取视频信息
* @param url
* @returns {Promise<{duration: *, owner: *, bvid: *, stat: *, pages: *, dynamic: *, pic: *, title: *, aid: *, desc: *, cid: *}>}
*/
export async function getVideoInfo(url) {
// const baseVideoInfo = "http://api.bilibili.com/x/web-interface/view";
const videoId = /video\/[^\?\/ ]+/.exec(url)[0].split("/")[1];
// 获取视频信息,然后发送
return fetch(`${ BILI_VIDEO_INFO }?bvid=${ videoId }`)
.then(async resp => {
const respJson = await resp.json();
const respData = respJson.data;
return {
title: respData.title,
pic: respData.pic,
desc: respData.desc,
duration: respData.duration,
dynamic: respJson.data.dynamic,
stat: respData.stat,
bvid: respData.bvid,
aid: respData.aid,
cid: respData.pages?.[0].cid,
owner: respData.owner,
pages: respData?.pages,
};
});
}
/**
* 获取动态
* @param dynamicId
* @returns {Promise<any>}
*/
export async function getDynamic(dynamicId) {
const dynamicApi = BILI_DYNAMIC.replace("{}", dynamicId);
return axios.get(dynamicApi, {
headers: {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36',
'referer': 'https://www.bilibili.com',
}
}).then(resp => {
const dynamicData = resp.data.data.card
const card = JSON.parse(dynamicData.card)
const dynamicOrigin = card.item
const dynamicDesc = dynamicOrigin.description
const pictures = dynamicOrigin.pictures
let dynamicSrc = []
for (let pic of pictures) {
const img_src = pic.img_src
dynamicSrc.push(img_src)
}
// console.log(dynamic_src)
return {
dynamicSrc,
dynamicDesc
}
})
}