koishi-plugin-ll-mc 1.0.1 → 1.0.3
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/index.js +96 -8
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -51,6 +51,99 @@ exports.inject = {
|
|
|
51
51
|
optional: ["markdownToImage", "puppeteer", "canvas"],
|
|
52
52
|
};
|
|
53
53
|
const logger = new koishi_1.Logger("mc");
|
|
54
|
+
// ===== 官方QQ平台 群名/群昵称 修复补丁 =====
|
|
55
|
+
const nameCache = { channel: new Map(), member: new Map() };
|
|
56
|
+
const NAME_CACHE_TTL = 60 * 60 * 1000; // 缓存 1 小时,避免官方接口限频
|
|
57
|
+
const warnThrottle = new Map(); // key -> lastWarnTime
|
|
58
|
+
function cacheGet(map, key) {
|
|
59
|
+
const item = map.get(key);
|
|
60
|
+
return item && Date.now() - item.t < NAME_CACHE_TTL ? item.v : undefined;
|
|
61
|
+
}
|
|
62
|
+
function cacheSet(map, key, value) {
|
|
63
|
+
map.set(key, { v: value, t: Date.now() });
|
|
64
|
+
}
|
|
65
|
+
// 同类警告 10 分钟内只打一次,避免刷屏
|
|
66
|
+
function throttledWarn(key, message) {
|
|
67
|
+
const now = Date.now();
|
|
68
|
+
const last = warnThrottle.get(key) || 0;
|
|
69
|
+
if (now - last < 10 * 60 * 1000)
|
|
70
|
+
return;
|
|
71
|
+
warnThrottle.set(key, now);
|
|
72
|
+
logger.warn(message);
|
|
73
|
+
}
|
|
74
|
+
async function resolveUsername(session, userId) {
|
|
75
|
+
const author = session.author;
|
|
76
|
+
if (author?.nick)
|
|
77
|
+
return author.nick; // OneBot:昵称在这
|
|
78
|
+
if (author?.name)
|
|
79
|
+
return author.name;
|
|
80
|
+
// 官方QQ平台:群消息原始事件自带 member.nick,零 API 调用
|
|
81
|
+
const raw = session.event?._data?.d;
|
|
82
|
+
if (raw?.member?.nick)
|
|
83
|
+
return raw.member.nick;
|
|
84
|
+
if (raw?.author?.username)
|
|
85
|
+
return raw.author.username;
|
|
86
|
+
// 兜底:调用 getGuildMember(仅限群聊;私聊没有群,直接返回 userId)
|
|
87
|
+
const guildId = session.guildId;
|
|
88
|
+
if (!guildId || session.isDirect)
|
|
89
|
+
return userId;
|
|
90
|
+
const key = `${guildId}:${userId}`;
|
|
91
|
+
const cached = cacheGet(nameCache.member, key);
|
|
92
|
+
if (cached)
|
|
93
|
+
return cached;
|
|
94
|
+
if (typeof session.bot?.getGuildMember === "function") {
|
|
95
|
+
try {
|
|
96
|
+
const member = await session.bot.getGuildMember(guildId, userId);
|
|
97
|
+
const name = member?.name || member?.user?.name;
|
|
98
|
+
if (name) {
|
|
99
|
+
cacheSet(nameCache.member, key, name);
|
|
100
|
+
return name;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
throttledWarn(`member:${key}`, `[mc] 获取成员昵称失败 ${userId}: ${e?.message}(若为 11253 应用无接口访问权限,请到 QQ 开放平台申请"获取群成员信息"权限)`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return userId;
|
|
108
|
+
}
|
|
109
|
+
async function resolveChannelName(session) {
|
|
110
|
+
if (session.event?.channel?.name)
|
|
111
|
+
return session.event.channel.name; // OneBot 走这里
|
|
112
|
+
const channelId = session.channelId;
|
|
113
|
+
// 私聊或没有群上下文:不调用群接口(官机 C2C 的 channelId 是用户 openid,不是群)
|
|
114
|
+
if (session.isDirect || !session.guildId)
|
|
115
|
+
return channelId;
|
|
116
|
+
const cached = cacheGet(nameCache.channel, channelId);
|
|
117
|
+
if (cached)
|
|
118
|
+
return cached;
|
|
119
|
+
const bot = session.bot;
|
|
120
|
+
if (typeof bot?.getChannel === "function") {
|
|
121
|
+
try {
|
|
122
|
+
const ch = await bot.getChannel(channelId);
|
|
123
|
+
if (ch?.name) {
|
|
124
|
+
cacheSet(nameCache.channel, channelId, ch.name);
|
|
125
|
+
return ch.name;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch { /* 官方QQ对群无效,继续走 getGuild */ }
|
|
129
|
+
}
|
|
130
|
+
// 官方QQ平台:群信息走 getGuild(内部 getGuildInfo 返回群名)
|
|
131
|
+
const guildId = session.guildId;
|
|
132
|
+
if (typeof bot?.getGuild === "function") {
|
|
133
|
+
try {
|
|
134
|
+
const g = await bot.getGuild(guildId);
|
|
135
|
+
if (g?.name) {
|
|
136
|
+
cacheSet(nameCache.channel, channelId, g.name);
|
|
137
|
+
return g.name;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
throttledWarn(`guild:${guildId}`, `[mc] 获取群名失败 ${guildId}: ${e?.message}(若为 11253/11255,请到 QQ 开放平台申请"获取群信息"权限,或确认机器人仍在该群)`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return channelId;
|
|
145
|
+
}
|
|
146
|
+
// ===== 补丁结束 =====
|
|
54
147
|
// --- 定义字体选项常量 ---
|
|
55
148
|
const FONT_OPTIONS = {
|
|
56
149
|
TITLE: "HarmonyOS_Sans_Medium",
|
|
@@ -503,12 +596,10 @@ async function apply(ctx, config) {
|
|
|
503
596
|
return next();
|
|
504
597
|
session[PROCESSED] = true;
|
|
505
598
|
const { userId, channelId, author } = session;
|
|
506
|
-
|
|
507
|
-
const username = author?.nick || author?.name || userId;
|
|
599
|
+
const username = await resolveUsername(session, userId);
|
|
508
600
|
const userAvatar = author?.avatar;
|
|
509
601
|
try {
|
|
510
|
-
const channelName =
|
|
511
|
-
(channelId ? await getChannelName(session.bot, channelId) : channelId);
|
|
602
|
+
const channelName = channelId ? await resolveChannelName(session) : channelId;
|
|
512
603
|
await ctx.database.upsert("message_counter_records", (row) => [
|
|
513
604
|
{
|
|
514
605
|
channelId,
|
|
@@ -536,16 +627,13 @@ async function apply(ctx, config) {
|
|
|
536
627
|
if (!session.channelId)
|
|
537
628
|
return;
|
|
538
629
|
const { channelId, bot } = session;
|
|
539
|
-
let sessionChannelName = session.event.channel.name;
|
|
540
630
|
const botUser = bot.user;
|
|
541
631
|
if (!botUser) {
|
|
542
632
|
logger.warn("Bot user is undefined, skipping bot message tracking.");
|
|
543
633
|
return;
|
|
544
634
|
}
|
|
545
635
|
try {
|
|
546
|
-
const channelName =
|
|
547
|
-
(await getChannelName(bot, channelId)) ||
|
|
548
|
-
channelId;
|
|
636
|
+
const channelName = (await resolveChannelName(session)) || channelId;
|
|
549
637
|
await ctx.database.upsert("message_counter_records", (row) => [
|
|
550
638
|
{
|
|
551
639
|
channelId,
|