yz-yuki-plugin 2.0.10-2 → 2.0.10-5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # 2.0.10
2
+ * 哔哩视频解析过风控
2
3
  * 更改搜索正则
3
4
 
4
5
  # 2.0.9
@@ -15,9 +15,9 @@ checkDynamicCD: '*/23 * * * *'
15
15
  # 请求头 User-Agent 列表。如出现 -352 风控,可尝试更换请求头,请根据需要自行添加或修改。
16
16
  # 可设置多个请求头,每次重启后会随机选择一个。获取方法请浏览器自行搜索。
17
17
  userAgentList:
18
- - 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36'
19
- #- 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0'
20
- #- 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0'
18
+ - 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36'
19
+ #- 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:156.0) Gecko/20100101 Firefox/156.0'
20
+ #- 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36 Edg/152.0.0.0'
21
21
 
22
22
  # 筛选何时发布的动态,单位为秒,默认7200秒即2小时,即以当前时间为基准,筛选过去2小时内的发布动态,并推送。
23
23
  # 取值范围:3600-36000秒,即过去的1-10h。应大于checkDynamicCD的周期。
@@ -528,6 +528,10 @@ message.use(async (e) => {
528
528
  if (videoIDMatch[2]) {
529
529
  // 匹配 b23.tv/ 后面的部分
530
530
  const bvidStr = await new BilibiliWebDataFetcher(e).getBVIDByShortUrl(videoIDMatch[2]);
531
+ if (bvidStr === false) {
532
+ e.reply('遭遇风控或意外,短链解析失败,无法获取BVID~');
533
+ return;
534
+ }
531
535
  videoID = { bvid: bvidStr };
532
536
  }
533
537
  else if (videoIDMatch[4].startsWith('av')) {
@@ -43,6 +43,8 @@ class BiliApi {
43
43
  biliVideoInfoWbi: `https://api.bilibili.com/x/web-interface/wbi/view`,
44
44
  //短链
45
45
  biliShortVideoUrl: `https://b23.tv/`,
46
+ //短链412解控接口
47
+ biliCapchaCheck: 'https://security.bilibili.com/th/captcha/cc/check',
46
48
  biliLiveStatus: 'https://api.live.bilibili.com/room/v1/Room/get_status_info_by_uids',
47
49
  biliCard: 'https://api.bilibili.com/x/web-interface/card',
48
50
  biliStat: 'https://api.bilibili.com/x/relation/stat',
@@ -127,6 +129,25 @@ class BiliApi {
127
129
  'User-Agent': this.USER_AGENT
128
130
  };
129
131
  }
132
+ get BILIBILI_CAPTCHA_CHECK_HEADERS() {
133
+ return {
134
+ 'Accept': '*/*',
135
+ 'Accept-Encoding': 'gzip, deflate, br, zstd',
136
+ 'Accept-Language': 'zh-CN,en-US;q=0.5',
137
+ 'Connection': 'keep-alive',
138
+ 'Content-type': 'application/x-www-form-urlencoded',
139
+ 'Host': 'security.bilibili.com',
140
+ 'Origin': 'https://www.bilibili.com',
141
+ 'Pragma': 'no-cache',
142
+ 'Referer': 'https://www.bilibili.com/',
143
+ 'Sec-Fetch-Dest': 'empty',
144
+ 'Sec-Fetch-Mode': 'cors',
145
+ 'Sec-Fetch-Site': 'same-site',
146
+ 'Sec-GPC': '1',
147
+ 'TE': 'trailers',
148
+ 'User-Agent': this.USER_AGENT
149
+ };
150
+ }
130
151
  /**返回GatWay payload */
131
152
  async BILIBILI_BROWSER_DATA(_uuid) {
132
153
  return {
@@ -6,6 +6,7 @@ import axioss from 'axios';
6
6
  import { wrapper } from 'axios-cookiejar-support';
7
7
  import lodash from 'lodash';
8
8
  import * as tough from 'tough-cookie';
9
+ import crypto from 'crypto';
9
10
 
10
11
  const axios = wrapper(axioss);
11
12
  class BilibiliWebDataFetcher {
@@ -220,10 +221,114 @@ class BilibiliWebDataFetcher {
220
221
  timeout: 15000,
221
222
  headers
222
223
  });
223
- const htmlContent = await res.data;
224
- const htmlContentRegex = /itemprop="url"\s*content="https:\/\/www.bilibili.com\/video\/(BV[a-zA-Z0-9]+)\/">/;
225
- const BVID = htmlContent.match(htmlContentRegex)?.[1];
226
- return `${BVID}`;
224
+ if (res.status === 200) {
225
+ const htmlContent = await res.data;
226
+ const htmlContentRegex = /property="og:url"\s*content="https:\/\/www.bilibili.com\/video\/(BV[a-zA-Z0-9]+)\/">/;
227
+ const BVID = htmlContent.match(htmlContentRegex)?.[1];
228
+ if (BVID) {
229
+ logger.info(`哔哩视频解析:status 200 解析短链成功,BVID: ${BVID}`);
230
+ return `${BVID}`;
231
+ }
232
+ else {
233
+ logger.error('哔哩视频解析:status 200 正则不匹配,无法获取BVID');
234
+ return false;
235
+ }
236
+ }
237
+ else if (res.status === 302) {
238
+ const locationHeader = res.headers['location'];
239
+ const bvidRegex = /\/video\/(BV[a-zA-Z0-9]+)/;
240
+ const bvidMatch = locationHeader?.match(bvidRegex)?.[1];
241
+ if (bvidMatch) {
242
+ logger.info(`哔哩视频解析:status 302 解析短链成功,BVID: ${bvidMatch}`);
243
+ return `${bvidMatch}`;
244
+ }
245
+ else {
246
+ logger.error('哔哩视频解析:status 302 正则不匹配,无法获取BVID');
247
+ return false;
248
+ }
249
+ }
250
+ else if (res.status === 412) {
251
+ const X_BILI_SEC_TOKEN = res.headers['set-cookie']
252
+ ?.find(c => c.includes('X-BILI-SEC-TOKEN='))
253
+ ?.split(';')[0]
254
+ .split('=')[1];
255
+ let decodedResult = null; // 显式设为可空
256
+ if (X_BILI_SEC_TOKEN) {
257
+ const base64_text = X_BILI_SEC_TOKEN.split('.')[1];
258
+ const decoded = Buffer.from(base64_text + '==', 'base64').toString('utf8');
259
+ const obj = JSON.parse(decoded); //{"q":"xxxxx","r":"xxxxx","ip":"xx.xx.xx.xx","fp":"xxx","verity":0,"type":"1","exp":1788276102,"iat":1788272502}
260
+ const limit = 0x4c4b40;
261
+ for (let i = 0; i < limit; i++) {
262
+ const hash = crypto
263
+ .createHash('sha256')
264
+ .update(obj.q + String(i))
265
+ .digest('hex');
266
+ if (hash === obj.r) {
267
+ decodedResult = i;
268
+ break; // 找到后立即跳出循环,节省时间
269
+ }
270
+ }
271
+ // 只有找到了结果才发送请求
272
+ if (decodedResult !== null) {
273
+ const capchaCheckRes = await axios.post(BiliApi.BILIBIL_API.biliCapchaCheck, { token: X_BILI_SEC_TOKEN, result: decodedResult }, { headers: BiliApi.BILIBILI_CAPTCHA_CHECK_HEADERS });
274
+ const capchaCheckResData = capchaCheckRes.data;
275
+ if (capchaCheckResData.code === 0) {
276
+ const afterCapchaCheckHeaders = lodash.merge(BiliApi.BILIBILI_DYNAMIC_SPACE_HEADERS, {
277
+ Cookie: mark === 'localCk' ? `${bili_ticket};${cookie}` : undefined
278
+ }, {
279
+ Cookie: `X-BILI-SEC-TOKEN=${capchaCheckResData.message}`
280
+ });
281
+ const res = await axios.get(url, {
282
+ jar: ck, // 仅在非 localCk 时传递 jar
283
+ timeout: 15000,
284
+ headers: afterCapchaCheckHeaders
285
+ });
286
+ if (res.status === 200) {
287
+ const htmlContent = await res.data;
288
+ const htmlContentRegex = /property="og:url"\s*content="https:\/\/www.bilibili.com\/video\/(BV[a-zA-Z0-9]+)\/">/;
289
+ const BVID = htmlContent.match(htmlContentRegex)?.[1];
290
+ if (BVID) {
291
+ logger.info(`哔哩视频解析:status 412-200 解析短链成功,BVID: ${BVID}`);
292
+ return `${BVID}`;
293
+ }
294
+ else {
295
+ logger.error('哔哩视频解析:status 412-200 正则不匹配,无法获取BVID');
296
+ return false;
297
+ }
298
+ }
299
+ else if (res.status === 302) {
300
+ const locationHeader = res.headers['location'];
301
+ const bvidRegex = /\/video\/(BV[a-zA-Z0-9]+)/;
302
+ const bvidMatch = locationHeader?.match(bvidRegex)?.[1];
303
+ if (bvidMatch) {
304
+ logger.info(`哔哩视频解析:status 412-302 解析短链成功,BVID: ${bvidMatch}`);
305
+ return `${bvidMatch}`;
306
+ }
307
+ else {
308
+ logger.error('哔哩视频解析:status 412-302 正则不匹配,无法获取BVID');
309
+ return false;
310
+ }
311
+ }
312
+ else {
313
+ logger.error('哔哩视频解析:解风控失败,短链解析失败,无法获取BVID');
314
+ return false;
315
+ }
316
+ }
317
+ else if (capchaCheckResData.code === -1) {
318
+ logger.error('哔哩视频解析:解风控失败,风控方法可能已更新');
319
+ return false;
320
+ }
321
+ }
322
+ else {
323
+ logger.error('哔哩视频解析:解风控失败,未找到匹配的验证码值');
324
+ return false;
325
+ }
326
+ }
327
+ else {
328
+ logger.error('哔哩视频解析:遭遇风控或意外,短链解析失败,无法获取BVID');
329
+ return false;
330
+ }
331
+ }
227
332
  }
228
333
  }
229
334
 
@@ -478,7 +478,7 @@ class BiliRiskCookie {
478
478
  * 简单策略:优先从 Redis 读取长期 cookie(如 SESSDATA),若缺失则触发完整获取流程
479
479
  * */
480
480
  async ensureLoginCookies(jar) {
481
- // 常见域名为 .weibo.cnm.weibo.cn,根据实际情况检查
481
+ // 常见域名为 .bilibili.combilibili.com,根据实际情况检查
482
482
  const SESSDATA_Key1 = `${this.prefix}:.bilibili.com:SESSDATA`;
483
483
  const SESSDATA_Key2 = `${this.prefix}:bilibili.com:SESSDATA`;
484
484
  const isLogin = (await Redis.get(SESSDATA_Key1)) || (await Redis.get(SESSDATA_Key2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yz-yuki-plugin",
3
- "version": "2.0.10-2",
3
+ "version": "2.0.10-5",
4
4
  "description": "优纪插件,yunzaijs 关于 微博推送、B站推送 等功能的拓展插件",
5
5
  "author": "snowtafir",
6
6
  "type": "module",