nonebot-plugin-shitbot 0.1.2__tar.gz → 0.2__tar.gz

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 (41) hide show
  1. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/PKG-INFO +1 -1
  2. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/README.md +17 -13
  3. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/aux.py +10 -0
  4. nonebot_plugin_shitbot-0.2/nonebot_plugin_shitbot/commands/autoreply_cmd.py +550 -0
  5. nonebot_plugin_shitbot-0.2/nonebot_plugin_shitbot/commands/autoreply_main_cmd.py +99 -0
  6. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/commands/convert_cmd.py +2 -2
  7. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/commands/shitpost_cmd.py +3 -1
  8. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/config.py +5 -0
  9. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/config.yaml +1 -0
  10. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/default_config.yaml +7 -6
  11. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/handlers.py +7 -3
  12. nonebot_plugin_shitbot-0.2/nonebot_plugin_shitbot/msgdatabase.py +323 -0
  13. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/msgutils.py +59 -19
  14. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot.egg-info/PKG-INFO +1 -1
  15. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot.egg-info/SOURCES.txt +1 -0
  16. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/pyproject.toml +1 -1
  17. nonebot_plugin_shitbot-0.1.2/nonebot_plugin_shitbot/commands/autoreply_cmd.py +0 -486
  18. nonebot_plugin_shitbot-0.1.2/nonebot_plugin_shitbot/commands/autoreply_main_cmd.py +0 -105
  19. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/LICENSE +0 -0
  20. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/__init__.py +0 -0
  21. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/command.py +0 -0
  22. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/commands/__init__.py +0 -0
  23. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/commands/advrandpic_cmd.py +0 -0
  24. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/commands/help_cmd.py +0 -0
  25. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/commands/md2pic_cmd.py +0 -0
  26. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/commands/perm_cmd.py +0 -0
  27. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/commands/pixiv_cmd.py +0 -0
  28. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/commands/randpic_cmd.py +0 -0
  29. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/commands/session_cmd.py +0 -0
  30. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/css/github-markdown-dark-dimmed.css +0 -0
  31. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/parser.py +0 -0
  32. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/permissions.py +0 -0
  33. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/scripts/p2png.sh +0 -0
  34. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/scripts/png2fr.sh +0 -0
  35. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/scripts/png2v.sh +0 -0
  36. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/session.py +0 -0
  37. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot/tasks.py +0 -0
  38. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot.egg-info/dependency_links.txt +0 -0
  39. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot.egg-info/requires.txt +0 -0
  40. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/nonebot_plugin_shitbot.egg-info/top_level.txt +0 -0
  41. {nonebot_plugin_shitbot-0.1.2 → nonebot_plugin_shitbot-0.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nonebot-plugin-shitbot
3
- Version: 0.1.2
3
+ Version: 0.2
4
4
  Summary: NoneBot shitpost plugin
5
5
  Requires-Python: >=3.10
6
6
  License-File: LICENSE
@@ -16,19 +16,13 @@
16
16
 
17
17
  - 用户多命令管理
18
18
 
19
- - 权限管理系统(见docs/权限系统.md)
20
-
21
- ## TODO List(大致按优先级排序 但随缘想先解决哪个就解决哪个)
19
+ - 参数解析(见docs/参数解析.md)
22
20
 
23
- - B站视频解析并下载(支持链接块或者BV号)
24
-
25
- - 添加单元测试
26
-
27
- - 实现 /stop 用于终止当前会话
21
+ - 权限管理系统(见docs/权限系统.md)
28
22
 
29
- - 为代码添加更多注释 并按照nonebot所说的插件规范修改代码(?)
23
+ - 信息处理函数库(msgutils) 涵盖对信息对象的转换、处理、发送 运用函数式方案处理信息
30
24
 
31
- - 手搓数据库 用于自动回复系统以及搬史系统
25
+ - 手搓信息管理数据库
32
26
  - 数据库由两部分组成: messages以及medias
33
27
  - messages用于存储信息 通过将 Message 转化为 DumpedMsg 后以 yaml 格式存储
34
28
  - 文件名为该文件的sha256sum值 通过比较文件名去重
@@ -37,9 +31,19 @@
37
31
  - 文件名为该文件的sha256sum值 通过比较文件名去重
38
32
  - 维护一个映射表(的yaml文件) 用于记录文件的引用数(只会被messages中的信息引用 因此仅由数据库本身维护) 通常若元信息的引用数为0 则删除元信息
39
33
 
40
- - 基于上一点重构 /autoreply
34
+ - 自动回复系统
35
+
36
+ ## TODO List(大致按优先级排序 但随缘想先解决哪个就解决哪个)
37
+
38
+ - 添加单元测试 (技术债务这块 最讨厌的一集 想写哪个就写哪个)
39
+
40
+ - B站视频解析并下载(支持链接块或者BV号)(6.12更新:我鬼脑意淫后越想越觉得写这个好累 所以把优先级后调)
41
+
42
+ - 实现 /stop 用于终止当前会话(暂时没啥思路 我只能想到装饰器+CancelTask注入 但要怎么找到需要被注入的任务我还没思路)
43
+
44
+ - 为代码添加更多注释和写文档 (依旧技术债务 依旧最烦 依旧随缘)
41
45
 
42
- - 智能化/shitpost
46
+ - 智能化/shitpost (鉴于数据库搓好了 如果我后面认为这个写起来也不难的话我就来搓)
43
47
  - 使用用上面提到的数据库
44
48
  - 添加一个元信息映射表(yaml) 类型大概是Dict[str, Dict[str, Any]] 键是史的文件名 也就是哈希值 值中保存着史的:real_id列表 时间戳 好评数 发送失败次数 存储着已经发送过该史的群号的列表
45
49
 
@@ -53,7 +57,7 @@
53
57
  \end{aligned}
54
58
  $$
55
59
 
56
- - 暂时想到这些 哪天我又有什么点子也说不定
60
+ - 暂时想到这些 哪天我又有什么点子也说不定(6.12更新:一个月下来能看到 TODO List 越来越少还是挺感慨的 为什么补上这条括号内容?因为上面的项我都加了 这条不加我会犯强迫症)
57
61
 
58
62
  ## 配置
59
63
 
@@ -51,6 +51,16 @@ async def rm_cache(group_id: str, user_id: str, pid: str):
51
51
  logger.info(f"已删除缓存: {cache_path}")
52
52
 
53
53
 
54
+ def get_file_sha256(file_path: Path | str):
55
+ file = Path(file_path) if isinstance(file_path, str) else file_path
56
+ if not file.is_file():
57
+ raise FileNotFoundError(f"No such file or not a regular file: {file}")
58
+ # Compute sha256sum
59
+ with file.open("rb") as f:
60
+ hash_hex = hashlib.file_digest(f, "sha256").hexdigest()
61
+ return hash_hex
62
+
63
+
54
64
  def rename_file_to_sha256(file_path: Path | str):
55
65
  file = Path(file_path) if isinstance(file_path, str) else file_path
56
66
  if not file.is_file():
@@ -0,0 +1,550 @@
1
+ import asyncio
2
+ import yaml
3
+
4
+ from pathlib import Path
5
+
6
+ from nonebot.adapters.onebot.v11 import Bot, Message, MessageEvent
7
+
8
+ from ..command import BotCommand
9
+ from ..session import BotSession
10
+ from ..parser import BotArgParser
11
+ from ..msgdatabase import BotMsgDataBase
12
+ from ..msgutils import DumpedMsg, DumpedSeg, DataVariables, dump_message, msg_filter, modify_msg_data
13
+ from ..tasks import autoreply_lock
14
+ from .autoreply_main_cmd import BotCommandAutoReplyMain
15
+
16
+
17
+ class BotCommandAutoreply(BotCommand):
18
+ _name = "autoreply"
19
+ _autoreply_dir = BotCommandAutoReplyMain._autoreply_dir
20
+ _rule_path = BotCommandAutoReplyMain._rule_path
21
+ _msg_table_path = BotCommandAutoReplyMain._msg_table_path
22
+
23
+ def __init__(self, bot: Bot, session: BotSession, *, _pid: int, _internal=None):
24
+ super().__init__(bot, session, _pid=_pid, _internal=_internal)
25
+ self._roger_lock = asyncio.Lock()
26
+ self._is_accept_msg = False
27
+ self._rule = {}
28
+ self._msg_table = {}
29
+ self._temp_msg: DumpedMsg = []
30
+
31
+ self._auto: bool = False
32
+ self._key: list[str] = []
33
+ self._rp: list[str] = []
34
+ self._T: list[str] = []
35
+ self._t: list[str] = []
36
+ self._K: list[str] = []
37
+ self._k: list[str] = []
38
+ self._R: list[str] = []
39
+ self._r: list[str] = []
40
+ self._m: int = -1
41
+ self._l: int = 0
42
+ self._sum: list[str] = []
43
+ self._st: list[int] = []
44
+
45
+ self._rstate: str = ""
46
+
47
+ def _load_meta(self):
48
+ if not self._rule_path.exists() or not self._msg_table_path.exists():
49
+ raise FileNotFoundError
50
+ _rule = yaml.safe_load(self._rule_path.read_text(encoding="utf-8"))
51
+ _msg_table = yaml.safe_load(self._msg_table_path.read_text(encoding="utf-8"))
52
+ if (_rule is not None and not isinstance(_rule, dict)) or (
53
+ _msg_table is not None and not isinstance(_msg_table, dict)
54
+ ):
55
+ raise ValueError
56
+ self._rule = _rule if _rule is not None else {}
57
+ self._msg_table = _msg_table if _msg_table is not None else {}
58
+
59
+ def _update_meta(self):
60
+ self._rule_path.write_text(
61
+ yaml.safe_dump(self._rule, allow_unicode=True), encoding="utf-8"
62
+ )
63
+ self._msg_table_path.write_text(
64
+ yaml.safe_dump(self._msg_table, allow_unicode=True), encoding="utf-8"
65
+ )
66
+ arsession = BotSession.get_obj("public", "autoreply")
67
+ if arsession is None:
68
+ return
69
+ main_command = arsession.commands.get(arsession.curpid)
70
+ if main_command is None or not isinstance(
71
+ main_command, BotCommandAutoReplyMain
72
+ ):
73
+ return
74
+ main_command.load_meta()
75
+
76
+ async def _set_reply(self, reply: str):
77
+ old_msg_hash = self._msg_table.get(reply, "")
78
+ if self._temp_msg == []:
79
+ if old_msg_hash:
80
+ return
81
+ self._msg_table[reply] = ""
82
+ self._update_meta()
83
+ return
84
+
85
+ def _filter(seg: DumpedSeg) -> bool:
86
+ return seg["type"] in ["text", "image", "face"]
87
+
88
+ filtered_msg = msg_filter(_filter, self._temp_msg)
89
+ msg_path = await self._database.save_msg(filtered_msg)
90
+ msg_hash = msg_path.name
91
+ self._msg_table[reply] = msg_hash
92
+ self._database.inc_msg_rc(msg_hash)
93
+ if old_msg_hash:
94
+ self._database.dec_msg_rc(old_msg_hash)
95
+ self._database.del_msg(old_msg_hash)
96
+ self._update_meta()
97
+
98
+ def _del_reply(self, reply: str):
99
+ for key in self._rule.keys():
100
+ if reply in self._rule[key]["replys"]:
101
+ self._rule[key]["replys"].remove(reply)
102
+ msg_hash = self._msg_table.get(reply, "")
103
+ if not msg_hash:
104
+ self._msg_table.pop(reply, None)
105
+ self._update_meta()
106
+ return
107
+ self._database.dec_msg_rc(msg_hash)
108
+ self._database.del_msg(msg_hash)
109
+ self._msg_table.pop(reply, None)
110
+ self._update_meta()
111
+
112
+ def _set_key(
113
+ self,
114
+ key: str,
115
+ *,
116
+ trans: list[str] | None = None,
117
+ dels: list[str] | None = None,
118
+ is_contain: bool | None = None,
119
+ keywords: list[str] | None = None,
120
+ replys: list[str] | None = None,
121
+ ):
122
+ if key not in self._rule:
123
+ self._rule[key] = {
124
+ "trans": [],
125
+ "dels": [],
126
+ "is_contain": False,
127
+ "keywords": [],
128
+ "replys": [],
129
+ }
130
+ if trans is not None:
131
+ self._rule[key]["trans"] = trans
132
+ if dels is not None:
133
+ self._rule[key]["dels"] = dels
134
+ if is_contain is not None:
135
+ self._rule[key]["is_contain"] = is_contain
136
+ if keywords is not None:
137
+ self._rule[key]["keywords"] = keywords
138
+ if replys is not None:
139
+ self._rule[key]["replys"] = replys
140
+ self._update_meta()
141
+
142
+ def _del_key(self, key: str):
143
+ self._rule.pop(key, None)
144
+ self._update_meta()
145
+
146
+ def _init_parser(self):
147
+ parser = BotArgParser()
148
+ parser.set_rule(max=0, need_subcmd=True)
149
+ start = parser.add_subparser("start")
150
+ stop = parser.add_subparser("stop")
151
+ lst = parser.add_subparser("list")
152
+ info = parser.add_subparser("info")
153
+ prnt = parser.add_subparser("print")
154
+ create = parser.add_subparser("create")
155
+ delete = parser.add_subparser("delete")
156
+ reply = parser.add_subparser("reply")
157
+ key = parser.add_subparser("key")
158
+
159
+ start.set_rule(max=0)
160
+ start.add_opt("--auto", default=[0])
161
+
162
+ stop.set_rule(max=0)
163
+ stop.add_opt("--auto", default=[0])
164
+
165
+ lst.set_rule(min=1,max=1)
166
+
167
+ info.set_rule(max=None)
168
+
169
+ prnt.set_rule(max=None)
170
+
171
+ create.set_rule(max=0)
172
+ create.add_opt("--key", required=True, max_appeared=None)
173
+ create.add_opt("--rp", required=True, max_appeared=None)
174
+
175
+ delete.set_rule(max=0)
176
+ delete.add_opt("--key", required=True, max_appeared=None)
177
+ delete.add_opt("--rp", required=True, max_appeared=None)
178
+
179
+ reply.set_rule(min=1,max=1, need_subcmd=True)
180
+ reply_start = reply.add_subparser("start")
181
+ reply_stop = reply.add_subparser("stop")
182
+ reply_modify = reply.add_subparser("modify")
183
+
184
+ key.set_rule(min=1,max=1)
185
+ key.add_opt("-T", required=True, choice=["delmark", "delspace", "upper", "lower"], max_appeared=None)
186
+ key.add_opt("-t", required=True, choice=["delmark", "delspace", "upper", "lower"], max_appeared=None)
187
+ key.add_opt("-D", required=True, max_appeared=None)
188
+ key.add_opt("-d", required=True, max_appeared=None)
189
+ key.add_opt("-K", required=True, max_appeared=None)
190
+ key.add_opt("-k", required=True, max_appeared=None)
191
+ key.add_opt("-R", required=True, max_appeared=None)
192
+ key.add_opt("-r", required=True, max_appeared=None)
193
+ key.add_opt("-m", required=True, choice=["equal", "contain"], default=[""])
194
+
195
+ reply_start.set_rule(max=0)
196
+ reply_start.add_opt("-l", required=True, type=int, default=[1])
197
+
198
+ reply_stop.set_rule(max=0)
199
+
200
+ reply_modify.set_rule(max=0)
201
+ reply_modify.add_opt("--sum", required=True, max_appeared=None)
202
+ reply_modify.add_opt("--st", required=True, type=int, max_appeared=None)
203
+
204
+ return parser
205
+
206
+ async def _guard_state(self, subsubcmd=None):
207
+ if subsubcmd is None:
208
+ return await super()._guard_state()
209
+ if subsubcmd == "start" and self._argv is not None:
210
+ return await super()._guard_state()
211
+ if subsubcmd == "stop" and self._argv is None:
212
+ tip = "错误:会话未开始\n"
213
+ tip += "尚未开始收集自动信息,请先使用 /autoreply value start 开始收集。"
214
+ await self.send_msg(tip)
215
+ self.unlock()
216
+ return False
217
+ if subsubcmd == "stop" and self._rstate != "start":
218
+ return await super()._guard_state()
219
+ return True
220
+
221
+ async def _start(self):
222
+ autoreply_session = BotSession.make("public", "autoreply")
223
+ main_command = BotCommandAutoReplyMain.make(
224
+ self.bot, autoreply_session, _pid=autoreply_session.curpid
225
+ )
226
+ if main_command is None:
227
+ await self.send_msg("警告: 自动回复正在运行中")
228
+ else:
229
+ await main_command.run(Message())
230
+ if self._auto:
231
+ from ruamel.yaml import YAML
232
+ config_path = Path(__file__).parent.parent / "config.yaml"
233
+ config_yaml = YAML()
234
+ data = config_yaml.load(config_path)
235
+ data["if_auto_start_autoreply"] = True
236
+ config_yaml.dump(data, config_path)
237
+ await self.send_msg("自动回复已开启")
238
+ self.unlock()
239
+
240
+ async def _stop(self):
241
+ async def _exe():
242
+ autoreply_session = BotSession.get_obj("public", "autoreply")
243
+ if autoreply_session is None:
244
+ await self.send_msg("警告: 自动回复未开启")
245
+ return
246
+ main_command = autoreply_session.commands.get(autoreply_session.curpid)
247
+ if main_command is None:
248
+ await self.send_msg("警告: 自动回复未开启")
249
+ return
250
+ main_command.unlock()
251
+
252
+ await _exe()
253
+ if self._auto:
254
+ from ruamel.yaml import YAML
255
+ config_path = Path(__file__).parent.parent / "config.yaml"
256
+ config_yaml = YAML()
257
+ data = config_yaml.load(config_path)
258
+ data["if_auto_start_autoreply"] = False
259
+ config_yaml.dump(data, config_path)
260
+ await self.send_msg("自动回复已关闭")
261
+ self.unlock()
262
+
263
+ async def _list(self, tpe: str):
264
+ lst = []
265
+ if tpe == "key":
266
+ lst = self._rule.keys()
267
+ if tpe == "reply":
268
+ lst = self._msg_table.keys()
269
+ await self.send_msg("\n".join(lst))
270
+ self.unlock()
271
+
272
+ async def _info(self, keys: list[str]):
273
+ tip = ""
274
+ for key in keys:
275
+ tip += f"{key}: {self._rule[key] if key in self._rule else '未创建'}\n"
276
+
277
+ await self.send_msg(tip)
278
+ self.unlock()
279
+
280
+ async def _print(self, replys: list[str]):
281
+ for reply in replys:
282
+ await self.send_msg(f"{reply} 内容:")
283
+ if reply not in self._msg_table:
284
+ await self.send_msg(f"警告: {reply} 未被创建")
285
+ continue
286
+ if self._msg_table[reply] == "":
287
+ await self.send_msg(f"警告: {reply} 未被设置")
288
+ continue
289
+ msg_hash = self._msg_table[reply]
290
+ async with autoreply_lock:
291
+ msg = self._database.prepare_send_msg(msg_hash)
292
+ try:
293
+ await self.send_msg(msg)
294
+ except Exception as e:
295
+ await self.send_msg(f"警告: {reply} 发送失败: {e}")
296
+
297
+ self.unlock()
298
+
299
+ async def _create(self):
300
+ async with autoreply_lock:
301
+ for key in self._key:
302
+ if key in self._rule:
303
+ await self.send_msg(f"警告: 键 {key} 已存在")
304
+ continue
305
+ self._set_key(key)
306
+ for reply in self._rp:
307
+ if reply in self._msg_table:
308
+ await self.send_msg(f"警告: 回复 {reply} 已存在")
309
+ continue
310
+ await self._set_reply(reply)
311
+ await self.send_msg("创建成功")
312
+
313
+ self.unlock()
314
+
315
+ async def _delete(self):
316
+ async with autoreply_lock:
317
+ for key in self._key:
318
+ if key not in self._rule:
319
+ await self.send_msg(f"警告: 键 {key} 不存在")
320
+ continue
321
+ self._del_key(key)
322
+ for reply in self._rp:
323
+ if reply not in self._msg_table:
324
+ await self.send_msg(f"警告: 回复 {reply} 不存在")
325
+ continue
326
+ self._del_reply(reply)
327
+ await self.send_msg("删除成功")
328
+
329
+ self.unlock()
330
+
331
+ async def _reply_start(self, reply_name: str):
332
+ if reply_name not in self._msg_table:
333
+ await self.send_msg(f"警告: 回复信息 {reply_name} 不存在")
334
+ return
335
+ self._rstate = "start"
336
+ self._reply_name = reply_name
337
+ await self.send_msg(f"请发送仅包含图片或文字的信息, 或者发送 /autoreply reply {reply_name} stop 停止设置")
338
+ self._is_accept_msg = True
339
+
340
+ async def _reply_stop(self, reply_name: str):
341
+ if reply_name not in self._msg_table:
342
+ await self.send_msg(f"警告: 回复信息 {reply_name} 不存在")
343
+ return
344
+ self._rstate = "stop"
345
+ self._is_accept_msg = False
346
+ async with self._roger_lock:
347
+ if not self._temp_msg:
348
+ await self.send_msg("错误: 未收到任何信息")
349
+ self.unlock()
350
+ return
351
+ async with autoreply_lock:
352
+ await self._set_reply(reply_name)
353
+ self._temp_msg = []
354
+ await self.send_msg("设置成功")
355
+ self.unlock()
356
+
357
+ async def _reply_modify(self, reply_name: str):
358
+ reply_hash = self._msg_table.get(reply_name, "")
359
+ if reply_hash == "":
360
+ await self.send_msg(f"警告: 回复信息 {reply_name} 不存在或未设置")
361
+ return
362
+ async with autoreply_lock:
363
+ self._temp_msg = self._database.get_msg(reply_hash)
364
+ if not self._temp_msg:
365
+ await self.send_msg("错误: 未收到任何信息")
366
+ self.unlock()
367
+ return
368
+ self._temp_msg = modify_msg_data(
369
+ self._temp_msg,
370
+ {
371
+ "summary": DataVariables(self._sum),
372
+ "sub_type": DataVariables(self._st),
373
+ },
374
+ ["image"]
375
+ )
376
+ await self._set_reply(reply_name)
377
+ self._temp_msg = []
378
+ await self.send_msg("修改成功")
379
+ self.unlock()
380
+
381
+ async def _key_modify(self, key_name: str):
382
+ if key_name not in self._rule:
383
+ await self.send_msg(f"错误: 键 {key_name} 不存在")
384
+ self.unlock()
385
+ return
386
+ def _rm_dup(lst_A: list, lst_R: list):
387
+ dup = []
388
+ for elem in lst_A:
389
+ if elem in lst_R:
390
+ dup.append(elem)
391
+ for elem in dup:
392
+ lst_A.remove(elem)
393
+ lst_R.remove(elem)
394
+ return dup
395
+
396
+ def _get_lst(lst_S, lst_A, lst_R):
397
+ lst = lst_S[:]
398
+ for elem in lst_A:
399
+ if elem not in lst_R:
400
+ lst.append(elem)
401
+ for elem in lst_R:
402
+ if elem in lst_S:
403
+ lst.remove(elem)
404
+ return lst
405
+
406
+ for (lst_A, lst_R) in [(self._T, self._t), (self._D, self._d), (self._K, self._k), (self._R, self._r)]:
407
+ _rm_dup(lst_A, lst_R)
408
+ for lst in [self._R, self._r]:
409
+ rem = []
410
+ for elem in lst:
411
+ if self._msg_table.get(elem, "") == "":
412
+ await self.send_msg(f"警告: 回复信息 {elem} 不存在或未设置")
413
+ rem.append(elem)
414
+ for elem in rem:
415
+ lst.remove(elem)
416
+ data = []
417
+ for (lst_S, lst_A, lst_R) in [(self._rule[key_name]["trans"], self._T, self._t), (self._rule[key_name]["dels"], self._D, self._d), (self._rule[key_name]["keywords"], self._K, self._k), (self._rule[key_name]["replys"], self._R, self._r)]:
418
+ data.append(_get_lst(lst_S, lst_A, lst_R))
419
+
420
+
421
+ _m = None
422
+ if self._m == 0:
423
+ _m = False
424
+ elif self._m == 1:
425
+ _m = True
426
+
427
+ async with autoreply_lock:
428
+ self._set_key(
429
+ key_name,
430
+ trans=data[0],
431
+ dels=data[1],
432
+ is_contain=_m,
433
+ keywords=data[2],
434
+ replys=data[3]
435
+ )
436
+ await self.send_msg("修改成功")
437
+ self.unlock()
438
+
439
+
440
+
441
+ async def roger(self, event: MessageEvent):
442
+ async with self._roger_lock:
443
+ if not self._is_accept_msg:
444
+ return
445
+ if self._l <= 0:
446
+ return
447
+ dumped_msg = await dump_message(self.bot, event.message)
448
+ self._temp_msg.extend(dumped_msg)
449
+ self._l -= 1
450
+ if self._l <= 0:
451
+ reply_name = getattr(self, "_reply_name", None)
452
+ if reply_name is None:
453
+ raise ValueError
454
+ asyncio.create_task(self.run(Message(f"reply {reply_name} stop")))
455
+
456
+
457
+
458
+ async def run(self, args: Message):
459
+ async with autoreply_lock:
460
+ self._database = BotMsgDataBase(self._autoreply_dir)
461
+ self._rule_path.touch(exist_ok=True)
462
+ self._msg_table_path.touch(exist_ok=True)
463
+ self._load_meta()
464
+
465
+ if not self.session:
466
+ return
467
+ new_argv = args.extract_plain_text().strip().split()
468
+
469
+ if not await self._legal_case(new_argv):
470
+ if self._argv is None:
471
+ self.unlock()
472
+ return
473
+ subsubcmd = None
474
+ self._parser.parse_argv(new_argv)
475
+ subcmd = self._parser.subcmd
476
+ if subcmd is None:
477
+ self.unlock()
478
+ return
479
+ subparser = self._parser.subparsers[subcmd]
480
+ subsubcmd = subparser.subcmd
481
+
482
+ if not await self._guard_state(subsubcmd):
483
+ return
484
+
485
+ if not self._check_perm("autoreplymanager"):
486
+ await self.send_msg("权限不足")
487
+ self.unlock()
488
+ return
489
+
490
+ self._argv = new_argv
491
+
492
+ _auto = subparser.opts_value.get("--auto", [0])[0]
493
+ self._auto = _auto >= 1
494
+
495
+ self._key = subparser.opts_value.get("--key", [])
496
+ self._rp = subparser.opts_value.get("--rp", [])
497
+
498
+ self._T = subparser.opts_value.get("-T", [])
499
+ self._t = subparser.opts_value.get("-t", [])
500
+ self._D = subparser.opts_value.get("-D", [])
501
+ self._d = subparser.opts_value.get("-d", [])
502
+ self._K = subparser.opts_value.get("-K", [])
503
+ self._k = subparser.opts_value.get("-k", [])
504
+ self._R = subparser.opts_value.get("-R", [])
505
+ self._r = subparser.opts_value.get("-r", [])
506
+ _ms = subparser.opts_value.get("-m", [""])
507
+ if _ms[0] == "equal":
508
+ self._m = 0
509
+ if _ms[0] == "contain":
510
+ self._m = 1
511
+
512
+ if subsubcmd is not None:
513
+ subsubparser = subparser.subparsers[subsubcmd]
514
+ self._l = subsubparser.opts_value.get("-l", [1])[0]
515
+ self._l = max(1, self._l)
516
+ self._sum = subsubparser.opts_value.get("--sum", [])
517
+ self._st = subsubparser.opts_value.get("--st", [])
518
+ self._rstate = subsubcmd if subsubcmd != "modify" else ""
519
+
520
+
521
+ if subcmd == "start":
522
+ await self._start()
523
+ if subcmd == "stop":
524
+ await self._stop()
525
+ if subcmd == "list":
526
+ lst = subparser.value[0]
527
+ await self._list(lst)
528
+ if subcmd == "info":
529
+ await self._info(subparser.value)
530
+ if subcmd == "print":
531
+ await self._print(subparser.value)
532
+ if subcmd == "create":
533
+ await self._create()
534
+ if subcmd == "delete":
535
+ await self._delete()
536
+ reply_name = ""
537
+ if subcmd == "reply":
538
+ reply_name = subparser.value[0]
539
+ if subsubcmd == "start":
540
+ await self._reply_start(reply_name)
541
+ if subsubcmd == "stop":
542
+ await self._reply_stop(reply_name)
543
+ if subsubcmd == "modify":
544
+ await self._reply_modify(reply_name)
545
+ if subcmd == "key":
546
+ key_name = subparser.value[0]
547
+ await self._key_modify(key_name)
548
+
549
+
550
+