From 2f794fd80b3ff27a9c5342ba26a67d216cb28d52 Mon Sep 17 00:00:00 2001
From: zhiyu <542716863@qq.com>
Date: Thu, 8 Feb 2024 00:23:47 +0800
Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9E=20fix:=20V1.3.3=20=E4=BF=AE?=
=?UTF-8?q?=E5=A4=8Dbili=E9=9F=B3=E4=B9=90=E9=80=BB=E8=BE=91=20=EF=BC=88?=
=?UTF-8?q?=E7=8E=B0=E5=9C=A8=E5=8D=B3=E5=8F=AF=E4=BD=BF=E7=94=A8=E5=91=BD?=
=?UTF-8?q?=E4=BB=A4=EF=BC=9Abili=E9=9F=B3=E4=B9=90+=E9=93=BE=E6=8E=A5?=
=?UTF-8?q?=EF=BC=8C=E4=B8=8B=E8=BD=BD=E9=9F=B3=E4=B9=90=E5=95=A6=EF=BC=81?=
=?UTF-8?q?=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
1. 将m4s发送转换为mp3发送格式
2. 提升了bili解析的扩展性
3. 整理了path获取的方式
---
apps/tools.js | 107 +++++++++++++-----------
config/version.yaml | 2 +-
constants/tools.js | 21 +++++
utils/biliInfo.js | 57 -------------
utils/bilibili.js | 193 +++++++++++++++++++++++++++++++++++++-------
5 files changed, 246 insertions(+), 134 deletions(-)
delete mode 100644 utils/biliInfo.js
diff --git a/apps/tools.js b/apps/tools.js
index cfed092..4d24446 100644
--- a/apps/tools.js
+++ b/apps/tools.js
@@ -6,35 +6,54 @@ import { Buffer } from 'node:buffer';
import axios from "axios";
import _ from "lodash";
import tunnel from "tunnel";
-import HttpProxyAgent, { HttpsProxyAgent } from "https-proxy-agent";
-import { mkdirIfNotExists, checkAndRemoveFile, deleteFolderRecursive } from "../utils/file.js";
-import { downloadBFile, getAudioUrl, getDownloadUrl, mergeFileToMp4 } from "../utils/bilibili.js";
-import { parseUrl, parseM3u8, downloadM3u8Videos, mergeAcFileToMp4 } from "../utils/acfun.js";
+import HttpProxyAgent from "https-proxy-agent";
+import { checkAndRemoveFile, deleteFolderRecursive, mkdirIfNotExists } from "../utils/file.js";
+import {
+ downloadBFile,
+ getBiliAudio,
+ getDownloadUrl,
+ getDynamic,
+ getVideoInfo,
+ m4sToMp3,
+ mergeFileToMp4
+} from "../utils/bilibili.js";
+import { downloadM3u8Videos, mergeAcFileToMp4, parseM3u8, parseUrl } from "../utils/acfun.js";
import {
- transMap,
- douyinTypeMap,
DIVIDING_LINE,
- XHS_NO_WATERMARK_HEADER,
+ douyinTypeMap,
REDIS_YUNZAI_ISOVERSEA,
+ transMap,
TWITTER_BEARER_TOKEN,
+ XHS_NO_WATERMARK_HEADER,
} from "../constants/constant.js";
import { containsChinese, formatBiliInfo, getIdVideo, secondsToTime } from "../utils/common.js";
import config from "../model/index.js";
import Translate from "../utils/trans-strategy.js";
import * as xBogus from "../utils/x-bogus.cjs";
-import { getVideoInfo, getDynamic } from "../utils/biliInfo.js";
-import { getBodianAudio, getBodianMv, getBodianMusicInfo } from "../utils/bodian.js";
+import { getBodianAudio, getBodianMusicInfo, getBodianMv } from "../utils/bodian.js";
import { av2BV } from "../utils/bilibili-bv-av-convert.js";
import querystring from "querystring";
import TokenBucket from "../utils/token-bucket.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 { XHS_VIDEO } from "../constants/tools.js";
+import { BILI_SUMMARY, DY_INFO, TIKTOK_INFO, TWITTER_TWEET_INFO, XHS_REQ_LINK, XHS_VIDEO } from "../constants/tools.js";
import child_process from 'node:child_process'
import { getAudio, getVideo } from "../utils/y2b.js";
import { processTikTokUrl } from "../utils/tiktok.js";
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() {
super({
name: "R插件工具和学习类",
@@ -197,9 +216,7 @@ export class tools extends plugin {
"http",
"https",
);
- const path = `${ this.defaultPath }${
- this.e.group_id || this.e.user_id
- }/temp.mp4`;
+ const path = `${ this.getCurDownloadPath(e) }/temp.mp4`;
await this.downloadVideo(resUrl).then(() => {
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 => {
e.reply(
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音乐")) {
- await this.biliMusic(url, e);
+ await this.biliMusic(e, url);
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);
// 下载文件
getDownloadUrl(url)
@@ -367,9 +384,13 @@ export class tools extends plugin {
return true;
}
- async biliMusic(url, e) {
- const { audioUrl } = await getAudioUrl(url);
- e.reply(segment.record(audioUrl))
+ // 下载哔哩哔哩音乐
+ async biliMusic(e, url) {
+ 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
}
@@ -399,6 +420,8 @@ export class tools extends plugin {
return url;
}
+ // 小蓝鸟解析:停止更新
+
/**
* 哔哩哔哩总结
* @author zhiyu1998
@@ -492,7 +515,6 @@ export class tools extends plugin {
return true;
}
- // 小蓝鸟解析:停止更新
// 例子:https://twitter.com/chonkyanimalx/status/1595834168000204800
async twitter(e) {
// 配置参数及解析
@@ -512,14 +534,14 @@ export class tools extends plugin {
await fetch(TWITTER_TWEET_INFO.replace("{}", id), {
headers: {
"User-Agent": "v2TweetLookupJS",
- "authorization": `Bearer ${Buffer.from(TWITTER_BEARER_TOKEN, "base64").toString()}`
+ "authorization": `Bearer ${ Buffer.from(TWITTER_BEARER_TOKEN, "base64").toString() }`
},
...params,
agent: !isOversea ? '' : new HttpProxyAgent(this.myProxy),
}).then(async resp => {
logger.info(resp)
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)) {
mkdirsSync(downloadPath);
@@ -569,7 +591,7 @@ export class tools extends plugin {
// acfun解析
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);
let inputMsg = e.msg;
@@ -619,9 +641,9 @@ export class tools extends plugin {
} else {
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,
}).then(async resp => {
const xhsHtml = await resp.text();
@@ -641,7 +663,7 @@ export class tools extends plugin {
this.downloadVideo(xhsVideoUrl).then(path => {
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"));
});
@@ -730,7 +752,7 @@ export class tools extends plugin {
const API = `https://imginn.com/${ suffix }`;
// logger.info(API);
let imgPromise = [];
- const downloadPath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`;
+ const downloadPath = `${ this.getCurDownloadPath(e) }`;
// 判断是否是海外服务器
const isOversea = await this.isOverseasServer();
// 简单封装图片下载
@@ -813,7 +835,7 @@ export class tools extends plugin {
segment.image(albumPic120),
]);
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(_ => {
Bot.acquireGfs(e.group_id).upload(
fs.readFileSync(path + "/temp.mp3"),
@@ -968,12 +990,12 @@ export class tools extends plugin {
const format = `${ bestVideo.id }x${ bestAudio.id }`
// 下载地址格式化
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);
// yt-dlp下载
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`;
logger.mark(cmd)
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}}
@@ -1208,18 +1239,4 @@ export class tools extends plugin {
logger.warn(`解析被限制使用`);
}
}
-
- /**
- * 构造安全的命令
- * @type {{existsPromptKey: string, existsTransKey: string}}
- */
- static Constants = {
- existsTransKey: Object.keys(transMap).join("|"),
- };
-
- /**
- * 构造令牌桶,防止解析致使服务器宕机(默认限制5s调用一次)
- * @type {TokenBucket}
- */
- static #tokenBucket = new TokenBucket(1, 1, 5);
}
diff --git a/config/version.yaml b/config/version.yaml
index 71b98af..cb0999d 100644
--- a/config/version.yaml
+++ b/config/version.yaml
@@ -1,5 +1,5 @@
- {
- version: 1.3.2,
+ version: 1.3.3,
data:
[
新增油管解析功能,
diff --git a/constants/tools.js b/constants/tools.js
index d3026cf..7357b68 100644
--- a/constants/tools.js
+++ b/constants/tools.js
@@ -5,6 +5,27 @@
*/
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
* https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/video/info.md
diff --git a/utils/biliInfo.js b/utils/biliInfo.js
deleted file mode 100644
index 535a87f..0000000
--- a/utils/biliInfo.js
+++ /dev/null
@@ -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 };
diff --git a/utils/bilibili.js b/utils/bilibili.js
index 431f0a3..2951c10 100644
--- a/utils/bilibili.js
+++ b/utils/bilibili.js
@@ -2,8 +2,17 @@ import fs from "node:fs";
import axios from 'axios'
import child_process from 'node:child_process'
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}
+ */
+export async function downloadBFile(url, fullFileName, progressCallback) {
return axios
.get(url, {
responseType: 'stream',
@@ -35,7 +44,12 @@ async function downloadBFile (url, fullFileName, progressCallback) {
});
}
-async function getDownloadUrl (url) {
+/**
+ * 获取下载链接
+ * @param url
+ * @returns {Promise}
+ */
+export async function getDownloadUrl(url) {
return axios
.get(url, {
headers: {
@@ -65,34 +79,15 @@ async function getDownloadUrl (url) {
});
}
-async function getAudioUrl (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(/