feat: 增加哔哩哔哩解析

This commit is contained in:
zhiyu1998 2022-11-25 22:27:33 +08:00
parent f48dcc82da
commit 19e1ad13a8
3 changed files with 189 additions and 27 deletions

View File

@ -5,7 +5,9 @@ import { segment } from "oicq";
// 其他库
import md5 from "md5";
import axios from "axios";
import path from 'path'
import _ from 'lodash'
import { mkdirsSync } from '../utils/file.js'
import { downloadBFile, getDownloadUrl, mergeFileToMp4 } from '../utils/bilibili.js'
export class tools extends plugin {
constructor () {
@ -27,6 +29,10 @@ export class tools extends plugin {
reg: "(.*)(www.tiktok.com)",
fnc: "tiktok",
},
{
reg: "(.*)(bilibili.com)",
fnc: "bili",
},
],
});
this.defaultPath = `./data/rcmp4/`
@ -90,6 +96,34 @@ export class tools extends plugin {
return true
}
// bilibi解析
async bili (e) {
const urlRex = /(http:|https:)\/\/www.bilibili.com\/[A-Za-z\d._?%&+\-=\/#]*/g;
const url = urlRex.exec(e.msg.trim())[0]
const path = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }/temp`
// 待优化
if (fs.existsSync(`${ path }.mp4`)) {
console.log("视频已存在");
fs.unlinkSync(`${ path }.mp4`);
}
e.reply('识别:哔哩哔哩,解析中...')
await getDownloadUrl(url)
.then(data => {
this.downBili(path, data.videoUrl, data.audioUrl)
.then(data => {
e.reply(segment.video(`${ path }.mp4`))
})
.catch(data => {
e.reply('解析失败,请重试一下')
});
})
.catch(err => {
e.reply('解析失败,请重试一下')
});
return true
}
// 请求参数
async douyinRequest (url) {
const params = {
@ -112,10 +146,10 @@ export class tools extends plugin {
});
}
// 根URL据下载视频 / 音频
// 工具:根URL据下载视频 / 音频
async downloadVideo (url) {
if (!fs.existsSync(this.defaultPath)) {
this.mkdirsSync(this.defaultPath);
mkdirsSync(this.defaultPath);
}
const target = this.defaultPath + `${ this.e.group_id || this.e.user_id }/temp.mp4`
// 待优化
@ -140,29 +174,36 @@ export class tools extends plugin {
});
}
// 同步递归创建文件夹
mkdirsSync (dirname) {
if (fs.existsSync(dirname)) {
return true;
} else {
if (this.mkdirsSync(path.dirname(dirname))) {
fs.mkdirSync(dirname);
return true;
}
}
}
// 递归创建目录 异步方法
mkdirs (dirname, callback) {
fs.exists(dirname, function (exists) {
if (exists) {
callback();
} else {
// console.log(path.dirname(dirname));
this.mkdirs(path.dirname(dirname), function () {
fs.mkdir(dirname, callback);
});
}
});
// 工具:下载哔哩哔哩
async downBili (title, videoUrl, audioUrl) {
return Promise.all([
downloadBFile(
videoUrl,
title + '-video.m4s',
_.throttle(
value =>
console.log('download-progress', {
type: 'video',
data: value,
}),
1000,
),
),
downloadBFile(
audioUrl,
title + '-audio.m4s',
_.throttle(
value =>
console.log('download-progress', {
type: 'audio',
data: value,
}),
1000,
),
),
])
.then(data => {
return mergeFileToMp4(data[0].fullFileName, data[1].fullFileName, title + '.mp4');
})
}
}

91
utils/bilibili.js Normal file
View File

@ -0,0 +1,91 @@
import fs from "node:fs";
import axios from 'axios'
import child_process from 'node:child_process'
function downloadBFile (url, fullFileName, progressCallback) {
return axios
.get(url, {
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(({ data, headers }) => {
let currentLen = 0;
const totalLen = headers['content-length'];
return new Promise((resolve, reject) => {
data.on('data', ({ length }) => {
currentLen += length;
progressCallback?.(currentLen / totalLen);
});
data.pipe(
fs.createWriteStream(fullFileName).on('finish', () => {
resolve({
fullFileName,
totalLen,
});
}),
);
});
});
}
function getDownloadUrl (url) {
return axios
.get(url, {
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(({ data }) => {
const info = JSON.parse(
data.match(/<script>window\.__playinfo__=({.*})<\/script><script>/)?.[1],
);
const videoUrl =
info?.data?.dash?.video?.[0]?.baseUrl ?? info?.data?.dash?.video?.[0]?.backupUrl?.[0];
const audioUrl =
info?.data?.dash?.audio?.[0]?.baseUrl ?? info?.data?.dash?.audio?.[0]?.backupUrl?.[0];
const title = data.match(/title="(.*?)"/)?.[1]?.replaceAll?.(/\\|\/|:|\*|\?|"|<|>|\|/g, '');
if (videoUrl && audioUrl) {
return { videoUrl, audioUrl, title };
}
return Promise.reject('获取下载地址失败');
});
}
function mergeFileToMp4 (vFullFileName, aFullFileName, outputFileName, shouldDelete = true) {
let cmd = 'ffmpeg';
const env = {
...process.env,
PATH: '/usr/local/bin:' + child_process.execSync('echo $PATH').toString(),
};
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 (err) {
reject(err);
}
resolve({ outputFileName });
},
);
});
}
export { downloadBFile, getDownloadUrl, mergeFileToMp4 }

30
utils/file.js Normal file
View File

@ -0,0 +1,30 @@
import fs from "node:fs";
import path from "path";
// 同步递归创建文件夹
function mkdirsSync (dirname) {
if (fs.existsSync(dirname)) {
return true;
} else {
if (this.mkdirsSync(path.dirname(dirname))) {
fs.mkdirSync(dirname);
return true;
}
}
}
// 递归创建目录 异步方法
function mkdirs (dirname, callback) {
fs.exists(dirname, function (exists) {
if (exists) {
callback();
} else {
// console.log(path.dirname(dirname));
this.mkdirs(path.dirname(dirname), function () {
fs.mkdir(dirname, callback);
});
}
});
}
export { mkdirs, mkdirsSync }