koishi-plugin-bind-bot 2.1.0 → 2.1.2
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/export-utils.js +13 -6
- package/lib/force-bind-utils.js +12 -8
- package/lib/handlers/binding.handler.js +63 -27
- package/lib/handlers/buid.handler.js +102 -45
- package/lib/handlers/lottery.handler.js +11 -9
- package/lib/handlers/mcid.handler.js +197 -86
- package/lib/handlers/tag.handler.js +86 -31
- package/lib/handlers/whitelist.handler.js +252 -77
- package/lib/index.js +260 -142
- package/lib/repositories/mcidbind.repository.js +2 -2
- package/lib/repositories/schedule-mute.repository.js +2 -2
- package/lib/services/api.service.js +28 -22
- package/lib/services/database.service.js +16 -14
- package/lib/services/nickname.service.js +10 -10
- package/lib/types/api.d.ts +90 -0
- package/lib/types/config.d.ts +61 -0
- package/lib/types/database.d.ts +50 -0
- package/lib/types/update-data.d.ts +83 -0
- package/lib/utils/error-utils.js +7 -8
- package/lib/utils/helpers.js +45 -7
- package/lib/utils/message-utils.js +36 -23
- package/lib/utils/session-manager.js +6 -1
- package/package.json +12 -2
|
@@ -197,7 +197,7 @@ class MCIDBINDRepository {
|
|
|
197
197
|
*/
|
|
198
198
|
async deleteAll() {
|
|
199
199
|
try {
|
|
200
|
-
this.logger.debug('数据库',
|
|
200
|
+
this.logger.debug('数据库', '删除所有绑定记录');
|
|
201
201
|
const result = await this.ctx.database.remove('mcidbind', {});
|
|
202
202
|
this.logger.info('数据库', `成功删除所有绑定记录(删除${result.removed}条)`, true);
|
|
203
203
|
return result.removed;
|
|
@@ -324,7 +324,7 @@ class MCIDBINDRepository {
|
|
|
324
324
|
*/
|
|
325
325
|
async findAllAdmins() {
|
|
326
326
|
try {
|
|
327
|
-
this.logger.debug('数据库',
|
|
327
|
+
this.logger.debug('数据库', '获取所有管理员');
|
|
328
328
|
const allRecords = await this.ctx.database.get('mcidbind', {});
|
|
329
329
|
return allRecords.filter(record => record.isAdmin);
|
|
330
330
|
}
|
|
@@ -50,7 +50,7 @@ class ScheduleMuteRepository {
|
|
|
50
50
|
*/
|
|
51
51
|
async findAll() {
|
|
52
52
|
try {
|
|
53
|
-
this.logger.debug('数据库',
|
|
53
|
+
this.logger.debug('数据库', '获取所有定时禁言任务');
|
|
54
54
|
const tasks = await this.ctx.database.get('schedule_mute_tasks', {});
|
|
55
55
|
return tasks;
|
|
56
56
|
}
|
|
@@ -65,7 +65,7 @@ class ScheduleMuteRepository {
|
|
|
65
65
|
*/
|
|
66
66
|
async findAllEnabled() {
|
|
67
67
|
try {
|
|
68
|
-
this.logger.debug('数据库',
|
|
68
|
+
this.logger.debug('数据库', '获取所有已启用的定时禁言任务');
|
|
69
69
|
const tasks = await this.ctx.database.get('schedule_mute_tasks', { enabled: true });
|
|
70
70
|
return tasks;
|
|
71
71
|
}
|
|
@@ -28,7 +28,7 @@ class ApiService {
|
|
|
28
28
|
const response = await axios_1.default.get(`https://api.mojang.com/users/profiles/minecraft/${username}`, {
|
|
29
29
|
timeout: 10000, // 添加10秒超时
|
|
30
30
|
headers: {
|
|
31
|
-
'User-Agent': 'KoishiMCVerifier/1.0'
|
|
31
|
+
'User-Agent': 'KoishiMCVerifier/1.0' // 添加User-Agent头
|
|
32
32
|
}
|
|
33
33
|
});
|
|
34
34
|
if (response.status === 200 && response.data) {
|
|
@@ -54,13 +54,15 @@ class ApiService {
|
|
|
54
54
|
: error.message || '未知错误';
|
|
55
55
|
this.logger.error('Mojang API', `验证用户名"${username}"时发生错误: ${errorMessage}`);
|
|
56
56
|
// 如果是网络相关错误,尝试使用备用API检查
|
|
57
|
-
if (axios_1.default.isAxiosError(error) &&
|
|
58
|
-
error.code === '
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
57
|
+
if (axios_1.default.isAxiosError(error) &&
|
|
58
|
+
(error.code === 'ENOTFOUND' ||
|
|
59
|
+
error.code === 'ETIMEDOUT' ||
|
|
60
|
+
error.code === 'ECONNRESET' ||
|
|
61
|
+
error.code === 'ECONNREFUSED' ||
|
|
62
|
+
error.code === 'ECONNABORTED' ||
|
|
63
|
+
error.response?.status === 429 || // 添加429 (Too Many Requests)
|
|
64
|
+
error.response?.status === 403)) {
|
|
65
|
+
// 添加403 (Forbidden)
|
|
64
66
|
// 尝试使用playerdb.co作为备用API
|
|
65
67
|
this.logger.info('Mojang API', `遇到错误(${error.code || error.response?.status}),将尝试使用备用API`);
|
|
66
68
|
return this.tryBackupAPI(username);
|
|
@@ -84,7 +86,7 @@ class ApiService {
|
|
|
84
86
|
'User-Agent': 'KoishiMCVerifier/1.0'
|
|
85
87
|
}
|
|
86
88
|
});
|
|
87
|
-
if (backupResponse.status === 200 && backupResponse.data?.code ===
|
|
89
|
+
if (backupResponse.status === 200 && backupResponse.data?.code === 'player.found') {
|
|
88
90
|
const playerData = backupResponse.data.data.player;
|
|
89
91
|
const rawId = playerData.raw_id || playerData.id.replace(/-/g, ''); // 确保使用不带连字符的UUID
|
|
90
92
|
this.logger.info('备用API', `用户名"${username}"验证成功,UUID: ${rawId},标准名称: ${playerData.username}`);
|
|
@@ -117,7 +119,7 @@ class ApiService {
|
|
|
117
119
|
const response = await axios_1.default.get(`https://api.mojang.com/user/profile/${cleanUuid}`, {
|
|
118
120
|
timeout: 10000,
|
|
119
121
|
headers: {
|
|
120
|
-
'User-Agent': 'KoishiMCVerifier/1.0'
|
|
122
|
+
'User-Agent': 'KoishiMCVerifier/1.0'
|
|
121
123
|
}
|
|
122
124
|
});
|
|
123
125
|
if (response.status === 200 && response.data) {
|
|
@@ -131,13 +133,15 @@ class ApiService {
|
|
|
131
133
|
}
|
|
132
134
|
catch (error) {
|
|
133
135
|
// 如果是网络相关错误,尝试使用备用API
|
|
134
|
-
if (axios_1.default.isAxiosError(error) &&
|
|
135
|
-
error.code === '
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
136
|
+
if (axios_1.default.isAxiosError(error) &&
|
|
137
|
+
(error.code === 'ENOTFOUND' ||
|
|
138
|
+
error.code === 'ETIMEDOUT' ||
|
|
139
|
+
error.code === 'ECONNRESET' ||
|
|
140
|
+
error.code === 'ECONNREFUSED' ||
|
|
141
|
+
error.code === 'ECONNABORTED' ||
|
|
142
|
+
error.response?.status === 429 || // 添加429 (Too Many Requests)
|
|
143
|
+
error.response?.status === 403)) {
|
|
144
|
+
// 添加403 (Forbidden)
|
|
141
145
|
this.logger.info('Mojang API', `通过UUID查询用户名时遇到错误(${error.code || error.response?.status}),将尝试使用备用API`);
|
|
142
146
|
return this.getUsernameByUuidBackupAPI(uuid);
|
|
143
147
|
}
|
|
@@ -161,10 +165,10 @@ class ApiService {
|
|
|
161
165
|
const response = await axios_1.default.get(`https://playerdb.co/api/player/minecraft/${formattedUuid}`, {
|
|
162
166
|
timeout: 10000,
|
|
163
167
|
headers: {
|
|
164
|
-
'User-Agent': 'KoishiMCVerifier/1.0'
|
|
168
|
+
'User-Agent': 'KoishiMCVerifier/1.0'
|
|
165
169
|
}
|
|
166
170
|
});
|
|
167
|
-
if (response.status === 200 && response.data?.code ===
|
|
171
|
+
if (response.status === 200 && response.data?.code === 'player.found') {
|
|
168
172
|
const playerData = response.data.data.player;
|
|
169
173
|
this.logger.debug('备用API', `UUID "${formattedUuid}" 当前用户名: ${playerData.username}`);
|
|
170
174
|
return playerData.username;
|
|
@@ -193,11 +197,13 @@ class ApiService {
|
|
|
193
197
|
return null;
|
|
194
198
|
}
|
|
195
199
|
this.logger.debug('B站官方API', `开始查询UID ${uid} 的官方信息`);
|
|
196
|
-
const response = await axios_1.default.get(
|
|
200
|
+
const response = await axios_1.default.get('https://api.bilibili.com/x/space/acc/info', {
|
|
197
201
|
params: { mid: uid },
|
|
198
202
|
timeout: 10000,
|
|
199
203
|
headers: {
|
|
200
|
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
|
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'
|
|
201
207
|
}
|
|
202
208
|
});
|
|
203
209
|
if (response.data.code === 0 && response.data.data) {
|
|
@@ -312,7 +318,7 @@ class ApiService {
|
|
|
312
318
|
'dungeons', // 地下城风格
|
|
313
319
|
'facepalm', // 捂脸
|
|
314
320
|
'mojavatar', // Mojave姿态
|
|
315
|
-
'head'
|
|
321
|
+
'head' // 头部特写
|
|
316
322
|
];
|
|
317
323
|
// 随机选择一个动作
|
|
318
324
|
const randomPose = poses[Math.floor(Math.random() * poses.length)];
|
|
@@ -27,7 +27,7 @@ class DatabaseService {
|
|
|
27
27
|
try {
|
|
28
28
|
// 处理空值
|
|
29
29
|
if (!qqId) {
|
|
30
|
-
this.logger.warn('MCIDBIND',
|
|
30
|
+
this.logger.warn('MCIDBIND', '尝试查询空QQ号');
|
|
31
31
|
return null;
|
|
32
32
|
}
|
|
33
33
|
const normalizedQQId = this.normalizeQQId(qqId);
|
|
@@ -45,7 +45,7 @@ class DatabaseService {
|
|
|
45
45
|
async getMcBindByUsername(mcUsername) {
|
|
46
46
|
// 处理空值
|
|
47
47
|
if (!mcUsername) {
|
|
48
|
-
this.logger.warn('MCIDBIND',
|
|
48
|
+
this.logger.warn('MCIDBIND', '尝试查询空MC用户名');
|
|
49
49
|
return null;
|
|
50
50
|
}
|
|
51
51
|
// 使用 Repository 查询
|
|
@@ -58,16 +58,16 @@ class DatabaseService {
|
|
|
58
58
|
try {
|
|
59
59
|
// 验证输入参数
|
|
60
60
|
if (!userId) {
|
|
61
|
-
this.logger.error('MCIDBIND',
|
|
61
|
+
this.logger.error('MCIDBIND', '创建/更新绑定失败: 无效的用户ID');
|
|
62
62
|
return false;
|
|
63
63
|
}
|
|
64
64
|
if (!mcUsername) {
|
|
65
|
-
this.logger.error('MCIDBIND',
|
|
65
|
+
this.logger.error('MCIDBIND', '创建/更新绑定失败: 无效的MC用户名');
|
|
66
66
|
return false;
|
|
67
67
|
}
|
|
68
68
|
const normalizedQQId = this.normalizeQQId(userId);
|
|
69
69
|
if (!normalizedQQId) {
|
|
70
|
-
this.logger.error('MCIDBIND',
|
|
70
|
+
this.logger.error('MCIDBIND', '创建/更新绑定失败: 无法提取有效的QQ号');
|
|
71
71
|
return false;
|
|
72
72
|
}
|
|
73
73
|
// 查询是否已存在绑定记录
|
|
@@ -118,12 +118,12 @@ class DatabaseService {
|
|
|
118
118
|
try {
|
|
119
119
|
// 验证输入参数
|
|
120
120
|
if (!userId) {
|
|
121
|
-
this.logger.error('MCIDBIND',
|
|
121
|
+
this.logger.error('MCIDBIND', '删除绑定失败: 无效的用户ID');
|
|
122
122
|
return false;
|
|
123
123
|
}
|
|
124
124
|
const normalizedQQId = this.normalizeQQId(userId);
|
|
125
125
|
if (!normalizedQQId) {
|
|
126
|
-
this.logger.error('MCIDBIND',
|
|
126
|
+
this.logger.error('MCIDBIND', '删除绑定失败: 无法提取有效的QQ号');
|
|
127
127
|
return false;
|
|
128
128
|
}
|
|
129
129
|
// 查询是否存在绑定记录
|
|
@@ -161,7 +161,7 @@ class DatabaseService {
|
|
|
161
161
|
try {
|
|
162
162
|
// 验证输入参数
|
|
163
163
|
if (!username) {
|
|
164
|
-
this.logger.warn('绑定检查',
|
|
164
|
+
this.logger.warn('绑定检查', '尝试检查空MC用户名');
|
|
165
165
|
return false;
|
|
166
166
|
}
|
|
167
167
|
// 跳过临时用户名的检查
|
|
@@ -207,7 +207,7 @@ class DatabaseService {
|
|
|
207
207
|
async getBuidBindByBuid(buid) {
|
|
208
208
|
try {
|
|
209
209
|
if (!buid) {
|
|
210
|
-
this.logger.warn('B站账号绑定',
|
|
210
|
+
this.logger.warn('B站账号绑定', '尝试查询空B站UID');
|
|
211
211
|
return null;
|
|
212
212
|
}
|
|
213
213
|
const bind = await this.mcidbindRepo.findByBuidUid(buid);
|
|
@@ -245,7 +245,7 @@ class DatabaseService {
|
|
|
245
245
|
try {
|
|
246
246
|
const normalizedQQId = this.normalizeQQId(userId);
|
|
247
247
|
if (!normalizedQQId) {
|
|
248
|
-
this.logger.error('B站账号绑定',
|
|
248
|
+
this.logger.error('B站账号绑定', '创建/更新绑定失败: 无法提取有效的QQ号');
|
|
249
249
|
return false;
|
|
250
250
|
}
|
|
251
251
|
// 检查该UID是否已被其他用户绑定(安全检查)
|
|
@@ -266,7 +266,9 @@ class DatabaseService {
|
|
|
266
266
|
medalName: buidUser.medal?.name || '',
|
|
267
267
|
medalLevel: buidUser.medal?.level || 0,
|
|
268
268
|
wealthMedalLevel: buidUser.wealthMedalLevel || 0,
|
|
269
|
-
lastActiveTime: buidUser.last_active_time
|
|
269
|
+
lastActiveTime: buidUser.last_active_time
|
|
270
|
+
? new Date(buidUser.last_active_time)
|
|
271
|
+
: new Date(),
|
|
270
272
|
lastModified: new Date()
|
|
271
273
|
};
|
|
272
274
|
if (bind) {
|
|
@@ -302,7 +304,7 @@ class DatabaseService {
|
|
|
302
304
|
try {
|
|
303
305
|
const normalizedQQId = this.normalizeQQId(userId);
|
|
304
306
|
if (!normalizedQQId) {
|
|
305
|
-
this.logger.error('B站账号信息更新',
|
|
307
|
+
this.logger.error('B站账号信息更新', '更新失败: 无法提取有效的QQ号');
|
|
306
308
|
return false;
|
|
307
309
|
}
|
|
308
310
|
// 查询是否已存在绑定记录
|
|
@@ -339,7 +341,7 @@ class DatabaseService {
|
|
|
339
341
|
async checkAndUpdateUsername(bind) {
|
|
340
342
|
try {
|
|
341
343
|
if (!bind || !bind.mcUuid) {
|
|
342
|
-
this.logger.warn('用户名更新',
|
|
344
|
+
this.logger.warn('用户名更新', '无法检查用户名更新: 空绑定或空UUID');
|
|
343
345
|
return bind;
|
|
344
346
|
}
|
|
345
347
|
// 通过UUID查询最新用户名
|
|
@@ -377,7 +379,7 @@ class DatabaseService {
|
|
|
377
379
|
async checkAndUpdateUsernameWithCache(bind) {
|
|
378
380
|
try {
|
|
379
381
|
if (!bind || !bind.mcUuid) {
|
|
380
|
-
this.logger.warn('改名检测缓存',
|
|
382
|
+
this.logger.warn('改名检测缓存', '无法检查用户名更新: 空绑定或空UUID');
|
|
381
383
|
return bind;
|
|
382
384
|
}
|
|
383
385
|
const now = new Date();
|
|
@@ -28,7 +28,7 @@ class NicknameService {
|
|
|
28
28
|
if (!nickname || !buidUsername)
|
|
29
29
|
return false;
|
|
30
30
|
// 期望格式:B站名称(ID:MC用户名)或 B站名称(ID:未绑定)
|
|
31
|
-
const mcInfo = mcUsername && !mcUsername.startsWith('_temp_') ? mcUsername :
|
|
31
|
+
const mcInfo = mcUsername && !mcUsername.startsWith('_temp_') ? mcUsername : '未绑定';
|
|
32
32
|
const expectedFormat = `${buidUsername}(ID:${mcInfo})`;
|
|
33
33
|
return nickname === expectedFormat;
|
|
34
34
|
}
|
|
@@ -40,14 +40,14 @@ class NicknameService {
|
|
|
40
40
|
// 1. 尝试获取B站官方API的用户信息(最权威)
|
|
41
41
|
let officialUsername = null;
|
|
42
42
|
try {
|
|
43
|
-
this.logger.debug('群昵称设置',
|
|
43
|
+
this.logger.debug('群昵称设置', '正在查询B站官方API...');
|
|
44
44
|
const officialInfo = await this.getBilibiliOfficialUserInfo(buidUid);
|
|
45
45
|
if (officialInfo && officialInfo.name) {
|
|
46
46
|
officialUsername = officialInfo.name;
|
|
47
47
|
this.logger.info('群昵称设置', `[层1-官方API] ✅ "${officialUsername}"`, true);
|
|
48
48
|
}
|
|
49
49
|
else {
|
|
50
|
-
this.logger.warn('群昵称设置',
|
|
50
|
+
this.logger.warn('群昵称设置', '[层1-官方API] ❌ 查询失败');
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
catch (officialError) {
|
|
@@ -56,13 +56,13 @@ class NicknameService {
|
|
|
56
56
|
// 2. 尝试获取ZMINFO API的用户信息(可能有缓存)
|
|
57
57
|
let zminfoUserData = null;
|
|
58
58
|
try {
|
|
59
|
-
this.logger.debug('群昵称设置',
|
|
59
|
+
this.logger.debug('群昵称设置', '正在查询ZMINFO API...');
|
|
60
60
|
zminfoUserData = await this.validateBUID(buidUid);
|
|
61
61
|
if (zminfoUserData && zminfoUserData.username) {
|
|
62
62
|
this.logger.debug('群昵称设置', `[层2-ZMINFO] "${zminfoUserData.username}"`);
|
|
63
63
|
}
|
|
64
64
|
else {
|
|
65
|
-
this.logger.warn('群昵称设置',
|
|
65
|
+
this.logger.warn('群昵称设置', '[层2-ZMINFO] 查询失败');
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
catch (zminfoError) {
|
|
@@ -101,7 +101,7 @@ class NicknameService {
|
|
|
101
101
|
return; // 无需更新
|
|
102
102
|
}
|
|
103
103
|
if (!zminfoData) {
|
|
104
|
-
this.logger.debug('群昵称设置',
|
|
104
|
+
this.logger.debug('群昵称设置', '无ZMINFO数据,跳过数据库同步');
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
107
107
|
try {
|
|
@@ -136,7 +136,7 @@ class NicknameService {
|
|
|
136
136
|
else {
|
|
137
137
|
this.logger.warn('群昵称设置', `⚠️ 验证失败,期望"${nickname}",实际"${verifyNickname}",可能是权限不足或API延迟`);
|
|
138
138
|
if (!currentNickname) {
|
|
139
|
-
this.logger.warn('群昵称设置',
|
|
139
|
+
this.logger.warn('群昵称设置', '建议检查: 1.机器人是否为群管理员 2.群设置是否允许管理员修改昵称 3.OneBot实现是否支持该功能');
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
}
|
|
@@ -159,7 +159,7 @@ class NicknameService {
|
|
|
159
159
|
const actualUserId = targetUserId || session.userId;
|
|
160
160
|
const normalizedUserId = this.normalizeQQId(actualUserId);
|
|
161
161
|
const targetGroupId = specifiedGroupId || this.config.autoNicknameGroupId;
|
|
162
|
-
const mcInfo =
|
|
162
|
+
const mcInfo = mcUsername && !mcUsername.startsWith('_temp_') ? mcUsername : '未绑定';
|
|
163
163
|
this.logger.debug('群昵称设置', `开始处理QQ(${normalizedUserId})的群昵称设置,目标群: ${targetGroupId}`);
|
|
164
164
|
// 检查前置条件
|
|
165
165
|
if (!session.bot.internal) {
|
|
@@ -173,7 +173,7 @@ class NicknameService {
|
|
|
173
173
|
// 获取最新的B站用户名
|
|
174
174
|
let latestBuidUsername = buidUsername;
|
|
175
175
|
if (buidUid) {
|
|
176
|
-
this.logger.debug('群昵称设置',
|
|
176
|
+
this.logger.debug('群昵称设置', '开始四层判断获取最新B站用户名...');
|
|
177
177
|
this.logger.debug('群昵称设置', `[层3-数据库] "${buidUsername}"`);
|
|
178
178
|
const result = await this.getLatestBuidUsername(buidUid, buidUsername);
|
|
179
179
|
latestBuidUsername = result.username;
|
|
@@ -210,7 +210,7 @@ class NicknameService {
|
|
|
210
210
|
catch (getInfoError) {
|
|
211
211
|
// 无法获取当前昵称,直接设置新昵称
|
|
212
212
|
this.logger.warn('群昵称设置', `获取QQ(${normalizedUserId})当前群昵称失败: ${getInfoError.message}`);
|
|
213
|
-
this.logger.debug('群昵称设置',
|
|
213
|
+
this.logger.debug('群昵称设置', '将直接尝试设置新昵称...');
|
|
214
214
|
await this.setAndVerifyNickname(session, targetGroupId, normalizedUserId, targetNickname);
|
|
215
215
|
}
|
|
216
216
|
}
|
package/lib/types/api.d.ts
CHANGED
|
@@ -5,59 +5,149 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* Mojang API 响应接口
|
|
7
7
|
* 用于获取MC用户UUID和用户名
|
|
8
|
+
*
|
|
9
|
+
* @see https://api.mojang.com/users/profiles/minecraft/{username}
|
|
10
|
+
* @see https://api.mojang.com/user/profile/{uuid}
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```json
|
|
14
|
+
* {
|
|
15
|
+
* "id": "069a79f444e94726a5befca90e38aaf5",
|
|
16
|
+
* "name": "Notch"
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
8
19
|
*/
|
|
9
20
|
export interface MojangProfile {
|
|
21
|
+
/** UUID (不带连字符,32位十六进制字符串) */
|
|
10
22
|
id: string;
|
|
23
|
+
/** 玩家名称 (Mojang返回的标准大小写) */
|
|
11
24
|
name: string;
|
|
12
25
|
}
|
|
13
26
|
/**
|
|
14
27
|
* ZMINFO API - 用户信息接口
|
|
28
|
+
*
|
|
29
|
+
* @see {zminfoApiUrl}/api/user/{uid}
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```json
|
|
33
|
+
* {
|
|
34
|
+
* "uid": "12345678",
|
|
35
|
+
* "username": "用户名",
|
|
36
|
+
* "avatar_url": "https://...",
|
|
37
|
+
* "guard_level": 3,
|
|
38
|
+
* "guard_level_text": "总督",
|
|
39
|
+
* "max_guard_level": 3,
|
|
40
|
+
* "max_guard_level_text": "总督",
|
|
41
|
+
* "medal": {
|
|
42
|
+
* "name": "粉丝牌",
|
|
43
|
+
* "level": 20,
|
|
44
|
+
* "uid": "87654321",
|
|
45
|
+
* "room": 123456
|
|
46
|
+
* },
|
|
47
|
+
* "wealthMedalLevel": 15,
|
|
48
|
+
* "last_active_time": "2025-10-23T12:00:00Z"
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
15
51
|
*/
|
|
16
52
|
export interface ZminfoUser {
|
|
53
|
+
/** B站用户UID */
|
|
17
54
|
uid: string;
|
|
55
|
+
/** B站用户名 */
|
|
18
56
|
username: string;
|
|
57
|
+
/** 用户头像URL */
|
|
19
58
|
avatar_url: string;
|
|
59
|
+
/** 当前舰长等级 (0=无, 1=总督, 2=提督, 3=舰长) */
|
|
20
60
|
guard_level: number;
|
|
61
|
+
/** 当前舰长等级文本描述 */
|
|
21
62
|
guard_level_text: string;
|
|
63
|
+
/** 历史最高舰长等级 */
|
|
22
64
|
max_guard_level: number;
|
|
65
|
+
/** 历史最高舰长等级文本描述 */
|
|
23
66
|
max_guard_level_text: string;
|
|
67
|
+
/** 粉丝牌信息 (如果用户拥有) */
|
|
24
68
|
medal: {
|
|
69
|
+
/** 粉丝牌名称 */
|
|
25
70
|
name: string;
|
|
71
|
+
/** 粉丝牌等级 */
|
|
26
72
|
level: number;
|
|
73
|
+
/** UP主UID */
|
|
27
74
|
uid: string;
|
|
75
|
+
/** 直播间房间号 */
|
|
28
76
|
room: number;
|
|
29
77
|
} | null;
|
|
78
|
+
/** 荣耀等级 (财富勋章等级) */
|
|
30
79
|
wealthMedalLevel: number;
|
|
80
|
+
/** 最后活跃时间 (ISO 8601格式) */
|
|
31
81
|
last_active_time: string;
|
|
32
82
|
}
|
|
33
83
|
/**
|
|
34
84
|
* ZMINFO API 响应接口
|
|
85
|
+
*
|
|
86
|
+
* @example 成功响应
|
|
87
|
+
* ```json
|
|
88
|
+
* {
|
|
89
|
+
* "success": true,
|
|
90
|
+
* "message": "success",
|
|
91
|
+
* "data": {
|
|
92
|
+
* "user": { ... }
|
|
93
|
+
* }
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* @example 失败响应
|
|
98
|
+
* ```json
|
|
99
|
+
* {
|
|
100
|
+
* "success": false,
|
|
101
|
+
* "message": "User not found"
|
|
102
|
+
* }
|
|
103
|
+
* ```
|
|
35
104
|
*/
|
|
36
105
|
export interface ZminfoApiResponse {
|
|
106
|
+
/** 请求是否成功 */
|
|
37
107
|
success: boolean;
|
|
108
|
+
/** 响应消息 */
|
|
38
109
|
message: string;
|
|
110
|
+
/** 响应数据 (仅成功时存在) */
|
|
39
111
|
data?: {
|
|
112
|
+
/** 用户信息 */
|
|
40
113
|
user?: ZminfoUser;
|
|
41
114
|
};
|
|
42
115
|
}
|
|
43
116
|
/**
|
|
44
117
|
* Bilibili Live API - 粉丝勋章信息接口
|
|
118
|
+
*
|
|
119
|
+
* @see https://api.live.bilibili.com/xlive/app-ucenter/v1/user/GetMyMedals
|
|
45
120
|
*/
|
|
46
121
|
export interface MedalInfo {
|
|
122
|
+
/** UP主UID */
|
|
47
123
|
target_id: number;
|
|
124
|
+
/** 粉丝牌等级 */
|
|
48
125
|
level: number;
|
|
126
|
+
/** 粉丝牌名称 */
|
|
49
127
|
medal_name: string;
|
|
128
|
+
/** 粉丝牌渐变色起始颜色 */
|
|
50
129
|
medal_color_start: number;
|
|
130
|
+
/** 粉丝牌渐变色结束颜色 */
|
|
51
131
|
medal_color_end: number;
|
|
132
|
+
/** 粉丝牌边框颜色 */
|
|
52
133
|
medal_color_border: number;
|
|
134
|
+
/** 舰长等级 (0=无, 1=总督, 2=提督, 3=舰长) */
|
|
53
135
|
guard_level: number;
|
|
136
|
+
/** 佩戴状态 (0=未佩戴, 1=已佩戴) */
|
|
54
137
|
wearing_status: number;
|
|
138
|
+
/** 粉丝牌ID */
|
|
55
139
|
medal_id: number;
|
|
140
|
+
/** 当前亲密度 */
|
|
56
141
|
intimacy: number;
|
|
142
|
+
/** 下一级所需亲密度 */
|
|
57
143
|
next_intimacy: number;
|
|
144
|
+
/** 今日亲密度 */
|
|
58
145
|
today_feed: number;
|
|
146
|
+
/** 每日亲密度上限 */
|
|
59
147
|
day_limit: number;
|
|
148
|
+
/** 舰长图标URL */
|
|
60
149
|
guard_icon: string;
|
|
150
|
+
/** 荣耀图标URL */
|
|
61
151
|
honor_icon: string;
|
|
62
152
|
}
|
|
63
153
|
/**
|
package/lib/types/config.d.ts
CHANGED
|
@@ -4,43 +4,104 @@
|
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
6
|
* 插件配置接口
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* 该接口定义了 BIND-BOT 插件的所有配置选项,包括:
|
|
10
|
+
* - 基础配置 (冷却时间、管理员等)
|
|
11
|
+
* - 服务器配置
|
|
12
|
+
* - 显示选项
|
|
13
|
+
* - B站相关配置
|
|
14
|
+
* - 天选播报配置
|
|
15
|
+
* - 强制绑定配置
|
|
7
16
|
*/
|
|
8
17
|
export interface Config {
|
|
18
|
+
/** 绑定冷却天数 (防止频繁更改绑定) */
|
|
9
19
|
cooldownDays: number;
|
|
20
|
+
/** 主管理员QQ号 (拥有最高权限) */
|
|
10
21
|
masterId: string;
|
|
22
|
+
/** Minecraft服务器配置列表 */
|
|
11
23
|
servers: ServerConfig[];
|
|
24
|
+
/** 是否允许文本前缀 (支持不使用命令前缀) */
|
|
12
25
|
allowTextPrefix: boolean;
|
|
26
|
+
/** 机器人昵称 (用于消息中的称呼) */
|
|
13
27
|
botNickname: string;
|
|
28
|
+
/** 自动撤回时间 (秒, 0表示不撤回) */
|
|
14
29
|
autoRecallTime: number;
|
|
30
|
+
/** 是否撤回用户消息 */
|
|
15
31
|
recallUserMessage: boolean;
|
|
32
|
+
/** 调试模式 (输出详细日志) */
|
|
16
33
|
debugMode: boolean;
|
|
34
|
+
/** 是否显示B站头像 */
|
|
17
35
|
showAvatar: boolean;
|
|
36
|
+
/** 是否显示MC皮肤渲染 */
|
|
18
37
|
showMcSkin: boolean;
|
|
38
|
+
/** ZMINFO API 地址 (用于获取B站用户信息) */
|
|
19
39
|
zminfoApiUrl: string;
|
|
40
|
+
/** 是否启用天选播报功能 */
|
|
20
41
|
enableLotteryBroadcast: boolean;
|
|
42
|
+
/** 天选播报目标群ID (为空则不播报到群) */
|
|
21
43
|
lotteryTargetGroupId: string;
|
|
44
|
+
/** 天选播报私聊目标ID (为空则不私聊播报) */
|
|
22
45
|
lotteryTargetPrivateId: string;
|
|
46
|
+
/** 自动群昵称设置目标群ID (仅在该群自动设置昵称) */
|
|
23
47
|
autoNicknameGroupId: string;
|
|
48
|
+
/** 强制绑定使用的SESSDATA (B站Cookie) */
|
|
24
49
|
forceBindSessdata: string;
|
|
50
|
+
/** 强制绑定目标UP主UID */
|
|
25
51
|
forceBindTargetUpUid: number;
|
|
52
|
+
/** 强制绑定目标直播间房间号 */
|
|
26
53
|
forceBindTargetRoomId: number;
|
|
54
|
+
/** 强制绑定目标粉丝牌名称 */
|
|
27
55
|
forceBindTargetMedalName: string;
|
|
28
56
|
}
|
|
29
57
|
/**
|
|
30
58
|
* 服务器配置接口
|
|
59
|
+
*
|
|
60
|
+
* @remarks
|
|
61
|
+
* 定义单个 Minecraft 服务器的配置信息,包括 RCON 连接、白名单命令模板等
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* {
|
|
66
|
+
* id: 'survival',
|
|
67
|
+
* name: '生存服',
|
|
68
|
+
* rconAddress: '127.0.0.1:25575',
|
|
69
|
+
* rconPassword: 'password123',
|
|
70
|
+
* addCommand: 'whitelist add {username}',
|
|
71
|
+
* removeCommand: 'whitelist remove {username}',
|
|
72
|
+
* idType: 'username',
|
|
73
|
+
* allowSelfApply: true,
|
|
74
|
+
* acceptEmptyResponse: false,
|
|
75
|
+
* displayAddress: 'mc.example.com',
|
|
76
|
+
* description: '主生存服务器',
|
|
77
|
+
* enabled: true
|
|
78
|
+
* }
|
|
79
|
+
* ```
|
|
31
80
|
*/
|
|
32
81
|
export interface ServerConfig {
|
|
82
|
+
/** 服务器唯一标识符 */
|
|
33
83
|
id: string;
|
|
84
|
+
/** 服务器显示名称 */
|
|
34
85
|
name: string;
|
|
86
|
+
/** RCON 地址 (格式: host:port) */
|
|
35
87
|
rconAddress: string;
|
|
88
|
+
/** RCON 密码 */
|
|
36
89
|
rconPassword: string;
|
|
90
|
+
/** 添加白名单命令模板 (支持变量: {username}, {uuid}) */
|
|
37
91
|
addCommand: string;
|
|
92
|
+
/** 移除白名单命令模板 (支持变量: {username}, {uuid}) */
|
|
38
93
|
removeCommand: string;
|
|
94
|
+
/** ID 类型 (username: 使用用户名, uuid: 使用UUID) */
|
|
39
95
|
idType: 'username' | 'uuid';
|
|
96
|
+
/** 是否允许用户自助申请白名单 */
|
|
40
97
|
allowSelfApply: boolean;
|
|
98
|
+
/** 是否接受 RCON 空响应 (某些服务器返回空字符串表示成功) */
|
|
41
99
|
acceptEmptyResponse?: boolean;
|
|
100
|
+
/** 服务器展示地址 (用于显示给用户) */
|
|
42
101
|
displayAddress?: string;
|
|
102
|
+
/** 服务器说明信息 */
|
|
43
103
|
description?: string;
|
|
104
|
+
/** 服务器是否启用 */
|
|
44
105
|
enabled?: boolean;
|
|
45
106
|
}
|
|
46
107
|
/**
|