@zhin.js/plugin-repeater 0.0.0 → 0.0.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/index.js CHANGED
@@ -23,17 +23,14 @@
23
23
  * maxLength: 200
24
24
  * ```
25
25
  */
26
- import { usePlugin, MessageCommand } from "zhin.js";
26
+ import { usePlugin, MessageCommand, Schema } from "zhin.js";
27
27
  const plugin = usePlugin();
28
- const { logger, root, addCommand, addMiddleware, onDispose, declareSkill } = plugin;
29
- const configService = root.inject("config");
30
- const appConfig = configService?.get("zhin.config.yml") || {};
31
- const config = {
32
- threshold: 3,
33
- cooldown: 30_000,
34
- maxLength: 200,
35
- ...appConfig.repeater,
36
- };
28
+ const { logger, addCommand, addMiddleware, onDispose, declareConfig } = plugin;
29
+ const config = declareConfig("repeater", Schema.object({
30
+ threshold: Schema.number().default(3).min(2).max(10).description("触发复读的最少人数"),
31
+ cooldown: Schema.number().default(30_000).min(5000).max(300_000).description("同一群冷却时间 (ms)"),
32
+ maxLength: Schema.number().default(200).min(10).max(1000).description("消息长度上限"),
33
+ }));
37
34
  const groupStates = new Map();
38
35
  const cooldownSet = new Map();
39
36
  function getGroupId(message) {
@@ -114,10 +111,5 @@ addCommand(new MessageCommand("repeater-status")
114
111
  ];
115
112
  return lines.join("\n");
116
113
  }));
117
- declareSkill({
118
- description: "复读机:当群内连续多人发送相同消息时,Bot 自动跟读。支持阈值和冷却配置。",
119
- keywords: ["repeater", "复读", "复读机", "跟读", "echo", "parrot"],
120
- tags: ["repeater", "fun", "group"],
121
- });
122
114
  logger.info(`插件已加载 (阈值=${config.threshold}人, 冷却=${config.cooldown / 1000}s)`);
123
115
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/plugin-repeater",
3
- "version": "0.0.0",
3
+ "version": "0.0.2",
4
4
  "description": "Repeater plugin for Zhin.js — auto-repeat messages when group members echo the same content",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -14,11 +14,16 @@
14
14
  "./package.json": "./package.json"
15
15
  },
16
16
  "files": [
17
+ "src",
17
18
  "lib",
19
+ "client",
20
+ "dist",
21
+ "skills",
18
22
  "README.md"
19
23
  ],
20
24
  "keywords": [
21
25
  "zhin",
26
+ "zhin.js",
22
27
  "bot",
23
28
  "plugin",
24
29
  "repeater",
@@ -36,10 +41,10 @@
36
41
  "dependencies": {},
37
42
  "devDependencies": {
38
43
  "typescript": "^5.3.3",
39
- "zhin.js": "1.0.42"
44
+ "zhin.js": "1.0.54"
40
45
  },
41
46
  "peerDependencies": {
42
- "zhin.js": ">=1.0.42"
47
+ "zhin.js": ">=1.0.54"
43
48
  },
44
49
  "repository": {
45
50
  "type": "git",
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: repeater
3
+ description: 复读机:当群内连续多人发送相同消息时,Bot 自动跟读。支持阈值和冷却配置。
4
+ keywords:
5
+ - repeater
6
+ - 复读
7
+ - 复读机
8
+ - 跟读
9
+ - echo
10
+ - parrot
11
+ tags:
12
+ - repeater
13
+ - fun
14
+ - group
15
+ tools: []
16
+ ---
17
+
18
+ ## 执行规则
19
+
20
+ - 行为由中间件与命令 `repeater-status` 控制;无需额外 AI 工具即可工作。
package/src/index.ts ADDED
@@ -0,0 +1,136 @@
1
+ /**
2
+ * @zhin.js/plugin-repeater
3
+ *
4
+ * 复读机插件 —— 当群内连续多人发送相同消息时自动跟读
5
+ *
6
+ * 规则:
7
+ * - 同一群聊内,连续 N 人(默认 3)发送完全相同的消息后触发复读
8
+ * - 同一用户的连续消息不计入(防止单人刷屏触发)
9
+ * - 每条消息在同一群只复读一次
10
+ * - 可配置中断策略(不同消息会重置计数)
11
+ * - 支持冷却时间防止频繁复读
12
+ *
13
+ * 命令:
14
+ * repeater-status 查看当前复读机状态
15
+ *
16
+ * 配置(zhin.config.yml):
17
+ * ```yaml
18
+ * plugins:
19
+ * - "@zhin.js/plugin-repeater"
20
+ * repeater:
21
+ * threshold: 3
22
+ * cooldown: 30000
23
+ * maxLength: 200
24
+ * ```
25
+ */
26
+ import { usePlugin, MessageCommand, Schema } from "zhin.js";
27
+
28
+ const plugin = usePlugin();
29
+ const { logger, addCommand, addMiddleware, onDispose, declareConfig } = plugin;
30
+
31
+ const config = declareConfig("repeater", Schema.object({
32
+ threshold: Schema.number().default(3).min(2).max(10).description("触发复读的最少人数"),
33
+ cooldown: Schema.number().default(30_000).min(5000).max(300_000).description("同一群冷却时间 (ms)"),
34
+ maxLength: Schema.number().default(200).min(10).max(1000).description("消息长度上限"),
35
+ }));
36
+
37
+ interface RepeatState {
38
+ content: string;
39
+ users: Set<string>;
40
+ repeated: boolean;
41
+ lastTime: number;
42
+ }
43
+
44
+ const groupStates = new Map<string, RepeatState>();
45
+
46
+ const cooldownSet = new Map<string, number>();
47
+
48
+ function getGroupId(message: any): string | null {
49
+ if (message.type !== "group") return null;
50
+ return String(message.$group?.id || message.$target?.id || "");
51
+ }
52
+
53
+ function getSenderId(message: any): string {
54
+ return String(message.$sender?.id || "");
55
+ }
56
+
57
+ let totalRepeats = 0;
58
+
59
+ addMiddleware(async function repeaterMiddleware(message: any, next: () => Promise<void>) {
60
+ const groupId = getGroupId(message);
61
+ if (!groupId) return next();
62
+
63
+ const content = (message.$raw || "").trim();
64
+ if (!content || content.length > config.maxLength) return next();
65
+
66
+ const senderId = getSenderId(message);
67
+ if (!senderId) return next();
68
+
69
+ const state = groupStates.get(groupId);
70
+
71
+ if (state && state.content === content) {
72
+ if (state.users.has(senderId)) return next();
73
+
74
+ state.users.add(senderId);
75
+ state.lastTime = Date.now();
76
+
77
+ if (state.users.size >= config.threshold && !state.repeated) {
78
+ const lastCd = cooldownSet.get(groupId);
79
+ if (lastCd && Date.now() - lastCd < config.cooldown) {
80
+ return next();
81
+ }
82
+
83
+ state.repeated = true;
84
+ cooldownSet.set(groupId, Date.now());
85
+ totalRepeats++;
86
+
87
+ await message.$reply(content);
88
+ return;
89
+ }
90
+ } else {
91
+ groupStates.set(groupId, {
92
+ content,
93
+ users: new Set([senderId]),
94
+ repeated: false,
95
+ lastTime: Date.now(),
96
+ });
97
+ }
98
+
99
+ return next();
100
+ });
101
+
102
+ const staleCleanup = setInterval(() => {
103
+ const now = Date.now();
104
+ const expiry = 5 * 60_000;
105
+ for (const [key, state] of groupStates) {
106
+ if (now - state.lastTime > expiry) groupStates.delete(key);
107
+ }
108
+ for (const [key, time] of cooldownSet) {
109
+ if (now - time > config.cooldown * 2) cooldownSet.delete(key);
110
+ }
111
+ }, 120_000);
112
+
113
+ onDispose(() => {
114
+ clearInterval(staleCleanup);
115
+ groupStates.clear();
116
+ cooldownSet.clear();
117
+ });
118
+
119
+ addCommand(
120
+ new MessageCommand("repeater-status")
121
+ .desc("复读机状态", "查看复读机的运行状态")
122
+ .action(async () => {
123
+ const activeGroups = groupStates.size;
124
+ const lines = [
125
+ "复读机状态",
126
+ `监控群数: ${activeGroups}`,
127
+ `触发阈值: ${config.threshold} 人`,
128
+ `冷却时间: ${config.cooldown / 1000}s`,
129
+ `消息长度上限: ${config.maxLength}`,
130
+ `累计复读: ${totalRepeats} 次`,
131
+ ];
132
+ return lines.join("\n");
133
+ }),
134
+ );
135
+
136
+ logger.info(`插件已加载 (阈值=${config.threshold}人, 冷却=${config.cooldown / 1000}s)`);