koishi-plugin-best-cave 2.4.7 → 2.5.1
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 +19 -17
- package/package.json +1 -1
- package/readme.md +18 -13
package/lib/index.js
CHANGED
|
@@ -657,7 +657,8 @@ var HashManager = class {
|
|
|
657
657
|
hash: "string",
|
|
658
658
|
type: "string"
|
|
659
659
|
}, {
|
|
660
|
-
primary: ["cave", "hash", "type"]
|
|
660
|
+
primary: ["cave", "hash", "type"],
|
|
661
|
+
indexes: ["type"]
|
|
661
662
|
});
|
|
662
663
|
}
|
|
663
664
|
static {
|
|
@@ -1033,7 +1034,10 @@ function apply(ctx, config) {
|
|
|
1033
1034
|
userName: "string",
|
|
1034
1035
|
status: "string",
|
|
1035
1036
|
time: "timestamp"
|
|
1036
|
-
}, {
|
|
1037
|
+
}, {
|
|
1038
|
+
primary: "id",
|
|
1039
|
+
indexes: ["status", "channelId", "userId"]
|
|
1040
|
+
});
|
|
1037
1041
|
const fileManager = new FileManager(ctx.baseDir, config, logger);
|
|
1038
1042
|
const reusableIds = /* @__PURE__ */ new Set();
|
|
1039
1043
|
const profileManager = config.enableName ? new NameManager(ctx) : null;
|
|
@@ -1072,12 +1076,10 @@ function apply(ctx, config) {
|
|
|
1072
1076
|
});
|
|
1073
1077
|
cave.subcommand(".add [content:text]", "添加回声洞").usage("添加一条回声洞。可直接发送内容,也可回复或引用消息。").action(async ({ session }, content) => {
|
|
1074
1078
|
try {
|
|
1075
|
-
let sourceElements;
|
|
1076
|
-
if (
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
sourceElements = import_koishi3.h.parse(content);
|
|
1080
|
-
} else {
|
|
1079
|
+
let sourceElements = [];
|
|
1080
|
+
if (content?.trim()) sourceElements.push(...import_koishi3.h.parse(content));
|
|
1081
|
+
if (session.quote?.elements) sourceElements.push(...session.quote.elements);
|
|
1082
|
+
if (sourceElements.length === 0) {
|
|
1081
1083
|
await session.send("请在一分钟内发送你要添加的内容");
|
|
1082
1084
|
const reply = await session.prompt(6e4);
|
|
1083
1085
|
if (!reply) return "等待操作超时";
|
|
@@ -1160,17 +1162,17 @@ function apply(ctx, config) {
|
|
|
1160
1162
|
const adminChannelId = config.adminChannel?.split(":")[1];
|
|
1161
1163
|
if (session.channelId !== adminChannelId) return "此指令仅限在管理群组中使用";
|
|
1162
1164
|
try {
|
|
1163
|
-
const
|
|
1164
|
-
if (!
|
|
1165
|
+
const aggregatedStats = await ctx.database.select("cave", { status: "active" }).groupBy(["userId", "userName"], { count: /* @__PURE__ */ __name((row) => import_koishi3.$.count(row.id), "count") }).execute();
|
|
1166
|
+
if (!aggregatedStats.length) return "目前没有回声洞投稿";
|
|
1165
1167
|
const userStats = /* @__PURE__ */ new Map();
|
|
1166
|
-
for (const
|
|
1167
|
-
const
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
stat.
|
|
1171
|
-
stat.userName =
|
|
1168
|
+
for (const stat of aggregatedStats) {
|
|
1169
|
+
const existing = userStats.get(stat.userId);
|
|
1170
|
+
if (existing) {
|
|
1171
|
+
existing.count += stat.count;
|
|
1172
|
+
const existingGroup = aggregatedStats.find((s) => s.userId === stat.userId && s.userName === existing.userName);
|
|
1173
|
+
if (stat.count > (existingGroup?.count || 0)) existing.userName = stat.userName;
|
|
1172
1174
|
} else {
|
|
1173
|
-
userStats.set(userId, { userName:
|
|
1175
|
+
userStats.set(stat.userId, { userName: stat.userName, count: stat.count });
|
|
1174
1176
|
}
|
|
1175
1177
|
}
|
|
1176
1178
|
const sortedStats = Array.from(userStats.values()).sort((a, b) => b.count - a.count);
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -2,20 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/koishi-plugin-best-cave)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
功能强大、高度可定制的回声洞插件。支持丰富的媒体类型、内容查重、人工审核、用户昵称、数据迁移以及本地/S3 双重文件存储后端。
|
|
6
|
+
|
|
7
|
+
## 🧩 前置依赖
|
|
8
|
+
|
|
9
|
+
- **数据库 (`koishi-plugin-database`)**: 本插件强依赖数据库来存储数据,请确保您已至少配置了一个数据库插件(如 `koishi-plugin-database-sqlite` 或 `koishi-plugin-database-mysql`)。
|
|
10
|
+
- **图片处理 (`sharp`)**: 如果您启用了 `enableSimilarity` (内容查重) 功能,插件需要使用 `sharp` 库来处理图片。通常情况下它会自动安装,如遇安装问题,请参考 `sharp` 的官方文档解决。
|
|
6
11
|
|
|
7
12
|
## ✨ 功能亮点
|
|
8
13
|
|
|
9
14
|
- **丰富的内容形式**:不止于文本,轻松发布包含图片、视频、音频甚至文件的混合内容。插件能自动解析回复或引用的消息,并将其完整存入回声洞。
|
|
10
|
-
- **灵活的存储后端**:媒体文件可存储在 **本地服务器** (`data/cave` 目录)
|
|
11
|
-
- **高级内容查重**:(可选) 启用后,插件会在添加时自动计算文本 (Simhash) 和图片 (pHash)
|
|
15
|
+
- **灵活的存储后端**:媒体文件可存储在 **本地服务器** (`data/cave` 目录),或配置使用任何 **S3 兼容** 的云端对象存储(如 AWS S3, MinIO, 阿里云 OSS, 腾讯云 COS 等)。支持通过公共URL、本地文件路径或Base64三种方式发送媒体。
|
|
16
|
+
- **高级内容查重**:(可选) 启用后,插件会在添加时自动计算文本 (Simhash) 和图片 (pHash) 的哈希值。对于相似度过高的投稿将直接拒绝,有效防止重复。管理员还可通过维护工具找出局部相似或拼接的图片。
|
|
12
17
|
- **完善的审核机制**:(可选) 启用后,所有新投稿都将进入待审核状态,并通知管理群组。只有管理员审核通过后,内容才会对用户可见,确保内容质量。
|
|
13
18
|
- **精细的作用域**:通过 `perChannel` 配置,可设定回声洞是在所有群聊中共享(全局模式),还是在每个群聊中独立(分群模式)。
|
|
14
19
|
- **专属用户昵称**:(可选) 用户可以为自己在回声洞中的发言设置一个专属昵称,增加趣味性。
|
|
15
20
|
- **便捷的数据管理**:(可选) 管理员可通过指令轻松地将所有回声洞数据导出为 `JSON` 文件备份,或从文件中恢复数据,迁移无忧。
|
|
16
21
|
- **强大的维护工具**:管理员可以通过 `cave.hash` 指令为历史数据批量生成哈希值,并通过 `cave.check` 获取一份所有内容的相似度报告。
|
|
17
22
|
- **权限分离**:普通用户可删除自己的投稿。审核、数据管理等高级操作则仅限在指定的 **管理群组** 内由管理员执行。
|
|
18
|
-
-
|
|
23
|
+
- **高效的ID管理**:优先复用已删除的ID,并在无可用ID时采用高效的“最大ID+1”策略,确保回声洞序号紧凑,并能高效处理大量数据。
|
|
19
24
|
|
|
20
25
|
## 📖 指令说明
|
|
21
26
|
|
|
@@ -24,7 +29,7 @@
|
|
|
24
29
|
| 指令 | 别名/选项 | 说明 |
|
|
25
30
|
| :--- | :--- | :--- |
|
|
26
31
|
| `cave` | | 随机查看一条回声洞。 |
|
|
27
|
-
| `cave.add [内容]` | `cave -a [内容]` |
|
|
32
|
+
| `cave.add [内容]` | `cave -a [内容]` | 添加新的回声洞。可以直接跟文字,也可以**回复一条带图片/视频的消息后发送 `cave.add`**,或等待机器人提示后发送。 |
|
|
28
33
|
| `cave.view <序号>` | `cave -g <序号>` | 查看指定序号的回声洞。 |
|
|
29
34
|
| `cave.del <序号>` | `cave -r <序号>` | 删除指定序号的回声洞。仅投稿人或在管理群组内的管理员可操作。 |
|
|
30
35
|
| `cave.list` | `cave -l` | 查询并列出自己投稿过的所有回声洞序号及总数。 |
|
|
@@ -42,8 +47,8 @@
|
|
|
42
47
|
| `cave.pend <序号>` | `enablePend: true` | **(仅限管理群组)** 查看指定待审核内容的详情。 |
|
|
43
48
|
| `cave.pend.Y [...序号]` | `enablePend: true` | **(仅限管理群组)** 通过审核。若不提供序号,则通过所有待审核内容。 |
|
|
44
49
|
| `cave.pend.N [...序号]` | `enablePend: true` | **(仅限管理群组)** 拒绝审核。若不提供序号,则拒绝所有待审核内容。 |
|
|
45
|
-
| `cave.export` | `enableIO: true` | **(仅限管理群组)** 将所有`active`状态的回声洞导出到 `cave_export.json`。 |
|
|
46
|
-
| `cave.import` | `enableIO: true` | **(仅限管理群组)** 从 `cave_import.json` 文件中导入数据。 |
|
|
50
|
+
| `cave.export` | `enableIO: true` | **(仅限管理群组)** 将所有`active`状态的回声洞导出到 `data/cave/cave_export.json`。 |
|
|
51
|
+
| `cave.import` | `enableIO: true` | **(仅限管理群组)** 从 `data/cave/cave_import.json` 文件中导入数据。 |
|
|
47
52
|
| `cave.hash` | `enableSimilarity: true` | **(仅限管理群组)** 校验所有历史数据,为缺失哈希的回声洞补全记录。 |
|
|
48
53
|
| `cave.check` | `enableSimilarity: true` | **(仅限管理群组)** 检查所有回声洞的哈希,生成一份关于文本和图片相似度的报告。 |
|
|
49
54
|
|
|
@@ -56,8 +61,8 @@
|
|
|
56
61
|
| `perChannel` | `boolean` | `false` | 是否启用分群模式。`true` 表示各群的回声洞独立。 |
|
|
57
62
|
| `enableName` | `boolean` | `false` | 是否启用自定义昵称功能 (`cave.name` 指令)。 |
|
|
58
63
|
| `enableIO` | `boolean` | `false` | 是否启用数据导入/导出功能 (`cave.export` / `.import` 指令)。 |
|
|
59
|
-
| `adminChannel` | `string` | `'onebot:'` | **管理群组ID**。格式为 `平台名:群号`,如 `onebot:12345678
|
|
60
|
-
| `caveFormat` | `string` | `'回声洞 ——({id})\|—— {name}'` | 回声洞消息的显示格式。`{id}`是序号,`{name}
|
|
64
|
+
| `adminChannel` | `string` | `'onebot:'` | **管理群组ID**。格式为 `平台名:群号`,如 `onebot:12345678`。管理指令仅在此群组生效。若配置无效,审核将自动通过。 |
|
|
65
|
+
| `caveFormat` | `string` | `'回声洞 ——({id})\|—— {name}'` | 回声洞消息的显示格式。`{id}`是序号,`{name}`是昵称。`\|` 作为换行符,其前面的部分为页眉,后面的为页脚。 |
|
|
61
66
|
|
|
62
67
|
### 复核配置 (审核与查重)
|
|
63
68
|
|
|
@@ -73,8 +78,8 @@
|
|
|
73
78
|
| 配置项 | 类型 | 默认值 | 说明 |
|
|
74
79
|
| :--- | :--- | :--- | :--- |
|
|
75
80
|
| `localPath` | `string` | | 为本地文件提供一个可访问的绝对路径。配置后,将以 `file:///` 协议发送本地媒体。 |
|
|
76
|
-
| `enableS3` | `boolean` | `false` | 是否启用 S3
|
|
77
|
-
| `publicUrl` | `string` | | **(S3 可选)** S3 存储桶的公共访问 URL。如果提供,插件将直接用此 URL
|
|
81
|
+
| `enableS3` | `boolean` | `false` | 是否启用 S3 兼容对象存储。若为 `false`,所有媒体文件将保存在本地 `data/cave` 目录下。 |
|
|
82
|
+
| `publicUrl` | `string` | | **(S3 可选)** S3 存储桶的公共访问 URL。如果提供,插件将直接用此 URL 发送媒体链接,性能最佳。 |
|
|
78
83
|
| `endpoint` | `string` | | **(S3 必填)** S3 兼容存储的 Endpoint URL。 |
|
|
79
84
|
| `bucket` | `string` | | **(S3 必填)** S3 存储桶 (Bucket) 名称。 |
|
|
80
85
|
| `region` | `string` | `'auto'` | **(S3 可选)** S3 区域 (Region)。 |
|
|
@@ -84,10 +89,10 @@
|
|
|
84
89
|
## ⚠️ 注意事项
|
|
85
90
|
|
|
86
91
|
1. **媒体发送方式**:插件会按以下优先级决定如何发送图片、视频等媒体文件:
|
|
87
|
-
1. **S3 公共URL**:如果 `enableS3` 和 `publicUrl`
|
|
92
|
+
1. **S3 公共URL**:如果 `enableS3` 和 `publicUrl` 已配置。**(推荐)**
|
|
88
93
|
2. **本地文件路径**:如果 `localPath` 已配置。
|
|
89
94
|
3. **Base64 编码**:如果以上两项均未配置,将文件转为 Base64 发送(可能受平台大小限制或支持问题)。
|
|
90
95
|
2. **文件存储权限**:若使用本地存储,请确保 Koishi 拥有对 `data/cave` 目录的读写权限。若使用 S3,请确保 Access Key 权限和存储桶策略(如ACL设为`public-read`)配置正确。
|
|
91
96
|
3. **异步删除**:删除操作(`cave.del` 或审核拒绝)会将内容状态标记为 `delete`,然后由后台任务异步清理关联的文件和数据库条目,以避免阻塞当前指令。
|
|
92
97
|
4. **数据迁移**:导入功能会读取插件数据目录下的 `cave_import.json`。导出功能则会生成 `cave_export.json`。请在操作前放置或备份好相应文件。导入时,ID会从现有最大ID开始自增,不会覆盖或修改老数据。
|
|
93
|
-
5. **查重机制**:图片查重在投稿时,仅基于**整图**的相似度进行判断和拒绝。插件还会为图片的四个象限生成哈希,但这些局部哈希仅用于 `cave.check`
|
|
98
|
+
5. **查重机制**:图片查重在投稿时,仅基于**整图**的相似度进行判断和拒绝。插件还会为图片的四个象限生成哈希,但这些局部哈希仅用于 `cave.check` 指令生成相似度报告,供管理员识别拼接图、裁剪图等情况,**并不会在投稿时直接导致拒绝**。
|