koishi-plugin-wordpress-notifier 2.5.3 → 2.5.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/lib/index.d.ts CHANGED
@@ -5,7 +5,6 @@ declare module 'koishi' {
5
5
  interface Tables {
6
6
  wordpress_post_updates: WordPressPostUpdateRecord;
7
7
  wordpress_user_registrations: WordPressUserRegistrationRecord;
8
- wordpress_group_pushes: WordPressGroupPushRecord;
9
8
  }
10
9
  }
11
10
  export interface Config {
@@ -61,13 +60,6 @@ export interface WordPressUserRegistrationRecord {
61
60
  userId: number;
62
61
  pushedAt: Date;
63
62
  }
64
- export interface WordPressGroupPushRecord {
65
- id: number;
66
- groupId: string;
67
- postId: number;
68
- pushedAt: Date;
69
- isUpdate: boolean;
70
- }
71
63
  export interface WordPressNotification {
72
64
  type: 'post' | 'update' | 'user';
73
65
  data: any;
package/lib/index.js CHANGED
@@ -15,7 +15,7 @@ exports.Config = koishi_1.Schema.object({
15
15
  mentionAll: koishi_1.Schema.boolean().default(false).description('是否 @全体成员'),
16
16
  maxArticles: koishi_1.Schema.number().default(5).description('每次最多推送的文章数量'),
17
17
  username: koishi_1.Schema.string().default('').description('WordPress 用户名(用于 Basic 认证,与应用程序密码配合使用)'),
18
- applicationPassword: koishi_1.Schema.string().default('').description('WordPress 应用程序密码(用于 Basic 认证,例如:hGR2sPFuYnclxHc4AvJqcUtB)'),
18
+ applicationPassword: koishi_1.Schema.string().default('').description('WordPress 应用程序密码(用于 Basic 认证,例如:hGR2sPFuYnclxHc4AvJq cUtB)'),
19
19
  superAdmins: koishi_1.Schema.array(koishi_1.Schema.string()).default([]).description('超级管理员 QQ 号列表')
20
20
  });
21
21
  function apply(ctx, config) {
@@ -42,19 +42,6 @@ function apply(ctx, config) {
42
42
  autoInc: true,
43
43
  unique: ['userId']
44
44
  });
45
- ctx.model.extend('wordpress_group_pushes', {
46
- id: 'integer',
47
- groupId: 'string',
48
- postId: 'integer',
49
- pushedAt: 'timestamp',
50
- isUpdate: 'boolean'
51
- }, {
52
- primary: 'id',
53
- autoInc: true,
54
- unique: ['groupId', 'postId']
55
- });
56
- // 确保所有插入操作都不手动指定 id 字段,让数据库自动生成
57
- // Koishi 框架的 autoInc: true 配置会自动处理自增主键
58
45
  ctx.logger.info('数据库表配置完成,autoInc: true 已启用,确保插入操作不手动指定 id 字段');
59
46
  // 为所有数据库操作添加详细日志,便于诊断自增主键问题
60
47
  ctx.on('ready', async () => {
@@ -62,9 +49,26 @@ function apply(ctx, config) {
62
49
  ctx.logger.info('数据库表配置:');
63
50
  ctx.logger.info('wordpress_post_updates: id 字段设置为 autoInc: true');
64
51
  ctx.logger.info('wordpress_user_registrations: id 字段设置为 autoInc: true');
65
- ctx.logger.info('wordpress_group_pushes: id 字段设置为 autoInc: true');
66
- ctx.logger.info('插件将确保所有插入操作不手动指定 id 字段,让数据库自动生成');
52
+ ctx.logger.info('所有群聊共用一个文章标记,不再区分群聊');
53
+ // 检查并修复数据库表结构问题
54
+ await checkAndFixTableStructure();
55
+ // 执行初始推送
56
+ await pushNewPosts();
67
57
  });
58
+ // 检查数据库表结构的函数
59
+ async function checkAndFixTableStructure() {
60
+ try {
61
+ ctx.logger.info('开始检查数据库表结构...');
62
+ ctx.logger.info('所有群聊现在共用一个文章标记,不再区分群聊');
63
+ ctx.logger.info('wordpress_group_pushes 表已不再使用,已移除相关功能');
64
+ ctx.logger.info('表结构检查和修复完成');
65
+ }
66
+ catch (error) {
67
+ const errorMessage = error instanceof Error ? error.message : String(error);
68
+ ctx.logger.error(`检查表结构失败:${errorMessage}`);
69
+ ctx.logger.error(`错误栈:${error instanceof Error ? error.stack : '无'}`);
70
+ }
71
+ }
68
72
  async function fetchLatestPosts() {
69
73
  try {
70
74
  const url = `${config.wordpressUrl}/wp-json/wp/v2/posts?per_page=${config.maxArticles}&orderby=date&order=desc`;
@@ -181,28 +185,6 @@ function apply(ctx, config) {
181
185
  return null;
182
186
  }
183
187
  }
184
- async function isGroupPushed(groupId, postId) {
185
- try {
186
- // 明确查询 groupId + postId 组合是否存在
187
- const query = { groupId, postId };
188
- ctx.logger.info(`检查群 ${groupId} 是否已推送文章 ${postId},查询条件:${JSON.stringify(query)}`);
189
- const records = await ctx.database.get('wordpress_group_pushes', query);
190
- const result = records.length > 0;
191
- ctx.logger.info(`检查群 ${groupId} 是否已推送文章 ${postId}:${result ? '是' : '否'}`);
192
- // 添加调试日志,显示所有相关记录
193
- if (records.length > 0) {
194
- ctx.logger.debug(`找到 ${records.length} 条匹配记录:${JSON.stringify(records)}`);
195
- }
196
- return result;
197
- }
198
- catch (error) {
199
- const errorMessage = error instanceof Error ? error.message : String(error);
200
- ctx.logger.error(`检查推送记录失败:${errorMessage}`);
201
- ctx.logger.error(`错误栈:${error instanceof Error ? error.stack : '无'}`);
202
- // 发生错误时,默认返回 false,避免阻塞推送流程
203
- return false;
204
- }
205
- }
206
188
  async function markUserAsPushed(userId) {
207
189
  try {
208
190
  ctx.logger.info(`开始标记用户已推送,用户 ID: ${userId}`);
@@ -257,69 +239,6 @@ function apply(ctx, config) {
257
239
  throw error;
258
240
  }
259
241
  }
260
- async function markGroupAsPushed(groupId, postId, isUpdate) {
261
- try {
262
- ctx.logger.info(`开始标记群 ${groupId} 已推送文章 ${postId}`);
263
- // 1. 获取当前表中的所有记录,检查是否有相同 groupId 的不同 postId 记录
264
- const allGroupRecords = await ctx.database.get('wordpress_group_pushes', { groupId });
265
- ctx.logger.info(`群 ${groupId} 已有 ${allGroupRecords.length} 条推送记录`);
266
- if (allGroupRecords.length > 0) {
267
- ctx.logger.info(`已有记录示例:${JSON.stringify(allGroupRecords.slice(0, 2))}`);
268
- }
269
- // 2. 检查是否已存在该 groupId + postId 的组合
270
- const existingRecords = await ctx.database.get('wordpress_group_pushes', { groupId, postId });
271
- ctx.logger.info(`检查结果:群 ${groupId} 已推送文章 ${postId}:${existingRecords.length > 0 ? '是' : '否'}`);
272
- // 3. 创建新记录,不删除旧记录(除非是同篇文章的更新)
273
- const newRecord = {
274
- groupId,
275
- postId,
276
- pushedAt: new Date(),
277
- isUpdate
278
- };
279
- ctx.logger.info(`准备创建新记录:${JSON.stringify(newRecord)}`);
280
- await ctx.database.create('wordpress_group_pushes', newRecord);
281
- ctx.logger.info(`已创建新记录,群 ${groupId},文章 ${postId}`);
282
- // 4. 写入后验证,确保记录真正存入数据库
283
- const verification = await ctx.database.get('wordpress_group_pushes', { groupId, postId });
284
- if (verification.length > 0) {
285
- ctx.logger.info(`记录写入验证成功,群 ${groupId},文章 ${postId}`);
286
- // 验证后再次检查该群的所有记录
287
- const updatedAllGroupRecords = await ctx.database.get('wordpress_group_pushes', { groupId });
288
- ctx.logger.info(`群 ${groupId} 现在共有 ${updatedAllGroupRecords.length} 条推送记录`);
289
- }
290
- else {
291
- ctx.logger.error(`记录写入验证失败,群 ${groupId},文章 ${postId}`);
292
- }
293
- }
294
- catch (error) {
295
- // 处理唯一约束冲突错误
296
- const errorMessage = error instanceof Error ? error.message : String(error);
297
- ctx.logger.error(`标记推送记录失败:${errorMessage}`);
298
- ctx.logger.error(`错误栈:${error instanceof Error ? error.stack : '无'}`);
299
- ctx.logger.error(`插入参数:groupId=${groupId}, postId=${postId}, isUpdate=${isUpdate}`);
300
- // 详细记录错误信息,便于诊断
301
- if (errorMessage.includes('UNIQUE constraint failed')) {
302
- ctx.logger.error(`唯一约束冲突,可能的原因:`);
303
- ctx.logger.error(`1. 数据库表的 unique 约束设置错误,可能只针对 groupId 而不是 groupId+postId 组合`);
304
- ctx.logger.error(`2. 同一篇文章被多次推送`);
305
- ctx.logger.error(`3. 数据库表结构与模型定义不符`);
306
- // 尝试获取表结构信息(如果可能)
307
- try {
308
- const allRecords = await ctx.database.get('wordpress_group_pushes', {});
309
- ctx.logger.error(`当前表中共有 ${allRecords.length} 条记录`);
310
- if (allRecords.length > 0) {
311
- ctx.logger.error(`前 3 条记录:${JSON.stringify(allRecords.slice(0, 3))}`);
312
- }
313
- }
314
- catch (e) {
315
- ctx.logger.error(`获取表记录失败:${e}`);
316
- }
317
- }
318
- else {
319
- ctx.logger.error(`非约束冲突错误,插件将继续运行`);
320
- }
321
- }
322
- }
323
242
  function formatPostMessage(post, mention = false, isUpdate = false) {
324
243
  // 彻底过滤 HTML 标签和非法字符,只保留安全文本
325
244
  const sanitizeText = (text) => {
@@ -339,7 +258,7 @@ function apply(ctx, config) {
339
258
  }
340
259
  // 合并为单段文本,提升适配器兼容性
341
260
  const messageType = isUpdate ? '📝 文章更新' : '📝 新文章';
342
- const messageDate = isUpdate ? `📅 发布: ${date}\n 更新: ${modifiedDate}` : `� ${date}`;
261
+ const messageDate = isUpdate ? `📅 发布: ${date}\n🔄 更新: ${modifiedDate}` : `📅 ${date}`;
343
262
  const message = `${messageType}\n${messageDate}\n📄 ${excerpt}...\n🔗 ${post.link}`;
344
263
  segments.push(koishi_1.h.text(message));
345
264
  return segments;
@@ -448,31 +367,33 @@ function apply(ctx, config) {
448
367
  for (const post of posts) {
449
368
  ctx.logger.info(`正在处理文章: ${post.id} - ${post.title.rendered}`);
450
369
  ctx.logger.info(`文章 ID: ${post.id}, 发布时间: ${post.date}, 修改时间: ${post.modified}`);
451
- for (const target of config.targets) {
452
- try {
453
- ctx.logger.info(`正在处理目标: ${target}`);
454
- // 直接使用原始目标字符串,不进行数字转换,避免丢失平台前缀等信息
455
- const stringTarget = target;
456
- // 检查该群是否已推送过此文章
457
- const hasPushed = await isGroupPushed(stringTarget, post.id);
458
- ctx.logger.info(`检查结果: 群 ${stringTarget} 已推送文章 ${post.id}:${hasPushed ? '是' : '否'}`);
459
- if (!hasPushed) {
370
+ // 检查文章是否已推送过(所有群聊共用一个标记)
371
+ const postRecord = await getPostUpdateRecord(post.id);
372
+ const hasPushed = !!postRecord;
373
+ ctx.logger.info(`检查结果: 文章 ${post.id} 是否已推送:${hasPushed ? '是' : '否'}`);
374
+ if (!hasPushed) {
375
+ // 推送到所有目标群聊
376
+ for (const target of config.targets) {
377
+ try {
378
+ ctx.logger.info(`正在处理目标: ${target}`);
379
+ // 直接使用原始目标字符串,不进行数字转换,避免丢失平台前缀等信息
380
+ const stringTarget = target;
460
381
  const segments = formatPostMessage(post, true, false);
461
382
  ctx.logger.info(`准备推送新文章到目标: ${stringTarget}`);
462
383
  await bot.sendMessage(stringTarget, segments);
463
384
  ctx.logger.info(`已推送新文章到 ${stringTarget}: ${post.title.rendered}`);
464
- // 标记该群已推送此文章
465
- await markGroupAsPushed(stringTarget, post.id, false);
466
- ctx.logger.info(`已标记群 ${stringTarget} 已推送文章 ${post.id}`);
467
385
  }
468
- else {
469
- ctx.logger.info(`跳过推送: ${stringTarget} 已推送过文章 ${post.id}`);
386
+ catch (error) {
387
+ ctx.logger.error(`推送新文章到 ${target} 失败: ${error}`);
388
+ ctx.logger.error(`错误详情: ${JSON.stringify(error)}`);
470
389
  }
471
390
  }
472
- catch (error) {
473
- ctx.logger.error(`推送新文章到 ${target} 失败: ${error}`);
474
- ctx.logger.error(`错误详情: ${JSON.stringify(error)}`);
475
- }
391
+ // 标记文章已推送(所有群聊共用一个标记)
392
+ await updatePostUpdateRecord(post.id, new Date(post.modified));
393
+ ctx.logger.info(`已标记文章 ${post.id} 为已推送,所有群聊将不再推送此文章`);
394
+ }
395
+ else {
396
+ ctx.logger.info(`跳过推送: 文章 ${post.id} 已推送过,所有群聊将不再推送`);
476
397
  }
477
398
  }
478
399
  }
@@ -485,29 +406,26 @@ function apply(ctx, config) {
485
406
  const updateRecord = await getPostUpdateRecord(post.id);
486
407
  const postModifiedDate = new Date(post.modified);
487
408
  // 检查文章是否有更新
488
- if (!updateRecord || postModifiedDate > new Date(updateRecord.lastModified)) {
409
+ if (updateRecord && postModifiedDate > new Date(updateRecord.lastModified)) {
410
+ ctx.logger.info(`文章 ${post.id} 有更新,准备推送更新通知`);
411
+ // 推送到所有目标群聊
489
412
  for (const target of config.targets) {
490
413
  try {
491
414
  ctx.logger.info(`正在处理目标: ${target}`);
492
- // 直接使用原始目标字符串,与新文章推送逻辑保持一致
493
415
  const stringTarget = target;
494
- // 检查该群是否已推送过此文章
495
- if (await isGroupPushed(stringTarget, post.id)) {
496
- const segments = formatPostMessage(post, true, true);
497
- ctx.logger.info(`准备推送文章更新到目标: ${stringTarget}`);
498
- await bot.sendMessage(stringTarget, segments);
499
- ctx.logger.info(`已推送文章更新到 ${stringTarget}: ${post.title.rendered}`);
500
- // 更新该群推送记录
501
- await markGroupAsPushed(stringTarget, post.id, true);
502
- }
416
+ const segments = formatPostMessage(post, true, true);
417
+ ctx.logger.info(`准备推送文章更新到目标: ${stringTarget}`);
418
+ await bot.sendMessage(stringTarget, segments);
419
+ ctx.logger.info(`已推送文章更新到 ${stringTarget}: ${post.title.rendered}`);
503
420
  }
504
421
  catch (error) {
505
422
  ctx.logger.error(`推送文章更新到 ${target} 失败: ${error}`);
506
423
  ctx.logger.error(`错误详情: ${JSON.stringify(error)}`);
507
424
  }
508
425
  }
509
- // 更新文章更新记录
426
+ // 更新文章更新记录(所有群聊共用一个标记)
510
427
  await updatePostUpdateRecord(post.id, postModifiedDate);
428
+ ctx.logger.info(`已更新文章 ${post.id} 的推送记录,所有群聊将使用此更新时间作为新的推送基准`);
511
429
  }
512
430
  }
513
431
  }
@@ -689,8 +607,8 @@ ${targetText}
689
607
  ctx.command('wordpress.pushed', '查看已推送的文章列表')
690
608
  .action(async () => {
691
609
  ctx.logger.info('命令 wordpress.pushed 被调用');
692
- // 获取已推送的文章记录,使用 wordpress_group_pushes
693
- const records = await ctx.database.get('wordpress_group_pushes', {}, {
610
+ // 获取已推送的文章记录,使用 wordpress_post_updates
611
+ const records = await ctx.database.get('wordpress_post_updates', {}, {
694
612
  sort: {
695
613
  pushedAt: 'desc'
696
614
  }
@@ -700,7 +618,7 @@ ${targetText}
700
618
  }
701
619
  let message = '📋 已推送文章列表(按时间倒序):\n\n';
702
620
  for (const record of records) {
703
- message += `${record.id}. 文章 ID: ${record.postId}(群:${record.groupId},${record.isUpdate ? '更新' : '新文章'})\n`;
621
+ message += `${record.id}. 文章 ID: ${record.postId}\n`;
704
622
  message += `📅 推送时间: ${new Date(record.pushedAt).toLocaleString('zh-CN')}\n\n`;
705
623
  }
706
624
  return message;
@@ -731,7 +649,6 @@ ${targetText}
731
649
  // 获取所有记录
732
650
  const allUpdateRecords = await ctx.database.get('wordpress_post_updates', {});
733
651
  const allUserRecords = await ctx.database.get('wordpress_user_registrations', {});
734
- const allGroupRecords = await ctx.database.get('wordpress_group_pushes', {});
735
652
  // 筛选需要删除的记录
736
653
  const updateRecordsToRemove = allUpdateRecords.filter(record => {
737
654
  return new Date(record.pushedAt) < cutoffDate;
@@ -739,9 +656,6 @@ ${targetText}
739
656
  const userRecordsToRemove = allUserRecords.filter(record => {
740
657
  return new Date(record.pushedAt) < cutoffDate;
741
658
  });
742
- const groupRecordsToRemove = allGroupRecords.filter(record => {
743
- return new Date(record.pushedAt) < cutoffDate;
744
- });
745
659
  // 删除旧记录
746
660
  let result = 0;
747
661
  for (const record of updateRecordsToRemove) {
@@ -752,10 +666,6 @@ ${targetText}
752
666
  await ctx.database.remove('wordpress_user_registrations', { id: record.id });
753
667
  result++;
754
668
  }
755
- for (const record of groupRecordsToRemove) {
756
- await ctx.database.remove('wordpress_group_pushes', { id: record.id });
757
- result++;
758
- }
759
669
  ctx.logger.info(`已清理 ${result} 条 ${daysToKeep} 天前的推送记录`);
760
670
  return `已清理 ${result} 条 ${daysToKeep} 天前的推送记录`;
761
671
  });
@@ -778,10 +688,6 @@ ${targetText}
778
688
 
779
689
  💡 提示:所有命令都需要加 / 前缀`;
780
690
  });
781
- ctx.on('ready', async () => {
782
- ctx.logger.info('WordPress 推送插件已就绪');
783
- await pushNewPosts();
784
- });
785
691
  ctx.setInterval(() => {
786
692
  pushNewPosts();
787
693
  }, config.interval);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koishi-plugin-wordpress-notifier",
3
- "version": "2.5.3",
3
+ "version": "2.5.5",
4
4
  "description": "WordPress 文章自动推送到 QQ",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",