koishi-plugin-bind-bot 2.1.6 → 2.1.7
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.
|
@@ -98,37 +98,25 @@ class GroupRequestReviewHandler extends base_handler_1.BaseHandler {
|
|
|
98
98
|
*/
|
|
99
99
|
async handleNotice(session) {
|
|
100
100
|
try {
|
|
101
|
-
// 调试日志:记录所有notice事件
|
|
102
|
-
this.logger.info('入群审批', `[DEBUG] 收到notice事件 - type: ${session.type}, subtype: ${session.subtype}, guildId: ${session.guildId}`, true);
|
|
103
101
|
// 只处理群表情回应事件
|
|
104
102
|
if (session.subtype !== 'group-msg-emoji-like') {
|
|
105
|
-
this.logger.info('入群审批', `[DEBUG] 跳过: subtype不匹配 (${session.subtype})`, true);
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
// 只处理管理群的表情
|
|
109
|
-
if (session.guildId !== this.reviewConfig.reviewGroupId) {
|
|
110
|
-
this.logger.info('入群审批', `[DEBUG] 跳过: guildId不匹配 (收到: ${session.guildId}, 需要: ${this.reviewConfig.reviewGroupId})`, true);
|
|
111
103
|
return;
|
|
112
104
|
}
|
|
113
105
|
// 获取原始事件数据(直接访问 session.onebot,参考luckydraw实现)
|
|
114
106
|
const data = session.onebot;
|
|
115
|
-
this.logger.info('入群审批', `[DEBUG] onebot数据: ${JSON.stringify(data)}`, true);
|
|
116
107
|
const messageId = data?.message_id;
|
|
117
108
|
const userId = data?.user_id?.toString();
|
|
118
109
|
const likes = data?.likes || [];
|
|
119
110
|
if (!messageId || !userId || likes.length === 0) {
|
|
120
|
-
this.logger.info('入群审批', '[DEBUG] 跳过: 缺少必要数据或likes为空', true);
|
|
121
111
|
return;
|
|
122
112
|
}
|
|
123
113
|
const msgId = messageId.toString();
|
|
124
114
|
const emojiData = likes;
|
|
125
115
|
const operatorId = this.deps.normalizeQQId(userId);
|
|
126
|
-
this.logger.
|
|
116
|
+
this.logger.debug('入群审批', `收到表情回应 - 消息: ${msgId}, 操作者: ${operatorId}, 表情数: ${emojiData.length}`);
|
|
127
117
|
// 检查是否是待审批的消息
|
|
128
118
|
const pendingReq = this.pendingRequests.get(msgId);
|
|
129
119
|
if (!pendingReq) {
|
|
130
|
-
this.logger.info('入群审批', `[DEBUG] 跳过: 消息${msgId}不在待审批列表中`, true);
|
|
131
|
-
this.logger.info('入群审批', `[DEBUG] 当前待审批列表: ${Array.from(this.pendingRequests.keys()).join(', ')}`, true);
|
|
132
120
|
return;
|
|
133
121
|
}
|
|
134
122
|
// 检查是否已处理
|
|
@@ -589,20 +577,35 @@ class GroupRequestReviewHandler extends base_handler_1.BaseHandler {
|
|
|
589
577
|
* 执行自动绑定
|
|
590
578
|
*/
|
|
591
579
|
async performAutoBind(qq, uid, bot) {
|
|
592
|
-
const axios = require('axios');
|
|
593
580
|
try {
|
|
594
|
-
// 1.
|
|
595
|
-
this.logger.debug('入群审批',
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
581
|
+
// 1. 使用双API数据源获取最新用户信息(优先B站官方API)
|
|
582
|
+
this.logger.debug('入群审批', `开始获取 B站 UID ${uid} 的信息`);
|
|
583
|
+
// 尝试获取B站官方API的用户信息(最权威)
|
|
584
|
+
let officialUsername = null;
|
|
585
|
+
try {
|
|
586
|
+
this.logger.debug('入群审批', '正在查询B站官方API...');
|
|
587
|
+
const officialInfo = await this.deps.apiService.getBilibiliOfficialUserInfo(uid);
|
|
588
|
+
if (officialInfo && officialInfo.name) {
|
|
589
|
+
officialUsername = officialInfo.name;
|
|
590
|
+
this.logger.info('入群审批', `[官方API] ✅ 获取到用户名: "${officialUsername}"`, true);
|
|
600
591
|
}
|
|
601
|
-
|
|
602
|
-
|
|
592
|
+
else {
|
|
593
|
+
this.logger.warn('入群审批', '[官方API] ❌ 查询失败');
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
catch (officialError) {
|
|
597
|
+
this.logger.warn('入群审批', `[官方API] ❌ 查询出错: ${officialError.message}`);
|
|
598
|
+
}
|
|
599
|
+
// 获取ZMINFO API的完整用户信息(包含粉丝牌、大航海等数据)
|
|
600
|
+
this.logger.debug('入群审批', '正在查询ZMINFO API...');
|
|
601
|
+
const zminfoUser = await this.deps.apiService.validateBUID(uid);
|
|
602
|
+
if (!zminfoUser) {
|
|
603
603
|
throw new Error(`无法验证B站UID: ${uid}`);
|
|
604
604
|
}
|
|
605
|
-
|
|
605
|
+
this.logger.debug('入群审批', `[ZMINFO] 获取到用户名: "${zminfoUser.username}"`);
|
|
606
|
+
// 使用官方API的用户名(如果可用),否则使用ZMINFO的
|
|
607
|
+
const finalUsername = officialUsername || zminfoUser.username;
|
|
608
|
+
this.logger.info('入群审批', `🎯 最终采用用户名: "${finalUsername}"`, true);
|
|
606
609
|
// 2. 检查是否已被其他人绑定
|
|
607
610
|
const existingBind = await this.repos.mcidbind.findByBuidUid(uid);
|
|
608
611
|
if (existingBind && existingBind.qqId !== qq) {
|
|
@@ -617,15 +620,15 @@ class GroupRequestReviewHandler extends base_handler_1.BaseHandler {
|
|
|
617
620
|
qqId: qq,
|
|
618
621
|
mcUsername: tempMcUsername,
|
|
619
622
|
mcUuid: '',
|
|
620
|
-
buidUid:
|
|
621
|
-
buidUsername:
|
|
622
|
-
guardLevel:
|
|
623
|
-
guardLevelText:
|
|
624
|
-
maxGuardLevel:
|
|
625
|
-
maxGuardLevelText:
|
|
626
|
-
medalName:
|
|
627
|
-
medalLevel:
|
|
628
|
-
wealthMedalLevel:
|
|
623
|
+
buidUid: zminfoUser.uid,
|
|
624
|
+
buidUsername: finalUsername,
|
|
625
|
+
guardLevel: zminfoUser.guard_level || 0,
|
|
626
|
+
guardLevelText: zminfoUser.guard_level_text || '',
|
|
627
|
+
maxGuardLevel: zminfoUser.guard_level || 0,
|
|
628
|
+
maxGuardLevelText: zminfoUser.guard_level_text || '',
|
|
629
|
+
medalName: zminfoUser.medal?.name || '',
|
|
630
|
+
medalLevel: zminfoUser.medal?.level || 0,
|
|
631
|
+
wealthMedalLevel: zminfoUser.wealthMedalLevel || 0,
|
|
629
632
|
lastActiveTime: new Date(),
|
|
630
633
|
lastModified: new Date()
|
|
631
634
|
});
|
|
@@ -634,26 +637,29 @@ class GroupRequestReviewHandler extends base_handler_1.BaseHandler {
|
|
|
634
637
|
else {
|
|
635
638
|
// 更新现有绑定
|
|
636
639
|
await this.repos.mcidbind.update(qq, {
|
|
637
|
-
buidUid:
|
|
638
|
-
buidUsername:
|
|
639
|
-
guardLevel:
|
|
640
|
-
guardLevelText:
|
|
641
|
-
maxGuardLevel: Math.max(bind.maxGuardLevel || 0,
|
|
642
|
-
maxGuardLevelText:
|
|
643
|
-
?
|
|
640
|
+
buidUid: zminfoUser.uid,
|
|
641
|
+
buidUsername: finalUsername,
|
|
642
|
+
guardLevel: zminfoUser.guard_level || 0,
|
|
643
|
+
guardLevelText: zminfoUser.guard_level_text || '',
|
|
644
|
+
maxGuardLevel: Math.max(bind.maxGuardLevel || 0, zminfoUser.guard_level || 0),
|
|
645
|
+
maxGuardLevelText: zminfoUser.guard_level > (bind.maxGuardLevel || 0)
|
|
646
|
+
? zminfoUser.guard_level_text
|
|
644
647
|
: bind.maxGuardLevelText,
|
|
645
|
-
medalName:
|
|
646
|
-
medalLevel:
|
|
647
|
-
wealthMedalLevel:
|
|
648
|
+
medalName: zminfoUser.medal?.name || '',
|
|
649
|
+
medalLevel: zminfoUser.medal?.level || 0,
|
|
650
|
+
wealthMedalLevel: zminfoUser.wealthMedalLevel || 0,
|
|
648
651
|
lastActiveTime: new Date(),
|
|
649
652
|
lastModified: new Date()
|
|
650
653
|
});
|
|
651
654
|
this.logger.info('入群审批', `已更新绑定 - QQ: ${qq}, UID: ${uid}`, true);
|
|
652
655
|
}
|
|
653
|
-
// 4.
|
|
656
|
+
// 4. 更新群昵称(使用标准格式)
|
|
654
657
|
try {
|
|
655
658
|
const groupId = this.reviewConfig.targetGroupId;
|
|
656
|
-
const
|
|
659
|
+
const mcInfo = bind.mcUsername && !bind.mcUsername.startsWith('_temp_')
|
|
660
|
+
? bind.mcUsername
|
|
661
|
+
: '未绑定';
|
|
662
|
+
const nickname = `${finalUsername}(ID:${mcInfo})`;
|
|
657
663
|
await bot.internal.setGroupCard(groupId, qq, nickname);
|
|
658
664
|
this.logger.info('入群审批', `已更新群昵称 - QQ: ${qq}, 昵称: ${nickname}`);
|
|
659
665
|
}
|
|
@@ -661,7 +667,7 @@ class GroupRequestReviewHandler extends base_handler_1.BaseHandler {
|
|
|
661
667
|
this.logger.warn('入群审批', `更新群昵称失败: ${error.message}`);
|
|
662
668
|
// 昵称更新失败不影响绑定
|
|
663
669
|
}
|
|
664
|
-
this.logger.info('入群审批', `自动绑定完成 - QQ: ${qq}, UID: ${uid}, 用户名: ${
|
|
670
|
+
this.logger.info('入群审批', `自动绑定完成 - QQ: ${qq}, UID: ${uid}, 用户名: ${finalUsername}`, true);
|
|
665
671
|
}
|
|
666
672
|
catch (error) {
|
|
667
673
|
this.logger.error('入群审批', `自动绑定失败: ${error.message}`, error);
|
|
@@ -7,9 +7,15 @@ import type { MojangProfile, ZminfoUser } from '../types';
|
|
|
7
7
|
export declare class ApiService {
|
|
8
8
|
private logger;
|
|
9
9
|
private config;
|
|
10
|
+
private cookieString;
|
|
10
11
|
constructor(logger: LoggerService, config: {
|
|
11
12
|
zminfoApiUrl: string;
|
|
13
|
+
SESSDATA?: string;
|
|
12
14
|
});
|
|
15
|
+
/**
|
|
16
|
+
* 处理cookie字符串,支持完整cookie或单独SESSDATA
|
|
17
|
+
*/
|
|
18
|
+
private processCookie;
|
|
13
19
|
/**
|
|
14
20
|
* 验证 Minecraft 用户名是否存在
|
|
15
21
|
* @param username MC 用户名
|
|
@@ -12,9 +12,30 @@ const axios_1 = __importDefault(require("axios"));
|
|
|
12
12
|
class ApiService {
|
|
13
13
|
logger;
|
|
14
14
|
config;
|
|
15
|
+
cookieString;
|
|
15
16
|
constructor(logger, config) {
|
|
16
17
|
this.logger = logger;
|
|
17
18
|
this.config = config;
|
|
19
|
+
this.cookieString = this.processCookie(config.SESSDATA || '');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 处理cookie字符串,支持完整cookie或单独SESSDATA
|
|
23
|
+
*/
|
|
24
|
+
processCookie(input) {
|
|
25
|
+
if (!input || input.trim() === '') {
|
|
26
|
+
return '';
|
|
27
|
+
}
|
|
28
|
+
const trimmedInput = input.trim();
|
|
29
|
+
// 如果输入包含多个cookie字段(包含分号),则认为是完整cookie
|
|
30
|
+
if (trimmedInput.includes(';')) {
|
|
31
|
+
return trimmedInput;
|
|
32
|
+
}
|
|
33
|
+
// 如果输入只是SESSDATA值(不包含"SESSDATA="前缀)
|
|
34
|
+
if (!trimmedInput.startsWith('SESSDATA=')) {
|
|
35
|
+
return `SESSDATA=${trimmedInput}`;
|
|
36
|
+
}
|
|
37
|
+
// 如果输入已经是"SESSDATA=xxx"格式
|
|
38
|
+
return trimmedInput;
|
|
18
39
|
}
|
|
19
40
|
// =========== Mojang API ===========
|
|
20
41
|
/**
|
|
@@ -197,14 +218,20 @@ class ApiService {
|
|
|
197
218
|
return null;
|
|
198
219
|
}
|
|
199
220
|
this.logger.debug('B站官方API', `开始查询UID ${uid} 的官方信息`);
|
|
221
|
+
const headers = {
|
|
222
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
223
|
+
Referer: 'https://space.bilibili.com/',
|
|
224
|
+
Origin: 'https://space.bilibili.com'
|
|
225
|
+
};
|
|
226
|
+
// 如果配置了Cookie,则添加到请求头(避免被风控)
|
|
227
|
+
if (this.cookieString) {
|
|
228
|
+
headers.Cookie = this.cookieString;
|
|
229
|
+
this.logger.debug('B站官方API', '使用Cookie进行请求');
|
|
230
|
+
}
|
|
200
231
|
const response = await axios_1.default.get('https://api.bilibili.com/x/space/acc/info', {
|
|
201
232
|
params: { mid: uid },
|
|
202
233
|
timeout: 10000,
|
|
203
|
-
headers
|
|
204
|
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
205
|
-
Referer: 'https://space.bilibili.com/',
|
|
206
|
-
Origin: 'https://space.bilibili.com'
|
|
207
|
-
}
|
|
234
|
+
headers
|
|
208
235
|
});
|
|
209
236
|
if (response.data.code === 0 && response.data.data) {
|
|
210
237
|
const userData = response.data.data;
|
|
@@ -14,7 +14,10 @@ class ServiceContainer {
|
|
|
14
14
|
nickname;
|
|
15
15
|
constructor(ctx, config, logger, mcidbindRepo, normalizeQQId) {
|
|
16
16
|
// 1. 实例化 API 服务(无依赖)
|
|
17
|
-
this.api = new api_service_1.ApiService(logger.createChild('API服务'), {
|
|
17
|
+
this.api = new api_service_1.ApiService(logger.createChild('API服务'), {
|
|
18
|
+
zminfoApiUrl: config.zminfoApiUrl,
|
|
19
|
+
SESSDATA: config.forceBindSessdata
|
|
20
|
+
});
|
|
18
21
|
// 2. 实例化数据库服务(依赖 API 服务)
|
|
19
22
|
this.database = new database_service_1.DatabaseService(ctx, logger.createChild('数据库服务'), mcidbindRepo, normalizeQQId, (uuid) => this.api.getUsernameByUuid(uuid));
|
|
20
23
|
// 3. 实例化群昵称服务(依赖 API 和数据库服务)
|