koishi-plugin-steam-info-check 1.0.7 → 1.0.8

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/dist/index.js CHANGED
@@ -12,11 +12,11 @@ const zh_CN_1 = __importDefault(require("./locales/zh-CN"));
12
12
  exports.name = 'steam-info';
13
13
  exports.inject = ['model', 'http', 'puppeteer', 'database'];
14
14
  exports.Config = koishi_1.Schema.object({
15
- steamApiKey: koishi_1.Schema.array(String).required().description('Steam API Key (supports multiple)'),
16
- proxy: koishi_1.Schema.string().description('Proxy URL (e.g., http://127.0.0.1:7890)'),
17
- steamRequestInterval: koishi_1.Schema.number().default(300).description('Polling interval in seconds'),
18
- steamBroadcastType: koishi_1.Schema.union(['all', 'part', 'none']).default('part').description('Broadcast type: all (list), part (gaming only), none (text only)'),
19
- steamDisableBroadcastOnStartup: koishi_1.Schema.boolean().default(false).description('Disable broadcast on startup'),
15
+ steamApiKey: koishi_1.Schema.array(String).required().description('Steam API Key(支持多个)'),
16
+ proxy: koishi_1.Schema.string().description('代理地址,例如 http://127.0.0.1:7890'),
17
+ steamRequestInterval: koishi_1.Schema.number().default(300).description('轮询间隔(秒)'),
18
+ steamBroadcastType: koishi_1.Schema.union(['all', 'part', 'none']).default('part').description('播报类型:all(全部图片列表)、part(仅开始游戏时图片)、none(仅文字)'),
19
+ steamDisableBroadcastOnStartup: koishi_1.Schema.boolean().default(false).description('启动时禁用首次播报(仅预热缓存)'),
20
20
  fonts: koishi_1.Schema.object({
21
21
  regular: koishi_1.Schema.string().default('fonts/MiSans-Regular.ttf'),
22
22
  light: koishi_1.Schema.string().default('fonts/MiSans-Light.ttf'),
@@ -65,7 +65,7 @@ function apply(ctx, config) {
65
65
  // Commands and scheduler depend on steam/drawer being ready
66
66
  ctx.using(['steam', 'drawer'], (ctx) => {
67
67
  ctx.command('steam', 'Steam 信息');
68
- ctx.command('steam.bind <steamId:string>', 'Bind Steam ID', { authority: config.commandAuthority.bind })
68
+ ctx.command('steam.bind <steamId:string>', '绑定 Steam ID', { authority: config.commandAuthority.bind })
69
69
  .alias('steambind', '绑定steam')
70
70
  .action(async ({ session }, steamId) => {
71
71
  if (!session)
@@ -75,6 +75,16 @@ function apply(ctx, config) {
75
75
  const targetId = await ctx.steam.getSteamId(steamId);
76
76
  if (!targetId)
77
77
  return session.text('.id_not_found');
78
+ // 检查是否已绑定
79
+ try {
80
+ const existing = await ctx.database.get('steam_bind', { userId: session.userId, channelId: session.channelId });
81
+ if (existing.length) {
82
+ return session.text('.already_bound');
83
+ }
84
+ }
85
+ catch (e) {
86
+ exports.logger.warn('检查已绑定状态失败:' + String(e));
87
+ }
78
88
  await ctx.database.upsert('steam_bind', [
79
89
  {
80
90
  userId: session.userId,
@@ -84,7 +94,7 @@ function apply(ctx, config) {
84
94
  ], ['userId', 'channelId']);
85
95
  return session.text('.bind_success', [targetId]);
86
96
  });
87
- ctx.command('steam.unbind', 'Unbind Steam ID', { authority: config.commandAuthority.unbind })
97
+ ctx.command('steam.unbind', '解绑 Steam ID', { authority: config.commandAuthority.unbind })
88
98
  .alias('steamunbind', '解绑steam')
89
99
  .action(async ({ session }) => {
90
100
  if (!session)
@@ -95,7 +105,7 @@ function apply(ctx, config) {
95
105
  });
96
106
  return result ? session.text('.unbind_success') : session.text('.not_bound');
97
107
  });
98
- ctx.command('steam.info [target:text]', 'View Steam Profile', { authority: config.commandAuthority.info })
108
+ ctx.command('steam.info [target:text]', '查看 Steam 资料', { authority: config.commandAuthority.info })
99
109
  .alias('steaminfo', 'steam信息')
100
110
  .action(async ({ session }, target) => {
101
111
  if (!session)
@@ -136,7 +146,7 @@ function apply(ctx, config) {
136
146
  return session.text('.error');
137
147
  }
138
148
  });
139
- ctx.command('steam.check', 'Check Friends Status', { authority: config.commandAuthority.check })
149
+ ctx.command('steam.check', '查看好友在线状态', { authority: config.commandAuthority.check })
140
150
  .alias('steamcheck', '查看steam', '查steam')
141
151
  .action(async ({ session }) => {
142
152
  if (!session)
@@ -164,7 +174,7 @@ function apply(ctx, config) {
164
174
  return session.text('.error');
165
175
  }
166
176
  });
167
- ctx.command('steam.enable', 'Enable Broadcast', { authority: config.commandAuthority.enable })
177
+ ctx.command('steam.enable', '启用播报', { authority: config.commandAuthority.enable })
168
178
  .alias('steamenable', '启用steam')
169
179
  .action(async ({ session }) => {
170
180
  if (!session)
@@ -177,7 +187,7 @@ function apply(ctx, config) {
177
187
  }]);
178
188
  return session.text('.enable_success');
179
189
  });
180
- ctx.command('steam.disable', 'Disable Broadcast', { authority: config.commandAuthority.disable })
190
+ ctx.command('steam.disable', '禁用播报', { authority: config.commandAuthority.disable })
181
191
  .alias('steamdisable', '禁用steam')
182
192
  .action(async ({ session }) => {
183
193
  if (!session)
@@ -190,7 +200,7 @@ function apply(ctx, config) {
190
200
  }]);
191
201
  return session.text('.disable_success');
192
202
  });
193
- ctx.command('steam.update [name:string] [avatar:image]', 'Update Group Info', { authority: config.commandAuthority.update })
203
+ ctx.command('steam.update [name:string] [avatar:image]', '更新群信息', { authority: config.commandAuthority.update })
194
204
  .alias('steamupdate', '更新群信息')
195
205
  .action(async ({ session }, name, avatar) => {
196
206
  if (!session)
@@ -212,7 +222,7 @@ function apply(ctx, config) {
212
222
  await ctx.database.upsert('steam_channel', [update]);
213
223
  return session.text('.update_success');
214
224
  });
215
- ctx.command('steam.nickname <nickname:string>', 'Set Steam Nickname', { authority: config.commandAuthority.nickname })
225
+ ctx.command('steam.nickname <nickname:string>', '设置 Steam 昵称', { authority: config.commandAuthority.nickname })
216
226
  .alias('steamnickname', 'steam昵称')
217
227
  .action(async ({ session }, nickname) => {
218
228
  if (!session)
@@ -249,11 +259,29 @@ async function ensureChannelMeta(ctx, session) {
249
259
  if (!name && session.platform?.includes('onebot') && session.bot?.internal?.getGroupInfo) {
250
260
  try {
251
261
  const info = await session.bot.internal.getGroupInfo({ group_id: channelId });
252
- if (info?.group_name)
253
- name = info.group_name;
262
+ // 支持多种返回结构:直接 group_name、data.group_name(napcat)、或嵌套情况
263
+ if (info) {
264
+ try {
265
+ if (info.group_name) {
266
+ name = info.group_name;
267
+ }
268
+ else if (info.data && info.data.group_name) {
269
+ name = info.data.group_name;
270
+ }
271
+ else if (info.data && info.data.group && info.data.group.group_name) {
272
+ name = info.data.group.group_name;
273
+ }
274
+ else {
275
+ exports.logger.warn('getGroupInfo 返回了未识别结构:' + JSON.stringify(info));
276
+ }
277
+ }
278
+ catch (e) {
279
+ exports.logger.warn('解析 getGroupInfo 返回值时出错:' + String(e));
280
+ }
281
+ }
254
282
  }
255
- catch {
256
- /* ignore */
283
+ catch (err) {
284
+ exports.logger.warn('getGroupInfo 调用失败:' + String(err));
257
285
  }
258
286
  }
259
287
  let avatar = current.avatar;
@@ -278,79 +306,92 @@ async function ensureChannelMeta(ctx, session) {
278
306
  }
279
307
  async function seedStatusCache(ctx) {
280
308
  const binds = await ctx.database.get('steam_bind', {});
309
+ exports.logger.debug && exports.logger.debug(`seedStatusCache: load binds count=${binds.length}`);
281
310
  if (!binds.length)
282
311
  return;
283
312
  const steamIds = [...new Set(binds.map(b => b.steamId))];
284
313
  const summaries = await ctx.steam.getPlayerSummaries(steamIds);
314
+ exports.logger.debug && exports.logger.debug(`seedStatusCache: fetched summaries=${summaries.length}`);
285
315
  for (const player of summaries) {
286
316
  statusCache.set(player.steamid, player);
287
317
  }
288
318
  }
289
319
  async function broadcast(ctx, config) {
290
- const channels = await ctx.database.get('steam_channel', { enable: true });
291
- if (channels.length === 0)
292
- return;
293
- const channelIds = channels.map(c => c.id);
294
- const binds = await ctx.database.get('steam_bind', { channelId: channelIds });
295
- if (binds.length === 0)
296
- return;
297
- const steamIds = [...new Set(binds.map(b => b.steamId))];
298
- const currentSummaries = await ctx.steam.getPlayerSummaries(steamIds);
299
- const currentMap = new Map(currentSummaries.map(p => [p.steamid, p]));
300
- for (const channel of channels) {
301
- const channelBinds = binds.filter(b => b.channelId === channel.id);
302
- const msgs = [];
303
- const startGamingPlayers = [];
304
- for (const bind of channelBinds) {
305
- const current = currentMap.get(bind.steamId);
306
- const old = statusCache.get(bind.steamId);
307
- if (!current)
308
- continue;
309
- if (!old)
310
- continue;
311
- const oldGame = old.gameextrainfo;
312
- const newGame = current.gameextrainfo;
313
- const name = bind.nickname || current.personaname;
314
- if (newGame && !oldGame) {
315
- msgs.push(`${name} 开始玩 ${newGame} 了`);
316
- startGamingPlayers.push({ ...current, nickname: bind.nickname });
317
- }
318
- else if (!newGame && oldGame) {
319
- msgs.push(`${name} 玩了 ${oldGame} 后不玩了`);
320
- }
321
- else if (newGame && oldGame && newGame !== oldGame) {
322
- msgs.push(`${name} 停止玩 ${oldGame},开始玩 ${newGame} 了`);
323
- }
324
- }
325
- if (msgs.length > 0) {
326
- const botKey = channel.platform && channel.assignee ? `${channel.platform}:${channel.assignee}` : undefined;
327
- const bot = botKey ? ctx.bots[botKey] : Object.values(ctx.bots)[0];
328
- if (!bot)
329
- continue;
330
- if (config.steamBroadcastType === 'none') {
331
- await bot.sendMessage(channel.id, msgs.join('\n'));
332
- }
333
- else if (config.steamBroadcastType === 'part') {
334
- if (startGamingPlayers.length > 0) {
335
- const images = await Promise.all(startGamingPlayers.map(p => ctx.drawer.drawStartGaming(p, p.nickname)));
336
- const combined = await ctx.drawer.concatImages(images);
337
- const img = combined ? (typeof combined === 'string' ? combined : koishi_1.h.image(combined, 'image/png')) : '';
338
- await bot.sendMessage(channel.id, msgs.join('\n') + img);
320
+ try {
321
+ const channels = await ctx.database.get('steam_channel', { enable: true });
322
+ exports.logger.debug && exports.logger.debug(`broadcast: enabled channels=${channels.length}`);
323
+ if (channels.length === 0)
324
+ return;
325
+ const channelIds = channels.map(c => c.id);
326
+ const binds = await ctx.database.get('steam_bind', { channelId: channelIds });
327
+ exports.logger.debug && exports.logger.debug(`broadcast: binds total=${binds.length}`);
328
+ if (binds.length === 0)
329
+ return;
330
+ const steamIds = [...new Set(binds.map(b => b.steamId))];
331
+ exports.logger.debug && exports.logger.debug(`broadcast: unique steamIds=${steamIds.length}`);
332
+ const currentSummaries = await ctx.steam.getPlayerSummaries(steamIds);
333
+ exports.logger.debug && exports.logger.debug(`broadcast: fetched summaries=${currentSummaries.length}`);
334
+ const currentMap = new Map(currentSummaries.map(p => [p.steamid, p]));
335
+ for (const channel of channels) {
336
+ exports.logger.debug && exports.logger.debug(`broadcast: channel=${channel.id} processing`);
337
+ const channelBinds = binds.filter(b => b.channelId === channel.id);
338
+ const msgs = [];
339
+ const startGamingPlayers = [];
340
+ for (const bind of channelBinds) {
341
+ const current = currentMap.get(bind.steamId);
342
+ const old = statusCache.get(bind.steamId);
343
+ if (!current)
344
+ continue;
345
+ if (!old)
346
+ continue;
347
+ const oldGame = old.gameextrainfo;
348
+ const newGame = current.gameextrainfo;
349
+ const name = bind.nickname || current.personaname;
350
+ if (newGame && !oldGame) {
351
+ msgs.push(`${name} 开始玩 ${newGame} 了`);
352
+ startGamingPlayers.push({ ...current, nickname: bind.nickname });
339
353
  }
340
- else {
341
- await bot.sendMessage(channel.id, msgs.join('\n'));
354
+ else if (!newGame && oldGame) {
355
+ msgs.push(`${name} 玩了 ${oldGame} 后不玩了`);
356
+ }
357
+ else if (newGame && oldGame && newGame !== oldGame) {
358
+ msgs.push(`${name} 停止玩 ${oldGame},开始玩 ${newGame} 了`);
342
359
  }
343
360
  }
344
- else if (config.steamBroadcastType === 'all') {
345
- const channelPlayers = channelBinds.map(b => currentMap.get(b.steamId)).filter(Boolean);
346
- const parentAvatar = channel.avatar ? Buffer.from(channel.avatar, 'base64') : await ctx.drawer.getDefaultAvatar();
347
- const image = await ctx.drawer.drawFriendsStatus(parentAvatar, channel.name || channel.id, channelPlayers, channelBinds);
348
- const img = image ? (typeof image === 'string' ? image : koishi_1.h.image(image, 'image/png')) : '';
349
- await bot.sendMessage(channel.id, msgs.join('\n') + img);
361
+ if (msgs.length > 0) {
362
+ exports.logger.debug && exports.logger.debug(`broadcast: channel=${channel.id} msgs=${msgs.length}`);
363
+ const botKey = channel.platform && channel.assignee ? `${channel.platform}:${channel.assignee}` : undefined;
364
+ const bot = botKey ? ctx.bots[botKey] : Object.values(ctx.bots)[0];
365
+ if (!bot)
366
+ continue;
367
+ if (config.steamBroadcastType === 'none') {
368
+ await bot.sendMessage(channel.id, msgs.join('\n'));
369
+ }
370
+ else if (config.steamBroadcastType === 'part') {
371
+ if (startGamingPlayers.length > 0) {
372
+ const images = await Promise.all(startGamingPlayers.map(p => ctx.drawer.drawStartGaming(p, p.nickname)));
373
+ const combined = await ctx.drawer.concatImages(images);
374
+ const img = combined ? (typeof combined === 'string' ? combined : koishi_1.h.image(combined, 'image/png')) : '';
375
+ await bot.sendMessage(channel.id, msgs.join('\n') + img);
376
+ }
377
+ else {
378
+ await bot.sendMessage(channel.id, msgs.join('\n'));
379
+ }
380
+ }
381
+ else if (config.steamBroadcastType === 'all') {
382
+ const channelPlayers = channelBinds.map(b => currentMap.get(b.steamId)).filter(Boolean);
383
+ const parentAvatar = channel.avatar ? Buffer.from(channel.avatar, 'base64') : await ctx.drawer.getDefaultAvatar();
384
+ const image = await ctx.drawer.drawFriendsStatus(parentAvatar, channel.name || channel.id, channelPlayers, channelBinds);
385
+ const img = image ? (typeof image === 'string' ? image : koishi_1.h.image(image, 'image/png')) : '';
386
+ await bot.sendMessage(channel.id, msgs.join('\n') + img);
387
+ }
350
388
  }
351
389
  }
390
+ for (const p of currentSummaries) {
391
+ statusCache.set(p.steamid, p);
392
+ }
352
393
  }
353
- for (const p of currentSummaries) {
354
- statusCache.set(p.steamid, p);
394
+ catch (err) {
395
+ exports.logger.warn('broadcast 发生异常:' + String(err));
355
396
  }
356
397
  }
@@ -3,10 +3,12 @@ declare const _default: {
3
3
  steam: {
4
4
  bind: {
5
5
  bind_success: string;
6
+ already_bound: string;
6
7
  invalid_id: string;
7
8
  id_not_found: string;
8
9
  error: string;
9
10
  messages: {
11
+ already_bound: string;
10
12
  invalid_id: string;
11
13
  id_not_found: string;
12
14
  bind_success: string;
@@ -5,10 +5,12 @@ exports.default = {
5
5
  steam: {
6
6
  bind: {
7
7
  bind_success: '绑定成功!Steam ID: {0}',
8
+ already_bound: '您已经绑定过帐号了!',
8
9
  invalid_id: '请输入有效的 Steam ID。',
9
10
  id_not_found: '无法找到该 Steam ID。',
10
11
  error: '发生错误。',
11
12
  messages: {
13
+ already_bound: '您已经绑定过帐号了!',
12
14
  invalid_id: '请输入有效的 Steam ID。',
13
15
  id_not_found: '无法找到该 Steam ID。',
14
16
  bind_success: '绑定成功!Steam ID: {0}',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koishi-plugin-steam-info-check",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Steam friends status broadcast plugin for Koishi",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/index.ts CHANGED
@@ -31,11 +31,11 @@ export interface Config {
31
31
  }
32
32
 
33
33
  export const Config: Schema<Config> = Schema.object({
34
- steamApiKey: Schema.array(String).required().description('Steam API Key (supports multiple)'),
35
- proxy: Schema.string().description('Proxy URL (e.g., http://127.0.0.1:7890)'),
36
- steamRequestInterval: Schema.number().default(300).description('Polling interval in seconds'),
37
- steamBroadcastType: Schema.union(['all', 'part', 'none']).default('part').description('Broadcast type: all (list), part (gaming only), none (text only)'),
38
- steamDisableBroadcastOnStartup: Schema.boolean().default(false).description('Disable broadcast on startup'),
34
+ steamApiKey: Schema.array(String).required().description('Steam API Key(支持多个)'),
35
+ proxy: Schema.string().description('代理地址,例如 http://127.0.0.1:7890'),
36
+ steamRequestInterval: Schema.number().default(300).description('轮询间隔(秒)'),
37
+ steamBroadcastType: Schema.union(['all', 'part', 'none']).default('part').description('播报类型:all(全部图片列表)、part(仅开始游戏时图片)、none(仅文字)'),
38
+ steamDisableBroadcastOnStartup: Schema.boolean().default(false).description('启动时禁用首次播报(仅预热缓存)'),
39
39
  fonts: Schema.object({
40
40
  regular: Schema.string().default('fonts/MiSans-Regular.ttf'),
41
41
  light: Schema.string().default('fonts/MiSans-Light.ttf'),
@@ -98,15 +98,25 @@ export function apply(ctx: Context, config: Config) {
98
98
  ctx.using(['steam', 'drawer'], (ctx) => {
99
99
  ctx.command('steam', 'Steam 信息')
100
100
 
101
- ctx.command('steam.bind <steamId:string>', 'Bind Steam ID', { authority: config.commandAuthority.bind })
101
+ ctx.command('steam.bind <steamId:string>', '绑定 Steam ID', { authority: config.commandAuthority.bind })
102
102
  .alias('steambind', '绑定steam')
103
103
  .action(async ({ session }, steamId) => {
104
104
  if (!session) return
105
105
  if (!steamId || !/^\d+$/.test(steamId)) return session.text('.invalid_id')
106
-
106
+
107
107
  const targetId = await ctx.steam.getSteamId(steamId)
108
108
  if (!targetId) return session.text('.id_not_found')
109
109
 
110
+ // 检查是否已绑定
111
+ try {
112
+ const existing = await ctx.database.get('steam_bind', { userId: session.userId, channelId: session.channelId })
113
+ if (existing.length) {
114
+ return session.text('.already_bound')
115
+ }
116
+ } catch (e) {
117
+ logger.warn('检查已绑定状态失败:' + String(e))
118
+ }
119
+
110
120
  await ctx.database.upsert('steam_bind', [
111
121
  {
112
122
  userId: session.userId,
@@ -118,7 +128,7 @@ export function apply(ctx: Context, config: Config) {
118
128
  return session.text('.bind_success', [targetId])
119
129
  })
120
130
 
121
- ctx.command('steam.unbind', 'Unbind Steam ID', { authority: config.commandAuthority.unbind })
131
+ ctx.command('steam.unbind', '解绑 Steam ID', { authority: config.commandAuthority.unbind })
122
132
  .alias('steamunbind', '解绑steam')
123
133
  .action(async ({ session }) => {
124
134
  if (!session) return
@@ -129,7 +139,7 @@ export function apply(ctx: Context, config: Config) {
129
139
  return result ? session.text('.unbind_success') : session.text('.not_bound')
130
140
  })
131
141
 
132
- ctx.command('steam.info [target:text]', 'View Steam Profile', { authority: config.commandAuthority.info })
142
+ ctx.command('steam.info [target:text]', '查看 Steam 资料', { authority: config.commandAuthority.info })
133
143
  .alias('steaminfo', 'steam信息')
134
144
  .action(async ({ session }, target) => {
135
145
  if (!session) return
@@ -166,7 +176,7 @@ export function apply(ctx: Context, config: Config) {
166
176
  }
167
177
  })
168
178
 
169
- ctx.command('steam.check', 'Check Friends Status', { authority: config.commandAuthority.check })
179
+ ctx.command('steam.check', '查看好友在线状态', { authority: config.commandAuthority.check })
170
180
  .alias('steamcheck', '查看steam', '查steam')
171
181
  .action(async ({ session }) => {
172
182
  if (!session) return
@@ -194,7 +204,7 @@ export function apply(ctx: Context, config: Config) {
194
204
  }
195
205
  })
196
206
 
197
- ctx.command('steam.enable', 'Enable Broadcast', { authority: config.commandAuthority.enable })
207
+ ctx.command('steam.enable', '启用播报', { authority: config.commandAuthority.enable })
198
208
  .alias('steamenable', '启用steam')
199
209
  .action(async ({ session }) => {
200
210
  if (!session) return
@@ -207,7 +217,7 @@ export function apply(ctx: Context, config: Config) {
207
217
  return session.text('.enable_success')
208
218
  })
209
219
 
210
- ctx.command('steam.disable', 'Disable Broadcast', { authority: config.commandAuthority.disable })
220
+ ctx.command('steam.disable', '禁用播报', { authority: config.commandAuthority.disable })
211
221
  .alias('steamdisable', '禁用steam')
212
222
  .action(async ({ session }) => {
213
223
  if (!session) return
@@ -220,7 +230,7 @@ export function apply(ctx: Context, config: Config) {
220
230
  return session.text('.disable_success')
221
231
  })
222
232
 
223
- ctx.command('steam.update [name:string] [avatar:image]', 'Update Group Info', { authority: config.commandAuthority.update })
233
+ ctx.command('steam.update [name:string] [avatar:image]', '更新群信息', { authority: config.commandAuthority.update })
224
234
  .alias('steamupdate', '更新群信息')
225
235
  .action(async ({ session }, name, avatar) => {
226
236
  if (!session) return
@@ -243,7 +253,7 @@ export function apply(ctx: Context, config: Config) {
243
253
  return session.text('.update_success')
244
254
  })
245
255
 
246
- ctx.command('steam.nickname <nickname:string>', 'Set Steam Nickname', { authority: config.commandAuthority.nickname })
256
+ ctx.command('steam.nickname <nickname:string>', '设置 Steam 昵称', { authority: config.commandAuthority.nickname })
247
257
  .alias('steamnickname', 'steam昵称')
248
258
  .action(async ({ session }, nickname) => {
249
259
  if (!session) return
@@ -283,9 +293,24 @@ async function ensureChannelMeta(ctx: Context, session: Session) {
283
293
  if (!name && session.platform?.includes('onebot') && session.bot?.internal?.getGroupInfo) {
284
294
  try {
285
295
  const info = await session.bot.internal.getGroupInfo({ group_id: channelId })
286
- if (info?.group_name) name = info.group_name
287
- } catch {
288
- /* ignore */
296
+ // 支持多种返回结构:直接 group_name、data.group_name(napcat)、或嵌套情况
297
+ if (info) {
298
+ try {
299
+ if (info.group_name) {
300
+ name = info.group_name
301
+ } else if (info.data && info.data.group_name) {
302
+ name = info.data.group_name
303
+ } else if (info.data && info.data.group && info.data.group.group_name) {
304
+ name = info.data.group.group_name
305
+ } else {
306
+ logger.warn('getGroupInfo 返回了未识别结构:' + JSON.stringify(info))
307
+ }
308
+ } catch (e) {
309
+ logger.warn('解析 getGroupInfo 返回值时出错:' + String(e))
310
+ }
311
+ }
312
+ } catch (err) {
313
+ logger.warn('getGroupInfo 调用失败:' + String(err))
289
314
  }
290
315
  }
291
316
 
@@ -311,28 +336,36 @@ async function ensureChannelMeta(ctx: Context, session: Session) {
311
336
 
312
337
  async function seedStatusCache(ctx: Context) {
313
338
  const binds = await ctx.database.get('steam_bind', {})
339
+ logger.debug && logger.debug(`seedStatusCache: load binds count=${binds.length}`)
314
340
  if (!binds.length) return
315
341
  const steamIds = [...new Set(binds.map(b => b.steamId))]
316
342
  const summaries = await ctx.steam.getPlayerSummaries(steamIds)
343
+ logger.debug && logger.debug(`seedStatusCache: fetched summaries=${summaries.length}`)
317
344
  for (const player of summaries) {
318
345
  statusCache.set(player.steamid, player)
319
346
  }
320
347
  }
321
348
 
322
349
  async function broadcast(ctx: Context, config: Config) {
323
- const channels = await ctx.database.get('steam_channel', { enable: true })
350
+ try {
351
+ const channels = await ctx.database.get('steam_channel', { enable: true })
352
+ logger.debug && logger.debug(`broadcast: enabled channels=${channels.length}`)
324
353
  if (channels.length === 0) return
325
354
 
326
- const channelIds = channels.map(c => c.id)
355
+ const channelIds = channels.map(c => c.id)
327
356
  const binds = await ctx.database.get('steam_bind', { channelId: channelIds })
357
+ logger.debug && logger.debug(`broadcast: binds total=${binds.length}`)
328
358
  if (binds.length === 0) return
329
359
 
330
360
  const steamIds = [...new Set(binds.map(b => b.steamId))]
331
-
332
- const currentSummaries = await ctx.steam.getPlayerSummaries(steamIds)
361
+ logger.debug && logger.debug(`broadcast: unique steamIds=${steamIds.length}`)
362
+
363
+ const currentSummaries = await ctx.steam.getPlayerSummaries(steamIds)
364
+ logger.debug && logger.debug(`broadcast: fetched summaries=${currentSummaries.length}`)
333
365
  const currentMap = new Map(currentSummaries.map(p => [p.steamid, p]))
334
366
 
335
367
  for (const channel of channels) {
368
+ logger.debug && logger.debug(`broadcast: channel=${channel.id} processing`)
336
369
  const channelBinds = binds.filter(b => b.channelId === channel.id)
337
370
  const msgs: string[] = []
338
371
  const startGamingPlayers: any[] = []
@@ -360,6 +393,7 @@ async function broadcast(ctx: Context, config: Config) {
360
393
  }
361
394
 
362
395
  if (msgs.length > 0) {
396
+ logger.debug && logger.debug(`broadcast: channel=${channel.id} msgs=${msgs.length}`)
363
397
  const botKey = channel.platform && channel.assignee ? `${channel.platform}:${channel.assignee}` : undefined
364
398
  const bot = botKey ? ctx.bots[botKey] : Object.values(ctx.bots)[0]
365
399
  if (!bot) continue
@@ -388,4 +422,7 @@ async function broadcast(ctx: Context, config: Config) {
388
422
  for (const p of currentSummaries) {
389
423
  statusCache.set(p.steamid, p)
390
424
  }
425
+ } catch (err) {
426
+ logger.warn('broadcast 发生异常:' + String(err))
427
+ }
391
428
  }
@@ -3,10 +3,12 @@ export default {
3
3
  steam: {
4
4
  bind: {
5
5
  bind_success: '绑定成功!Steam ID: {0}',
6
+ already_bound: '您已经绑定过帐号了!',
6
7
  invalid_id: '请输入有效的 Steam ID。',
7
8
  id_not_found: '无法找到该 Steam ID。',
8
9
  error: '发生错误。',
9
10
  messages: {
11
+ already_bound: '您已经绑定过帐号了!',
10
12
  invalid_id: '请输入有效的 Steam ID。',
11
13
  id_not_found: '无法找到该 Steam ID。',
12
14
  bind_success: '绑定成功!Steam ID: {0}',