koishi-plugin-ll-mc 1.0.6 → 1.0.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.
Files changed (2) hide show
  1. package/lib/index.js +69 -8
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -398,6 +398,12 @@ exports.Config = koishi_1.Schema.intersect([
398
398
  koishi_1.Schema.object({}),
399
399
  ]),
400
400
  ]),
401
+ // --- 群头像手动指定(官机没有群头像,只能手动填) ---
402
+ koishi_1.Schema.object({
403
+ groupAvatarMap: koishi_1.Schema.dict(String)
404
+ .default({})
405
+ .description('群头像手动指定(键=群ID,官机填群openid,OneBot 填数字群号;值=头像图片URL,或直接填数字QQ群号自动生成头像链接)。官机平台不提供群头像接口,只能手动填才能显示真头像。'),
406
+ }).description("群头像手动指定"),
401
407
  ]);
402
408
  const periodMapping = {
403
409
  today: { field: "todayPostCount", name: "今日" },
@@ -487,6 +493,8 @@ async function apply(ctx, config) {
487
493
  await reloadIconCache();
488
494
  await reloadBarBgImgCache();
489
495
  await reloadFontCache();
496
+ // 预热 OneBot 群列表(用于官机群头像按群名匹配)
497
+ refreshNapCatGuildMap();
490
498
  // 执行非破坏性的状态初始化
491
499
  await initializeResetStates();
492
500
  // 安全地检查并弥补真正错过的重置任务
@@ -1958,31 +1966,84 @@ async function apply(ctx, config) {
1958
1966
  (channelInfo[channelId]?.channelName || `群聊${channelId}`),
1959
1967
  // 使用 channelId 作为 RankingData 的 userId 和头像源
1960
1968
  userId: channelId,
1961
- avatar: groupAvatarUrl(channelId),
1969
+ avatar: groupAvatarUrl(channelId, channelInfo[channelId]?.channelName),
1962
1970
  count,
1963
1971
  percentage: calculatePercentage(count, totalCount),
1964
1972
  }));
1965
1973
  }
1966
1974
  /**
1967
- * 群头像 URL
1968
- * - "#":占位群号
1969
- * - 数字群号(OneBot/NapCat):p.qlogo.cn/gh/{群号}
1970
- * - 官机 openid(32位十六进制):官方 API 不提供群头像,尝试与成员头像同源的 qqapp 端点;
1971
- * 若无效,下载失败会走内置默认头像兜底
1975
+ * 群头像 URL 解析链:
1976
+ * 1. 配置手动指定 groupAvatarMap(键=群ID,值=URL 或数字群号)
1977
+ * 2. 数字群号(OneBot/NapCat)→ p.qlogo.cn/gh/{群号}
1978
+ * 3. 官机 openid 按群名从 NapCat 群列表匹配数字群号(两个机器人在同一群时自动生效)
1979
+ * 4. 官机 qqapp 端点尝试(与成员头像同源,多数情况对群无效)
1980
+ * 5. 默认占位头像(下载失败也会走内置兜底)
1972
1981
  */
1973
- function groupAvatarUrl(channelId) {
1974
- if (channelId === "#" || !channelId) {
1982
+ function groupAvatarUrl(channelId, channelName) {
1983
+ if (!channelId || channelId === "#") {
1975
1984
  return `https://p.qlogo.cn/gh/426230045/426230045/100`;
1976
1985
  }
1986
+ // 1. 手动指定
1987
+ const manual = config.groupAvatarMap?.[channelId];
1988
+ if (manual) {
1989
+ return /^\d+$/.test(manual)
1990
+ ? `https://p.qlogo.cn/gh/${manual}/${manual}/100`
1991
+ : manual;
1992
+ }
1993
+ // 2. 数字群号(OneBot)
1977
1994
  if (/^\d+$/.test(channelId)) {
1978
1995
  return `https://p.qlogo.cn/gh/${channelId}/${channelId}/100`;
1979
1996
  }
1997
+ // 3. 官机 openid:按群名匹配 NapCat 数字群号
1998
+ if (channelName) {
1999
+ refreshNapCatGuildMap();
2000
+ const numeric = napCatGuildIdByName.get(channelName);
2001
+ if (numeric) {
2002
+ return `https://p.qlogo.cn/gh/${numeric}/${numeric}/100`;
2003
+ }
2004
+ }
2005
+ // 4. 官机 qqapp 端点尝试
1980
2006
  const qqBot = (ctx.bots || []).find(b => b.platform === "qq" && b.config?.id);
1981
2007
  if (qqBot?.config?.id) {
1982
2008
  return `https://q.qlogo.cn/qqapp/${qqBot.config.id}/${channelId}/640`;
1983
2009
  }
2010
+ // 5. 默认占位
1984
2011
  return `https://p.qlogo.cn/gh/426230045/426230045/100`;
1985
2012
  }
2013
+ // NapCat/OneBot 群列表缓存:群名 -> 数字群号(用于官机群按名匹配头像)
2014
+ const napCatGuildIdByName = new Map();
2015
+ let napCatMapTask = null;
2016
+ function refreshNapCatGuildMap() {
2017
+ if (napCatMapTask) return;
2018
+ napCatMapTask = (async () => {
2019
+ try {
2020
+ const found = [];
2021
+ for (const bot of ctx.bots || []) {
2022
+ if (bot.platform === "qq") continue;
2023
+ if (typeof bot.getGuildList !== "function") continue;
2024
+ const list = await bot.getGuildList();
2025
+ for (const g of list?.data || []) {
2026
+ if (g?.name && g?.id) {
2027
+ found.push([g.name, g.id]);
2028
+ }
2029
+ }
2030
+ }
2031
+ if (found.length) {
2032
+ for (const [name, id] of found) {
2033
+ napCatGuildIdByName.set(name, id);
2034
+ }
2035
+ if (config.verbose) logger.info(`[mc] 已缓存 ${found.length} 个 OneBot 群(用于官机群头像匹配)`);
2036
+ }
2037
+ }
2038
+ catch (e) {
2039
+ logger.warn(`[mc] 获取 OneBot 群列表失败: ${e?.message}`);
2040
+ }
2041
+ finally {
2042
+ // 10 分钟后允许重新刷新
2043
+ setTimeout(() => { napCatMapTask = null; }, 10 * 60 * 1000);
2044
+ }
2045
+ })();
2046
+ }
1986
2047
  // --- 辅助函数:图表生成 ---
1987
2048
  /**
1988
2049
  * 生成图表的静态 CSS 样式。
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-ll-mc",
3
3
  "description": "消息统计插件(克隆自 message-counter),支持排除指定群聊",
4
- "version": "1.0.6",
4
+ "version": "1.0.7",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [