koishi-plugin-imx 2.2.2 → 2.2.3

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
@@ -9,12 +9,16 @@ export interface Config {
9
9
  secret?: string;
10
10
  path?: string;
11
11
  watchChannels?: string[];
12
+ broadcastToAll?: boolean;
13
+ excludeChannels?: string[];
12
14
  };
13
15
  greeting?: {
14
16
  enabled?: boolean;
15
17
  channels?: string[];
16
18
  morningTime?: string;
17
19
  eveningTime?: string;
20
+ broadcastToAll?: boolean;
21
+ excludeChannels?: string[];
18
22
  };
19
23
  commands?: {
20
24
  enabled?: boolean;
@@ -35,6 +39,8 @@ export interface Config {
35
39
  roomId?: string;
36
40
  watchChannels?: string[];
37
41
  checkInterval?: number;
42
+ broadcastToAll?: boolean;
43
+ excludeChannels?: string[];
38
44
  };
39
45
  userAgent?: string;
40
46
  };
@@ -44,6 +50,8 @@ export interface Config {
44
50
  secret?: string;
45
51
  path?: string;
46
52
  watchChannels?: string[];
53
+ broadcastToAll?: boolean;
54
+ excludeChannels?: string[];
47
55
  };
48
56
  };
49
57
  shared?: {
package/lib/index.js CHANGED
@@ -50,12 +50,16 @@ exports.Config = koishi_1.Schema.object({
50
50
  secret: koishi_1.Schema.string().description('MX Space Webhook Secret').role('secret'),
51
51
  path: koishi_1.Schema.string().description('Webhook 路径').default('/mx-space/webhook'),
52
52
  watchChannels: koishi_1.Schema.array(koishi_1.Schema.string()).description('监听的频道ID列表').default([]),
53
+ broadcastToAll: koishi_1.Schema.boolean().description('是否广播到所有联系人').default(false),
54
+ excludeChannels: koishi_1.Schema.array(koishi_1.Schema.string()).description('排除的频道ID列表(当启用广播到所有联系人时)').default([]),
53
55
  }).description('Webhook 配置'),
54
56
  greeting: koishi_1.Schema.object({
55
57
  enabled: koishi_1.Schema.boolean().description('启用问候功能').default(true),
56
58
  channels: koishi_1.Schema.array(koishi_1.Schema.string()).description('问候消息发送的频道').default([]),
57
59
  morningTime: koishi_1.Schema.string().description('早安时间 (cron格式)').default('0 0 6 * * *'),
58
60
  eveningTime: koishi_1.Schema.string().description('晚安时间 (cron格式)').default('0 0 22 * * *'),
61
+ broadcastToAll: koishi_1.Schema.boolean().description('是否广播问候消息到所有联系人').default(false),
62
+ excludeChannels: koishi_1.Schema.array(koishi_1.Schema.string()).description('排除的频道ID列表(当启用广播到所有联系人时)').default([]),
59
63
  }).description('问候功能配置'),
60
64
  commands: koishi_1.Schema.object({
61
65
  enabled: koishi_1.Schema.boolean().description('启用命令功能').default(true),
@@ -76,6 +80,8 @@ exports.Config = koishi_1.Schema.object({
76
80
  roomId: koishi_1.Schema.string().description('B站直播间房间号'),
77
81
  watchChannels: koishi_1.Schema.array(koishi_1.Schema.string()).description('监听的频道ID列表').default([]),
78
82
  checkInterval: koishi_1.Schema.number().description('检查间隔(分钟)').default(1).min(1).max(10),
83
+ broadcastToAll: koishi_1.Schema.boolean().description('是否广播到所有联系人').default(false),
84
+ excludeChannels: koishi_1.Schema.array(koishi_1.Schema.string()).description('排除的频道ID列表(当启用广播到所有联系人时)').default([]),
79
85
  }).description('直播间监控配置'),
80
86
  userAgent: koishi_1.Schema.string().description('User-Agent').default('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'),
81
87
  }).description('Bilibili 配置'),
@@ -85,6 +91,8 @@ exports.Config = koishi_1.Schema.object({
85
91
  secret: koishi_1.Schema.string().description('GitHub Webhook Secret').role('secret'),
86
92
  path: koishi_1.Schema.string().description('Webhook 路径').default('/github/webhook'),
87
93
  watchChannels: koishi_1.Schema.array(koishi_1.Schema.string()).description('监听的频道ID列表').default([]),
94
+ broadcastToAll: koishi_1.Schema.boolean().description('是否广播到所有联系人').default(false),
95
+ excludeChannels: koishi_1.Schema.array(koishi_1.Schema.string()).description('排除的频道ID列表(当启用广播到所有联系人时)').default([]),
88
96
  }).description('GitHub Webhook 配置'),
89
97
  }).description('GitHub 配置'),
