koishi-plugin-wordpress-notifier 2.9.3 → 2.9.4

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/README.md CHANGED
@@ -205,6 +205,13 @@ npm install koishi-plugin-wordpress-notifier
205
205
 
206
206
  ## 版本历史
207
207
 
208
+ ### v2.9.4
209
+ - 🎉 **Bug 修复**:修复文章更新检测误判问题,仅使用修改时间判断,避免因哈希值变化导致所有文章被重复推送
210
+ - 🚀 **性能优化**:将文章检查数量从 20 篇减少到 10 篇,减少不必要的检查
211
+ - ✨ **功能完善**:完整实现新用户注册推送功能
212
+ - 📊 **用户体验**:添加详细的更新检测日志,便于调试和追踪
213
+ - 🔧 **代码优化**:改进更新检测逻辑,使用秒级时间戳比较,避免精度问题
214
+
208
215
  ### v2.9.3
209
216
  - 🎉 **并发控制**:使用 p-limit 替代手动队列,彻底解决线程安全问题
210
217
  - 🚀 **性能优化**:添加 10 秒缓存防抖,避免重复请求
package/lib/schedule.js CHANGED
@@ -52,7 +52,10 @@ class ScheduleService {
52
52
  const interval = (this.config.checkInterval || 30) * 60 * 1000;
53
53
  this.intervalId = setInterval(async () => {
54
54
  try {
55
+ // 检查文章更新
55
56
  await this.checkAndPushArticles();
57
+ // 检查新用户注册
58
+ await this.checkNewUsers();
56
59
  }
57
60
  catch (error) {
58
61
  this.ctx.logger.error('Error in scheduled task:', error);
@@ -178,8 +181,8 @@ class ScheduleService {
178
181
  if (!this.isPushTimeAllowed()) {
179
182
  return;
180
183
  }
181
- // 获取最新文章
182
- const articles = await this.wordpressService.getLatestPosts(20);
184
+ // 获取最新文章(只获取最新的 10 篇,减少不必要的检查)
185
+ const articles = await this.wordpressService.getLatestPosts(10);
183
186
  if (articles.length === 0) {
184
187
  this.ctx.logger.info('暂无新文章');
185
188
  return;
@@ -230,17 +233,24 @@ class ScheduleService {
230
233
  if (pushedArticle) {
231
234
  const currentModified = new Date(article.modified || article.date);
232
235
  const storedModified = new Date(pushedArticle.modified);
233
- const currentHash = this.pushService.generateHash(JSON.stringify(article));
234
- // 检查是否有更新
235
- if (currentModified > storedModified || currentHash !== pushedArticle.hash) {
236
+ // 修复:仅比较修改时间,移除哈希值比较,避免因动态字段变化导致误判
237
+ // 使用时间戳比较,忽略毫秒级差异,避免因时间精度导致误判
238
+ const currentTime = Math.floor(currentModified.getTime() / 1000); // 秒级时间戳
239
+ const storedTime = Math.floor(storedModified.getTime() / 1000);
240
+ // 检查是否有更新(仅当修改时间真正发生变化时才推送)
241
+ if (currentTime > storedTime) {
242
+ this.ctx.logger.info(`检测到文章 ${article.id} 有更新,修改时间从 ${storedModified.toISOString()} 变更为 ${currentModified.toISOString()}`);
236
243
  // 推送更新通知
237
244
  const success = await this.pushService.pushArticleUpdate(article, groupId);
238
245
  if (success) {
239
246
  // 更新存储的修改时间和哈希值
240
- await this.storageService.updatePushedArticle(article.id, groupId, currentModified, currentHash);
247
+ await this.storageService.updatePushedArticle(article.id, groupId, currentModified, this.pushService.generateHash(JSON.stringify(article)));
241
248
  this.ctx.logger.info(`已推送文章 ${article.id} 的更新到群聊 ${groupId}`);
242
249
  }
243
250
  }
251
+ else {
252
+ this.ctx.logger.debug(`文章 ${article.id} 无更新,跳过`);
253
+ }
244
254
  }
245
255
  }
246
256
  }
@@ -289,13 +299,70 @@ class ScheduleService {
289
299
  }
290
300
  // 检查新用户注册
291
301
  async checkNewUsers() {
292
- // 模拟实现
293
- this.ctx.logger.info('检查新用户注册');
302
+ try {
303
+ // 检查是否启用用户注册推送
304
+ if (!this.config.enableUserRegisterPush) {
305
+ return;
306
+ }
307
+ // 获取最新注册的用户(最近10个)
308
+ const users = await this.wordpressService.getLatestUsers(10);
309
+ if (users.length === 0) {
310
+ this.ctx.logger.info('暂无新用户注册');
311
+ return;
312
+ }
313
+ // 获取所有启用推送的群聊
314
+ const groups = await this.storageService.getEnabledGroups();
315
+ if (groups.length === 0) {
316
+ this.ctx.logger.info('没有启用推送的群聊');
317
+ return;
318
+ }
319
+ this.ctx.logger.info(`检查 ${users.length} 个新用户,推送至 ${groups.length} 个群聊`);
320
+ // 收集所有推送任务
321
+ const pushTasks = [];
322
+ // 检查每个用户
323
+ for (const user of users) {
324
+ for (const groupId of groups) {
325
+ pushTasks.push(async () => {
326
+ try {
327
+ // 记录用户并检查是否为新用户
328
+ const isNewUser = await this.storageService.recordWpUser(user.id, user.name, new Date(user.registered_date));
329
+ if (isNewUser) {
330
+ // 获取未通知的用户
331
+ const unnotifiedUsers = await this.storageService.getUnnotifiedWpUsers();
332
+ // 为每个未通知的用户推送
333
+ for (const unnotifiedUser of unnotifiedUsers) {
334
+ const success = await this.pushService.pushUserRegister(unnotifiedUser, groupId);
335
+ if (success) {
336
+ // 标记为已通知
337
+ await this.storageService.markWpUserNotified(unnotifiedUser.wpUserId);
338
+ this.ctx.logger.info(`已推送新用户 ${unnotifiedUser.username} 到群聊 ${groupId}`);
339
+ }
340
+ else {
341
+ this.ctx.logger.warn(`推送新用户 ${unnotifiedUser.username} 到群聊 ${groupId} 失败`);
342
+ }
343
+ }
344
+ }
345
+ }
346
+ catch (error) {
347
+ this.ctx.logger.error(`处理用户 ${user.id} 注册推送失败:`, error);
348
+ }
349
+ });
350
+ }
351
+ }
352
+ // 执行推送任务
353
+ const result = await this.executeWithConcurrencyLimit(pushTasks);
354
+ // 记录推送统计
355
+ this.ctx.logger.info(`新用户注册推送完成:成功 ${result.success} 次,失败 ${result.failed} 次`);
356
+ }
357
+ catch (error) {
358
+ this.ctx.logger.error('检查新用户注册失败:', error);
359
+ }
294
360
  }
295
361
  // 手动触发检查
296
362
  async triggerCheck() {
297
363
  try {
298
364
  await this.checkAndPushArticles();
365
+ await this.checkNewUsers();
299
366
  }
300
367
  catch (error) {
301
368
  this.ctx.logger.error('Error triggering check:', error);
@@ -91,6 +91,7 @@ export declare class WordPressService {
91
91
  private cleanupCache;
92
92
  getLatestPosts(perPage?: number, page?: number): Promise<WordPressPost[]>;
93
93
  getPostById(id: number): Promise<WordPressPost>;
94
+ getLatestUsers(perPage?: number, page?: number): Promise<any[]>;
94
95
  getStatus(): {
95
96
  wordpressUrl: string;
96
97
  apiEndpoint: string;
package/lib/wordpress.js CHANGED
@@ -393,6 +393,40 @@ class WordPressService {
393
393
  throw error;
394
394
  }
395
395
  }
396
+ // 获取最新注册的用户
397
+ async getLatestUsers(perPage = 10, page = 1) {
398
+ this.stats.commandCount++;
399
+ const cacheKey = `latest-users-${perPage}-${page}`;
400
+ const cachedData = this.getCache(cacheKey);
401
+ if (cachedData) {
402
+ return cachedData;
403
+ }
404
+ try {
405
+ // 获取最新注册的用户
406
+ const requestParams = {
407
+ per_page: Math.min(perPage, 100),
408
+ page: Math.max(1, page),
409
+ orderby: 'registered_date',
410
+ order: 'desc'
411
+ };
412
+ const response = await this.executeWithConcurrencyControl(() => this.client.get(`${this.config.apiEndpoint || '/wp-json/wp/v2'}/users`, {
413
+ params: requestParams
414
+ }), { method: 'GET', params: requestParams });
415
+ const users = response.data.map((user) => ({
416
+ id: user.id,
417
+ name: user.name,
418
+ registered_date: user.registered_date,
419
+ email: user.email,
420
+ link: user.link
421
+ }));
422
+ this.setCache(cacheKey, users);
423
+ return users;
424
+ }
425
+ catch (error) {
426
+ this.logError('Failed to get latest users:', error);
427
+ throw error;
428
+ }
429
+ }
396
430
  // 获取服务状态
397
431
  getStatus() {
398
432
  const successRate = this.stats.totalRequests > 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koishi-plugin-wordpress-notifier",
3
- "version": "2.9.3",
3
+ "version": "2.9.4",
4
4
  "description": "WordPress 文章自动推送插件",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",