koishi-plugin-ll-mc 1.0.2 → 1.0.4
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 +43 -8
- package/package.json +45 -45
package/lib/index.js
CHANGED
|
@@ -54,6 +54,7 @@ const logger = new koishi_1.Logger("mc");
|
|
|
54
54
|
// ===== 官方QQ平台 群名/群昵称 修复补丁 =====
|
|
55
55
|
const nameCache = { channel: new Map(), member: new Map() };
|
|
56
56
|
const NAME_CACHE_TTL = 60 * 60 * 1000; // 缓存 1 小时,避免官方接口限频
|
|
57
|
+
const warnThrottle = new Map(); // key -> lastWarnTime
|
|
57
58
|
function cacheGet(map, key) {
|
|
58
59
|
const item = map.get(key);
|
|
59
60
|
return item && Date.now() - item.t < NAME_CACHE_TTL ? item.v : undefined;
|
|
@@ -61,6 +62,15 @@ function cacheGet(map, key) {
|
|
|
61
62
|
function cacheSet(map, key, value) {
|
|
62
63
|
map.set(key, { v: value, t: Date.now() });
|
|
63
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
|
+
}
|
|
64
74
|
async function resolveUsername(session, userId) {
|
|
65
75
|
const author = session.author;
|
|
66
76
|
if (author?.nick)
|
|
@@ -73,13 +83,15 @@ async function resolveUsername(session, userId) {
|
|
|
73
83
|
return raw.member.nick;
|
|
74
84
|
if (raw?.author?.username)
|
|
75
85
|
return raw.author.username;
|
|
76
|
-
// 兜底:调用 getGuildMember
|
|
77
|
-
const guildId = session.guildId
|
|
86
|
+
// 兜底:调用 getGuildMember(仅限群聊;私聊没有群,直接返回 userId)
|
|
87
|
+
const guildId = session.guildId;
|
|
88
|
+
if (!guildId || session.isDirect)
|
|
89
|
+
return userId;
|
|
78
90
|
const key = `${guildId}:${userId}`;
|
|
79
91
|
const cached = cacheGet(nameCache.member, key);
|
|
80
92
|
if (cached)
|
|
81
93
|
return cached;
|
|
82
|
-
if (
|
|
94
|
+
if (typeof session.bot?.getGuildMember === "function") {
|
|
83
95
|
try {
|
|
84
96
|
const member = await session.bot.getGuildMember(guildId, userId);
|
|
85
97
|
const name = member?.name || member?.user?.name;
|
|
@@ -89,7 +101,7 @@ async function resolveUsername(session, userId) {
|
|
|
89
101
|
}
|
|
90
102
|
}
|
|
91
103
|
catch (e) {
|
|
92
|
-
|
|
104
|
+
throttledWarn(`member:${key}`, `[mc] 获取成员昵称失败 ${userId}: ${e?.message}(若为 11253 应用无接口访问权限,请到 QQ 开放平台申请"获取群成员信息"权限)`);
|
|
93
105
|
}
|
|
94
106
|
}
|
|
95
107
|
return userId;
|
|
@@ -98,6 +110,9 @@ async function resolveChannelName(session) {
|
|
|
98
110
|
if (session.event?.channel?.name)
|
|
99
111
|
return session.event.channel.name; // OneBot 走这里
|
|
100
112
|
const channelId = session.channelId;
|
|
113
|
+
// 私聊或没有群上下文:不调用群接口(官机 C2C 的 channelId 是用户 openid,不是群)
|
|
114
|
+
if (session.isDirect || !session.guildId)
|
|
115
|
+
return channelId;
|
|
101
116
|
const cached = cacheGet(nameCache.channel, channelId);
|
|
102
117
|
if (cached)
|
|
103
118
|
return cached;
|
|
@@ -113,8 +128,8 @@ async function resolveChannelName(session) {
|
|
|
113
128
|
catch { /* 官方QQ对群无效,继续走 getGuild */ }
|
|
114
129
|
}
|
|
115
130
|
// 官方QQ平台:群信息走 getGuild(内部 getGuildInfo 返回群名)
|
|
116
|
-
const guildId = session.guildId
|
|
117
|
-
if (
|
|
131
|
+
const guildId = session.guildId;
|
|
132
|
+
if (typeof bot?.getGuild === "function") {
|
|
118
133
|
try {
|
|
119
134
|
const g = await bot.getGuild(guildId);
|
|
120
135
|
if (g?.name) {
|
|
@@ -123,7 +138,7 @@ async function resolveChannelName(session) {
|
|
|
123
138
|
}
|
|
124
139
|
}
|
|
125
140
|
catch (e) {
|
|
126
|
-
|
|
141
|
+
throttledWarn(`guild:${guildId}`, `[mc] 获取群名失败 ${guildId}: ${e?.message}(若为 11253/11255,请到 QQ 开放平台申请"获取群信息"权限,或确认机器人仍在该群)`);
|
|
127
142
|
}
|
|
128
143
|
}
|
|
129
144
|
return channelId;
|
|
@@ -1943,11 +1958,31 @@ async function apply(ctx, config) {
|
|
|
1943
1958
|
(channelInfo[channelId]?.channelName || `群聊${channelId}`),
|
|
1944
1959
|
// 使用 channelId 作为 RankingData 的 userId 和头像源
|
|
1945
1960
|
userId: channelId,
|
|
1946
|
-
avatar:
|
|
1961
|
+
avatar: groupAvatarUrl(channelId),
|
|
1947
1962
|
count,
|
|
1948
1963
|
percentage: calculatePercentage(count, totalCount),
|
|
1949
1964
|
}));
|
|
1950
1965
|
}
|
|
1966
|
+
/**
|
|
1967
|
+
* 群头像 URL:
|
|
1968
|
+
* - "#":占位群号
|
|
1969
|
+
* - 数字群号(OneBot/NapCat):p.qlogo.cn/gh/{群号}
|
|
1970
|
+
* - 官机 openid(32位十六进制):官方 API 不提供群头像,尝试与成员头像同源的 qqapp 端点;
|
|
1971
|
+
* 若无效,下载失败会走内置默认头像兜底
|
|
1972
|
+
*/
|
|
1973
|
+
function groupAvatarUrl(channelId) {
|
|
1974
|
+
if (channelId === "#" || !channelId) {
|
|
1975
|
+
return `https://p.qlogo.cn/gh/426230045/426230045/100`;
|
|
1976
|
+
}
|
|
1977
|
+
if (/^\d+$/.test(channelId)) {
|
|
1978
|
+
return `https://p.qlogo.cn/gh/${channelId}/${channelId}/100`;
|
|
1979
|
+
}
|
|
1980
|
+
const qqBot = (ctx.bots || []).find(b => b.platform === "qq" && b.config?.id);
|
|
1981
|
+
if (qqBot?.config?.id) {
|
|
1982
|
+
return `https://q.qlogo.cn/qqapp/${qqBot.config.id}/${channelId}/640`;
|
|
1983
|
+
}
|
|
1984
|
+
return `https://p.qlogo.cn/gh/426230045/426230045/100`;
|
|
1985
|
+
}
|
|
1951
1986
|
// --- 辅助函数:图表生成 ---
|
|
1952
1987
|
/**
|
|
1953
1988
|
* 生成图表的静态 CSS 样式。
|
package/package.json
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "koishi-plugin-ll-mc",
|
|
3
|
+
"description": "消息统计插件(克隆自 message-counter),支持排除指定群聊",
|
|
4
|
+
"version": "1.0.4",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"typings": "lib/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib",
|
|
9
|
+
"assets"
|
|
10
|
+
],
|
|
11
|
+
"koishi": {
|
|
12
|
+
"description": {
|
|
13
|
+
"zh": "消息统计插件:发言排行榜、群排行榜,支持排除指定群聊"
|
|
14
|
+
},
|
|
15
|
+
"service": {
|
|
16
|
+
"required": [
|
|
17
|
+
"database",
|
|
18
|
+
"cron"
|
|
19
|
+
],
|
|
20
|
+
"optional": [
|
|
21
|
+
"markdownToImage",
|
|
22
|
+
"puppeteer",
|
|
23
|
+
"canvas"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"author": "lee",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"keywords": [
|
|
30
|
+
"koishi",
|
|
31
|
+
"koishi-plugin",
|
|
32
|
+
"message-counter",
|
|
33
|
+
"rank"
|
|
34
|
+
],
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"koishi": "^4.18.9"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"koishi": "^4.18.11",
|
|
40
|
+
"koishi-plugin-cron": "^3.1.0",
|
|
41
|
+
"koishi-plugin-markdown-to-image-service": "^1.3.6",
|
|
42
|
+
"koishi-plugin-puppeteer": "^3.9.0",
|
|
43
|
+
"typescript": "^5.4.0"
|
|
44
|
+
}
|
|
45
|
+
}
|