koishi-plugin-temporaryban 1.0.3 → 1.0.4-beta.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/README.md +135 -17
- package/lib/commands/admin.d.ts +4 -0
- package/lib/commands/admin.js +23 -0
- package/lib/commands/check.d.ts +4 -0
- package/lib/commands/check.js +27 -0
- package/lib/commands/dictionary.d.ts +4 -0
- package/lib/commands/dictionary.js +62 -0
- package/lib/commands/index.d.ts +6 -0
- package/lib/commands/index.js +15 -0
- package/lib/commands/stats.d.ts +4 -0
- package/lib/commands/stats.js +44 -0
- package/lib/commands/whitelist.d.ts +3 -0
- package/lib/commands/whitelist.js +52 -0
- package/lib/config.d.ts +18 -1
- package/lib/config.js +18 -1
- package/lib/index.js +12 -179
- package/lib/locales/en-US.d.ts +64 -0
- package/lib/locales/en-US.js +65 -0
- package/lib/locales/zh-CN.d.ts +64 -0
- package/lib/locales/zh-CN.js +65 -0
- package/lib/services/detector.d.ts +4 -1
- package/lib/services/detector.js +215 -4
- package/lib/services/mailer.d.ts +6 -1
- package/lib/services/mailer.js +4 -4
- package/lib/utils/permission.d.ts +3 -0
- package/lib/utils/permission.js +13 -0
- package/lib/utils/types.d.ts +4 -0
- package/lib/utils/types.js +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,13 +2,126 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/koishi-plugin-temporaryban)
|
|
4
4
|
|
|
5
|
+
[English](#english) | [中文](#chinese)
|
|
6
|
+
|
|
7
|
+
<a name="english"></a>
|
|
8
|
+
## English
|
|
9
|
+
|
|
10
|
+
A powerful Koishi forbidden words detection and temporary ban plugin. Supports database persistence for word lists, multiple detection mechanisms, automatic email reporting, and comprehensive group management commands.
|
|
11
|
+
|
|
12
|
+
### ✨ Key Features
|
|
13
|
+
|
|
14
|
+
- **Multiple Detection Mechanisms**:
|
|
15
|
+
- 🏠 **Local Dictionary (Database)**: Supports dynamic addition/deletion via database, no restart required.
|
|
16
|
+
- ☁️ **Cloud API**: Integrated **Baidu AI**, **Aliyun Green**, and **Tencent Cloud TMS** for intelligent detection.
|
|
17
|
+
- 🌐 **Online API**: Supports generic online API detection.
|
|
18
|
+
- **Smart Punishment System**:
|
|
19
|
+
- 🚫 Automatically recalls violating messages.
|
|
20
|
+
- ⏱️ Triggers automatic mute after cumulative violations.
|
|
21
|
+
- 🛡️ **Dynamic Whitelist**: Automatically recognizes group owners and admins; supports manual user whitelist configuration.
|
|
22
|
+
- **Email Notification & Summary**:
|
|
23
|
+
- 📧 Supports immediate notification for each violation.
|
|
24
|
+
- 📊 **Daily/Periodic Summary**: Supports sending summary reports every N days to avoid spam.
|
|
25
|
+
- 🎨 Beautiful HTML email templates.
|
|
26
|
+
- **Convenient Management Commands**:
|
|
27
|
+
- New `temporaryban` command system for managing word lists, whitelists, and viewing statistics directly in groups.
|
|
28
|
+
|
|
29
|
+
### 📦 Installation
|
|
30
|
+
|
|
31
|
+
This plugin depends on Koishi's **Database** service. Please ensure you have installed and configured a database plugin (e.g., MySQL, SQLite).
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Install plugin
|
|
35
|
+
npm install koishi-plugin-temporaryban
|
|
36
|
+
|
|
37
|
+
# Install database plugin (e.g., mysql)
|
|
38
|
+
npm install @koishijs/plugin-database-mysql
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### ⚙️ Configuration
|
|
42
|
+
|
|
43
|
+
#### 1. Basic Settings
|
|
44
|
+
|
|
45
|
+
- **`debug`**: Enable debug mode for detailed logs.
|
|
46
|
+
- **`adminList`**: Global admin list (User ID). Users in this list can use advanced management commands (e.g., manual report trigger).
|
|
47
|
+
|
|
48
|
+
#### 2. Cloud API Configuration
|
|
49
|
+
|
|
50
|
+
Supports **Baidu AI**, **Aliyun**, and **Tencent Cloud**. Configure the respective sections (`baidu`, `aliyun`, `tencent`) with your API keys if you wish to use them.
|
|
51
|
+
|
|
52
|
+
#### 3. Email Notification (SMTP)
|
|
53
|
+
|
|
54
|
+
| Option | Description | Example |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| `host` | SMTP Server Address | `smtp.qq.com` |
|
|
57
|
+
| `port` | SMTP Port | `465` (SSL) |
|
|
58
|
+
| `user` | Sender Account | `123456@qq.com` |
|
|
59
|
+
| `pass` | **Authorization Code/Password** | Use Auth Code for QQ Mail |
|
|
60
|
+
| `receivers` | List of admin emails to receive notifications | `['admin@example.com']` |
|
|
61
|
+
| `summaryIntervalDays` | **Summary Interval (Days)** | `1` (Daily); `0` (Immediate) |
|
|
62
|
+
|
|
63
|
+
#### 4. Group Monitoring (Groups)
|
|
64
|
+
|
|
65
|
+
You can configure each group separately:
|
|
66
|
+
|
|
67
|
+
- **`groupId`**: Target Group ID.
|
|
68
|
+
- **`detectionMethod`**: Detection method (`local`, `api`, `baidu`, `aliyun`, `tencent`).
|
|
69
|
+
- **`triggerThreshold`**: Violations count to trigger mute (Default: 3).
|
|
70
|
+
- **`triggerWindowMinutes`**: Violation counting window (Default: 5 mins).
|
|
71
|
+
- **`muteMinutes`**: Mute duration (Default: 10 mins).
|
|
72
|
+
|
|
73
|
+
### 💻 Commands
|
|
74
|
+
|
|
75
|
+
All commands start with `temporaryban`.
|
|
76
|
+
|
|
77
|
+
#### Global Commands
|
|
78
|
+
*Global Admins (`config.adminList`) only*
|
|
79
|
+
|
|
80
|
+
- **`temporaryban.report`**
|
|
81
|
+
- Manually trigger a violation summary report for the last 24 hours and send via email.
|
|
82
|
+
|
|
83
|
+
#### Group Management Commands
|
|
84
|
+
*Group Owner, Group Admin, or Global Admin only*
|
|
85
|
+
|
|
86
|
+
- **`temporaryban.add <word>`**
|
|
87
|
+
- Add a forbidden word to the current group dictionary.
|
|
88
|
+
- **`temporaryban.remove <word>`**
|
|
89
|
+
- Remove a forbidden word from the current group dictionary.
|
|
90
|
+
- **`temporaryban.list`**
|
|
91
|
+
- List all forbidden words in the current group.
|
|
92
|
+
- **`temporaryban.whitelist.add <user>`**
|
|
93
|
+
- Add a user to the current group whitelist.
|
|
94
|
+
- **`temporaryban.whitelist.remove <user>`**
|
|
95
|
+
- Remove a user from the current group whitelist.
|
|
96
|
+
- **`temporaryban.stats`**
|
|
97
|
+
- View violation statistics for the current period.
|
|
98
|
+
- **`temporaryban.clean <user>`**
|
|
99
|
+
- Clear violation records for a user (Manual pardon).
|
|
100
|
+
- **`temporaryban.check <text>`**
|
|
101
|
+
- Check if text contains forbidden words (Detection only, no punishment).
|
|
102
|
+
|
|
103
|
+
### 🛠️ Development
|
|
104
|
+
|
|
105
|
+
This project follows a modular structure:
|
|
106
|
+
|
|
107
|
+
- **`src/commands/`**: Command implementations split by category.
|
|
108
|
+
- **`src/services/`**: Core logic (Detector, Mailer).
|
|
109
|
+
- **`src/utils/`**: Helper functions and types.
|
|
110
|
+
- **`src/locales/`**: Internationalization files.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
<a name="chinese"></a>
|
|
115
|
+
## 中文
|
|
116
|
+
|
|
5
117
|
一个功能强大的 Koishi 违禁词检测与自动禁言插件。支持数据库持久化词库、多重检测机制、自动邮件汇报以及完善的群组管理指令。
|
|
6
118
|
|
|
7
|
-
|
|
119
|
+
### ✨ 核心特性
|
|
8
120
|
|
|
9
121
|
- **多重检测机制**:
|
|
10
122
|
- 🏠 **本地词库 (Database)**:基于数据库存储,支持动态添加/删除,无需重启。
|
|
11
|
-
-
|
|
123
|
+
- ☁️ **云端检测**:集成 **百度 AI**、**阿里云内容安全**、**腾讯云 TMS**,支持智能识别。
|
|
124
|
+
- 🌐 **在线 API**:支持通用 API 敏感词检测接口。
|
|
12
125
|
- **智能惩罚系统**:
|
|
13
126
|
- 🚫 自动撤回违规消息。
|
|
14
127
|
- ⏱️ 累计违规次数触发自动禁言。
|
|
@@ -20,7 +133,7 @@
|
|
|
20
133
|
- **便捷的管理指令**:
|
|
21
134
|
- 全新的 `temporaryban` 指令体系,支持在群内直接管理词库、白名单和查看统计。
|
|
22
135
|
|
|
23
|
-
|
|
136
|
+
### 📦 安装与依赖
|
|
24
137
|
|
|
25
138
|
本插件需要依赖 Koishi 的 **Database** 服务。请确保您已安装并配置了任意一款数据库插件(如 MySQL, SQLite 等)。
|
|
26
139
|
|
|
@@ -32,14 +145,18 @@ npm install koishi-plugin-temporaryban
|
|
|
32
145
|
npm install @koishijs/plugin-database-mysql
|
|
33
146
|
```
|
|
34
147
|
|
|
35
|
-
|
|
148
|
+
### ⚙️ 配置说明
|
|
36
149
|
|
|
37
|
-
|
|
150
|
+
#### 1. 基础设置
|
|
38
151
|
|
|
39
152
|
- **`debug`**: 开启调试模式,输出详细日志。
|
|
40
153
|
- **`adminList`**: 全局管理员列表 (OneBot ID)。在此列表中的用户可以使用高级管理指令(如手动触发报告)。
|
|
41
154
|
|
|
42
|
-
|
|
155
|
+
#### 2. 云端检测配置
|
|
156
|
+
|
|
157
|
+
支持 **百度 AI**、**阿里云**、**腾讯云**。请在配置项中分别填写对应的 API Key/Secret (`baidu`, `aliyun`, `tencent`) 以启用。
|
|
158
|
+
|
|
159
|
+
#### 3. 邮件通知 (SMTP)
|
|
43
160
|
|
|
44
161
|
| 配置项 | 说明 | 示例 |
|
|
45
162
|
| --- | --- | --- |
|
|
@@ -50,28 +167,27 @@ npm install @koishijs/plugin-database-mysql
|
|
|
50
167
|
| `receivers` | 接收通知的管理员邮箱列表 | `['admin@example.com']` |
|
|
51
168
|
| `summaryIntervalDays` | **汇总周期(天)** | `1` (每天发送一次汇总); `0` (立即发送) |
|
|
52
169
|
|
|
53
|
-
|
|
170
|
+
#### 4. 群组监控 (Groups)
|
|
54
171
|
|
|
55
172
|
您可以为每个群组单独配置:
|
|
56
173
|
|
|
57
174
|
- **`groupId`**: 目标群号。
|
|
58
|
-
- **`detectionMethod`**: 检测方式 (`local`
|
|
175
|
+
- **`detectionMethod`**: 检测方式 (`local`, `api`, `baidu`, `aliyun`, `tencent`)。
|
|
59
176
|
- **`triggerThreshold`**: 触发禁言的累计违规次数(默认 3 次)。
|
|
60
177
|
- **`triggerWindowMinutes`**: 违规计数窗口时间(默认 5 分钟)。
|
|
61
178
|
- **`muteMinutes`**: 禁言时长(默认 10 分钟)。
|
|
62
|
-
- **`localBadWordDict`**: **[已弃用/仅供迁移]** 首次启动时会自动将此处的词汇导入数据库。之后的增删操作请使用指令。
|
|
63
179
|
|
|
64
|
-
|
|
180
|
+
### 💻 指令使用
|
|
65
181
|
|
|
66
182
|
所有指令均以 `temporaryban` (或简写,需自行配置别名) 开头。
|
|
67
183
|
|
|
68
|
-
|
|
184
|
+
#### 全局指令
|
|
69
185
|
*仅限 `config.adminList` 中的全局管理员使用*
|
|
70
186
|
|
|
71
187
|
- **`temporaryban.report`**
|
|
72
188
|
- 手动触发最近 24 小时的违规汇总报告并发送邮件。
|
|
73
189
|
|
|
74
|
-
|
|
190
|
+
#### 群组管理指令
|
|
75
191
|
*仅限群主、群管理员或全局管理员使用*
|
|
76
192
|
|
|
77
193
|
- **`temporaryban.add <word>`**
|
|
@@ -94,12 +210,14 @@ npm install @koishijs/plugin-database-mysql
|
|
|
94
210
|
- 检测一段文本是否包含违禁词(仅检测,不触发惩罚)。
|
|
95
211
|
- 示例:`temporaryban.check 这句话有问题吗`
|
|
96
212
|
|
|
97
|
-
|
|
213
|
+
### 🛠️ 开发说明
|
|
214
|
+
|
|
215
|
+
本项目采用模块化结构开发:
|
|
98
216
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
217
|
+
- **`src/commands/`**: 按类别拆分的命令实现。
|
|
218
|
+
- **`src/services/`**: 核心服务逻辑 (Detector, Mailer)。
|
|
219
|
+
- **`src/utils/`**: 工具函数和类型定义。
|
|
220
|
+
- **`src/locales/`**: 国际化语言文件。
|
|
103
221
|
|
|
104
222
|
## 📝 License
|
|
105
223
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerAdminCommands = registerAdminCommands;
|
|
4
|
+
function registerAdminCommands(ctx, config, mailer) {
|
|
5
|
+
const cmd = ctx.command('temporaryban');
|
|
6
|
+
cmd.subcommand('.report')
|
|
7
|
+
.action(async ({ session }) => {
|
|
8
|
+
if (!session?.userId || !config.adminList?.includes(session.userId)) {
|
|
9
|
+
return session?.text('commands.temporaryban.messages.global_admin_only');
|
|
10
|
+
}
|
|
11
|
+
const result = await mailer.sendSummaryReport(24);
|
|
12
|
+
if (result.success) {
|
|
13
|
+
if (result.count === 0)
|
|
14
|
+
return session?.text('commands.temporaryban.messages.no_violations');
|
|
15
|
+
return session?.text('commands.temporaryban.messages.report_sent', [result.receivers, result.count]);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
if (result.error === 'smtp_not_configured')
|
|
19
|
+
return session?.text('commands.temporaryban.messages.smtp_not_configured');
|
|
20
|
+
return session?.text('commands.temporaryban.messages.report_failed', [result.error]);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerCheckCommands = registerCheckCommands;
|
|
4
|
+
const permission_1 = require("../utils/permission");
|
|
5
|
+
function registerCheckCommands(ctx, config, detector) {
|
|
6
|
+
const cmd = ctx.command('temporaryban');
|
|
7
|
+
// 9. Check
|
|
8
|
+
cmd.subcommand('.check <text:text>')
|
|
9
|
+
.action(async ({ session }, text) => {
|
|
10
|
+
if (!session)
|
|
11
|
+
return;
|
|
12
|
+
if (!(0, permission_1.checkPermission)(session, config))
|
|
13
|
+
return session.text('commands.temporaryban.messages.permission_denied');
|
|
14
|
+
if (!session.guildId)
|
|
15
|
+
return session.text('commands.temporaryban.messages.group_only');
|
|
16
|
+
if (!text)
|
|
17
|
+
return session.text('commands.temporaryban.messages.specify_text');
|
|
18
|
+
const groupConfig = config.groups.find(g => g.groupId === session.guildId);
|
|
19
|
+
if (!groupConfig)
|
|
20
|
+
return session.text('commands.temporaryban.messages.group_not_configured');
|
|
21
|
+
const res = await detector.check(text, session.guildId, groupConfig.detectionMethod);
|
|
22
|
+
if (res.detected) {
|
|
23
|
+
return session.text('commands.temporaryban.messages.detected', [res.detectedWords?.join(', ')]);
|
|
24
|
+
}
|
|
25
|
+
return session.text('commands.temporaryban.messages.safe');
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerDictionaryCommands = registerDictionaryCommands;
|
|
4
|
+
const permission_1 = require("../utils/permission");
|
|
5
|
+
function registerDictionaryCommands(ctx, config, detector) {
|
|
6
|
+
const cmd = ctx.command('temporaryban');
|
|
7
|
+
// 2. Add Word (Group Admin)
|
|
8
|
+
cmd.subcommand('.add <word:string>')
|
|
9
|
+
.action(async ({ session }, word) => {
|
|
10
|
+
if (!session)
|
|
11
|
+
return;
|
|
12
|
+
if (!(0, permission_1.checkPermission)(session, config))
|
|
13
|
+
return session.text('commands.temporaryban.messages.permission_denied');
|
|
14
|
+
if (!session.guildId)
|
|
15
|
+
return session.text('commands.temporaryban.messages.group_only');
|
|
16
|
+
if (!word)
|
|
17
|
+
return session.text('commands.temporaryban.messages.specify_word');
|
|
18
|
+
const groupConfig = config.groups.find(g => g.groupId === session.guildId);
|
|
19
|
+
if (!groupConfig)
|
|
20
|
+
return session.text('commands.temporaryban.messages.group_not_configured');
|
|
21
|
+
const success = await detector.addWord(session.guildId, word);
|
|
22
|
+
if (!success)
|
|
23
|
+
return session.text('commands.temporaryban.messages.word_exists');
|
|
24
|
+
return session.text('commands.temporaryban.messages.word_added', [word]);
|
|
25
|
+
});
|
|
26
|
+
// 3. Remove Word
|
|
27
|
+
cmd.subcommand('.remove <word:string>')
|
|
28
|
+
.action(async ({ session }, word) => {
|
|
29
|
+
if (!session)
|
|
30
|
+
return;
|
|
31
|
+
if (!(0, permission_1.checkPermission)(session, config))
|
|
32
|
+
return session.text('commands.temporaryban.messages.permission_denied');
|
|
33
|
+
if (!session.guildId)
|
|
34
|
+
return session.text('commands.temporaryban.messages.group_only');
|
|
35
|
+
if (!word)
|
|
36
|
+
return session.text('commands.temporaryban.messages.specify_word');
|
|
37
|
+
const groupConfig = config.groups.find(g => g.groupId === session.guildId);
|
|
38
|
+
if (!groupConfig)
|
|
39
|
+
return session.text('commands.temporaryban.messages.group_not_configured');
|
|
40
|
+
const success = await detector.removeWord(session.guildId, word);
|
|
41
|
+
if (!success)
|
|
42
|
+
return session.text('commands.temporaryban.messages.word_not_found');
|
|
43
|
+
return session.text('commands.temporaryban.messages.word_removed', [word]);
|
|
44
|
+
});
|
|
45
|
+
// 4. List Words
|
|
46
|
+
cmd.subcommand('.list')
|
|
47
|
+
.action(async ({ session }) => {
|
|
48
|
+
if (!session)
|
|
49
|
+
return;
|
|
50
|
+
if (!(0, permission_1.checkPermission)(session, config))
|
|
51
|
+
return session.text('commands.temporaryban.messages.permission_denied');
|
|
52
|
+
if (!session.guildId)
|
|
53
|
+
return session.text('commands.temporaryban.messages.group_only');
|
|
54
|
+
const groupConfig = config.groups.find(g => g.groupId === session.guildId);
|
|
55
|
+
if (!groupConfig)
|
|
56
|
+
return session.text('commands.temporaryban.messages.group_not_configured');
|
|
57
|
+
const items = detector.getWords(session.guildId);
|
|
58
|
+
if (items.length === 0)
|
|
59
|
+
return session.text('commands.temporaryban.messages.no_forbidden_words');
|
|
60
|
+
return session.text('commands.temporaryban.messages.forbidden_words_list', [items.length, items.map(i => i.word).join(', ')]);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Context } from 'koishi';
|
|
2
|
+
import { Config } from '../config';
|
|
3
|
+
import { DetectorService } from '../services/detector';
|
|
4
|
+
import { MailerService } from '../services/mailer';
|
|
5
|
+
import { UserRecord } from '../utils/types';
|
|
6
|
+
export declare function registerCommands(ctx: Context, config: Config, detector: DetectorService, mailer: MailerService, userRecords: Map<string, UserRecord>): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerCommands = registerCommands;
|
|
4
|
+
const admin_1 = require("./admin");
|
|
5
|
+
const dictionary_1 = require("./dictionary");
|
|
6
|
+
const whitelist_1 = require("./whitelist");
|
|
7
|
+
const stats_1 = require("./stats");
|
|
8
|
+
const check_1 = require("./check");
|
|
9
|
+
function registerCommands(ctx, config, detector, mailer, userRecords) {
|
|
10
|
+
(0, admin_1.registerAdminCommands)(ctx, config, mailer);
|
|
11
|
+
(0, dictionary_1.registerDictionaryCommands)(ctx, config, detector);
|
|
12
|
+
(0, whitelist_1.registerWhitelistCommands)(ctx, config);
|
|
13
|
+
(0, stats_1.registerStatsCommands)(ctx, config, userRecords);
|
|
14
|
+
(0, check_1.registerCheckCommands)(ctx, config, detector);
|
|
15
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerStatsCommands = registerStatsCommands;
|
|
4
|
+
const permission_1 = require("../utils/permission");
|
|
5
|
+
function registerStatsCommands(ctx, config, userRecords) {
|
|
6
|
+
const cmd = ctx.command('temporaryban');
|
|
7
|
+
// 7. Stats
|
|
8
|
+
cmd.subcommand('.stats')
|
|
9
|
+
.action(async ({ session }) => {
|
|
10
|
+
if (!session)
|
|
11
|
+
return;
|
|
12
|
+
if (!(0, permission_1.checkPermission)(session, config))
|
|
13
|
+
return session.text('commands.temporaryban.messages.permission_denied');
|
|
14
|
+
if (!session.guildId)
|
|
15
|
+
return session.text('commands.temporaryban.messages.group_only');
|
|
16
|
+
const prefix = `${session.guildId}-`;
|
|
17
|
+
let count = 0;
|
|
18
|
+
let violators = 0;
|
|
19
|
+
for (const [key, val] of userRecords.entries()) {
|
|
20
|
+
if (key.startsWith(prefix)) {
|
|
21
|
+
violators++;
|
|
22
|
+
count += val.count;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return session.text('commands.temporaryban.messages.stats_header', [violators]);
|
|
26
|
+
});
|
|
27
|
+
// 8. Clean
|
|
28
|
+
cmd.subcommand('.clean <user:string>')
|
|
29
|
+
.action(async ({ session }, user) => {
|
|
30
|
+
if (!session)
|
|
31
|
+
return;
|
|
32
|
+
if (!(0, permission_1.checkPermission)(session, config))
|
|
33
|
+
return session.text('commands.temporaryban.messages.permission_denied');
|
|
34
|
+
if (!session.guildId)
|
|
35
|
+
return session.text('commands.temporaryban.messages.group_only');
|
|
36
|
+
if (!user)
|
|
37
|
+
return session.text('commands.temporaryban.messages.specify_user_id');
|
|
38
|
+
const key = `${session.guildId}-${user}`;
|
|
39
|
+
if (userRecords.delete(key)) {
|
|
40
|
+
return session.text('commands.temporaryban.messages.records_cleared', [user]);
|
|
41
|
+
}
|
|
42
|
+
return session.text('commands.temporaryban.messages.no_active_records', [user]);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerWhitelistCommands = registerWhitelistCommands;
|
|
4
|
+
const permission_1 = require("../utils/permission");
|
|
5
|
+
function registerWhitelistCommands(ctx, config) {
|
|
6
|
+
const cmd = ctx.command('temporaryban');
|
|
7
|
+
// 5. Whitelist Add
|
|
8
|
+
cmd.subcommand('.whitelist.add <user:string>')
|
|
9
|
+
.action(async ({ session }, user) => {
|
|
10
|
+
if (!session)
|
|
11
|
+
return;
|
|
12
|
+
if (!(0, permission_1.checkPermission)(session, config))
|
|
13
|
+
return session.text('commands.temporaryban.messages.permission_denied');
|
|
14
|
+
if (!session.guildId)
|
|
15
|
+
return session.text('commands.temporaryban.messages.group_only');
|
|
16
|
+
if (!user)
|
|
17
|
+
return session.text('commands.temporaryban.messages.specify_user_id');
|
|
18
|
+
const groupConfig = config.groups.find(g => g.groupId === session.guildId);
|
|
19
|
+
if (!groupConfig)
|
|
20
|
+
return session.text('commands.temporaryban.messages.group_not_configured');
|
|
21
|
+
if (groupConfig.whitelist.some(u => u.userId === user))
|
|
22
|
+
return session.text('commands.temporaryban.messages.already_whitelisted');
|
|
23
|
+
groupConfig.whitelist.push({ userId: user });
|
|
24
|
+
try {
|
|
25
|
+
await ctx.scope.update(config);
|
|
26
|
+
}
|
|
27
|
+
catch (e) { }
|
|
28
|
+
return session.text('commands.temporaryban.messages.user_added_whitelist', [user]);
|
|
29
|
+
});
|
|
30
|
+
// 6. Whitelist Remove
|
|
31
|
+
cmd.subcommand('.whitelist.remove <user:string>')
|
|
32
|
+
.action(async ({ session }, user) => {
|
|
33
|
+
if (!session)
|
|
34
|
+
return;
|
|
35
|
+
if (!(0, permission_1.checkPermission)(session, config))
|
|
36
|
+
return session.text('commands.temporaryban.messages.permission_denied');
|
|
37
|
+
if (!session.guildId)
|
|
38
|
+
return session.text('commands.temporaryban.messages.group_only');
|
|
39
|
+
const groupConfig = config.groups.find(g => g.groupId === session.guildId);
|
|
40
|
+
if (!groupConfig)
|
|
41
|
+
return session.text('commands.temporaryban.messages.group_not_configured');
|
|
42
|
+
const idx = groupConfig.whitelist.findIndex(u => u.userId === user);
|
|
43
|
+
if (idx === -1)
|
|
44
|
+
return session.text('commands.temporaryban.messages.not_in_whitelist');
|
|
45
|
+
groupConfig.whitelist.splice(idx, 1);
|
|
46
|
+
try {
|
|
47
|
+
await ctx.scope.update(config);
|
|
48
|
+
}
|
|
49
|
+
catch (e) { }
|
|
50
|
+
return session.text('commands.temporaryban.messages.user_removed_whitelist', [user]);
|
|
51
|
+
});
|
|
52
|
+
}
|
package/lib/config.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ export interface GroupConfig {
|
|
|
32
32
|
id: string;
|
|
33
33
|
groupId: string;
|
|
34
34
|
enable: boolean;
|
|
35
|
-
detectionMethod: 'local' | 'api';
|
|
35
|
+
detectionMethod: 'local' | 'api' | 'baidu' | 'aliyun' | 'tencent';
|
|
36
36
|
localBadWordDict: string;
|
|
37
37
|
whitelist: WhitelistItem[];
|
|
38
38
|
triggerThreshold: number;
|
|
@@ -40,11 +40,28 @@ export interface GroupConfig {
|
|
|
40
40
|
muteMinutes: number;
|
|
41
41
|
detailedLog: boolean;
|
|
42
42
|
}
|
|
43
|
+
export interface BaiduConfig {
|
|
44
|
+
apiKey: string;
|
|
45
|
+
secretKey: string;
|
|
46
|
+
}
|
|
47
|
+
export interface AliyunConfig {
|
|
48
|
+
accessKeyId: string;
|
|
49
|
+
accessKeySecret: string;
|
|
50
|
+
endpoint: string;
|
|
51
|
+
}
|
|
52
|
+
export interface TencentConfig {
|
|
53
|
+
secretId: string;
|
|
54
|
+
secretKey: string;
|
|
55
|
+
region: string;
|
|
56
|
+
}
|
|
43
57
|
export interface Config {
|
|
44
58
|
debug: boolean;
|
|
45
59
|
adminList: string[];
|
|
46
60
|
smtp: SmtpConfig;
|
|
47
61
|
api: ApiConfig;
|
|
62
|
+
baidu: BaiduConfig;
|
|
63
|
+
aliyun: AliyunConfig;
|
|
64
|
+
tencent: TencentConfig;
|
|
48
65
|
groups: GroupConfig[];
|
|
49
66
|
}
|
|
50
67
|
export declare const Config: Schema<Config>;
|
package/lib/config.js
CHANGED
|
@@ -21,6 +21,20 @@ exports.Config = koishi_1.Schema.object({
|
|
|
21
21
|
apiId: koishi_1.Schema.string().description('ApiHz 开发者 ID (必填,否则无法使用 API 检测)').default(''),
|
|
22
22
|
apiKey: koishi_1.Schema.string().role('secret').description('ApiHz 开发者 Key (必填)').default(''),
|
|
23
23
|
}).description('在线检测设置 (ApiHz)'),
|
|
24
|
+
baidu: koishi_1.Schema.object({
|
|
25
|
+
apiKey: koishi_1.Schema.string().description('百度智能云 API Key').default(''),
|
|
26
|
+
secretKey: koishi_1.Schema.string().role('secret').description('百度智能云 Secret Key').default(''),
|
|
27
|
+
}).description('百度智能云设置'),
|
|
28
|
+
aliyun: koishi_1.Schema.object({
|
|
29
|
+
accessKeyId: koishi_1.Schema.string().description('阿里云 AccessKey ID').default(''),
|
|
30
|
+
accessKeySecret: koishi_1.Schema.string().role('secret').description('阿里云 AccessKey Secret').default(''),
|
|
31
|
+
endpoint: koishi_1.Schema.string().description('阿里云内容安全 Endpoint').default('green-cip.cn-shanghai.aliyuncs.com'),
|
|
32
|
+
}).description('阿里云内容安全设置'),
|
|
33
|
+
tencent: koishi_1.Schema.object({
|
|
34
|
+
secretId: koishi_1.Schema.string().description('腾讯云 SecretId').default(''),
|
|
35
|
+
secretKey: koishi_1.Schema.string().role('secret').description('腾讯云 SecretKey').default(''),
|
|
36
|
+
region: koishi_1.Schema.string().description('腾讯云地域 (例如 ap-shanghai)').default('ap-shanghai'),
|
|
37
|
+
}).description('腾讯云内容安全设置'),
|
|
24
38
|
groups: koishi_1.Schema.array(koishi_1.Schema.object({
|
|
25
39
|
id: koishi_1.Schema.string().hidden().default(''),
|
|
26
40
|
groupId: koishi_1.Schema.string().description('群组 ID (群号)。机器人将监控此群内的消息。').required(),
|
|
@@ -28,7 +42,10 @@ exports.Config = koishi_1.Schema.object({
|
|
|
28
42
|
detectionMethod: koishi_1.Schema.union([
|
|
29
43
|
koishi_1.Schema.const('local').description('本地词库 (数据库)'),
|
|
30
44
|
koishi_1.Schema.const('api').description('在线 API (ApiHz)'),
|
|
31
|
-
|
|
45
|
+
koishi_1.Schema.const('baidu').description('百度智能云'),
|
|
46
|
+
koishi_1.Schema.const('aliyun').description('阿里云 (内容安全增强版)'),
|
|
47
|
+
koishi_1.Schema.const('tencent').description('腾讯云 (TMS)'),
|
|
48
|
+
]).description('违禁词检测方式。').default('local'),
|
|
32
49
|
localBadWordDict: koishi_1.Schema.string()
|
|
33
50
|
.description('【初始导入/Legacy】本地违禁词库配置。插件现已使用数据库存储词库。首次启动时,若数据库为空,将自动导入此处的词汇。之后的增删操作请使用指令 `temporaryban.add/remove`,此配置项将不再生效。')
|
|
34
51
|
.default(''),
|