diff --git a/apps/tools.js b/apps/tools.js
index 0421607..5d46c3e 100644
--- a/apps/tools.js
+++ b/apps/tools.js
@@ -12,7 +12,7 @@ import {
downloadBFile,
getBiliAudio,
getDownloadUrl,
- getDynamic,
+ getDynamic, getScanCodeData,
getVideoInfo,
m4sToMp3,
mergeFileToMp4
@@ -50,10 +50,8 @@ import {
TIKTOK_INFO,
TWITTER_TWEET_INFO,
XHS_REQ_LINK,
- GENERAL_REQ_LINK, WEIBO_SINGLE_INFO, WEISHI_VIDEO_INFO
+ GENERAL_REQ_LINK, WEIBO_SINGLE_INFO, WEISHI_VIDEO_INFO, BILI_SCAN_CODE_GENERATE
} from "../constants/tools.js";
-import child_process from 'node:child_process'
-import { getAudio, getVideo } from "../utils/y2b.js";
import { processTikTokUrl } from "../utils/tiktok.js";
import { getDS } from "../utils/mihoyo.js";
import GeneralLinkAdapter from "../utils/general-link-adapter.js";
@@ -92,6 +90,11 @@ export class tools extends plugin {
reg: "(www.tiktok.com)|(vt.tiktok.com)|(vm.tiktok.com)",
fnc: "tiktok",
},
+ {
+ reg: "^#R插件B站扫码$",
+ fnc: "biliScan",
+ permission: 'master',
+ },
{
reg: "(bilibili.com|b23.tv|t.bilibili.com)",
fnc: "bili",
@@ -339,6 +342,24 @@ export class tools extends plugin {
return true;
}
+ async biliScan(e) {
+ e.reply('R插件开源免责声明:\n您将通过扫码完成获取哔哩哔哩refresh_token以及ck。\n本Bot将不会保存您的登录状态。\n我方仅提供视频解析及相关B站内容服务,若您的账号封禁、被盗等处罚与我方无关。\n害怕风险请勿扫码 ~', { recallMsg: 180 });
+ // 图片发送钩子
+ const imgSendHook = function (e, path) {
+ e.reply([segment.image(path), segment.at(e.user_id), '请扫码以完成获取'], { recallMsg: 180 })
+ };
+ // 发送请求
+ const saveCodePath = `${ this.defaultPath }qrcode.png`;
+
+ const { SESSDATA, refresh_token } = await getScanCodeData(saveCodePath, 8, () => imgSendHook(e, saveCodePath))
+
+ // 更新到配置文件
+ config.updateField("tools", "biliSessData", SESSDATA);
+ e.reply('登录成功!相关信息已保存至配置文件', true)
+ return true;
+ }
+
+
// bilibi解析
async bili(e) {
await this.limitUserUse(e, () => {
diff --git a/config/help.yaml b/config/help.yaml
index 1dd9eb8..abdc896 100644
--- a/config/help.yaml
+++ b/config/help.yaml
@@ -38,6 +38,9 @@
- icon: bilibili
title: "bilibili/b23"
desc: 哔哩哔哩分享实时下载
+ - icon: bqrcode
+ title: "R插件B站扫码"
+ desc: R插件B站扫码
- icon: bilimusic
title: "bili音乐+链接"
desc: 哔哩哔哩音乐分享实时下载
diff --git a/config/version.yaml b/config/version.yaml
index 431ea48..486d5a5 100644
--- a/config/version.yaml
+++ b/config/version.yaml
@@ -1,11 +1,10 @@
- {
- version: 1.6.2,
+ version: 1.6.3,
data:
[
+ 新增B站扫码功能,
新增即刻解析功能,
新增微视解析功能,
- 新增小世界解析功能,
- 新增贴吧解析功能,
支持锅巴插件,方便查看和修改配置,
添加#R帮助获取插件帮助,
添加#R版本获取插件版本,
diff --git a/constants/tools.js b/constants/tools.js
index 0bb034f..22bf60a 100644
--- a/constants/tools.js
+++ b/constants/tools.js
@@ -40,6 +40,20 @@ export const BILI_VIDEO_INFO = "http://api.bilibili.com/x/web-interface/view"
*/
export const BILI_NAV = "https://api.bilibili.com/x/web-interface/nav"
+/**
+ * 扫码登录的二维码生成
+ * https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/login/login_action/QR.md
+ * @type {string}
+ */
+export const BILI_SCAN_CODE_GENERATE = "https://passport.bilibili.com/x/passport-login/web/qrcode/generate"
+
+/**
+ * 扫码登录检测然后发送令牌数据
+ * https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/login/login_action/QR.md
+ * @type {string}
+ */
+export const BILI_SCAN_CODE_DETECT = "https://passport.bilibili.com/x/passport-login/web/qrcode/poll?qrcode_key={}";
+
/**
* 米游社网页端获取文章
* https://github.com/UIGF-org/mihoyo-api-collect/blob/main/hoyolab/article/article.md#%E8%8E%B7%E5%8F%96%E5%AE%8C%E6%95%B4%E6%96%87%E7%AB%A0%E4%BF%A1%E6%81%AF
diff --git a/model/index.js b/model/index.js
index 32ef893..1c8a88b 100644
--- a/model/index.js
+++ b/model/index.js
@@ -28,6 +28,26 @@ class RConfig {
return this.getYaml(name)
}
+ // 获取指定配置的某个字段
+ getField(name, field) {
+ const config = this.getConfig(name);
+ return config[field];
+ }
+
+ // 更新指定配置的某个字段
+ updateField(name, field, value) {
+ let config = this.getConfig(name);
+ config[field] = value; // 更新字段值
+ this.saveSet(name, config); // 保存更改
+ }
+
+ // 删除指定配置的某个字段
+ deleteField(name, field) {
+ let config = this.getConfig(name);
+ delete config[field]; // 删除指定字段
+ this.saveSet(name, config); // 保存更改
+ }
+
/**
* 获取配置yaml
* @param name 名称
diff --git a/package.json b/package.json
index 6758f3b..b34dd01 100644
--- a/package.json
+++ b/package.json
@@ -4,6 +4,7 @@
"type": "module",
"dependencies": {
"axios": "^1.3.4",
- "tunnel": "^0.0.6"
+ "tunnel": "^0.0.6",
+ "qrcode": "^1.5.3"
}
}
diff --git a/resources/img/icon/bqrcode.png b/resources/img/icon/bqrcode.png
new file mode 100644
index 0000000..e9078ed
Binary files /dev/null and b/resources/img/icon/bqrcode.png differ
diff --git a/utils/bilibili.js b/utils/bilibili.js
index 4099c75..94944ef 100644
--- a/utils/bilibili.js
+++ b/utils/bilibili.js
@@ -2,8 +2,21 @@ 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 {
+ BILI_BVID_TO_CID,
+ BILI_DYNAMIC,
+ BILI_PLAY_STREAM, BILI_SCAN_CODE_DETECT,
+ BILI_SCAN_CODE_GENERATE,
+ BILI_VIDEO_INFO
+} from "../constants/tools.js";
import { mkdirIfNotExists } from "./file.js";
+import qrcode from "qrcode"
+
+const biliHeaders = {
+ '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',
+}
/**
* 下载单个bili文件
@@ -17,9 +30,7 @@ export async function downloadBFile(url, fullFileName, progressCallback) {
.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',
+ ...biliHeaders
},
})
.then(({ data, headers }) => {
@@ -53,9 +64,7 @@ export async 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',
+ ...biliHeaders
},
})
.then(({ data }) => {
@@ -127,9 +136,7 @@ export async function m4sToMp3(m4sUrl, path) {
.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',
+ ...biliHeaders
},
}).then(async res => {
// 如果没有目录就创建一个
@@ -231,9 +238,7 @@ export async function getDynamic(dynamicId, SESSDATA) {
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',
+ ...biliHeaders,
Cookie: `SESSDATA=${ SESSDATA }`
},
}).then(resp => {
@@ -254,4 +259,60 @@ export async function getDynamic(dynamicId, SESSDATA) {
dynamicDesc
}
})
+}
+
+/**
+ * 扫码
+ * @param qrcodeSavePath 【必须】QR保存位置
+ * @param detectTime 【可选】检测时间(默认10s检测一次)
+ * @param hook 【可选】钩子函数,目前只用来人机交互
+ * @returns {Promise<{
+ * SESSDATA,
+ * refresh_token
+ * }>}
+ */
+export async function getScanCodeData(qrcodeSavePath = 'qrcode.png', detectTime = 10, hook = () => {}) {
+ try {
+ const resp = await axios.get(BILI_SCAN_CODE_GENERATE, { ...biliHeaders });
+ // 保存扫码的地址、扫码登录秘钥
+ const { url: scanUrl, qrcode_key } = resp.data.data;
+ await qrcode.toFile(qrcodeSavePath, scanUrl);
+
+ let code = 1;
+
+ // 设置最大尝试次数
+ let attemptCount = 0;
+ const maxAttempts = 3;
+
+ let loginResp;
+ // 检测扫码情况默认 10s 检测一次,并且尝试3次,没扫就拜拜
+ while (code !== 0 && attemptCount < maxAttempts) {
+ // 钩子函数,目前用于发送二维码给用户
+ hook();
+ loginResp = await axios.get(BILI_SCAN_CODE_DETECT.replace("{}", qrcode_key), { ...biliHeaders });
+ code = loginResp.data.data.code;
+ await new Promise(resolve => setTimeout(resolve, detectTime * 1000)); // Wait for detectTime seconds
+ }
+ // 获取刷新令牌
+ const { refresh_token } = loginResp.data.data;
+
+ // 获取cookie
+ const cookies = loginResp.headers['set-cookie'];
+ const SESSDATA = cookies
+ .map(cookie => cookie.split(';').find(item => item.trim().startsWith('SESSDATA=')))
+ .find(item => item !== undefined)
+ ?.split('=')[1];
+
+ return {
+ SESSDATA,
+ refresh_token
+ };
+ } catch (err) {
+ logger.error(err);
+ // 可能需要处理错误或返回一个默认值
+ return {
+ SESSDATA: '',
+ refresh_token: ''
+ };
+ }
}
\ No newline at end of file