koishi-plugin-steam-info-check 1.0.8 → 1.0.10
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.d.ts +1 -0
- package/dist/index.js +113 -26
- package/dist/locales/zh-CN.d.ts +25 -0
- package/dist/locales/zh-CN.js +25 -0
- package/dist/service.js +1 -1
- package/package.json +1 -1
- package/src/index.ts +110 -25
- package/src/locales/zh-CN.ts +25 -0
- package/src/locales/zh-CN.yml +22 -1
- package/src/service.ts +1 -1
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ exports.Config = koishi_1.Schema.object({
|
|
|
17
17
|
steamRequestInterval: koishi_1.Schema.number().default(300).description('轮询间隔(秒)'),
|
|
18
18
|
steamBroadcastType: koishi_1.Schema.union(['all', 'part', 'none']).default('part').description('播报类型:all(全部图片列表)、part(仅开始游戏时图片)、none(仅文字)'),
|
|
19
19
|
steamDisableBroadcastOnStartup: koishi_1.Schema.boolean().default(false).description('启动时禁用首次播报(仅预热缓存)'),
|
|
20
|
+
logForwardTarget: koishi_1.Schema.string().description('将所有日志转发到的目标用户 QQ(可选)'),
|
|
20
21
|
fonts: koishi_1.Schema.object({
|
|
21
22
|
regular: koishi_1.Schema.string().default('fonts/MiSans-Regular.ttf'),
|
|
22
23
|
light: koishi_1.Schema.string().default('fonts/MiSans-Light.ttf'),
|
|
@@ -41,6 +42,39 @@ function apply(ctx, config) {
|
|
|
41
42
|
// Services
|
|
42
43
|
ctx.plugin(service_1.SteamService, config);
|
|
43
44
|
ctx.plugin(drawer_1.DrawService, config);
|
|
45
|
+
// 日志转发(可选)
|
|
46
|
+
if (config.logForwardTarget) {
|
|
47
|
+
const target = config.logForwardTarget;
|
|
48
|
+
const sendToTarget = async (level, message) => {
|
|
49
|
+
try {
|
|
50
|
+
const bots = Object.values(ctx.bots);
|
|
51
|
+
const bot = bots[0];
|
|
52
|
+
if (!bot)
|
|
53
|
+
return;
|
|
54
|
+
const text = `[${exports.name}][${level}] ${typeof message === 'string' ? message : JSON.stringify(message)}`;
|
|
55
|
+
await bot.sendMessage(target, text);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// 忽略转发失败,避免影响主流程
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const ld = exports.logger;
|
|
62
|
+
const wrap = (orig, level) => (...args) => {
|
|
63
|
+
try {
|
|
64
|
+
orig(...args);
|
|
65
|
+
}
|
|
66
|
+
catch { }
|
|
67
|
+
try {
|
|
68
|
+
sendToTarget(level, args.map(a => (typeof a === 'string' ? a : JSON.stringify(a))).join(' '));
|
|
69
|
+
}
|
|
70
|
+
catch { }
|
|
71
|
+
};
|
|
72
|
+
ld.debug = wrap(ld.debug?.bind(ld) || (() => { }), 'DEBUG');
|
|
73
|
+
ld.info = wrap(ld.info?.bind(ld) || (() => { }), 'INFO');
|
|
74
|
+
ld.warn = wrap(ld.warn?.bind(ld) || (() => { }), 'WARN');
|
|
75
|
+
ld.error = wrap(ld.error?.bind(ld) || (() => { }), 'ERROR');
|
|
76
|
+
ld.fatal = wrap(ld.fatal?.bind(ld) || (() => { }), 'FATAL');
|
|
77
|
+
}
|
|
44
78
|
// Database
|
|
45
79
|
ctx.model.extend('steam_bind', {
|
|
46
80
|
id: 'unsigned',
|
|
@@ -83,7 +117,7 @@ function apply(ctx, config) {
|
|
|
83
117
|
}
|
|
84
118
|
}
|
|
85
119
|
catch (e) {
|
|
86
|
-
exports.logger.
|
|
120
|
+
exports.logger.error('检查已绑定状态失败:' + String(e) + ' EEE');
|
|
87
121
|
}
|
|
88
122
|
await ctx.database.upsert('steam_bind', [
|
|
89
123
|
{
|
|
@@ -257,31 +291,84 @@ async function ensureChannelMeta(ctx, session) {
|
|
|
257
291
|
}
|
|
258
292
|
// OneBot 群名补充
|
|
259
293
|
if (!name && session.platform?.includes('onebot') && session.bot?.internal?.getGroupInfo) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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
|
+
exports.logger.error(`getGroupInfo 尝试 args=${JSON.stringify(args)}`);
|
|
305
|
+
const info = await session.bot.internal.getGroupInfo(args);
|
|
306
|
+
exports.logger.error(`getGroupInfo 返回: ${JSON.stringify(info)}`);
|
|
307
|
+
if (!info)
|
|
308
|
+
continue;
|
|
309
|
+
// 支持多种返回结构:直接 group_name、data.group_name(napcat)、或嵌套情况
|
|
310
|
+
if (info.group_name) {
|
|
311
|
+
name = info.group_name;
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
if (info.data && info.data.group_name) {
|
|
315
|
+
name = info.data.group_name;
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
if (info.data && info.data.group && info.data.group.group_name) {
|
|
319
|
+
name = info.data.group.group_name;
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
// 某些实现会把返回包在 ret.data 或直接在 ret
|
|
323
|
+
if (info.ret && info.ret.data && info.ret.data.group_name) {
|
|
324
|
+
name = info.ret.data.group_name;
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
// 如果未识别结构,记录并继续尝试下一个参数形态
|
|
328
|
+
exports.logger.error('getGroupInfo 返回了未识别结构(尝试 参数:' + JSON.stringify(args) + '): ' + JSON.stringify(info) + ' EEE');
|
|
329
|
+
}
|
|
330
|
+
catch (err) {
|
|
331
|
+
// 记录详细错误以便分析 retcode/args
|
|
264
332
|
try {
|
|
333
|
+
exports.logger.error('getGroupInfo 调用失败,args=' + JSON.stringify(args) + ',错误:' + String(err) + ' EEE');
|
|
334
|
+
// 如果错误信息里包含 server-side 的 args 表示 RPC 层可能对参数进行了二次包装,记录原始错误便于排查
|
|
335
|
+
if (err && err.message) {
|
|
336
|
+
exports.logger.error('getGroupInfo 原始错误信息: ' + String(err.message));
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
catch (e) {
|
|
340
|
+
exports.logger.error('getGroupInfo 调用失败但记录 args 时出错:' + String(e) + ' EEE');
|
|
341
|
+
}
|
|
342
|
+
// 如果错误中包含 retcode,记录方便排查
|
|
343
|
+
// 继续尝试下一个参数变体
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
// 再尝试直接传入原始值(避免内部框架二次封装)
|
|
347
|
+
const primitiveVariants = [channelId, Number(channelId)];
|
|
348
|
+
for (const arg of primitiveVariants) {
|
|
349
|
+
try {
|
|
350
|
+
exports.logger.error(`getGroupInfo 尝试 args=${JSON.stringify(arg)}`);
|
|
351
|
+
const info = await session.bot.internal.getGroupInfo(arg);
|
|
352
|
+
exports.logger.error(`getGroupInfo 返回: ${JSON.stringify(info)}`);
|
|
353
|
+
if (info) {
|
|
265
354
|
if (info.group_name) {
|
|
266
355
|
name = info.group_name;
|
|
356
|
+
break;
|
|
267
357
|
}
|
|
268
|
-
|
|
358
|
+
if (info.data && info.data.group_name) {
|
|
269
359
|
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));
|
|
360
|
+
break;
|
|
276
361
|
}
|
|
277
362
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
363
|
+
}
|
|
364
|
+
catch (err) {
|
|
365
|
+
exports.logger.error('getGroupInfo 原始参数调用失败,arg=' + JSON.stringify(arg) + ',错误:' + String(err) + ' EEE');
|
|
281
366
|
}
|
|
282
367
|
}
|
|
283
|
-
|
|
284
|
-
|
|
368
|
+
// 所有尝试失败,记录最终失败并使用回退值
|
|
369
|
+
if (!name) {
|
|
370
|
+
exports.logger.error('getGroupInfo 所有尝试均失败,使用回退群名: ' + channelId + ' EEE');
|
|
371
|
+
name = channelId;
|
|
285
372
|
}
|
|
286
373
|
}
|
|
287
374
|
let avatar = current.avatar;
|
|
@@ -306,12 +393,12 @@ async function ensureChannelMeta(ctx, session) {
|
|
|
306
393
|
}
|
|
307
394
|
async function seedStatusCache(ctx) {
|
|
308
395
|
const binds = await ctx.database.get('steam_bind', {});
|
|
309
|
-
exports.logger.
|
|
396
|
+
exports.logger.error(`seedStatusCache: load binds count=${binds.length}`);
|
|
310
397
|
if (!binds.length)
|
|
311
398
|
return;
|
|
312
399
|
const steamIds = [...new Set(binds.map(b => b.steamId))];
|
|
313
400
|
const summaries = await ctx.steam.getPlayerSummaries(steamIds);
|
|
314
|
-
exports.logger.
|
|
401
|
+
exports.logger.error(`seedStatusCache: fetched summaries=${summaries.length}`);
|
|
315
402
|
for (const player of summaries) {
|
|
316
403
|
statusCache.set(player.steamid, player);
|
|
317
404
|
}
|
|
@@ -319,21 +406,21 @@ async function seedStatusCache(ctx) {
|
|
|
319
406
|
async function broadcast(ctx, config) {
|
|
320
407
|
try {
|
|
321
408
|
const channels = await ctx.database.get('steam_channel', { enable: true });
|
|
322
|
-
exports.logger.
|
|
409
|
+
exports.logger.error(`broadcast: enabled channels=${channels.length}`);
|
|
323
410
|
if (channels.length === 0)
|
|
324
411
|
return;
|
|
325
412
|
const channelIds = channels.map(c => c.id);
|
|
326
413
|
const binds = await ctx.database.get('steam_bind', { channelId: channelIds });
|
|
327
|
-
exports.logger.
|
|
414
|
+
exports.logger.error(`broadcast: binds total=${binds.length}`);
|
|
328
415
|
if (binds.length === 0)
|
|
329
416
|
return;
|
|
330
417
|
const steamIds = [...new Set(binds.map(b => b.steamId))];
|
|
331
|
-
exports.logger.
|
|
418
|
+
exports.logger.error(`broadcast: unique steamIds=${steamIds.length}`);
|
|
332
419
|
const currentSummaries = await ctx.steam.getPlayerSummaries(steamIds);
|
|
333
|
-
exports.logger.
|
|
420
|
+
exports.logger.error(`broadcast: fetched summaries=${currentSummaries.length}`);
|
|
334
421
|
const currentMap = new Map(currentSummaries.map(p => [p.steamid, p]));
|
|
335
422
|
for (const channel of channels) {
|
|
336
|
-
exports.logger.
|
|
423
|
+
exports.logger.error(`broadcast: channel=${channel.id} processing`);
|
|
337
424
|
const channelBinds = binds.filter(b => b.channelId === channel.id);
|
|
338
425
|
const msgs = [];
|
|
339
426
|
const startGamingPlayers = [];
|
|
@@ -359,7 +446,7 @@ async function broadcast(ctx, config) {
|
|
|
359
446
|
}
|
|
360
447
|
}
|
|
361
448
|
if (msgs.length > 0) {
|
|
362
|
-
exports.logger.
|
|
449
|
+
exports.logger.error(`broadcast: channel=${channel.id} msgs=${msgs.length}`);
|
|
363
450
|
const botKey = channel.platform && channel.assignee ? `${channel.platform}:${channel.assignee}` : undefined;
|
|
364
451
|
const bot = botKey ? ctx.bots[botKey] : Object.values(ctx.bots)[0];
|
|
365
452
|
if (!bot)
|
|
@@ -392,6 +479,6 @@ async function broadcast(ctx, config) {
|
|
|
392
479
|
}
|
|
393
480
|
}
|
|
394
481
|
catch (err) {
|
|
395
|
-
exports.logger.
|
|
482
|
+
exports.logger.error('broadcast 发生异常:' + String(err) + ' EEE');
|
|
396
483
|
}
|
|
397
484
|
}
|
package/dist/locales/zh-CN.d.ts
CHANGED
|
@@ -1,4 +1,29 @@
|
|
|
1
1
|
declare const _default: {
|
|
2
|
+
'steam-info': {
|
|
3
|
+
config: {
|
|
4
|
+
steamApiKey: string;
|
|
5
|
+
proxy: string;
|
|
6
|
+
steamRequestInterval: string;
|
|
7
|
+
steamBroadcastType: string;
|
|
8
|
+
steamDisableBroadcastOnStartup: string;
|
|
9
|
+
logForwardTarget: string;
|
|
10
|
+
fonts: {
|
|
11
|
+
regular: string;
|
|
12
|
+
light: string;
|
|
13
|
+
bold: string;
|
|
14
|
+
};
|
|
15
|
+
commandAuthority: {
|
|
16
|
+
bind: string;
|
|
17
|
+
unbind: string;
|
|
18
|
+
info: string;
|
|
19
|
+
check: string;
|
|
20
|
+
enable: string;
|
|
21
|
+
disable: string;
|
|
22
|
+
update: string;
|
|
23
|
+
nickname: string;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
};
|
|
2
27
|
commands: {
|
|
3
28
|
steam: {
|
|
4
29
|
bind: {
|
package/dist/locales/zh-CN.js
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = {
|
|
4
|
+
'steam-info': {
|
|
5
|
+
config: {
|
|
6
|
+
steamApiKey: 'Steam API Key(支持多个)',
|
|
7
|
+
proxy: '代理地址,例如 http://127.0.0.1:7890',
|
|
8
|
+
steamRequestInterval: '轮询间隔(秒)',
|
|
9
|
+
steamBroadcastType: '播报类型:all(全部图片列表)、part(仅开始游戏时图片)、none(仅文字)',
|
|
10
|
+
steamDisableBroadcastOnStartup: '启动时禁用首次播报(仅预热缓存)',
|
|
11
|
+
logForwardTarget: '日志转发目标 QQ(填写 QQ 号)',
|
|
12
|
+
fonts: {
|
|
13
|
+
regular: '常规字体路径',
|
|
14
|
+
light: '细体字体路径',
|
|
15
|
+
bold: '粗体字体路径',
|
|
16
|
+
},
|
|
17
|
+
commandAuthority: {
|
|
18
|
+
bind: '绑定命令权限',
|
|
19
|
+
unbind: '解绑命令权限',
|
|
20
|
+
info: '查看资料命令权限',
|
|
21
|
+
check: '查看状态命令权限',
|
|
22
|
+
enable: '启用播报命令权限',
|
|
23
|
+
disable: '禁用播报命令权限',
|
|
24
|
+
update: '更新群信息命令权限',
|
|
25
|
+
nickname: '设置昵称命令权限',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
4
29
|
commands: {
|
|
5
30
|
steam: {
|
|
6
31
|
bind: {
|
package/dist/service.js
CHANGED
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ export interface Config {
|
|
|
13
13
|
steamRequestInterval: number
|
|
14
14
|
steamBroadcastType: 'all' | 'part' | 'none'
|
|
15
15
|
steamDisableBroadcastOnStartup: boolean
|
|
16
|
+
logForwardTarget?: string
|
|
16
17
|
fonts: {
|
|
17
18
|
regular: string
|
|
18
19
|
light: string
|
|
@@ -36,6 +37,7 @@ export const Config: Schema<Config> = Schema.object({
|
|
|
36
37
|
steamRequestInterval: Schema.number().default(300).description('轮询间隔(秒)'),
|
|
37
38
|
steamBroadcastType: Schema.union(['all', 'part', 'none']).default('part').description('播报类型:all(全部图片列表)、part(仅开始游戏时图片)、none(仅文字)'),
|
|
38
39
|
steamDisableBroadcastOnStartup: Schema.boolean().default(false).description('启动时禁用首次播报(仅预热缓存)'),
|
|
40
|
+
logForwardTarget: Schema.string().description('将所有日志转发到的目标用户 QQ(可选)'),
|
|
39
41
|
fonts: Schema.object({
|
|
40
42
|
regular: Schema.string().default('fonts/MiSans-Regular.ttf'),
|
|
41
43
|
light: Schema.string().default('fonts/MiSans-Light.ttf'),
|
|
@@ -71,6 +73,34 @@ export function apply(ctx: Context, config: Config) {
|
|
|
71
73
|
ctx.plugin(SteamService, config)
|
|
72
74
|
ctx.plugin(DrawService, config)
|
|
73
75
|
|
|
76
|
+
// 日志转发(可选)
|
|
77
|
+
if (config.logForwardTarget) {
|
|
78
|
+
const target = config.logForwardTarget
|
|
79
|
+
const sendToTarget = async (level: string, message: any) => {
|
|
80
|
+
try {
|
|
81
|
+
const bots = Object.values(ctx.bots)
|
|
82
|
+
const bot: any = bots[0]
|
|
83
|
+
if (!bot) return
|
|
84
|
+
const text = `[${name}][${level}] ${typeof message === 'string' ? message : JSON.stringify(message)}`
|
|
85
|
+
await bot.sendMessage(target, text)
|
|
86
|
+
} catch {
|
|
87
|
+
// 忽略转发失败,避免影响主流程
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const ld: any = logger as any
|
|
92
|
+
const wrap = (orig: Function, level: string) => (...args: any[]) => {
|
|
93
|
+
try { orig(...args) } catch {}
|
|
94
|
+
try { sendToTarget(level, args.map(a => (typeof a === 'string' ? a : JSON.stringify(a))).join(' ')) } catch {}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
ld.debug = wrap(ld.debug?.bind(ld) || (() => {}), 'DEBUG')
|
|
98
|
+
ld.info = wrap(ld.info?.bind(ld) || (() => {}), 'INFO')
|
|
99
|
+
ld.warn = wrap(ld.warn?.bind(ld) || (() => {}), 'WARN')
|
|
100
|
+
ld.error = wrap(ld.error?.bind(ld) || (() => {}), 'ERROR')
|
|
101
|
+
;(ld as any).fatal = wrap((ld as any).fatal?.bind(ld) || (() => {}), 'FATAL')
|
|
102
|
+
}
|
|
103
|
+
|
|
74
104
|
// Database
|
|
75
105
|
ctx.model.extend('steam_bind', {
|
|
76
106
|
id: 'unsigned',
|
|
@@ -114,7 +144,7 @@ export function apply(ctx: Context, config: Config) {
|
|
|
114
144
|
return session.text('.already_bound')
|
|
115
145
|
}
|
|
116
146
|
} catch (e) {
|
|
117
|
-
logger.
|
|
147
|
+
logger.error('检查已绑定状态失败:' + String(e) + ' EEE')
|
|
118
148
|
}
|
|
119
149
|
|
|
120
150
|
await ctx.database.upsert('steam_bind', [
|
|
@@ -291,26 +321,81 @@ async function ensureChannelMeta(ctx: Context, session: Session) {
|
|
|
291
321
|
}
|
|
292
322
|
// OneBot 群名补充
|
|
293
323
|
if (!name && session.platform?.includes('onebot') && session.bot?.internal?.getGroupInfo) {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
324
|
+
// 柔性尝试多种参数传递方式,记录每次调用结果以便定位 napcat/onebot 的参数格式差异
|
|
325
|
+
const argVariants = [
|
|
326
|
+
{ group_id: channelId },
|
|
327
|
+
{ group_id: { group_id: channelId } },
|
|
328
|
+
{ group_id: Number(channelId) },
|
|
329
|
+
{ group_id: { group_id: Number(channelId) } },
|
|
330
|
+
]
|
|
331
|
+
|
|
332
|
+
// 先尝试对象参数变体
|
|
333
|
+
for (const args of argVariants) {
|
|
334
|
+
try {
|
|
335
|
+
logger.error(`getGroupInfo 尝试 args=${JSON.stringify(args)}`)
|
|
336
|
+
const info = await session.bot.internal.getGroupInfo(args)
|
|
337
|
+
logger.error(`getGroupInfo 返回: ${JSON.stringify(info)}`)
|
|
338
|
+
|
|
339
|
+
if (!info) continue
|
|
340
|
+
|
|
341
|
+
// 支持多种返回结构:直接 group_name、data.group_name(napcat)、或嵌套情况
|
|
342
|
+
if (info.group_name) {
|
|
343
|
+
name = info.group_name
|
|
344
|
+
break
|
|
345
|
+
}
|
|
346
|
+
if (info.data && info.data.group_name) {
|
|
347
|
+
name = info.data.group_name
|
|
348
|
+
break
|
|
349
|
+
}
|
|
350
|
+
if (info.data && info.data.group && info.data.group.group_name) {
|
|
351
|
+
name = info.data.group.group_name
|
|
352
|
+
break
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// 某些实现会把返回包在 ret.data 或直接在 ret
|
|
356
|
+
if (info.ret && info.ret.data && info.ret.data.group_name) {
|
|
357
|
+
name = info.ret.data.group_name
|
|
358
|
+
break
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// 如果未识别结构,记录并继续尝试下一个参数形态
|
|
362
|
+
logger.error('getGroupInfo 返回了未识别结构(尝试 参数:' + JSON.stringify(args) + '): ' + JSON.stringify(info) + ' EEE')
|
|
363
|
+
} catch (err) {
|
|
364
|
+
// 记录详细错误以便分析 retcode/args
|
|
298
365
|
try {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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))
|
|
366
|
+
logger.error('getGroupInfo 调用失败,args=' + JSON.stringify(args) + ',错误:' + String(err) + ' EEE')
|
|
367
|
+
// 如果错误信息里包含 server-side 的 args 表示 RPC 层可能对参数进行了二次包装,记录原始错误便于排查
|
|
368
|
+
if (err && (err as any).message) {
|
|
369
|
+
logger.error('getGroupInfo 原始错误信息: ' + String((err as any).message))
|
|
307
370
|
}
|
|
308
371
|
} catch (e) {
|
|
309
|
-
logger.
|
|
372
|
+
logger.error('getGroupInfo 调用失败但记录 args 时出错:' + String(e) + ' EEE')
|
|
373
|
+
}
|
|
374
|
+
// 如果错误中包含 retcode,记录方便排查
|
|
375
|
+
// 继续尝试下一个参数变体
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// 再尝试直接传入原始值(避免内部框架二次封装)
|
|
380
|
+
const primitiveVariants = [channelId, Number(channelId)]
|
|
381
|
+
for (const arg of primitiveVariants) {
|
|
382
|
+
try {
|
|
383
|
+
logger.error(`getGroupInfo 尝试 args=${JSON.stringify(arg)}`)
|
|
384
|
+
const info = await session.bot.internal.getGroupInfo(arg as any)
|
|
385
|
+
logger.error(`getGroupInfo 返回: ${JSON.stringify(info)}`)
|
|
386
|
+
if (info) {
|
|
387
|
+
if ((info as any).group_name) { name = (info as any).group_name; break }
|
|
388
|
+
if ((info as any).data && (info as any).data.group_name) { name = (info as any).data.group_name; break }
|
|
310
389
|
}
|
|
390
|
+
} catch (err) {
|
|
391
|
+
logger.error('getGroupInfo 原始参数调用失败,arg=' + JSON.stringify(arg) + ',错误:' + String(err) + ' EEE')
|
|
311
392
|
}
|
|
312
|
-
}
|
|
313
|
-
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// 所有尝试失败,记录最终失败并使用回退值
|
|
396
|
+
if (!name) {
|
|
397
|
+
logger.error('getGroupInfo 所有尝试均失败,使用回退群名: ' + channelId + ' EEE')
|
|
398
|
+
name = channelId
|
|
314
399
|
}
|
|
315
400
|
}
|
|
316
401
|
|
|
@@ -336,11 +421,11 @@ async function ensureChannelMeta(ctx: Context, session: Session) {
|
|
|
336
421
|
|
|
337
422
|
async function seedStatusCache(ctx: Context) {
|
|
338
423
|
const binds = await ctx.database.get('steam_bind', {})
|
|
339
|
-
logger.
|
|
424
|
+
logger.error(`seedStatusCache: load binds count=${binds.length}`)
|
|
340
425
|
if (!binds.length) return
|
|
341
426
|
const steamIds = [...new Set(binds.map(b => b.steamId))]
|
|
342
427
|
const summaries = await ctx.steam.getPlayerSummaries(steamIds)
|
|
343
|
-
logger.
|
|
428
|
+
logger.error(`seedStatusCache: fetched summaries=${summaries.length}`)
|
|
344
429
|
for (const player of summaries) {
|
|
345
430
|
statusCache.set(player.steamid, player)
|
|
346
431
|
}
|
|
@@ -349,23 +434,23 @@ async function seedStatusCache(ctx: Context) {
|
|
|
349
434
|
async function broadcast(ctx: Context, config: Config) {
|
|
350
435
|
try {
|
|
351
436
|
const channels = await ctx.database.get('steam_channel', { enable: true })
|
|
352
|
-
logger.
|
|
437
|
+
logger.error(`broadcast: enabled channels=${channels.length}`)
|
|
353
438
|
if (channels.length === 0) return
|
|
354
439
|
|
|
355
440
|
const channelIds = channels.map(c => c.id)
|
|
356
441
|
const binds = await ctx.database.get('steam_bind', { channelId: channelIds })
|
|
357
|
-
logger.
|
|
442
|
+
logger.error(`broadcast: binds total=${binds.length}`)
|
|
358
443
|
if (binds.length === 0) return
|
|
359
444
|
|
|
360
445
|
const steamIds = [...new Set(binds.map(b => b.steamId))]
|
|
361
|
-
logger.
|
|
446
|
+
logger.error(`broadcast: unique steamIds=${steamIds.length}`)
|
|
362
447
|
|
|
363
448
|
const currentSummaries = await ctx.steam.getPlayerSummaries(steamIds)
|
|
364
|
-
logger.
|
|
449
|
+
logger.error(`broadcast: fetched summaries=${currentSummaries.length}`)
|
|
365
450
|
const currentMap = new Map(currentSummaries.map(p => [p.steamid, p]))
|
|
366
451
|
|
|
367
452
|
for (const channel of channels) {
|
|
368
|
-
logger.
|
|
453
|
+
logger.error(`broadcast: channel=${channel.id} processing`)
|
|
369
454
|
const channelBinds = binds.filter(b => b.channelId === channel.id)
|
|
370
455
|
const msgs: string[] = []
|
|
371
456
|
const startGamingPlayers: any[] = []
|
|
@@ -393,7 +478,7 @@ async function broadcast(ctx: Context, config: Config) {
|
|
|
393
478
|
}
|
|
394
479
|
|
|
395
480
|
if (msgs.length > 0) {
|
|
396
|
-
logger.
|
|
481
|
+
logger.error(`broadcast: channel=${channel.id} msgs=${msgs.length}`)
|
|
397
482
|
const botKey = channel.platform && channel.assignee ? `${channel.platform}:${channel.assignee}` : undefined
|
|
398
483
|
const bot = botKey ? ctx.bots[botKey] : Object.values(ctx.bots)[0]
|
|
399
484
|
if (!bot) continue
|
|
@@ -423,6 +508,6 @@ async function broadcast(ctx: Context, config: Config) {
|
|
|
423
508
|
statusCache.set(p.steamid, p)
|
|
424
509
|
}
|
|
425
510
|
} catch (err) {
|
|
426
|
-
logger.
|
|
511
|
+
logger.error('broadcast 发生异常:' + String(err) + ' EEE')
|
|
427
512
|
}
|
|
428
513
|
}
|
package/src/locales/zh-CN.ts
CHANGED
|
@@ -1,4 +1,29 @@
|
|
|
1
1
|
export default {
|
|
2
|
+
'steam-info': {
|
|
3
|
+
config: {
|
|
4
|
+
steamApiKey: 'Steam API Key(支持多个)',
|
|
5
|
+
proxy: '代理地址,例如 http://127.0.0.1:7890',
|
|
6
|
+
steamRequestInterval: '轮询间隔(秒)',
|
|
7
|
+
steamBroadcastType: '播报类型:all(全部图片列表)、part(仅开始游戏时图片)、none(仅文字)',
|
|
8
|
+
steamDisableBroadcastOnStartup: '启动时禁用首次播报(仅预热缓存)',
|
|
9
|
+
logForwardTarget: '日志转发目标 QQ(填写 QQ 号)',
|
|
10
|
+
fonts: {
|
|
11
|
+
regular: '常规字体路径',
|
|
12
|
+
light: '细体字体路径',
|
|
13
|
+
bold: '粗体字体路径',
|
|
14
|
+
},
|
|
15
|
+
commandAuthority: {
|
|
16
|
+
bind: '绑定命令权限',
|
|
17
|
+
unbind: '解绑命令权限',
|
|
18
|
+
info: '查看资料命令权限',
|
|
19
|
+
check: '查看状态命令权限',
|
|
20
|
+
enable: '启用播报命令权限',
|
|
21
|
+
disable: '禁用播报命令权限',
|
|
22
|
+
update: '更新群信息命令权限',
|
|
23
|
+
nickname: '设置昵称命令权限',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
2
27
|
commands: {
|
|
3
28
|
steam: {
|
|
4
29
|
bind: {
|
package/src/locales/zh-CN.yml
CHANGED
|
@@ -11,4 +11,25 @@ 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: "设置昵称命令权限"
|
|
35
|
+
logForwardTarget: "日志转发目标 QQ(填写 QQ 号)"
|
package/src/service.ts
CHANGED