yz-yuki-plugin 2.0.8-1 → 2.0.8-10

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.
@@ -1,7 +1,19 @@
1
- import axios from 'axios';
2
1
  import WeiboApi from './weibo.main.api.js';
2
+ import { WeiboMainModels } from './weibo.main.models.js';
3
3
  import { WeiboQuery } from './weibo.main.query.js';
4
+ import axios from 'axios';
5
+ import { randomInt } from 'crypto';
6
+ import lodash from 'lodash';
4
7
 
8
+ function generateRandomString(length = 6) {
9
+ const characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
10
+ let result = '';
11
+ for (let i = 0; i < length; i++) {
12
+ const randomIndex = randomInt(0, characters.length);
13
+ result += characters[randomIndex];
14
+ }
15
+ return result;
16
+ }
5
17
  class WeiboWebDataFetcher {
6
18
  e;
7
19
  constructor(e) { }
@@ -10,25 +22,55 @@ class WeiboWebDataFetcher {
10
22
  const param = { containerid: '100505' + target };
11
23
  const url = new URL(WeiboApi.WEIBO_API.weiboGetIndex);
12
24
  url.search = new URLSearchParams(param).toString();
25
+ const { cookie, mark } = await WeiboMainModels.readSyncCookie();
26
+ let COOKIE = '', XSRF_TOKEN = '';
27
+ if (String(cookie).includes('XSRF-TOKEN')) {
28
+ COOKIE = cookie;
29
+ XSRF_TOKEN = await WeiboMainModels.readSavedCookieItems(cookie, ['XSRF-TOKEN'], false);
30
+ }
31
+ else {
32
+ logger.warn(`优纪插件:获取博主信息,未登录,如获取报错或失败请先 #扫码微博登录`);
33
+ XSRF_TOKEN = generateRandomString();
34
+ COOKIE = `XSRF_TOKEN=${XSRF_TOKEN}`;
35
+ }
13
36
  const resp = await axios(url.toString(), {
14
37
  method: 'GET',
15
38
  timeout: 10000,
16
- headers: { 'accept': '*/*', 'Content-Type': 'application/json', 'referer': 'https://m.weibo.cn' }
39
+ headers: lodash.merge(WeiboApi.WEIBO_HEADERS, { 'X-XSRF-TOKEN': `${XSRF_TOKEN}`, 'Cookie': `${COOKIE}`, 'referer': 'https://m.weibo.cn' })
17
40
  });
41
+ // 处理 Set-Cookie 响应头
42
+ if (resp.headers['set-cookie']) {
43
+ await WeiboMainModels.updateCookieWithSetCookie(resp.headers['set-cookie'], mark);
44
+ }
18
45
  return resp;
19
46
  }
20
47
  /**通过关键词搜索微博大v */
21
48
  async searchBloggerInfo(keyword) {
22
49
  const url = WeiboApi.WEIBO_API.weiboAjaxSearch;
50
+ const { cookie, mark } = await WeiboMainModels.readSyncCookie();
51
+ let COOKIE = '', XSRF_TOKEN = '';
23
52
  const params = {
24
53
  q: keyword
25
54
  };
55
+ if (String(cookie).includes('XSRF-TOKEN')) {
56
+ COOKIE = cookie;
57
+ XSRF_TOKEN = await WeiboMainModels.readSavedCookieItems(cookie, ['XSRF-TOKEN'], false);
58
+ }
59
+ else {
60
+ logger.warn(`优纪插件:搜索微博大V,未登录,如获取报错或失败请先 #扫码微博登录`);
61
+ XSRF_TOKEN = generateRandomString();
62
+ COOKIE = `XSRF_TOKEN=${XSRF_TOKEN}`;
63
+ }
26
64
  const resp = await axios(url, {
27
65
  method: 'GET',
28
66
  params,
29
67
  timeout: 10000,
30
- headers: { 'accept': '*/*', 'Content-Type': 'application/json', 'referer': 'https://s.weibo.com' }
68
+ headers: lodash.merge(WeiboApi.WEIBO_HEADERS, { 'X-XSRF-TOKEN': `${XSRF_TOKEN}`, 'Cookie': `${COOKIE}`, 'referer': 'https://m.weibo.cn' })
31
69
  });
70
+ // 处理 Set-Cookie 响应头
71
+ if (resp.headers['set-cookie']) {
72
+ await WeiboMainModels.updateCookieWithSetCookie(resp.headers['set-cookie'], mark);
73
+ }
32
74
  return resp;
33
75
  }
34
76
  /**获取主页动态资源相关数组 */
@@ -37,12 +79,27 @@ class WeiboWebDataFetcher {
37
79
  const url = new URL(WeiboApi.WEIBO_API.weiboGetIndex);
38
80
  url.search = new URLSearchParams(params).toString();
39
81
  await new Promise(resolve => setTimeout(resolve, Math.floor(Math.random() * (6500 - 1000 + 1) + 1000)));
82
+ const { cookie, mark } = await WeiboMainModels.readSyncCookie();
83
+ let COOKIE = '', XSRF_TOKEN = '';
84
+ if (String(cookie).includes('XSRF-TOKEN')) {
85
+ COOKIE = cookie;
86
+ XSRF_TOKEN = await WeiboMainModels.readSavedCookieItems(cookie, ['XSRF-TOKEN'], false);
87
+ }
88
+ else {
89
+ logger.warn(`优纪插件:获取主页动态资源,未登录,如获取报错或失败请先 #扫码微博登录`);
90
+ XSRF_TOKEN = generateRandomString();
91
+ COOKIE = `XSRF_TOKEN=${XSRF_TOKEN}`;
92
+ }
40
93
  try {
41
94
  const response = await axios(url.toString(), {
42
95
  method: 'GET',
43
96
  timeout: 10000,
44
- headers: { 'accept': '*/*', 'Content-Type': 'application/json', 'referer': 'https://m.weibo.cn' }
97
+ headers: lodash.merge(WeiboApi.WEIBO_HEADERS, { 'X-XSRF-TOKEN': `${XSRF_TOKEN}`, 'Cookie': `${COOKIE}`, 'referer': 'https://m.weibo.cn' })
45
98
  });
99
+ // 处理 Set-Cookie 响应头
100
+ if (response.headers['set-cookie']) {
101
+ await WeiboMainModels.updateCookieWithSetCookie(response.headers['set-cookie'], mark);
102
+ }
46
103
  const { ok, data, msg } = response?.data;
47
104
  if (!ok && msg !== '这里还没有内容') {
48
105
  throw new Error(response?.config.url);
@@ -0,0 +1,347 @@
1
+ import WeiboApi from './weibo.main.api.js';
2
+ import { getRidFromBd } from './weibo.risk.bd.rid.js';
3
+ import { parse, serialize } from 'cookie';
4
+ import lodash from 'lodash';
5
+ import moment from 'moment';
6
+ import fetch from 'node-fetch';
7
+ import { Segment, Redis } from 'yunzaijs';
8
+
9
+ class WeiboMainModels {
10
+ /**
11
+ * *******************************************************************
12
+ * Login 相关
13
+ * *******************************************************************
14
+ */
15
+ /**申请登陆二维码(web端) */
16
+ static async applyLoginQRCode(e) {
17
+ const response = await fetch('https://passport.weibo.com/sso/signin?entry=wapsso&source=wapssowb&url=https://m.weibo.cn/', {
18
+ method: 'GET',
19
+ headers: lodash.merge(WeiboApi.WEIBO_GET_X_CSRF_TOKEN_HEADERS, { Host: 'passport.weibo.com' }),
20
+ redirect: 'follow'
21
+ });
22
+ const setCookie = response.headers.get('set-cookie');
23
+ const tokenMatch = setCookie?.match(/X-CSRF-TOKEN=([^;]+)/);
24
+ const X_CSRF_TOKEN = tokenMatch ? tokenMatch[1].replace(/X-CSRF-TOKEN=/g, '') : null;
25
+ if (X_CSRF_TOKEN) {
26
+ const resData = (await fetch('https://passport.weibo.com/sso/v2/qrcode/image?entry=wapsso&size=180', {
27
+ method: 'GET',
28
+ headers: lodash.merge(WeiboApi.WEIBO_LOGIN_QR_CODE_HEADERS, {
29
+ 'Host': 'passport.weibo.com',
30
+ 'X-CSRF-TOKEN': X_CSRF_TOKEN,
31
+ 'Cookie': `X-CSRF-TOKEN=${X_CSRF_TOKEN}`
32
+ }),
33
+ redirect: 'follow'
34
+ }).then(res => res.json()));
35
+ if (resData?.retcode === 20000000) {
36
+ const qrid = resData?.data?.qrid;
37
+ const qrcodeUrl = resData?.data?.image;
38
+ let msg = [];
39
+ if (qrid && qrcodeUrl) {
40
+ const imgResponse = await fetch(qrcodeUrl, {
41
+ method: 'GET',
42
+ headers: WeiboApi.WEIBO_LOGIN_QR_CODE_IMAGE_HEADERS,
43
+ redirect: 'follow'
44
+ });
45
+ if (!imgResponse.ok) {
46
+ logger.error(`获取微博登录二维码失败: ${imgResponse.status}`);
47
+ throw new Error(`获取微博登录图片失败,状态码: ${imgResponse.status}`);
48
+ }
49
+ // 等待3秒再获取rid
50
+ await new Promise(resolve => setTimeout(resolve, 3000));
51
+ const ridData = await getRidFromBd(X_CSRF_TOKEN);
52
+ if (ridData?.retcode === 20000000) {
53
+ const rid = ridData?.data?.rid;
54
+ const arrayBuffer = await imgResponse.arrayBuffer();
55
+ msg.push(Segment.image(Buffer.from(arrayBuffer)));
56
+ e.reply('请在3分钟内扫码以完成微博登陆绑定');
57
+ e.reply(msg);
58
+ logger.info(`优纪插件: 如果发送二维码图片消息失败可复制如下URL, 浏览器访问此URL查看二维码并扫码`);
59
+ logger.info(`优纪插件: 微博登陆二维码URL: ${qrcodeUrl}`);
60
+ return { qrid, rid, X_CSRF_TOKEN };
61
+ }
62
+ else {
63
+ logger.error('微博登录:获取rid失败');
64
+ e.reply(`获取微博登录rid密钥失败: ${JSON.stringify(ridData)},\n接口逆向进度受阻,未完成,无法登录。\n无妨,已切换启用临时ck`);
65
+ throw new Error(`获取微博登录rid密钥失败: ${JSON.stringify(ridData)},\n接口逆向进度受阻,未完成,无法登录。\n无妨,已切换启用临时ck`);
66
+ }
67
+ }
68
+ }
69
+ else {
70
+ e.reply(`获取微博登录二维码失败: ${JSON.stringify(resData)}`);
71
+ throw new Error(`获取微博登录二维码失败: ${JSON.stringify(resData)}`);
72
+ }
73
+ }
74
+ else {
75
+ logger.error('微博登录:获取X_CSRF_TOKEN失败');
76
+ return false;
77
+ }
78
+ }
79
+ /**处理扫码结果 */
80
+ static async pollLoginQRCode(e, qrid, rid, X_CSRF_TOKEN) {
81
+ const url = `https://passport.weibo.com/sso/v2/qrcode/check?entry=wapsso&source=wapssowb&url=https://m.weibo.cn/&qrid=${qrid}&rid=${rid}&ver=20250520`;
82
+ const response = await fetch(url, {
83
+ method: 'GET',
84
+ headers: lodash.merge(WeiboApi.WEIBO_POLL_LOGIN_STATUS_HEADERS, {
85
+ 'X-CSRF-TOKEN': X_CSRF_TOKEN,
86
+ 'Cookie': `X-CSRF-TOKEN=${X_CSRF_TOKEN}`
87
+ }),
88
+ redirect: 'follow'
89
+ });
90
+ if (!response.ok) {
91
+ throw new Error(`处理B站登录token网络请求失败,状态码: ${response.status}`);
92
+ }
93
+ const data = (await response.json());
94
+ if (data?.retcode === 20000000) {
95
+ // 获取 cookie url
96
+ const getCookieUrl = data?.data?.url;
97
+ if (getCookieUrl) {
98
+ const CookieResp = await fetch(getCookieUrl, {
99
+ method: 'GET',
100
+ headers: lodash.merge(WeiboApi.WEIBO_COOKIE_HEADERS, { Cookie: `X-CSRF-TOKEN=${X_CSRF_TOKEN}` }),
101
+ redirect: 'follow'
102
+ });
103
+ const setCookie = CookieResp.headers.get('set-cookie');
104
+ if (setCookie) {
105
+ await this.saveLoginCookie(e, setCookie);
106
+ e.reply(`~微博登陆成功~`);
107
+ return setCookie;
108
+ }
109
+ else {
110
+ e.reply(`获取微博登录Cookie失败: ${JSON.stringify(CookieResp.headers)}`);
111
+ return null;
112
+ }
113
+ }
114
+ }
115
+ else if (data?.retcode === 50114001) {
116
+ // 未扫码
117
+ // 继续轮询
118
+ await new Promise(resolve => setTimeout(resolve, 2000));
119
+ global?.logger?.mark(`优纪插件:扫码微博登录:未扫码,轮询中...`);
120
+ return this.pollLoginQRCode(e, qrid, rid, X_CSRF_TOKEN);
121
+ }
122
+ else if (data?.retcode === 50114002) {
123
+ // 已扫码未确认
124
+ // 继续轮询
125
+ await new Promise(resolve => setTimeout(resolve, 2000));
126
+ return this.pollLoginQRCode(e, qrid, rid, X_CSRF_TOKEN);
127
+ }
128
+ else if (data?.retcode === 50114003) {
129
+ // 二维码已失效
130
+ e.reply('微博登陆二维码已失效');
131
+ return null;
132
+ }
133
+ else {
134
+ e.reply('处理微博登录扫码结果出错');
135
+ throw new Error(`处理微博登录扫码结果出错: ${JSON.stringify(data)}`);
136
+ }
137
+ return null;
138
+ }
139
+ /**查看app扫码登陆获取的ck的有效状态*/
140
+ static async checkWeiboLogin(e) {
141
+ const LoginCookie = await this.readLoginCookie();
142
+ if (String(LoginCookie).trim().length < 10) {
143
+ e.reply('啊咧?微博登录CK呢?哦,没 #扫码微博登录# 或缓存失效了啊,那没事了。');
144
+ return;
145
+ }
146
+ else {
147
+ const { cookie, mark } = await WeiboMainModels.readSyncCookie();
148
+ let COOKIE = '', XSRF_TOKEN = '';
149
+ if (String(cookie).includes('XSRF-TOKEN')) {
150
+ COOKIE = cookie;
151
+ XSRF_TOKEN = await WeiboMainModels.readSavedCookieItems(cookie, ['XSRF-TOKEN'], false);
152
+ }
153
+ const resData = (await fetch('https://m.weibo.cn/api/config', {
154
+ method: 'GET',
155
+ headers: lodash.merge(WeiboApi.WEIBO_HEADERS, {
156
+ 'X-XSRF-TOKEN': `${XSRF_TOKEN}`,
157
+ 'Cookie': `${COOKIE}`,
158
+ 'Host': 'm.weibo.cn',
159
+ 'Referer': 'https://m.weibo.cn'
160
+ }),
161
+ redirect: 'follow'
162
+ }).then(res => res.json()));
163
+ global?.logger?.debug(`微博验证登录状态:${JSON.stringify(resData)}`);
164
+ if (resData.data?.login === true) {
165
+ const uid = Number(resData.data.uid);
166
+ const user_token = resData.data.user_token;
167
+ const infoRes = (await fetch(`https://m.weibo.cn/profile/info?uid=${uid}`, {
168
+ method: 'GET',
169
+ headers: lodash.merge(WeiboApi.WEIBO_HEADERS, {
170
+ 'X-XSRF-TOKEN': `${XSRF_TOKEN}`,
171
+ 'Cookie': `${COOKIE}`,
172
+ 'Host': 'm.weibo.cn',
173
+ 'x-h5-user-token': `${user_token}`,
174
+ 'Referer': `https://m.weibo.cn/profile/${uid}?user_token=${user_token}`
175
+ }),
176
+ redirect: 'follow'
177
+ }).then(res => res.json()));
178
+ let uname = infoRes.data?.user?.screen_name;
179
+ let mid = infoRes.data?.user?.id;
180
+ let follow_count = infoRes.data?.user?.follow_count;
181
+ let svip = infoRes.data?.user?.svip;
182
+ const cookie = await this.readLoginCookie();
183
+ const ALF = this.extractALFValue(cookie);
184
+ let TLL = 0;
185
+ if (ALF) {
186
+ TLL = Number(ALF) * 1000;
187
+ }
188
+ const EXP_TIME = moment(TLL * 1000).format('YYYY年MM月DD日 HH:mm:ss');
189
+ e.reply(`~微博账号已登陆~\n昵称:${uname}\nuid:${mid}\nsvip等级:${svip}\n关注:${follow_count}\n登录失效时间:${EXP_TIME}`);
190
+ }
191
+ else {
192
+ // 处理其他情况
193
+ e.reply('意外情况,未能获取微博登录ck的有效状态');
194
+ return;
195
+ }
196
+ }
197
+ }
198
+ /** 获取ALF值*/
199
+ static extractALFValue(cookieString) {
200
+ const match = cookieString.match(/ALF=(\d+)/);
201
+ if (match && match[1]) {
202
+ return parseInt(match[1], 10);
203
+ }
204
+ return null;
205
+ }
206
+ /**
207
+ * *******************************************************************
208
+ * cookie相关
209
+ * *******************************************************************
210
+ */
211
+ /**保存扫码登录的weiboLoginCK*/
212
+ static async saveLoginCookie(e, weiboLoginCk) {
213
+ if (weiboLoginCk && weiboLoginCk.length > 0) {
214
+ const weiboLoginCkKey = 'Yz:yuki:weibo:loginCookie';
215
+ Redis.set(weiboLoginCkKey, weiboLoginCk, { EX: 3600 * 24 * 300 });
216
+ }
217
+ else {
218
+ e.reply('扫码超时');
219
+ }
220
+ }
221
+ /** 读取扫码登陆后缓存的weiboCookie */
222
+ static async readLoginCookie() {
223
+ const CK_KEY = 'Yz:yuki:weibo:loginCookie';
224
+ const tempCk = await Redis.get(CK_KEY);
225
+ return tempCk ? tempCk : '';
226
+ }
227
+ /** 读取手动绑定的weibo CK */
228
+ static async readLocalBiliCk() {
229
+ const CK_KEY = 'Yz:yuki:weibo:localCookie';
230
+ const tempCk = await Redis.get(CK_KEY);
231
+ return tempCk ? tempCk : '';
232
+ }
233
+ /** 覆盖保存手动获取绑定的weibo ck */
234
+ static async saveLocalBiliCk(data) {
235
+ const weiboLoginCkKey = 'Yz:yuki:weibo:localCookie';
236
+ Redis.set(weiboLoginCkKey, data, { EX: 3600 * 24 * 300 });
237
+ }
238
+ /** 读取扫码登陆后缓存的weibo cookie的有效时间 */
239
+ static async readLoginCookieTTL() {
240
+ const CK_KEY = 'Yz:yuki:weibo:loginCookie';
241
+ const tempCk = await Redis.get(CK_KEY);
242
+ if (tempCk) {
243
+ const LoginCookieTTL = await Redis.ttl(CK_KEY);
244
+ return LoginCookieTTL;
245
+ }
246
+ else {
247
+ return -2;
248
+ }
249
+ }
250
+ /** 综合获取ck,返回优先级:localCK > loginCK */
251
+ static async readSyncCookie() {
252
+ const localCk = await this.readLocalBiliCk();
253
+ const loginCk = await this.readLoginCookie();
254
+ const validCk = (ck) => ck?.includes('SUB=') && ck?.includes('SUBP=');
255
+ if (validCk(localCk)) {
256
+ return { cookie: localCk, mark: 'localCk' };
257
+ }
258
+ else if (validCk(loginCk)) {
259
+ return { cookie: loginCk + ';', mark: 'loginCk' };
260
+ }
261
+ else {
262
+ return { cookie: '', mark: 'ckIsEmpty' };
263
+ }
264
+ }
265
+ /**
266
+ * 综合读取、筛选 传入的或本地或redis存储的cookie的item
267
+ * @param {string} mark 读取存储的CK类型,'localCK' 'loginCK' 或传入值 'xxx'并进行筛选
268
+ * @param {Array} items 选取获取CK的项 选全部值:items[0] = 'all' ,或选取其中的值 ['XSRF-TOKEN', 'SUB', 'SUBP', 'SRF', 'SCF', 'SRT', ' _T_WM', 'M_WEIBOCN_PARAMS', 'SSOLoginState','ALF']
269
+ * @param {boolean} isInverted 控制正取和反取,true为反取,默认为false正取
270
+ * @returns {string}
271
+ **/
272
+ static async readSavedCookieItems(mark, items, isInverted = false) {
273
+ let ckString;
274
+ switch (mark) {
275
+ case 'localCK':
276
+ ckString = await this.readLocalBiliCk();
277
+ break;
278
+ case 'loginCK':
279
+ ckString = await this.readLoginCookie();
280
+ break;
281
+ default:
282
+ ckString = mark;
283
+ }
284
+ const Wck = lodash.trim(ckString);
285
+ if (!Wck) {
286
+ return '';
287
+ }
288
+ if (items[0] === 'all') {
289
+ return Wck;
290
+ }
291
+ const cookiePairs = String(Wck)
292
+ .trim()
293
+ .match(/([a-zA-Z0-9_-]+)=([^;|,]+)/g) //正则 /(\w+)=([^;]+);/g 匹配 a=b 的内容,并分组为 [^;|,]+ 来匹配值,其中 [^;|,] 表示除了分号和,以外的任意字符
294
+ ?.map(match => match.split('='))
295
+ .filter(([key, value]) => (isInverted ? !items.includes(key) : items.includes(key)) && value !== '')
296
+ .map(([key, value]) => `${key}=${value}`)
297
+ .join(';') || '';
298
+ return cookiePairs;
299
+ }
300
+ // 取反读取ck、筛选 传入的或本地或redis存储的cookie的item
301
+ static async readSavedCookieOtherItems(mark, items) {
302
+ return await this.readSavedCookieItems(mark, items, true);
303
+ }
304
+ /**更新cookie */
305
+ static async updateCookieWithSetCookie(setCookieHeaders, mark) {
306
+ // 1. 读取当前保存的 Cookie
307
+ const currentCookie = await this.readLoginCookie();
308
+ // 使用 Record<string, string | undefined> 类型接收解析结果
309
+ const cookieObj = currentCookie ? parse(currentCookie) : {};
310
+ // 2. 解析 Set-Cookie 响应头并更新 Cookie 对象
311
+ setCookieHeaders.forEach(header => {
312
+ const parsedCookie = parse(header.split(';')[0]);
313
+ Object.entries(parsedCookie).forEach(([key, value]) => {
314
+ if (value === 'deleted') {
315
+ delete cookieObj[key];
316
+ }
317
+ else if (value !== undefined) {
318
+ // 添加类型守卫
319
+ cookieObj[key] = value;
320
+ }
321
+ });
322
+ });
323
+ // 3. 过滤掉 undefined 值并重新组合为字符串
324
+ const validCookies = {};
325
+ Object.entries(cookieObj).forEach(([key, value]) => {
326
+ if (value !== undefined) {
327
+ validCookies[key] = value;
328
+ }
329
+ });
330
+ const updatedCookie = Object.entries(validCookies)
331
+ .map(([key, value]) => serialize(key, value))
332
+ .join('; ');
333
+ // 4. 保存更新后的 Cookie
334
+ if (updatedCookie) {
335
+ let key = '';
336
+ if (mark === 'loginCK') {
337
+ key = 'Yz:yuki:weibo:loginCookie';
338
+ }
339
+ else if (mark === 'localCK') {
340
+ key = 'Yz:yuki:weibo:localCookie';
341
+ }
342
+ Redis.set(key, updatedCookie, { EX: 3600 * 24 * 300 });
343
+ }
344
+ }
345
+ }
346
+
347
+ export { WeiboMainModels };
@@ -156,7 +156,9 @@ class WeiboTask {
156
156
  if (getWhiteWords && Array.isArray(getWhiteWords) && getWhiteWords.length > 0) {
157
157
  // 构建白名单关键字正则表达式,转义特殊字符
158
158
  const whiteWords = new RegExp(getWhiteWords.map(word => word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'), 'g');
159
- if (!whiteWords.test(`${data?.title}${data?.content}`)) {
159
+ const content = `${data?.title}${data?.content}`;
160
+ if (!whiteWords.test(content)) {
161
+ logger.info(`博主 "${upName}" 微博动态:白名单关键词已开启,但动态消息未匹配,已跳过推送`);
160
162
  return; // 如果动态消息不在白名单中,则直接返回
161
163
  }
162
164
  }
@@ -166,8 +168,11 @@ class WeiboTask {
166
168
  if (getBanWords && Array.isArray(getBanWords) && getBanWords.length > 0) {
167
169
  // 构建屏蔽关键字正则表达式,转义特殊字符
168
170
  const banWords = new RegExp(getBanWords.map(word => word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'), 'g');
169
- if (banWords.test(`${data?.title}${data?.content}`)) {
170
- return 'return'; // 如果动态消息包含屏蔽关键字,则直接返回
171
+ const content = `${data?.title}${data?.content}`;
172
+ const matched = content.match(banWords);
173
+ if (matched) {
174
+ logger.info(`博主 "${upName}" 微博动态:触发屏蔽关键词 "${matched.join(', ')}" ,已跳过推送`);
175
+ return; // 如果动态消息包含屏蔽关键字,则直接返回
171
176
  }
172
177
  }
173
178
  else if (getBanWords && !Array.isArray(getBanWords)) {
@@ -210,6 +215,7 @@ class WeiboTask {
210
215
  // 构建白名单关键字正则表达式,转义特殊字符
211
216
  const whiteWords = new RegExp(getWhiteWords.map(word => word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'), 'g');
212
217
  if (!whiteWords.test(dynamicMsg.msg.join(''))) {
218
+ logger.info(`博主 "${upName}" 微博动态:白名单关键词已开启,但动态消息未匹配,已跳过推送`);
213
219
  return; // 如果动态消息不在白名单中,则直接返回
214
220
  }
215
221
  }
@@ -219,8 +225,11 @@ class WeiboTask {
219
225
  if (getBanWords && Array.isArray(getBanWords) && getBanWords.length > 0) {
220
226
  // 构建屏蔽关键字正则表达式,转义特殊字符
221
227
  const banWords = new RegExp(getBanWords.map(word => word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'), 'g');
222
- if (banWords.test(dynamicMsg.msg.join(''))) {
223
- return 'return'; // 如果动态消息包含屏蔽关键字,则直接返回
228
+ const content = dynamicMsg.msg.join('');
229
+ const matched = content.match(banWords);
230
+ if (matched) {
231
+ logger.info(`博主 "${upName}" 微博动态:触发屏蔽关键词 "${matched.join(', ')}" ,已跳过推送`);
232
+ return; // 如果动态消息包含屏蔽关键字,则直接返回
224
233
  }
225
234
  }
226
235
  else if (getBanWords && !Array.isArray(getBanWords)) {