feat: 增加哔哩哔哩解析自适应时间解析算法

This commit is contained in:
zhiyu1998 2023-03-26 21:12:00 +08:00
parent 4ab03fef25
commit 8aac44c724
4 changed files with 38 additions and 38 deletions

View File

@ -10,7 +10,7 @@ import HttpProxyAgent from "https-proxy-agent";
import { mkdirsSync } from "../utils/file.js";
import { downloadBFile, getDownloadUrl, mergeFileToMp4, getDynamic } from "../utils/bilibili.js";
import { parseUrl, parseM3u8, downloadM3u8Videos, mergeAcFileToMp4 } from "../utils/acfun.js";
import { transMap, douyinTypeMap, XHS_CK, TEN_THOUSAND } from "../utils/constant.js";
import { transMap, douyinTypeMap, XHS_CK, TEN_THOUSAND, BILI_DURATION } from "../utils/constant.js";
import { getIdVideo, generateRandomStr } from "../utils/common.js";
import config from "../model/index.js";
import Translate from "../utils/trans-strategy.js";
@ -332,7 +332,7 @@ export class tools extends plugin {
// 视频信息获取例子http://api.bilibili.com/x/web-interface/view?bvid=BV1hY411m7cB
// 请求视频信息
const videoInfo = await getVideoInfo(url);
const { title, desc, dynamic, stat, aid, cid } = videoInfo;
const { title, desc, duration, dynamic, stat, aid, cid } = videoInfo;
// 视频信息
let { view, danmaku, reply, favorite, coin, share, like } = stat;
// 数据处理
@ -341,7 +341,7 @@ export class tools extends plugin {
};
// 格式化数据
const combineContent =
`点赞:${dataProcessing(like)} | 硬币:${dataProcessing(coin)} | 收藏:${dataProcessing(
`\n点赞:${dataProcessing(like)} | 硬币:${dataProcessing(coin)} | 收藏:${dataProcessing(
favorite,
)} | 分享${dataProcessing(share)}\n` +
`总播放量:${dataProcessing(view)} | 弹幕数量:${dataProcessing(
@ -350,11 +350,11 @@ export class tools extends plugin {
`简介:${desc}`;
e.reply([`识别:哔哩哔哩:${title}`, combineContent]);
await getDownloadUrl(url)
await getDownloadUrl(url, duration > BILI_DURATION)
.then(data => {
this.downBili(`${path}temp`, data.videoUrl, data.audioUrl)
.then(data => {
e.reply(segment.video(`${path}temp.mp4`));
.then(_ => {
e.reply(segment.video(`${path}temp.mp4`));
})
.catch(err => {
logger.error(err);
@ -966,8 +966,7 @@ export class tools extends plugin {
title + "-video.m4s",
_.throttle(
value =>
logger.mark("download-progress", {
type: "video",
logger.mark("视频下载进度", {
data: value,
}),
1000,
@ -978,15 +977,14 @@ export class tools extends plugin {
title + "-audio.m4s",
_.throttle(
value =>
logger.mark("download-progress", {
type: "audio",
logger.mark("音频下载进度", {
data: value,
}),
1000,
),
),
]).then(data => {
return mergeFileToMp4(data[0].fullFileName, data[1].fullFileName, title + ".mp4");
return mergeFileToMp4(data[0].fullFileName, data[1].fullFileName, `${title}.mp4`);
});
}

View File

@ -14,6 +14,7 @@ async function getVideoInfo(url) {
return {
title: respData.title,
desc: respData.desc,
duration: respData.duration,
dynamic: respJson.data.dynamic,
stat: respData.stat,
aid: respData.aid,

View File

@ -1,8 +1,9 @@
import fs from "node:fs";
import axios from 'axios'
import child_process from 'node:child_process'
import util from "util";
function downloadBFile (url, fullFileName, progressCallback) {
async function downloadBFile (url, fullFileName, progressCallback) {
return axios
.get(url, {
responseType: 'stream',
@ -34,7 +35,7 @@ function downloadBFile (url, fullFileName, progressCallback) {
});
}
function getDownloadUrl (url) {
async function getDownloadUrl (url, isLargeVideo=false) {
return axios
.get(url, {
headers: {
@ -47,12 +48,16 @@ function getDownloadUrl (url) {
const info = JSON.parse(
data.match(/<script>window\.__playinfo__=({.*})<\/script><script>/)?.[1],
);
// 如果是大视频直接最低分辨率
const level = isLargeVideo ? (Math.min(info?.data?.dash?.video.length - 1, info?.data?.dash?.audio.length - 1)) : 0;
const videoUrl =
info?.data?.dash?.video?.[0]?.baseUrl ?? info?.data?.dash?.video?.[0]?.backupUrl?.[0];
info?.data?.dash?.video?.[level]?.baseUrl ?? info?.data?.dash?.video?.[level]?.backupUrl?.[0];
const audioUrl =
info?.data?.dash?.audio?.[0]?.baseUrl ?? info?.data?.dash?.audio?.[0]?.backupUrl?.[0];
info?.data?.dash?.audio?.[level]?.baseUrl ?? info?.data?.dash?.audio?.[level]?.backupUrl?.[0];
const title = data.match(/title="(.*?)"/)?.[1]?.replaceAll?.(/\\|\/|:|\*|\?|"|<|>|\|/g, '');
if (videoUrl && audioUrl) {
return { videoUrl, audioUrl, title };
}
@ -61,9 +66,7 @@ function getDownloadUrl (url) {
});
}
function mergeFileToMp4 (vFullFileName, aFullFileName, outputFileName, shouldDelete = true) {
let cmd = 'ffmpeg';
async function mergeFileToMp4 (vFullFileName, aFullFileName, outputFileName, shouldDelete = true) {
// 判断当前环境
let env;
if (process.platform === "win32") {
@ -74,30 +77,26 @@ function mergeFileToMp4 (vFullFileName, aFullFileName, outputFileName, shouldDel
PATH: '/usr/local/bin:' + child_process.execSync('echo $PATH').toString(),
};
} else {
console.log("暂时不支持当前操作系统!")
logger.error("暂时不支持当前操作系统!")
}
const execFile = util.promisify(child_process.execFile);
try {
const cmd = 'ffmpeg';
const args = ['-y', '-i', vFullFileName, '-i', aFullFileName, '-c', 'copy', outputFileName];
await execFile(cmd, args, { env });
return new Promise((resolve, reject) => {
child_process.exec(
`${ cmd } -y -i "${ vFullFileName }" -i "${ aFullFileName }" -c copy "${ outputFileName }"`,
{ env },
err => {
if (shouldDelete) {
fs.unlink(vFullFileName, f => f);
fs.unlink(aFullFileName, f => f);
}
if (shouldDelete) {
await fs.promises.unlink(vFullFileName);
await fs.promises.unlink(aFullFileName);
}
if (err) {
reject(err);
}
resolve({ outputFileName });
},
);
});
return { outputFileName };
} catch (err) {
throw err;
}
}
function getDynamic(dynamicId) {
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: {
@ -125,4 +124,4 @@ function getDynamic(dynamicId) {
})
}
export { downloadBFile, getDownloadUrl, mergeFileToMp4, getDynamic }
export { downloadBFile, getDownloadUrl, mergeFileToMp4, getDynamic }

View File

@ -39,3 +39,5 @@ export const TEN_THOUSAND = 10000;
export const CAT_LIMIT = 10;
export const XHS_CK = 'eGhzVHJhY2tlcklkPTczODhhYmY2LTI0MDgtNGU5YS04MTUyLTE0MGVhOGY1MTQ5ZjsgeGhzVHJhY2tlcklkLnNpZz1UcGUxTkNaX3B3UkFYdG01SVJmVEs0SWUxM0xBaGZuNmNZU2N4Vi1JYWxFOyBhMT0xODY2ZDkwMDM0NmI2NmppcjMzcGpxZ2MwM3JvcG1mczAydXMxdWNoeDEwMDAwMTM1MDUzOyB3ZWJJZD1mMTNkOGJkYjhiZGM3ZGE0MzY0NjA4NWJjYzQ1MDQ1YTsgZ2lkPXlZS0tmajg4SzA4MnlZS0tmajg4cUo3UzRLREtLVjNGcXFVVjd4Q0FrUzhxRk15OGxVNmlNeTg4OHlxMjgycThmMlk0UzAySjsgZ2lkLnNpZ249YlpzcFFzSUxEUmN5akZLQmN2L1FMWVhkU3lvPTsgd2ViX3Nlc3Npb249MDMwMDM3YTRjMDQyYjE1ZTVjMTg4OTUwOGIyNDRhZDExM2UwNTM7IHhoc1RyYWNrZXI9dXJsPW5vdGVEZXRhaWwmeGhzc2hhcmU9V2VpeGluU2Vzc2lvbjsgeGhzVHJhY2tlci5zaWc9YzdmcDVRclk2SGNvVERhUzluX2N3Z2RCRHh2MFZmWnpSU1NTcnlzbG5lQTsgZXh0cmFfZXhwX2lkcz1oNV8yMzAyMDExX29yaWdpbixoNV8xMjA4X2NsdCxoNV8xMTMwX2NsdCxpb3Nfd3hfbGF1bmNoX29wZW5fYXBwX2V4cCxoNV92aWRlb191aV9leHAzLHd4X2xhdW5jaF9vcGVuX2FwcF9kdXJhdGlvbl9vcmlnaW4scXVlc19jbHQyOyBleHRyYV9leHBfaWRzLnNpZz1DVUdrR3NYT3lBZmpVSXkyVGo3SjN4YmRNakFfSnpoR1JkYWd6cVlkbmJnOyB3ZWJCdWlsZD0xLjEuMjE7IHhzZWNhcHBpZD14aHMtcGMtd2ViOyB3ZWJzZWN0aWdhPTU5ZDNlZjFlNjBjNGFhMzdhN2RmM2MyMzQ2N2JkNDZkN2YxZGEwYjE5MThjZjMzNWVlN2YyZTllNTJhYzA0Y2Y7IHNlY19wb2lzb25faWQ9MTI0OTE1NWQtOWU5ZS00MzkyLTg2NTgtNTA1Yzc0YTUzMTM1'
export const BILI_DURATION = 400;