koishi-plugin-steam-info-check 1.0.7 → 1.0.9
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 +141 -79
- package/dist/locales/zh-CN.d.ts +2 -0
- package/dist/locales/zh-CN.js +2 -0
- package/dist/service.js +1 -1
- package/package.json +1 -1
- package/src/index.ts +88 -23
- package/src/locales/zh-CN.ts +2 -0
- package/src/locales/zh-CN.yml +21 -1
- package/src/service.ts +1 -1
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
|
|
16
|
-
proxy: koishi_1.Schema.string().description('
|
|
17
|
-
steamRequestInterval: koishi_1.Schema.number().default(300).description('
|
|
18
|
-
steamBroadcastType: koishi_1.Schema.union(['all', 'part', 'none']).default('part').description('
|
|
19
|
-
steamDisableBroadcastOnStartup: koishi_1.Schema.boolean().default(false).description('
|
|
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>', '
|
|
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.error('检查已绑定状态失败:' + String(e) + ' EEE');
|
|
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', '
|
|
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]', '
|
|
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', '
|
|
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', '
|
|
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', '
|
|
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]', '
|
|
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>', '
|
|
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)
|
|
@@ -247,13 +257,52 @@ async function ensureChannelMeta(ctx, session) {
|
|
|
247
257
|
}
|
|
248
258
|
// OneBot 群名补充
|
|
249
259
|
if (!name && session.platform?.includes('onebot') && session.bot?.internal?.getGroupInfo) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
260
|
+
// 柔性尝试多种参数传递方式,记录每次调用结果以便定位 napcat/onebot 的参数格式差异
|
|
261
|
+
const argVariants = [
|
|
262
|
+
{ group_id: channelId },
|
|
263
|
+
{ group_id: { group_id: channelId } },
|
|
264
|
+
{ group_id: Number(channelId) },
|
|
265
|
+
{ group_id: { group_id: Number(channelId) } },
|
|
266
|
+
];
|
|
267
|
+
for (const args of argVariants) {
|
|
268
|
+
try {
|
|
269
|
+
exports.logger.error(`getGroupInfo 尝试 args=${JSON.stringify(args)}`);
|
|
270
|
+
const info = await session.bot.internal.getGroupInfo(args);
|
|
271
|
+
exports.logger.error(`getGroupInfo 返回: ${JSON.stringify(info)}`);
|
|
272
|
+
if (!info)
|
|
273
|
+
continue;
|
|
274
|
+
// 支持多种返回结构:直接 group_name、data.group_name(napcat)、或嵌套情况
|
|
275
|
+
if (info.group_name) {
|
|
276
|
+
name = info.group_name;
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
if (info.data && info.data.group_name) {
|
|
280
|
+
name = info.data.group_name;
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
if (info.data && info.data.group && info.data.group.group_name) {
|
|
284
|
+
name = info.data.group.group_name;
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
// 某些实现会把返回包在 ret.data 或直接在 ret
|
|
288
|
+
if (info.ret && info.ret.data && info.ret.data.group_name) {
|
|
289
|
+
name = info.ret.data.group_name;
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
// 如果未识别结构,记录并继续尝试下一个参数形态
|
|
293
|
+
exports.logger.error('getGroupInfo 返回了未识别结构(尝试 参数:' + JSON.stringify(args) + '): ' + JSON.stringify(info) + ' EEE');
|
|
294
|
+
}
|
|
295
|
+
catch (err) {
|
|
296
|
+
// 记录详细错误以便分析 retcode/args
|
|
297
|
+
try {
|
|
298
|
+
exports.logger.error('getGroupInfo 调用失败,args=' + JSON.stringify(args) + ',错误:' + String(err) + ' EEE');
|
|
299
|
+
}
|
|
300
|
+
catch (e) {
|
|
301
|
+
exports.logger.error('getGroupInfo 调用失败但记录 args 时出错:' + String(e) + ' EEE');
|
|
302
|
+
}
|
|
303
|
+
// 如果错误中包含 retcode,记录方便排查
|
|
304
|
+
// 继续尝试下一个参数变体
|
|
305
|
+
}
|
|
257
306
|
}
|
|
258
307
|
}
|
|
259
308
|
let avatar = current.avatar;
|
|
@@ -278,79 +327,92 @@ async function ensureChannelMeta(ctx, session) {
|
|
|
278
327
|
}
|
|
279
328
|
async function seedStatusCache(ctx) {
|
|
280
329
|
const binds = await ctx.database.get('steam_bind', {});
|
|
330
|
+
exports.logger.error(`seedStatusCache: load binds count=${binds.length}`);
|
|
281
331
|
if (!binds.length)
|
|
282
332
|
return;
|
|
283
333
|
const steamIds = [...new Set(binds.map(b => b.steamId))];
|
|
284
334
|
const summaries = await ctx.steam.getPlayerSummaries(steamIds);
|
|
335
|
+
exports.logger.error(`seedStatusCache: fetched summaries=${summaries.length}`);
|
|
285
336
|
for (const player of summaries) {
|
|
286
337
|
statusCache.set(player.steamid, player);
|
|
287
338
|
}
|
|
288
339
|
}
|
|
289
340
|
async function broadcast(ctx, config) {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
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);
|
|
341
|
+
try {
|
|
342
|
+
const channels = await ctx.database.get('steam_channel', { enable: true });
|
|
343
|
+
exports.logger.error(`broadcast: enabled channels=${channels.length}`);
|
|
344
|
+
if (channels.length === 0)
|
|
345
|
+
return;
|
|
346
|
+
const channelIds = channels.map(c => c.id);
|
|
347
|
+
const binds = await ctx.database.get('steam_bind', { channelId: channelIds });
|
|
348
|
+
exports.logger.error(`broadcast: binds total=${binds.length}`);
|
|
349
|
+
if (binds.length === 0)
|
|
350
|
+
return;
|
|
351
|
+
const steamIds = [...new Set(binds.map(b => b.steamId))];
|
|
352
|
+
exports.logger.error(`broadcast: unique steamIds=${steamIds.length}`);
|
|
353
|
+
const currentSummaries = await ctx.steam.getPlayerSummaries(steamIds);
|
|
354
|
+
exports.logger.error(`broadcast: fetched summaries=${currentSummaries.length}`);
|
|
355
|
+
const currentMap = new Map(currentSummaries.map(p => [p.steamid, p]));
|
|
356
|
+
for (const channel of channels) {
|
|
357
|
+
exports.logger.error(`broadcast: channel=${channel.id} processing`);
|
|
358
|
+
const channelBinds = binds.filter(b => b.channelId === channel.id);
|
|
359
|
+
const msgs = [];
|
|
360
|
+
const startGamingPlayers = [];
|
|
361
|
+
for (const bind of channelBinds) {
|
|
362
|
+
const current = currentMap.get(bind.steamId);
|
|
363
|
+
const old = statusCache.get(bind.steamId);
|
|
364
|
+
if (!current)
|
|
365
|
+
continue;
|
|
366
|
+
if (!old)
|
|
367
|
+
continue;
|
|
368
|
+
const oldGame = old.gameextrainfo;
|
|
369
|
+
const newGame = current.gameextrainfo;
|
|
370
|
+
const name = bind.nickname || current.personaname;
|
|
371
|
+
if (newGame && !oldGame) {
|
|
372
|
+
msgs.push(`${name} 开始玩 ${newGame} 了`);
|
|
373
|
+
startGamingPlayers.push({ ...current, nickname: bind.nickname });
|
|
339
374
|
}
|
|
340
|
-
else {
|
|
341
|
-
|
|
375
|
+
else if (!newGame && oldGame) {
|
|
376
|
+
msgs.push(`${name} 玩了 ${oldGame} 后不玩了`);
|
|
377
|
+
}
|
|
378
|
+
else if (newGame && oldGame && newGame !== oldGame) {
|
|
379
|
+
msgs.push(`${name} 停止玩 ${oldGame},开始玩 ${newGame} 了`);
|
|
342
380
|
}
|
|
343
381
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
const
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
|
|
382
|
+
if (msgs.length > 0) {
|
|
383
|
+
exports.logger.error(`broadcast: channel=${channel.id} msgs=${msgs.length}`);
|
|
384
|
+
const botKey = channel.platform && channel.assignee ? `${channel.platform}:${channel.assignee}` : undefined;
|
|
385
|
+
const bot = botKey ? ctx.bots[botKey] : Object.values(ctx.bots)[0];
|
|
386
|
+
if (!bot)
|
|
387
|
+
continue;
|
|
388
|
+
if (config.steamBroadcastType === 'none') {
|
|
389
|
+
await bot.sendMessage(channel.id, msgs.join('\n'));
|
|
390
|
+
}
|
|
391
|
+
else if (config.steamBroadcastType === 'part') {
|
|
392
|
+
if (startGamingPlayers.length > 0) {
|
|
393
|
+
const images = await Promise.all(startGamingPlayers.map(p => ctx.drawer.drawStartGaming(p, p.nickname)));
|
|
394
|
+
const combined = await ctx.drawer.concatImages(images);
|
|
395
|
+
const img = combined ? (typeof combined === 'string' ? combined : koishi_1.h.image(combined, 'image/png')) : '';
|
|
396
|
+
await bot.sendMessage(channel.id, msgs.join('\n') + img);
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
await bot.sendMessage(channel.id, msgs.join('\n'));
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
else if (config.steamBroadcastType === 'all') {
|
|
403
|
+
const channelPlayers = channelBinds.map(b => currentMap.get(b.steamId)).filter(Boolean);
|
|
404
|
+
const parentAvatar = channel.avatar ? Buffer.from(channel.avatar, 'base64') : await ctx.drawer.getDefaultAvatar();
|
|
405
|
+
const image = await ctx.drawer.drawFriendsStatus(parentAvatar, channel.name || channel.id, channelPlayers, channelBinds);
|
|
406
|
+
const img = image ? (typeof image === 'string' ? image : koishi_1.h.image(image, 'image/png')) : '';
|
|
407
|
+
await bot.sendMessage(channel.id, msgs.join('\n') + img);
|
|
408
|
+
}
|
|
350
409
|
}
|
|
351
410
|
}
|
|
411
|
+
for (const p of currentSummaries) {
|
|
412
|
+
statusCache.set(p.steamid, p);
|
|
413
|
+
}
|
|
352
414
|
}
|
|
353
|
-
|
|
354
|
-
|
|
415
|
+
catch (err) {
|
|
416
|
+
exports.logger.error('broadcast 发生异常:' + String(err) + ' EEE');
|
|
355
417
|
}
|
|
356
418
|
}
|
package/dist/locales/zh-CN.d.ts
CHANGED
|
@@ -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;
|
package/dist/locales/zh-CN.js
CHANGED
|
@@ -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/dist/service.js
CHANGED
package/package.json
CHANGED
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
|
|
35
|
-
proxy: Schema.string().description('
|
|
36
|
-
steamRequestInterval: Schema.number().default(300).description('
|
|
37
|
-
steamBroadcastType: Schema.union(['all', 'part', 'none']).default('part').description('
|
|
38
|
-
steamDisableBroadcastOnStartup: Schema.boolean().default(false).description('
|
|
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>', '
|
|
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.error('检查已绑定状态失败:' + String(e) + ' EEE')
|
|
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', '
|
|
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]', '
|
|
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', '
|
|
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', '
|
|
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', '
|
|
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]', '
|
|
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>', '
|
|
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
|
|
@@ -281,11 +291,54 @@ async function ensureChannelMeta(ctx: Context, session: Session) {
|
|
|
281
291
|
}
|
|
282
292
|
// OneBot 群名补充
|
|
283
293
|
if (!name && session.platform?.includes('onebot') && session.bot?.internal?.getGroupInfo) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
294
|
+
// 柔性尝试多种参数传递方式,记录每次调用结果以便定位 napcat/onebot 的参数格式差异
|
|
295
|
+
const argVariants = [
|
|
296
|
+
{ group_id: channelId },
|
|
297
|
+
{ group_id: { group_id: channelId } },
|
|
298
|
+
{ group_id: Number(channelId) },
|
|
299
|
+
{ group_id: { group_id: Number(channelId) } },
|
|
300
|
+
]
|
|
301
|
+
|
|
302
|
+
for (const args of argVariants) {
|
|
303
|
+
try {
|
|
304
|
+
logger.error(`getGroupInfo 尝试 args=${JSON.stringify(args)}`)
|
|
305
|
+
const info = await session.bot.internal.getGroupInfo(args)
|
|
306
|
+
logger.error(`getGroupInfo 返回: ${JSON.stringify(info)}`)
|
|
307
|
+
|
|
308
|
+
if (!info) continue
|
|
309
|
+
|
|
310
|
+
// 支持多种返回结构:直接 group_name、data.group_name(napcat)、或嵌套情况
|
|
311
|
+
if (info.group_name) {
|
|
312
|
+
name = info.group_name
|
|
313
|
+
break
|
|
314
|
+
}
|
|
315
|
+
if (info.data && info.data.group_name) {
|
|
316
|
+
name = info.data.group_name
|
|
317
|
+
break
|
|
318
|
+
}
|
|
319
|
+
if (info.data && info.data.group && info.data.group.group_name) {
|
|
320
|
+
name = info.data.group.group_name
|
|
321
|
+
break
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// 某些实现会把返回包在 ret.data 或直接在 ret
|
|
325
|
+
if (info.ret && info.ret.data && info.ret.data.group_name) {
|
|
326
|
+
name = info.ret.data.group_name
|
|
327
|
+
break
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// 如果未识别结构,记录并继续尝试下一个参数形态
|
|
331
|
+
logger.error('getGroupInfo 返回了未识别结构(尝试 参数:' + JSON.stringify(args) + '): ' + JSON.stringify(info) + ' EEE')
|
|
332
|
+
} catch (err) {
|
|
333
|
+
// 记录详细错误以便分析 retcode/args
|
|
334
|
+
try {
|
|
335
|
+
logger.error('getGroupInfo 调用失败,args=' + JSON.stringify(args) + ',错误:' + String(err) + ' EEE')
|
|
336
|
+
} catch (e) {
|
|
337
|
+
logger.error('getGroupInfo 调用失败但记录 args 时出错:' + String(e) + ' EEE')
|
|
338
|
+
}
|
|
339
|
+
// 如果错误中包含 retcode,记录方便排查
|
|
340
|
+
// 继续尝试下一个参数变体
|
|
341
|
+
}
|
|
289
342
|
}
|
|
290
343
|
}
|
|
291
344
|
|
|
@@ -311,28 +364,36 @@ async function ensureChannelMeta(ctx: Context, session: Session) {
|
|
|
311
364
|
|
|
312
365
|
async function seedStatusCache(ctx: Context) {
|
|
313
366
|
const binds = await ctx.database.get('steam_bind', {})
|
|
367
|
+
logger.error(`seedStatusCache: load binds count=${binds.length}`)
|
|
314
368
|
if (!binds.length) return
|
|
315
369
|
const steamIds = [...new Set(binds.map(b => b.steamId))]
|
|
316
370
|
const summaries = await ctx.steam.getPlayerSummaries(steamIds)
|
|
371
|
+
logger.error(`seedStatusCache: fetched summaries=${summaries.length}`)
|
|
317
372
|
for (const player of summaries) {
|
|
318
373
|
statusCache.set(player.steamid, player)
|
|
319
374
|
}
|
|
320
375
|
}
|
|
321
376
|
|
|
322
377
|
async function broadcast(ctx: Context, config: Config) {
|
|
323
|
-
|
|
378
|
+
try {
|
|
379
|
+
const channels = await ctx.database.get('steam_channel', { enable: true })
|
|
380
|
+
logger.error(`broadcast: enabled channels=${channels.length}`)
|
|
324
381
|
if (channels.length === 0) return
|
|
325
382
|
|
|
326
|
-
|
|
383
|
+
const channelIds = channels.map(c => c.id)
|
|
327
384
|
const binds = await ctx.database.get('steam_bind', { channelId: channelIds })
|
|
385
|
+
logger.error(`broadcast: binds total=${binds.length}`)
|
|
328
386
|
if (binds.length === 0) return
|
|
329
387
|
|
|
330
388
|
const steamIds = [...new Set(binds.map(b => b.steamId))]
|
|
331
|
-
|
|
332
|
-
|
|
389
|
+
logger.error(`broadcast: unique steamIds=${steamIds.length}`)
|
|
390
|
+
|
|
391
|
+
const currentSummaries = await ctx.steam.getPlayerSummaries(steamIds)
|
|
392
|
+
logger.error(`broadcast: fetched summaries=${currentSummaries.length}`)
|
|
333
393
|
const currentMap = new Map(currentSummaries.map(p => [p.steamid, p]))
|
|
334
394
|
|
|
335
395
|
for (const channel of channels) {
|
|
396
|
+
logger.error(`broadcast: channel=${channel.id} processing`)
|
|
336
397
|
const channelBinds = binds.filter(b => b.channelId === channel.id)
|
|
337
398
|
const msgs: string[] = []
|
|
338
399
|
const startGamingPlayers: any[] = []
|
|
@@ -360,6 +421,7 @@ async function broadcast(ctx: Context, config: Config) {
|
|
|
360
421
|
}
|
|
361
422
|
|
|
362
423
|
if (msgs.length > 0) {
|
|
424
|
+
logger.error(`broadcast: channel=${channel.id} msgs=${msgs.length}`)
|
|
363
425
|
const botKey = channel.platform && channel.assignee ? `${channel.platform}:${channel.assignee}` : undefined
|
|
364
426
|
const bot = botKey ? ctx.bots[botKey] : Object.values(ctx.bots)[0]
|
|
365
427
|
if (!bot) continue
|
|
@@ -388,4 +450,7 @@ async function broadcast(ctx: Context, config: Config) {
|
|
|
388
450
|
for (const p of currentSummaries) {
|
|
389
451
|
statusCache.set(p.steamid, p)
|
|
390
452
|
}
|
|
453
|
+
} catch (err) {
|
|
454
|
+
logger.error('broadcast 发生异常:' + String(err) + ' EEE')
|
|
455
|
+
}
|
|
391
456
|
}
|
package/src/locales/zh-CN.ts
CHANGED
|
@@ -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}',
|
package/src/locales/zh-CN.yml
CHANGED
|
@@ -11,4 +11,24 @@ enable_success: "已开启本群播报。"
|
|
|
11
11
|
disable_success: "已关闭本群播报。"
|
|
12
12
|
args_missing: "参数缺失。"
|
|
13
13
|
update_success: "更新群信息成功。"
|
|
14
|
-
nickname_set: "昵称已设置为 {0}。"
|
|
14
|
+
nickname_set: "昵称已设置为 {0}。"
|
|
15
|
+
|
|
16
|
+
# 配置面板本地化
|
|
17
|
+
fonts:
|
|
18
|
+
regular: "常规字体路径"
|
|
19
|
+
light: "细体字体路径"
|
|
20
|
+
bold: "粗体字体路径"
|
|
21
|
+
|
|
22
|
+
steamDisableBroadcastOnStartup: "启动时禁用首次播报(仅预热缓存)"
|
|
23
|
+
steamRequestInterval: "轮询间隔(秒)"
|
|
24
|
+
steamBroadcastType: "播报类型(all/part/none)"
|
|
25
|
+
|
|
26
|
+
commandAuthority:
|
|
27
|
+
bind: "绑定命令权限"
|
|
28
|
+
unbind: "解绑命令权限"
|
|
29
|
+
info: "查看资料命令权限"
|
|
30
|
+
check: "查看状态命令权限"
|
|
31
|
+
enable: "启用播报命令权限"
|
|
32
|
+
disable: "禁用播报命令权限"
|
|
33
|
+
update: "更新群信息命令权限"
|
|
34
|
+
nickname: "设置昵称命令权限"
|
package/src/service.ts
CHANGED