90
98
  shared: koishi_1.Schema.object({
@@ -5,6 +5,8 @@ export interface Config {
5
5
  roomIds?: number[];
6
6
  watchChannels?: string[];
7
7
  checkInterval?: number;
8
+ broadcastToAll?: boolean;
9
+ excludeChannels?: string[];
8
10
  }
9
11
  export declare const Config: Schema<Config>;
10
12
  export declare function apply(ctx: Context, config: Config): void;
@@ -8,12 +8,15 @@ exports.apply = apply;
8
8
  const koishi_1 = require("koishi");
9
9
  const axios_1 = __importDefault(require("axios"));
10
10
  const axios_error_1 = require("../utils/axios-error");
11
+ const broadcast_1 = require("../utils/broadcast");
11
12
  exports.name = 'bilibili';
12
13
  exports.Config = koishi_1.Schema.object({
13
14
  enabled: koishi_1.Schema.boolean().description('启用 Bilibili 直播监控').default(false),
14
15
  roomIds: koishi_1.Schema.array(koishi_1.Schema.number()).description('监控的直播间ID列表').default([]),
15
16
  watchChannels: koishi_1.Schema.array(koishi_1.Schema.string()).description('推送通知的频道ID列表').default([]),
16
17
  checkInterval: koishi_1.Schema.number().description('检查间隔(分钟)').default(5).min(1).max(60),
18
+ broadcastToAll: koishi_1.Schema.boolean().description('是否广播到所有联系人').default(false),
19
+ excludeChannels: koishi_1.Schema.array(koishi_1.Schema.string()).description('排除的频道ID列表(当启用广播到所有联系人时)').default([]),
17
20
  });
18
21
  const liveStatusCache = new Map();
19
22
  function apply(ctx, config) {
@@ -64,7 +67,11 @@ async function checkLiveStatus(ctx, config, logger) {
64
67
  const roomInfo = await (0, axios_error_1.axiosRequestWithLog)(logger, () => getRoomInfo(roomId), `获取房间 ${roomId} 信息`);
65
68
  if (roomInfo) {
66
69
  const message = formatLiveMessage(roomInfo);
67
- await sendToChannels(ctx, config.watchChannels, message, logger);
70
+ await (0, broadcast_1.sendMessage)(ctx, message, {
71
+ watchChannels: config.watchChannels,
72
+ broadcastToAll: config.broadcastToAll,
73
+ excludeChannels: config.excludeChannels,
74
+ }, logger);
68
75
  }
69
76
  }
70
77
  liveStatusCache.set(roomId, isLive);
@@ -86,14 +93,3 @@ function formatLiveMessage(roomInfo) {
86
93
  `🔗 https://live.bilibili.com/${roomInfo.room_id}`,
87
94
  ].join('\n');
88
95
  }
89
- async function sendToChannels(ctx, channels, message, logger) {
90
- for (const channelId of channels) {
91
- try {
92
- await ctx.broadcast([channelId], message);
93
- }
94
- catch (error) {
95
- const simplified = (0, axios_error_1.simplifyAxiosError)(error, `发送消息到频道 ${channelId}`);
96
- logger.warn(simplified.message);
97
- }
98
- }
99
- }
@@ -8,12 +8,16 @@ export interface Config {
8
8
  secret?: string;
9
9
  path?: string;
10
10
  watchChannels?: string[];
11
+ broadcastToAll?: boolean;
12
+ excludeChannels?: string[];
11
13
  };
12
14
  greeting?: {
13
15
  enabled?: boolean;
14
16
  channels?: string[];
15
17
  morningTime?: string;
16
18
  eveningTime?: string;
19
+ broadcastToAll?: boolean;
20
+ excludeChannels?: string[];
17
21
  };
18
22
  commands?: {
19
23
  enabled?: boolean;
@@ -49,6 +49,7 @@ const mx_api_1 = require("../utils/mx-api");
49
49
  const mx_url_builder_1 = require("../utils/mx-url-builder");
50
50
  const mx_event_handler_1 = require("../utils/mx-event-handler");
51
51
  const axios_error_1 = require("../utils/axios-error");
52
+ const broadcast_1 = require("../utils/broadcast");
52
53
  dayjs_1.default.extend(relativeTime_1.default);
53
54
  exports.name = 'mx-space';
54
55
  exports.inject = ['server'];
@@ -59,12 +60,16 @@ exports.Config = koishi_1.Schema.object({
59
60
  secret: koishi_1.Schema.string().description('MX Space Webhook Secret').role('secret'),
60
61
  path: koishi_1.Schema.string().description('Webhook 路径').default('/mx-space/webhook'),
61
62
  watchChannels: koishi_1.Schema.array(koishi_1.Schema.string()).description('监听的频道ID列表').default([]),
63
+ broadcastToAll: koishi_1.Schema.boolean().description('是否广播到所有联系人').default(false),
64
+ excludeChannels: koishi_1.Schema.array(koishi_1.Schema.string()).description('排除的频道ID列表(当启用广播到所有联系人时)').default([]),
62
65
  }).description('Webhook 配置'),
63
66
  greeting: koishi_1.Schema.object({
64
67
  enabled: koishi_1.Schema.boolean().description('启用问候功能').default(true),
65
68
  channels: koishi_1.Schema.array(koishi_1.Schema.string()).description('问候消息发送的频道').default([]),
66
69
  morningTime: koishi_1.Schema.string().description('早安时间 (cron格式)').default('0 0 6 * * *'),
67
70
  eveningTime: koishi_1.Schema.string().description('晚安时间 (cron格式)').default('0 0 22 * * *'),
71
+ broadcastToAll: koishi_1.Schema.boolean().description('是否广播问候消息到所有联系人').default(false),
72
+ excludeChannels: koishi_1.Schema.array(koishi_1.Schema.string()).description('排除的频道ID列表(当启用广播到所有联系人时)').default([]),
68
73
  }).description('问候功能配置'),
69
74
  commands: koishi_1.Schema.object({
70
75
  enabled: koishi_1.Schema.boolean().description('启用命令功能').default(true),
@@ -302,7 +307,11 @@ function setupGreeting(ctx, config, logger) {
302
307
  ];
303
308
  const greeting = (0, lodash_1.sample)(greetings) || greetings[0];
304
309
  const message = `🌅 早上好!${greeting}\n\n${hitokoto || ''}`;
305
- await sendToChannels(ctx, config.greeting.channels || [], message, logger);
310
+ await (0, broadcast_1.sendMessage)(ctx, message, {
311
+ watchChannels: config.greeting.channels || [],
312
+ broadcastToAll: config.greeting.broadcastToAll || false,
313
+ excludeChannels: config.greeting.excludeChannels || [],
314
+ }, logger);
306
315
  }
307
316
  catch (error) {
308
317
  const simplified = (0, axios_error_1.simplifyAxiosError)(error, '发送早安消息');
@@ -322,7 +331,11 @@ function setupGreeting(ctx, config, logger) {
322
331
  ];
323
332
  const greeting = (0, lodash_1.sample)(greetings) || greetings[0];
324
333
  const message = `🌙 ${greeting}\n\n${hitokoto || ''}`;
325
- await sendToChannels(ctx, config.greeting.channels || [], message, logger);
334
+ await (0, broadcast_1.sendMessage)(ctx, message, {
335
+ watchChannels: config.greeting.channels || [],
336
+ broadcastToAll: config.greeting.broadcastToAll || false,
337
+ excludeChannels: config.greeting.excludeChannels || [],
338
+ }, logger);
326
339
  }
327
340
  catch (error) {
328
341
  const simplified = (0, axios_error_1.simplifyAxiosError)(error, '发送晚安消息');
@@ -477,19 +490,3 @@ function setupCommands(ctx, config, logger) {
477
490
  });
478
491
  logger.info('MX Space 命令已注册');
479
492
  }
480
- async function sendToChannels(ctx, channels, message, logger) {
481
- if (!channels.length)
482
- return;
483
- const tasks = channels.map(async (channelId) => {
484
- try {
485
- const bot = ctx.bots.find(bot => bot.selfId);
486
- if (bot) {
487
- await bot.sendMessage(channelId, message);
488
- }
489
- }
490
- catch (error) {
491
- logger.error(`发送消息到频道 ${channelId} 失败:`, error);
492
- }
493
- });
494
- await Promise.allSettled(tasks);
495
- }
@@ -0,0 +1,22 @@
1
+ import { Context, h } from 'koishi';
2
+ export interface BroadcastOptions {
3
+ watchChannels?: string[];
4
+ broadcastToAll?: boolean;
5
+ excludeChannels?: string[];
6
+ }
7
+ /**
8
+ * 广播消息到所有联系人
9
+ * @param ctx Koishi 上下文
10
+ * @param message 要发送的消息
11
+ * @param excludeChannels 排除的频道ID列表
12
+ * @param logger 日志记录器
13
+ */
14
+ export declare function broadcastToAllContacts(ctx: Context, message: string | h[], excludeChannels: string[] | undefined, logger: any): Promise<void>;
15
+ /**
16
+ * 根据配置发送消息到指定频道或广播到所有联系人
17
+ * @param ctx Koishi 上下文
18
+ * @param message 要发送的消息
19
+ * @param options 广播选项
20
+ * @param logger 日志记录器
21
+ */
22
+ export declare function sendMessage(ctx: Context, message: string | h[], options: BroadcastOptions, logger: any): Promise<void>;
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.broadcastToAllContacts = broadcastToAllContacts;
4
+ exports.sendMessage = sendMessage;
5
+ /**
6
+ * 广播消息到所有联系人
7
+ * @param ctx Koishi 上下文
8
+ * @param message 要发送的消息
9
+ * @param excludeChannels 排除的频道ID列表
10
+ * @param logger 日志记录器
11
+ */
12
+ async function broadcastToAllContacts(ctx, message, excludeChannels = [], logger) {
13
+ try {
14
+ let totalSent = 0;
15
+ let totalFailed = 0;
16
+ // 获取所有活跃的机器人实例
17
+ for (const bot of ctx.bots) {
18
+ if (!bot.online)
19
+ continue;
20
+ try {
21
+ // 获取群组列表
22
+ const guilds = await bot.getGuildList();
23
+ for (const guild of guilds.data) {
24
+ if (excludeChannels.includes(guild.id))
25
+ continue;
26
+ try {
27
+ // 获取群组的频道列表
28
+ const channels = await bot.getChannelList(guild.id);
29
+ for (const channel of channels.data) {
30
+ if (excludeChannels.includes(channel.id))
31
+ continue;
32
+ try {
33
+ await bot.sendMessage(channel.id, message);
34
+ totalSent++;
35
+ logger.debug(`成功发送消息到群组频道 ${guild.name}#${channel.name} (${channel.id})`);
36
+ }
37
+ catch (error) {
38
+ totalFailed++;
39
+ logger.debug(`发送消息到群组频道 ${channel.id} 失败:`, error);
40
+ }
41
+ }
42
+ }
43
+ catch (error) {
44
+ logger.debug(`获取群组 ${guild.id} 的频道列表失败:`, error);
45
+ }
46
+ }
47
+ // 获取好友列表(私聊)
48
+ try {
49
+ const friends = await bot.getFriendList();
50
+ for (const friend of friends.data) {
51
+ if (excludeChannels.includes(friend.id))
52
+ continue;
53
+ try {
54
+ await bot.sendPrivateMessage(friend.id, message);
55
+ totalSent++;
56
+ logger.debug(`成功发送私聊消息到 ${friend.nickname || friend.id}`);
57
+ }
58
+ catch (error) {
59
+ totalFailed++;
60
+ logger.debug(`发送私聊消息到 ${friend.id} 失败:`, error);
61
+ }
62
+ }
63
+ }
64
+ catch (error) {
65
+ logger.debug('获取好友列表失败 (可能平台不支持):', error);
66
+ }
67
+ }
68
+ catch (error) {
69
+ logger.warn(`机器人 ${bot.platform}:${bot.selfId} 广播失败:`, error);
70
+ }
71
+ }
72
+ logger.info(`广播消息完成: 成功 ${totalSent} 个,失败 ${totalFailed} 个`);
73
+ }
74
+ catch (error) {
75
+ logger.error('广播消息时发生错误:', error);
76
+ }
77
+ }
78
+ /**
79
+ * 根据配置发送消息到指定频道或广播到所有联系人
80
+ * @param ctx Koishi 上下文
81
+ * @param message 要发送的消息
82
+ * @param options 广播选项
83
+ * @param logger 日志记录器
84
+ */
85
+ async function sendMessage(ctx, message, options, logger) {
86
+ const { watchChannels = [], broadcastToAll = false, excludeChannels = [] } = options;
87
+ if (broadcastToAll) {
88
+ // 广播到所有联系人
89
+ await broadcastToAllContacts(ctx, message, excludeChannels, logger);
90
+ }
91
+ else if (watchChannels.length > 0) {
92
+ // 发送到指定频道
93
+ const tasks = watchChannels.map(async (channelId) => {
94
+ try {
95
+ const bot = ctx.bots.find(bot => bot.selfId);
96
+ if (bot) {
97
+ await bot.sendMessage(channelId, message);
98
+ logger.debug(`成功发送消息到频道 ${channelId}`);
99
+ }
100
+ }
101
+ catch (error) {
102
+ logger.error(`发送消息到频道 ${channelId} 失败:`, error);
103
+ }
104
+ });
105
+ await Promise.allSettled(tasks);
106
+ }
107
+ else {
108
+ logger.warn('没有配置监听频道且未启用广播到所有联系人,跳过消息发送');
109
+ }
110
+ }
@@ -11,6 +11,7 @@ const remove_markdown_1 = __importDefault(require("remove-markdown"));
11
11
  const api_client_1 = require("@mx-space/api-client");
12
12
  const mx_api_1 = require("./mx-api");
13
13
  const mx_url_builder_1 = require("./mx-url-builder");
14
+ const broadcast_1 = require("./broadcast");
14
15
  // MX Space 事件类型
15
16
  var BusinessEvents;
16
17
  (function (BusinessEvents) {
@@ -28,23 +29,18 @@ async function handleMxSpaceEvent(ctx, config, type, payload, logger) {
28
29
  const aggregateData = await (0, mx_api_1.getMxSpaceAggregateData)(ctx, config);
29
30
  const owner = aggregateData.user;
30
31
  const watchChannels = config.webhook?.watchChannels || [];
31
- if (!watchChannels.length) {
32
- logger.warn('没有配置监听频道,跳过事件处理');
32
+ const broadcastToAll = config.webhook?.broadcastToAll || false;
33
+ const excludeChannels = config.webhook?.excludeChannels || [];
34
+ if (!broadcastToAll && !watchChannels.length) {
35
+ logger.warn('没有配置监听频道且未启用广播到所有联系人,跳过事件处理');
33
36
  return;
34
37
  }
35
38
  const sendToChannels = async (message) => {
36
- const tasks = watchChannels.map(async (channelId) => {
37
- try {
38
- const bot = ctx.bots.find(bot => bot.selfId);
39
- if (bot) {
40
- await bot.sendMessage(channelId, message);
41
- }
42
- }
43
- catch (error) {
44
- logger.error(`发送消息到频道 ${channelId} 失败:`, error);
45
- }
46
- });
47
- await Promise.allSettled(tasks);
39
+ await (0, broadcast_1.sendMessage)(ctx, message, {
40
+ watchChannels,
41
+ broadcastToAll,
42
+ excludeChannels,
43
+ }, logger);
48
44
  };
49
45
  switch (type) {
50
46
  case BusinessEvents.POST_CREATE:
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-imx",
3
3
  "description": "Mix-Space Bot for Koishi - 集成多种功能的聊天机器人插件",
4
- "version": "2.2.2",
4
+ "version": "2.2.3",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [