koishi-plugin-group-verification 1.0.36 → 1.0.37

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 (3) hide show
  1. package/lib/index.js +42 -26
  2. package/package.json +1 -1
  3. package/src/index.ts +45 -28
package/lib/index.js CHANGED
@@ -60,19 +60,23 @@ function clogV(msg, ...args) {
60
60
  if (pluginLogLevel === "详细") logger.debug(msg, ...args);
61
61
  }
62
62
  __name(clogV, "clogV");
63
+ function renderMsg(tmpl) {
64
+ return tmpl.replace(/\\\\n/g, "").replace(/\\n/g, "\n").replace(/\x01/g, "\\n");
65
+ }
66
+ __name(renderMsg, "renderMsg");
63
67
  var Config = import_koishi.Schema.object({
64
68
  defaultReminderMessage: import_koishi.Schema.string().description("默认提醒消息模板(使用 \\n 表示换行,可包含下方变量)").default("{user}({id}) 申请入群\\n申请理由: {question}\\n匹配情况: {answer}/{threshold}\\n使用 gva 同意或 gvr 拒绝申请"),
65
69
  enableStrictGroupCheck: import_koishi.Schema.boolean().description("是否启用严格的群号检查(检查群号长度)").default(false),
66
70
  logLevel: import_koishi.Schema.union(["debug", "info", "warn"]).description("日志详细程度").default("info"),
67
71
  // debug=详细, info=中等, warn=简洁
68
- permissionDeniedMessage: import_koishi.Schema.string().description("权限不足时返回给调用者的提示").default("权限不足: 需要群主/管理员权限或koishi三级以上权限"),
69
- invalidGroupMessage: import_koishi.Schema.string().description("无效群号或机器人未在该群时的提示").default("群号 {group} 格式不合法或机器人不在该群中"),
70
- parameterConflictMessage: import_koishi.Schema.string().description("参数冲突时提示").default("参数冲突: -? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)"),
71
- noKeywordsMessage: import_koishi.Schema.string().description("未提供关键词且无法从现有配置继承时的提示").default("请先提供关键词创建配置,或使用 -? 查询配置,-r 删除配置"),
72
- blacklistAddSuccess: import_koishi.Schema.string().description("将用户加入黑名单后的提示,可使用 {user},{group},{reason}").default("已将用户 {user} 加入群 {group} 黑名单{reason}"),
73
- blacklistRemoveSuccess: import_koishi.Schema.string().description("从黑名单移除用户后的提示,可使用 {user},{group}").default("已从群 {group} 的黑名单中移除用户 {user}"),
74
- blacklistListEmpty: import_koishi.Schema.string().description("黑名单为空时提示").default("{group} 的黑名单为空"),
75
- blacklistInfoTemplate: import_koishi.Schema.string().description("查询指定用户状态时的模板,可用 {global},{group}").default("全局黑名单: {global}\n本群黑名单: {group}")
72
+ permissionDeniedMessage: import_koishi.Schema.string().description("权限不足时返回给调用者的提示,支持 \\n 换行").default("权限不足: 需要群主/管理员权限或koishi三级以上权限"),
73
+ invalidGroupMessage: import_koishi.Schema.string().description("无效群号或机器人未在该群时的提示,可用 {group},支持 \\n 换行").default("群号 {group} 格式不合法或机器人不在该群中"),
74
+ parameterConflictMessage: import_koishi.Schema.string().description("参数冲突时提示,支持 \\n 换行").default("参数冲突: -? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)"),
75
+ noKeywordsMessage: import_koishi.Schema.string().description("未提供关键词且无法从现有配置继承时的提示,支持 \\n 换行").default("请先提供关键词创建配置,或使用 -? 查询配置,-r 删除配置"),
76
+ blacklistAddSuccess: import_koishi.Schema.string().description('将用户加入黑名单后的提示,可用 {user},{group},{reason};{group} 含"群"前缀(all时为"全局"),支持 \\n 换行').default("已将用户 {user} 加入{group}黑名单{reason}"),
77
+ blacklistRemoveSuccess: import_koishi.Schema.string().description('从黑名单移除用户后的提示,可用 {user},{group};{group} 含"群"前缀,支持 \\n 换行').default("已从{group}的黑名单中移除用户 {user}"),
78
+ blacklistListEmpty: import_koishi.Schema.string().description('黑名单为空时提示,可用 {group};{group} 含""前缀,支持 \\n 换行').default("{group}的黑名单为空"),
79
+ blacklistInfoTemplate: import_koishi.Schema.string().description("查询指定用户状态时的模板,可用 {global},{group},支持 \\n 换行").default("全局黑名单: {global}\\n本群黑名单: {group}")
76
80
  }).description("群组验证插件配置");
77
81
  var inject = ["database"];
78
82
  var ESC_QUOTE = "\0";
@@ -442,6 +446,18 @@ async function handleGuildMemberRequestEvent(ctx, session) {
442
446
  } catch (e) {
443
447
  logger.warn("黑名单检查失败", e);
444
448
  }
449
+ {
450
+ let resolvedName;
451
+ try {
452
+ const userInfo = await session.bot.getUser(userId);
453
+ if (userInfo?.name) resolvedName = userInfo.name;
454
+ } catch (_) {
455
+ }
456
+ if (!resolvedName && session.username && session.username !== userId) {
457
+ resolvedName = session.username;
458
+ }
459
+ session.username = resolvedName || userId;
460
+ }
445
461
  const { isValid, matchedCount, requiredThreshold } = await verifyApplication(config, message, session);
446
462
  clogV(`验证结果 guild=${guildId} user=${userId} msg="${message}" matched=${matchedCount} threshold=${requiredThreshold} valid=${isValid}`);
447
463
  if (isValid) {
@@ -604,7 +620,7 @@ async function handleFailedVerification(ctx, session, config, matchedCount, requ
604
620
  logger.warn("handleFailedVerification invoked without guildId, aborting");
605
621
  return;
606
622
  }
607
- const username = session.username || "未知用户";
623
+ const username = session.username || userId;
608
624
  const message = session.content || "";
609
625
  clog(
610
626
  "debug",
@@ -716,7 +732,7 @@ async function processBlacklistCommand(ctx, session, rawArgs, config) {
716
732
  } else {
717
733
  if (config?.enableStrictGroupCheck) {
718
734
  if (!/^\d{5,15}$/.test(group)) {
719
- return (config.invalidGroupMessage || "群号 {group} 格式不合法或机器人不在该群中").replace("{group}", group);
735
+ return renderMsg((config.invalidGroupMessage || "群号 {group} 格式不合法或机器人不在该群中").replace("{group}", group));
720
736
  }
721
737
  }
722
738
  const [ok, err] = await checkPermission(session, group);
@@ -746,8 +762,9 @@ async function processBlacklistCommand(ctx, session, rawArgs, config) {
746
762
  logger.warn(`踢出用户 ${targetUser} 失败`, e);
747
763
  }
748
764
  }
749
- const tmpl = config && config.blacklistAddSuccess || "已将用户 {user} 加入群 {group} 黑名单{reason}";
750
- return tmpl.replace("{user}", targetUser).replace("{group}", group).replace("{reason}", reason ? `,原因: ${reason}` : "");
765
+ const tmpl = config && config.blacklistAddSuccess || "已将用户 {user} 加入{group}黑名单{reason}";
766
+ const groupLabelA = group.toLowerCase() === "all" ? "全局" : "" + group;
767
+ return renderMsg(tmpl.replace("{user}", targetUser).replace("{group}", groupLabelA).replace("{reason}", reason ? `,原因: ${reason}` : ""));
751
768
  }
752
769
  if (op === "r") {
753
770
  targetUser = parts[1];
@@ -760,7 +777,7 @@ async function processBlacklistCommand(ctx, session, rawArgs, config) {
760
777
  } else {
761
778
  if (config?.enableStrictGroupCheck) {
762
779
  if (!/^\d{5,15}$/.test(group)) {
763
- return (config.invalidGroupMessage || "群号 {group} 格式不合法或机器人不在该群中").replace("{group}", group);
780
+ return renderMsg((config.invalidGroupMessage || "群号 {group} 格式不合法或机器人不在该群中").replace("{group}", group));
764
781
  }
765
782
  }
766
783
  const [ok, err] = await checkPermission(session, group);
@@ -773,8 +790,9 @@ async function processBlacklistCommand(ctx, session, rawArgs, config) {
773
790
  delete entries[targetUser];
774
791
  await ctx.database.set("group_verification_blacklist", { id: row.id }, { entries });
775
792
  }
776
- const tmpl = config && config.blacklistRemoveSuccess || "已从群 {group} 的黑名单中移除用户 {user}";
777
- return tmpl.replace("{user}", targetUser).replace("{group}", group);
793
+ const tmpl = config && config.blacklistRemoveSuccess || "已从{group}的黑名单中移除用户 {user}";
794
+ const groupLabelR = group.toLowerCase() === "all" ? "全局" : "群 " + group;
795
+ return renderMsg(tmpl.replace("{user}", targetUser).replace("{group}", groupLabelR));
778
796
  }
779
797
  if (op === "l") {
780
798
  group = parts[1] || getCurrentGroup();
@@ -785,7 +803,7 @@ async function processBlacklistCommand(ctx, session, rawArgs, config) {
785
803
  } else {
786
804
  if (config?.enableStrictGroupCheck) {
787
805
  if (!/^\d{5,15}$/.test(group)) {
788
- return (config.invalidGroupMessage || "群号 {group} 格式不合法或机器人不在该群中").replace("{group}", group);
806
+ return renderMsg((config.invalidGroupMessage || "群号 {group} 格式不合法或机器人不在该群中").replace("{group}", group));
789
807
  }
790
808
  }
791
809
  const [ok, err] = await checkPermission(session, group);
@@ -793,11 +811,9 @@ async function processBlacklistCommand(ctx, session, rawArgs, config) {
793
811
  }
794
812
  const rows = await ctx.database.get("group_verification_blacklist", { groupId: group });
795
813
  if (rows.length === 0) {
796
- if (group && group.toLowerCase() === "all") {
797
- return "全局黑名单为空";
798
- }
799
- const tmpl = config && config.blacklistListEmpty || "群 {group} 的黑名单为空";
800
- return tmpl.replace("{group}", group);
814
+ const tmpl = config && config.blacklistListEmpty || "{group}的黑名单为空";
815
+ const groupLabelL = group && group.toLowerCase() === "all" ? "全局" : "群 " + group;
816
+ return renderMsg(tmpl.replace("{group}", groupLabelL));
801
817
  }
802
818
  const entries = rows[0].entries || {};
803
819
  let prefix = group && group.toLowerCase() === "all" ? "全局黑名单: \n" : `群 ${group} 黑名单:
@@ -815,7 +831,7 @@ async function processBlacklistCommand(ctx, session, rawArgs, config) {
815
831
  const groupArg = parts[2];
816
832
  const globalRows = await ctx.database.get("group_verification_blacklist", { groupId: "all" });
817
833
  const globalHit = globalRows.length > 0 && (globalRows[0].entries || {})[targetUser] !== void 0;
818
- const tmpl = config && config.blacklistInfoTemplate || "全局黑名单: {global}\n本群黑名单: {group}";
834
+ const tmpl = (config && config.blacklistInfoTemplate || "全局黑名单: {global}\\n本群黑名单: {group}").replace(/\\\\n/g, "").replace(/\\n/g, "\n").replace(/\x01/g, "\\n");
819
835
  const formatReply = /* @__PURE__ */ __name((localHit, groupsList) => {
820
836
  if (groupsList) {
821
837
  return tmpl.replace("{global}", globalHit ? "有" : "无").replace(
@@ -860,7 +876,7 @@ async function processBlacklistCommand(ctx, session, rawArgs, config) {
860
876
  const groupId = groupArg;
861
877
  if (config?.enableStrictGroupCheck && groupId.toLowerCase() !== "all") {
862
878
  if (!/^\d{5,15}$/.test(groupId)) {
863
- return (config.invalidGroupMessage || "群号 {group} 格式不合法或机器人不在该群中").replace("{group}", groupId);
879
+ return renderMsg((config.invalidGroupMessage || "群号 {group} 格式不合法或机器人不在该群中").replace("{group}", groupId));
864
880
  }
865
881
  }
866
882
  const [ok, err] = await checkPermission(session, groupId);
@@ -1008,7 +1024,7 @@ function apply(ctx, config) {
1008
1024
  return [false, `无法获取群 ${groupId} 的成员信息,请确认机器人已在该群中`];
1009
1025
  }
1010
1026
  clogV(`权限检查 - 权限不足`);
1011
- return [false, config.permissionDeniedMessage || "权限不足: 需要群主/管理员权限或koishi三级以上权限"];
1027
+ return [false, renderMsg(config.permissionDeniedMessage || "权限不足: 需要群主/管理员权限或koishi三级以上权限")];
1012
1028
  }
1013
1029
  __name(checkPermission2, "checkPermission");
1014
1030
  const groupVerify = ctx.command("group-verify", "群组验证管理命令").alias("gv", "gverify");
@@ -1046,7 +1062,7 @@ function apply(ctx, config) {
1046
1062
  clogV(`合并后options: ${JSON.stringify(cleanedOptions, null, 2)}
1047
1063
  `);
1048
1064
  if ((cleanedOptions.query || cleanedOptions.remove) && (parsedKeywords.length > 0 || cleanedOptions.method !== void 0 || cleanedOptions.threshold !== void 0 || cleanedOptions.message !== void 0 || cleanedOptions.enableMessage || cleanedOptions.disableMessage)) {
1049
- return config.parameterConflictMessage || "参数冲突: -? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)";
1065
+ return renderMsg(config.parameterConflictMessage || "参数冲突: -? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)");
1050
1066
  }
1051
1067
  const hasRealMessageParam = cleanedOptions.message !== void 0;
1052
1068
  const hasRealEnableMessageParam = cleanedOptions.enableMessage === true;
@@ -1160,7 +1176,7 @@ ${displayMsg}
1160
1176
  }
1161
1177
  if (keywordList.length === 0 && !cleanedOptions.query && !cleanedOptions.remove) {
1162
1178
  if (!existingConfig) {
1163
- return config.noKeywordsMessage || "请先提供关键词创建配置,或使用 -? 查询配置,-r 删除配置";
1179
+ return renderMsg(config.noKeywordsMessage || "请先提供关键词创建配置,或使用 -? 查询配置,-r 删除配置");
1164
1180
  }
1165
1181
  keywordList = existingConfig.keywords;
1166
1182
  }
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "bugs": {
9
9
  "url": "https://github.com/LHDyx/koishi-plugin-group-verification/issues"
10
10
  },
11
- "version": "1.0.36",
11
+ "version": "1.0.37",
12
12
  "main": "lib/index.js",
13
13
  "typings": "lib/index.d.ts",
14
14
  "files": [
package/src/index.ts CHANGED
@@ -35,6 +35,11 @@ function clogV(msg: string, ...args: any[]): void {
35
35
  if (pluginLogLevel === '详细') logger.debug(msg, ...args)
36
36
  }
37
37
 
38
+ /** 处理配置文本中的换行转义:\n→换行,\\n→字面量 \n */
39
+ function renderMsg(tmpl: string): string {
40
+ return tmpl.replace(/\\\\n/g, '\x01').replace(/\\n/g, '\n').replace(/\x01/g, '\\n')
41
+ }
42
+
38
43
  // 数据库模型定义
39
44
  declare module 'koishi' {
40
45
  interface Tables {
@@ -114,14 +119,14 @@ export const Config: Schema<Config> = Schema.object({
114
119
  .default('{user}({id}) 申请入群\\n申请理由: {question}\\n匹配情况: {answer}/{threshold}\\n使用 gva 同意或 gvr 拒绝申请'),
115
120
  enableStrictGroupCheck: Schema.boolean().description('是否启用严格的群号检查(检查群号长度)').default(false),
116
121
  logLevel: Schema.union(['debug', 'info', 'warn']).description('日志详细程度').default('info'), // debug=详细, info=中等, warn=简洁
117
- permissionDeniedMessage: Schema.string().description('权限不足时返回给调用者的提示').default('权限不足: 需要群主/管理员权限或koishi三级以上权限'),
118
- invalidGroupMessage: Schema.string().description('无效群号或机器人未在该群时的提示').default('群号 {group} 格式不合法或机器人不在该群中'),
119
- parameterConflictMessage: Schema.string().description('参数冲突时提示').default('参数冲突: -? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)'),
120
- noKeywordsMessage: Schema.string().description('未提供关键词且无法从现有配置继承时的提示').default('请先提供关键词创建配置,或使用 -? 查询配置,-r 删除配置'),
121
- blacklistAddSuccess: Schema.string().description('将用户加入黑名单后的提示,可使用 {user},{group},{reason}').default('已将用户 {user} 加入群 {group} 黑名单{reason}'),
122
- blacklistRemoveSuccess: Schema.string().description('从黑名单移除用户后的提示,可使用 {user},{group}').default('已从群 {group} 的黑名单中移除用户 {user}'),
123
- blacklistListEmpty: Schema.string().description('黑名单为空时提示').default('{group} 的黑名单为空'),
124
- blacklistInfoTemplate: Schema.string().description('查询指定用户状态时的模板,可用 {global},{group}').default('全局黑名单: {global}\n本群黑名单: {group}')
122
+ permissionDeniedMessage: Schema.string().description('权限不足时返回给调用者的提示,支持 \\n 换行').default('权限不足: 需要群主/管理员权限或koishi三级以上权限'),
123
+ invalidGroupMessage: Schema.string().description('无效群号或机器人未在该群时的提示,可用 {group},支持 \\n 换行').default('群号 {group} 格式不合法或机器人不在该群中'),
124
+ parameterConflictMessage: Schema.string().description('参数冲突时提示,支持 \\n 换行').default('参数冲突: -? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)'),
125
+ noKeywordsMessage: Schema.string().description('未提供关键词且无法从现有配置继承时的提示,支持 \\n 换行').default('请先提供关键词创建配置,或使用 -? 查询配置,-r 删除配置'),
126
+ blacklistAddSuccess: Schema.string().description('将用户加入黑名单后的提示,可用 {user},{group},{reason};{group} 含"群"前缀(all时为"全局"),支持 \\n 换行').default('已将用户 {user} 加入{group}黑名单{reason}'),
127
+ blacklistRemoveSuccess: Schema.string().description('从黑名单移除用户后的提示,可用 {user},{group};{group} 含"群"前缀,支持 \\n 换行').default('已从{group}的黑名单中移除用户 {user}'),
128
+ blacklistListEmpty: Schema.string().description('黑名单为空时提示,可用 {group};{group} 含"群"前缀,支持 \\n 换行').default('{group}的黑名单为空'),
129
+ blacklistInfoTemplate: Schema.string().description('查询指定用户状态时的模板,可用 {global},{group},支持 \\n 换行').default('全局黑名单: {global}\\n本群黑名单: {group}')
125
130
  })
126
131
  .description('群组验证插件配置')
127
132
 
@@ -604,6 +609,19 @@ export async function handleGuildMemberRequestEvent(ctx: Context, session: any)
604
609
  logger.warn('黑名单检查失败', e);
605
610
  }
606
611
 
612
+ // 解析用户昵称优先级:1) API拉取昵称 2) session.username(若非userId) 3) userId
613
+ {
614
+ let resolvedName: string | undefined
615
+ try {
616
+ const userInfo = await session.bot.getUser(userId)
617
+ if (userInfo?.name) resolvedName = userInfo.name
618
+ } catch (_) {}
619
+ if (!resolvedName && session.username && session.username !== userId) {
620
+ resolvedName = session.username
621
+ }
622
+ session.username = resolvedName || userId
623
+ }
624
+
607
625
  const { isValid, matchedCount, requiredThreshold } = await verifyApplication(config, message, session);
608
626
  clogV(`验证结果 guild=${guildId} user=${userId} msg="${message}" matched=${matchedCount} threshold=${requiredThreshold} valid=${isValid}`);
609
627
 
@@ -803,7 +821,7 @@ export async function handleFailedVerification(
803
821
  logger.warn('handleFailedVerification invoked without guildId, aborting')
804
822
  return
805
823
  }
806
- const username = session.username || '未知用户'
824
+ const username = session.username || userId
807
825
  const message = session.content || ''
808
826
  clog('debug', `待审核: guild=${guildId} user=${userId} matched=${matchedCount}/${requiredThreshold}`,
809
827
  `处理失败验证 guild=${guildId} user=${userId} msg="${session.content || ''}" matched=${matchedCount} threshold=${requiredThreshold}`)
@@ -955,7 +973,7 @@ export async function processBlacklistCommand(ctx: Context, session: any, rawArg
955
973
  // 严格群号检查(若开启)
956
974
  if (config?.enableStrictGroupCheck) {
957
975
  if (!/^\d{5,15}$/.test(group)) {
958
- return (config.invalidGroupMessage || '群号 {group} 格式不合法或机器人不在该群中').replace('{group}', group)
976
+ return renderMsg((config.invalidGroupMessage || '群号 {group} 格式不合法或机器人不在该群中').replace('{group}', group))
959
977
  }
960
978
  }
961
979
  const [ok, err] = await checkPermission(session, group)
@@ -988,8 +1006,9 @@ export async function processBlacklistCommand(ctx: Context, session: any, rawArg
988
1006
  logger.warn(`踢出用户 ${targetUser} 失败`, e)
989
1007
  }
990
1008
  }
991
- const tmpl = (config && config.blacklistAddSuccess) || '已将用户 {user} 加入群 {group} 黑名单{reason}'
992
- return tmpl.replace('{user}', targetUser).replace('{group}', group).replace('{reason}', reason ? `,原因: ${reason}` : '')
1009
+ const tmpl = (config && config.blacklistAddSuccess) || '已将用户 {user} 加入{group}黑名单{reason}'
1010
+ const groupLabelA = group.toLowerCase() === 'all' ? '全局' : '' + group
1011
+ return renderMsg(tmpl.replace('{user}', targetUser).replace('{group}', groupLabelA).replace('{reason}', reason ? `,原因: ${reason}` : ''))
993
1012
  }
994
1013
  if (op === 'r') {
995
1014
  targetUser = parts[1]
@@ -1002,7 +1021,7 @@ export async function processBlacklistCommand(ctx: Context, session: any, rawArg
1002
1021
  } else {
1003
1022
  if (config?.enableStrictGroupCheck) {
1004
1023
  if (!/^\d{5,15}$/.test(group)) {
1005
- return (config.invalidGroupMessage || '群号 {group} 格式不合法或机器人不在该群中').replace('{group}', group)
1024
+ return renderMsg((config.invalidGroupMessage || '群号 {group} 格式不合法或机器人不在该群中').replace('{group}', group))
1006
1025
  }
1007
1026
  }
1008
1027
  const [ok, err] = await checkPermission(session, group)
@@ -1015,8 +1034,9 @@ export async function processBlacklistCommand(ctx: Context, session: any, rawArg
1015
1034
  delete entries[targetUser]
1016
1035
  await ctx.database.set('group_verification_blacklist', { id: row.id }, { entries })
1017
1036
  }
1018
- const tmpl = (config && config.blacklistRemoveSuccess) || '已从群 {group} 的黑名单中移除用户 {user}'
1019
- return tmpl.replace('{user}', targetUser).replace('{group}', group)
1037
+ const tmpl = (config && config.blacklistRemoveSuccess) || '已从{group}的黑名单中移除用户 {user}'
1038
+ const groupLabelR = group.toLowerCase() === 'all' ? '全局' : '群 ' + group
1039
+ return renderMsg(tmpl.replace('{user}', targetUser).replace('{group}', groupLabelR))
1020
1040
  }
1021
1041
  if (op === 'l') {
1022
1042
  group = parts[1] || getCurrentGroup()
@@ -1027,7 +1047,7 @@ export async function processBlacklistCommand(ctx: Context, session: any, rawArg
1027
1047
  } else {
1028
1048
  if (config?.enableStrictGroupCheck) {
1029
1049
  if (!/^\d{5,15}$/.test(group)) {
1030
- return (config.invalidGroupMessage || '群号 {group} 格式不合法或机器人不在该群中').replace('{group}', group)
1050
+ return renderMsg((config.invalidGroupMessage || '群号 {group} 格式不合法或机器人不在该群中').replace('{group}', group))
1031
1051
  }
1032
1052
  }
1033
1053
  const [ok, err] = await checkPermission(session, group)
@@ -1035,13 +1055,9 @@ export async function processBlacklistCommand(ctx: Context, session: any, rawArg
1035
1055
  }
1036
1056
  const rows = await ctx.database.get('group_verification_blacklist', { groupId: group })
1037
1057
  if (rows.length === 0) {
1038
- // 特殊处理 all 表示全局黑名单
1039
- if (group && group.toLowerCase() === 'all') {
1040
- // 不使用模板,因为默认模板会产生 "群 all 的黑名单为空" 这种奇怪输出
1041
- return '全局黑名单为空'
1042
- }
1043
- const tmpl = (config && config.blacklistListEmpty) || '群 {group} 的黑名单为空'
1044
- return tmpl.replace('{group}', group)
1058
+ const tmpl = (config && config.blacklistListEmpty) || '{group}的黑名单为空'
1059
+ const groupLabelL = group && group.toLowerCase() === 'all' ? '全局' : '群 ' + group
1060
+ return renderMsg(tmpl.replace('{group}', groupLabelL))
1045
1061
  }
1046
1062
  const entries = rows[0].entries || {}
1047
1063
  // 构造列表消息,all 也是专用前缀
@@ -1060,7 +1076,8 @@ export async function processBlacklistCommand(ctx: Context, session: any, rawArg
1060
1076
  const globalHit = globalRows.length > 0 && (globalRows[0].entries || {})[targetUser] !== undefined
1061
1077
 
1062
1078
  // 使用模板格式化回复的辅助函数
1063
- const tmpl = (config && config.blacklistInfoTemplate) || '全局黑名单: {global}\n本群黑名单: {group}'
1079
+ const tmpl = ((config && config.blacklistInfoTemplate) || '全局黑名单: {global}\\n本群黑名单: {group}')
1080
+ .replace(/\\\\n/g, '\x01').replace(/\\n/g, '\n').replace(/\x01/g, '\\n')
1064
1081
  const formatReply = (localHit: boolean, groupsList?: string[]) => {
1065
1082
  if (groupsList) {
1066
1083
  return tmpl.replace('{global}', globalHit ? '有' : '无').replace(
@@ -1109,7 +1126,7 @@ export async function processBlacklistCommand(ctx: Context, session: any, rawArg
1109
1126
  const groupId = groupArg
1110
1127
  if (config?.enableStrictGroupCheck && groupId.toLowerCase() !== 'all') {
1111
1128
  if (!/^\d{5,15}$/.test(groupId)) {
1112
- return (config.invalidGroupMessage || '群号 {group} 格式不合法或机器人不在该群中').replace('{group}', groupId)
1129
+ return renderMsg((config.invalidGroupMessage || '群号 {group} 格式不合法或机器人不在该群中').replace('{group}', groupId))
1113
1130
  }
1114
1131
  }
1115
1132
  const [ok, err] = await checkPermission(session, groupId)
@@ -1294,7 +1311,7 @@ export function apply(ctx: Context, config: Config) {
1294
1311
  }
1295
1312
 
1296
1313
  clogV(`权限检查 - 权限不足`)
1297
- return [false, config.permissionDeniedMessage || '权限不足: 需要群主/管理员权限或koishi三级以上权限']
1314
+ return [false, renderMsg(config.permissionDeniedMessage || '权限不足: 需要群主/管理员权限或koishi三级以上权限')]
1298
1315
  }
1299
1316
 
1300
1317
  // 创建主命令及别名
@@ -1355,7 +1372,7 @@ export function apply(ctx: Context, config: Config) {
1355
1372
  if ((cleanedOptions.query || cleanedOptions.remove) &&
1356
1373
  (parsedKeywords.length > 0 || cleanedOptions.method !== undefined || cleanedOptions.threshold !== undefined ||
1357
1374
  cleanedOptions.message !== undefined || cleanedOptions.enableMessage || cleanedOptions.disableMessage)) {
1358
- return config.parameterConflictMessage || '参数冲突: -? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)'
1375
+ return renderMsg(config.parameterConflictMessage || '参数冲突: -? 或 -r 不能与其他参数或关键词一起使用(仅可搭配 -i)')
1359
1376
  }
1360
1377
 
1361
1378
  // 检查消息参数冲突
@@ -1511,7 +1528,7 @@ export function apply(ctx: Context, config: Config) {
1511
1528
  // 处理关键词: 如果没有关键词但有其他参数,从现有配置中获取
1512
1529
  if (keywordList.length === 0 && !cleanedOptions.query && !cleanedOptions.remove) {
1513
1530
  if (!existingConfig) {
1514
- return config.noKeywordsMessage || '请先提供关键词创建配置,或使用 -? 查询配置,-r 删除配置'
1531
+ return renderMsg(config.noKeywordsMessage || '请先提供关键词创建配置,或使用 -? 查询配置,-r 删除配置')
1515
1532
  }
1516
1533
  keywordList = existingConfig.keywords
1517
1534
  }