koishi-plugin-echo-cave 1.18.5 → 1.19.0
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 +4 -28
- package/lib/index.cjs +65 -36
- package/lib/index.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,19 +11,13 @@
|
|
|
11
11
|
## ✨ 功能特性
|
|
12
12
|
|
|
13
13
|
- 📥 **消息存储**:支持存储普通消息和转发消息到数据库
|
|
14
|
-
- 🖼️ **图片保存**:自动保存消息中的图片资源到本地
|
|
15
14
|
- 🔍 **消息查询**:支持随机获取消息或通过 ID 精确查找
|
|
16
15
|
- 🗑️ **消息管理**:支持删除特定 ID 的消息(消息存储者、原始发送者或管理员)
|
|
17
|
-
- 📊 **数据持久化**:使用 Koishi 数据库系统,确保数据不会丢失
|
|
18
16
|
- 👤 **个人追踪**:支持查看自己投稿的消息列表
|
|
19
17
|
- 🔍 **发言回溯**:支持查看自己被他人投稿的消息列表
|
|
20
|
-
- 🎨
|
|
21
|
-
- 🔒
|
|
18
|
+
- 🎨 **模板化展示**:消息展示时自带多种风格的外部包裹信息
|
|
19
|
+
- 🔒 **管理员保护**:可配置管理员消息保护
|
|
22
20
|
- 📏 **媒体限制**:支持配置媒体文件大小限制
|
|
23
|
-
- 🌐 **多语言支持**:支持中文语言包
|
|
24
|
-
- 🔄 **嵌套转发**:支持嵌套转发消息的递归处理
|
|
25
|
-
- 📝 **模板化展示**:支持多种风格的消息展示模板
|
|
26
|
-
- 🔁 **重复检测**:自动检测重复消息,避免存储重复内容
|
|
27
21
|
|
|
28
22
|
## 📋 命令列表
|
|
29
23
|
|
|
@@ -32,13 +26,13 @@
|
|
|
32
26
|
| `cave` | 随机获取一条回声洞消息 | 所有人 |
|
|
33
27
|
| `cave <id>` | 获取特定 ID 的回声洞消息 | 所有人 |
|
|
34
28
|
| `cave.echo` | 将引用的消息存入回声洞 | 所有人 |
|
|
35
|
-
| `cave.
|
|
29
|
+
| `cave.drop <id>` | 删除特定 ID 的回声洞消息 | 消息存储者、原始发送者或管理员 |
|
|
36
30
|
| `cave.listen` | 获取自己投稿的回声洞列表 | 所有人 |
|
|
37
31
|
| `cave.trace` | 获取自己发言被投稿的回声洞列表 | 所有人 |
|
|
38
32
|
|
|
39
33
|
## 🚀 使用指南
|
|
40
34
|
|
|
41
|
-
###
|
|
35
|
+
### 安装插件
|
|
42
36
|
|
|
43
37
|
```bash
|
|
44
38
|
npm install koishi-plugin-echo-cave
|
|
@@ -46,24 +40,6 @@ npm install koishi-plugin-echo-cave
|
|
|
46
40
|
|
|
47
41
|
或在插件商城中搜索 `koishi-plugin-echo-cave` 进行安装。
|
|
48
42
|
|
|
49
|
-
### 2. 基本使用
|
|
50
|
-
|
|
51
|
-
1. **存储消息**:在群聊中引用一条消息,然后发送命令 `cave.echo`
|
|
52
|
-
2. **查看随机消息**:发送命令 `cave` 获取一条随机消息
|
|
53
|
-
3. **查看特定消息**:发送命令 `cave <id>` 查看指定 ID 的消息
|
|
54
|
-
4. **删除消息**:消息存储者、原始发送者或管理员发送命令 `cave.wipe <id>` 删除指定 ID 的消息
|
|
55
|
-
5. **查看自己的投稿**:发送命令 `cave.listen` 查看自己曾经存入的所有回声洞消息
|
|
56
|
-
6. **查看自己的发言**:发送命令 `cave.trace` 查看自己曾经被他人存入的回声洞消息
|
|
57
|
-
|
|
58
|
-
## 🔧 技术说明
|
|
59
|
-
|
|
60
|
-
- 插件使用 Koishi 数据库系统存储消息记录
|
|
61
|
-
- 支持嵌套转发消息的处理
|
|
62
|
-
- 自动检测重复消息,避免存储重复内容
|
|
63
|
-
- 支持媒体文件大小限制
|
|
64
|
-
- 支持多语言配置(中文)
|
|
65
|
-
- 支持嵌套转发消息的递归处理
|
|
66
|
-
|
|
67
43
|
## 🛠️ 配置选项
|
|
68
44
|
|
|
69
45
|
| 配置项 | 类型 | 默认值 | 说明 |
|
package/lib/index.cjs
CHANGED
|
@@ -155,16 +155,14 @@ var require_zh_CN2 = __commonJS({
|
|
|
155
155
|
description: "\u83B7\u5F97\u7531\u81EA\u5DF1\u6295\u7A3F\u7684\u56DE\u58F0\u6D1E\u5217\u8868",
|
|
156
156
|
messages: {
|
|
157
157
|
noMsgContributed: '\u{1F680} \u60A8\u5728\u56DE\u58F0\u6D1E\u4E2D\u6682\u65E0\u6295\u7A3F\uFF0C\u5FEB\u4F7F\u7528 "cave.echo" \u547D\u4EE4\u6DFB\u52A0\u7B2C\u4E00\u6761\u6D88\u606F\u5427\uFF01',
|
|
158
|
-
msgListHeader: "\u{1F4DC} \u60A8\u5728\u672C\u9891\u9053\u6295\u7A3F\u7684\u56DE\u58F0\u6D1E\u6D88\u606F\u5217\u8868\uFF1A"
|
|
159
|
-
msgListItem: "ID: {0} | \u521B\u5EFA\u65F6\u95F4\uFF1A{1}"
|
|
158
|
+
msgListHeader: "\u{1F4DC} \u60A8\u5728\u672C\u9891\u9053\u6295\u7A3F\u7684\u56DE\u58F0\u6D1E\u6D88\u606F\u5217\u8868\uFF1A"
|
|
160
159
|
}
|
|
161
160
|
},
|
|
162
161
|
"cave.trace": {
|
|
163
162
|
description: "\u83B7\u5F97\u81EA\u5DF1\u53D1\u8A00\u7684\u56DE\u58F0\u6D1E\u5217\u8868",
|
|
164
163
|
messages: {
|
|
165
164
|
noMsgTraced: '\u{1F680} \u60A8\u5728\u56DE\u58F0\u6D1E\u4E2D\u6682\u65E0\u53D1\u8A00\u88AB\u6295\u7A3F\uFF0C\u5FEB\u4F7F\u7528 "cave.echo" \u547D\u4EE4\u6DFB\u52A0\u7B2C\u4E00\u6761\u6D88\u606F\u5427\uFF01',
|
|
166
|
-
msgListHeader: "\u{1F4DC} \u60A8\u5728\u672C\u9891\u9053\u53D1\u8A00\u7684\u56DE\u58F0\u6D1E\u6D88\u606F\u5217\u8868\uFF1A"
|
|
167
|
-
msgListItem: "ID: {0} | \u521B\u5EFA\u65F6\u95F4\uFF1A{1}"
|
|
165
|
+
msgListHeader: "\u{1F4DC} \u60A8\u5728\u672C\u9891\u9053\u53D1\u8A00\u7684\u56DE\u58F0\u6D1E\u6D88\u606F\u5217\u8868\uFF1A"
|
|
168
166
|
}
|
|
169
167
|
},
|
|
170
168
|
"cave.bind": {
|
|
@@ -510,9 +508,11 @@ async function addCave(ctx, session, cfg, userIds) {
|
|
|
510
508
|
return session.text("echo-cave.user.invalidAllMention");
|
|
511
509
|
}
|
|
512
510
|
parsedUserIds = result.parsedUserIds;
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
511
|
+
if (parsedUserIds.length > 0) {
|
|
512
|
+
const isAllUsersInGroup = await checkUsersInGroup(ctx, session, parsedUserIds);
|
|
513
|
+
if (!isAllUsersInGroup) {
|
|
514
|
+
return session.text("echo-cave.user.userNotInGroup");
|
|
515
|
+
}
|
|
516
516
|
}
|
|
517
517
|
}
|
|
518
518
|
let content;
|
|
@@ -540,13 +540,13 @@ async function addCave(ctx, session, cfg, userIds) {
|
|
|
540
540
|
}
|
|
541
541
|
content = JSON.stringify(await processMessageContent(ctx, msgJson, cfg));
|
|
542
542
|
}
|
|
543
|
-
await ctx.database.get("
|
|
543
|
+
await ctx.database.get("echo_cave_v2", { content }).then((existing) => {
|
|
544
544
|
if (existing) {
|
|
545
545
|
return session.text(".existingMsg");
|
|
546
546
|
}
|
|
547
547
|
});
|
|
548
548
|
try {
|
|
549
|
-
const result = await ctx.database.create("
|
|
549
|
+
const result = await ctx.database.create("echo_cave_v2", {
|
|
550
550
|
channelId,
|
|
551
551
|
createTime: /* @__PURE__ */ new Date(),
|
|
552
552
|
userId,
|
|
@@ -569,7 +569,7 @@ async function deleteCave(ctx, session, cfg, id) {
|
|
|
569
569
|
if (!id) {
|
|
570
570
|
return session.text(".noIdProvided");
|
|
571
571
|
}
|
|
572
|
-
const caves = await ctx.database.get("
|
|
572
|
+
const caves = await ctx.database.get("echo_cave_v2", id);
|
|
573
573
|
if (caves.length === 0) {
|
|
574
574
|
return session.text("echo-cave.general.noMsgWithId");
|
|
575
575
|
}
|
|
@@ -601,7 +601,7 @@ async function deleteCave(ctx, session, cfg, id) {
|
|
|
601
601
|
if (cfg.deleteMediaWhenDeletingMsg) {
|
|
602
602
|
await deleteMediaFilesFromMessage(ctx, caveMsg.content);
|
|
603
603
|
}
|
|
604
|
-
await ctx.database.remove("
|
|
604
|
+
await ctx.database.remove("echo_cave_v2", id);
|
|
605
605
|
return session.text(".msgDeleted", [id]);
|
|
606
606
|
}
|
|
607
607
|
async function deleteCaves(ctx, session, cfg, ids) {
|
|
@@ -616,7 +616,7 @@ async function deleteCaves(ctx, session, cfg, ids) {
|
|
|
616
616
|
const user = await ctx.database.getUser(session.platform, currentUserId);
|
|
617
617
|
const userAuthority = user.authority;
|
|
618
618
|
const isCurrentUserAdmin = userAuthority >= 4;
|
|
619
|
-
const caves = await ctx.database.get("
|
|
619
|
+
const caves = await ctx.database.get("echo_cave_v2", ids);
|
|
620
620
|
for (const cave of caves) {
|
|
621
621
|
const caveMsg = caves[0];
|
|
622
622
|
if (cfg.adminMessageProtection) {
|
|
@@ -642,7 +642,7 @@ async function deleteCaves(ctx, session, cfg, ids) {
|
|
|
642
642
|
if (cfg.deleteMediaWhenDeletingMsg) {
|
|
643
643
|
await deleteMediaFilesFromMessage(ctx, caveMsg.content);
|
|
644
644
|
}
|
|
645
|
-
await ctx.database.remove("
|
|
645
|
+
await ctx.database.remove("echo_cave_v2", cave.id);
|
|
646
646
|
}
|
|
647
647
|
const foundIds = new Set(caves.map((r) => r.id));
|
|
648
648
|
const missingIds = ids.filter((id) => !foundIds.has(id));
|
|
@@ -744,36 +744,38 @@ async function getCaveListByUser(ctx, session) {
|
|
|
744
744
|
return session.text("echo-cave.general.privateChatReminder");
|
|
745
745
|
}
|
|
746
746
|
const { userId, channelId } = session;
|
|
747
|
-
const caves = await ctx.database.get(
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
747
|
+
const caves = await ctx.database.get(
|
|
748
|
+
"echo_cave_v2",
|
|
749
|
+
{
|
|
750
|
+
userId,
|
|
751
|
+
channelId
|
|
752
|
+
},
|
|
753
|
+
["id"]
|
|
754
|
+
);
|
|
751
755
|
if (caves.length === 0) {
|
|
752
756
|
return session.text(".noMsgContributed");
|
|
753
757
|
}
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
response += session.text(".msgListItem", [cave.id, formatDate(cave.createTime)]) + "\n";
|
|
757
|
-
}
|
|
758
|
-
return response;
|
|
758
|
+
const ids = caves.map((cave) => cave.id).join(" | ");
|
|
759
|
+
return session.text(".msgListHeader") + "\n" + ids;
|
|
759
760
|
}
|
|
760
761
|
async function getCaveListByOriginUser(ctx, session) {
|
|
761
762
|
if (!session.guildId) {
|
|
762
763
|
return session.text("echo-cave.general.privateChatReminder");
|
|
763
764
|
}
|
|
764
765
|
const { userId, channelId } = session;
|
|
765
|
-
const caves = await ctx.database.get(
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
766
|
+
const caves = await ctx.database.get(
|
|
767
|
+
"echo_cave_v2",
|
|
768
|
+
{
|
|
769
|
+
originUserId: userId,
|
|
770
|
+
channelId
|
|
771
|
+
},
|
|
772
|
+
["id"]
|
|
773
|
+
);
|
|
769
774
|
if (caves.length === 0) {
|
|
770
775
|
return session.text(".noMsgTraced");
|
|
771
776
|
}
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
response += session.text(".msgListItem", [cave.id, formatDate(cave.createTime)]) + "\n";
|
|
775
|
-
}
|
|
776
|
-
return response;
|
|
777
|
+
const ids = caves.map((cave) => cave.id).join(" | ");
|
|
778
|
+
return session.text(".msgListHeader") + "\n" + ids;
|
|
777
779
|
}
|
|
778
780
|
async function getCave(ctx, session, cfg, id) {
|
|
779
781
|
if (!session.guildId) {
|
|
@@ -782,7 +784,7 @@ async function getCave(ctx, session, cfg, id) {
|
|
|
782
784
|
let caveMsg;
|
|
783
785
|
const { channelId } = session;
|
|
784
786
|
if (!id) {
|
|
785
|
-
const caves = await ctx.database.get("
|
|
787
|
+
const caves = await ctx.database.get("echo_cave_v2", {
|
|
786
788
|
channelId
|
|
787
789
|
});
|
|
788
790
|
if (caves.length === 0) {
|
|
@@ -790,7 +792,7 @@ async function getCave(ctx, session, cfg, id) {
|
|
|
790
792
|
}
|
|
791
793
|
caveMsg = caves[Math.floor(Math.random() * caves.length)];
|
|
792
794
|
} else {
|
|
793
|
-
const caves = await ctx.database.get("
|
|
795
|
+
const caves = await ctx.database.get("echo_cave_v2", {
|
|
794
796
|
id,
|
|
795
797
|
channelId
|
|
796
798
|
});
|
|
@@ -821,7 +823,7 @@ async function bindUsersToCave(ctx, session, id, userIds) {
|
|
|
821
823
|
if (parsedUserIds.length === 0) {
|
|
822
824
|
return session.text(".noValidUserIdProvided");
|
|
823
825
|
}
|
|
824
|
-
const caves = await ctx.database.get("
|
|
826
|
+
const caves = await ctx.database.get("echo_cave_v2", id);
|
|
825
827
|
if (caves.length === 0) {
|
|
826
828
|
return session.text("echo-cave.general.noMsgWithId");
|
|
827
829
|
}
|
|
@@ -829,7 +831,7 @@ async function bindUsersToCave(ctx, session, id, userIds) {
|
|
|
829
831
|
if (!isAllUsersInGroup) {
|
|
830
832
|
return session.text("echo-cave.user.userNotInGroup");
|
|
831
833
|
}
|
|
832
|
-
await ctx.database.set("
|
|
834
|
+
await ctx.database.set("echo_cave_v2", id, {
|
|
833
835
|
relatedUsers: parsedUserIds
|
|
834
836
|
});
|
|
835
837
|
return session.text(".userBoundSuccess", [id]);
|
|
@@ -857,7 +859,7 @@ async function searchCave(ctx, session, userIds) {
|
|
|
857
859
|
}
|
|
858
860
|
const targetUserId = parsedUserIds[0];
|
|
859
861
|
const { channelId } = session;
|
|
860
|
-
const caves = await ctx.database.get("
|
|
862
|
+
const caves = await ctx.database.get("echo_cave_v2", {
|
|
861
863
|
channelId
|
|
862
864
|
});
|
|
863
865
|
const matchingCaves = caves.filter(
|
|
@@ -910,6 +912,33 @@ function apply(ctx, cfg) {
|
|
|
910
912
|
autoInc: true
|
|
911
913
|
}
|
|
912
914
|
);
|
|
915
|
+
ctx.model.extend(
|
|
916
|
+
"echo_cave_v2",
|
|
917
|
+
{
|
|
918
|
+
id: "unsigned",
|
|
919
|
+
channelId: "string",
|
|
920
|
+
createTime: "timestamp",
|
|
921
|
+
userId: "string",
|
|
922
|
+
originUserId: "string",
|
|
923
|
+
type: "string",
|
|
924
|
+
content: "text",
|
|
925
|
+
relatedUsers: "list"
|
|
926
|
+
},
|
|
927
|
+
{
|
|
928
|
+
primary: "id",
|
|
929
|
+
autoInc: true
|
|
930
|
+
}
|
|
931
|
+
);
|
|
932
|
+
ctx.model.migrate(
|
|
933
|
+
"echo_cave",
|
|
934
|
+
{
|
|
935
|
+
id: "unsigned"
|
|
936
|
+
},
|
|
937
|
+
async (database) => {
|
|
938
|
+
const data = await database.get("echo_cave", {});
|
|
939
|
+
await database.upsert("echo_cave_v2", data);
|
|
940
|
+
}
|
|
941
|
+
);
|
|
913
942
|
ctx.command("cave [id:number]").action(
|
|
914
943
|
async ({ session }, id) => await getCave(ctx, session, cfg, id)
|
|
915
944
|
);
|
package/lib/index.d.ts
CHANGED