butterbot-python 3.1.0.dev1__py3-none-any.whl

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 (79) hide show
  1. butterbot/__init__.py +15 -0
  2. butterbot/app/__init__.py +41 -0
  3. butterbot/app/bot_app.py +374 -0
  4. butterbot/app/config.py +156 -0
  5. butterbot/app/source_manager.py +367 -0
  6. butterbot/core/__init__.py +46 -0
  7. butterbot/core/api/__init__.py +9 -0
  8. butterbot/core/api/base_api.py +32 -0
  9. butterbot/core/context/README.md +1 -0
  10. butterbot/core/context/__init__.py +9 -0
  11. butterbot/core/context/api_registry.py +109 -0
  12. butterbot/core/context/app_context.py +51 -0
  13. butterbot/core/context/config_provider.py +14 -0
  14. butterbot/core/data/__init__.py +15 -0
  15. butterbot/core/data/base_data.py +29 -0
  16. butterbot/core/data/base_model.py +197 -0
  17. butterbot/core/event/README.md +1 -0
  18. butterbot/core/event/__init__.py +10 -0
  19. butterbot/core/event/event.py +27 -0
  20. butterbot/core/event/event_bus.py +276 -0
  21. butterbot/core/event/subscriber.py +130 -0
  22. butterbot/core/exceptions.py +90 -0
  23. butterbot/core/filter/__init__.py +11 -0
  24. butterbot/core/filter/base_filter.py +74 -0
  25. butterbot/core/source/README.md +1 -0
  26. butterbot/core/source/__init__.py +9 -0
  27. butterbot/core/source/base_source.py +134 -0
  28. butterbot/core/types/__init__.py +9 -0
  29. butterbot/core/types/base_type.py +74 -0
  30. butterbot/sources/__init__.py +1 -0
  31. butterbot/sources/bilibili/README.md +10 -0
  32. butterbot/sources/bilibili/__init__.py +20 -0
  33. butterbot/sources/bilibili/api/__init__.py +5 -0
  34. butterbot/sources/bilibili/api/bili_api.py +123 -0
  35. butterbot/sources/bilibili/data/__init__.py +52 -0
  36. butterbot/sources/bilibili/data/danmaku_gift_data.py +135 -0
  37. butterbot/sources/bilibili/data/danmaku_guard_data.py +54 -0
  38. butterbot/sources/bilibili/data/danmaku_msg_data.py +71 -0
  39. butterbot/sources/bilibili/data/dto/__init__.py +59 -0
  40. butterbot/sources/bilibili/data/dto/danmaku_gift_dto.py +193 -0
  41. butterbot/sources/bilibili/data/dto/danmaku_guard_buy_dto.py +54 -0
  42. butterbot/sources/bilibili/data/dto/danmaku_msg_dto.py +123 -0
  43. butterbot/sources/bilibili/data/dto/dynamic_dto.py +276 -0
  44. butterbot/sources/bilibili/data/dto/live_room_dto.py +169 -0
  45. butterbot/sources/bilibili/data/dto/video_part_dto.py +18 -0
  46. butterbot/sources/bilibili/data/dynamic_data.py +362 -0
  47. butterbot/sources/bilibili/data/live_room_data.py +162 -0
  48. butterbot/sources/bilibili/data/video_part.py +46 -0
  49. butterbot/sources/bilibili/source/__init__.py +15 -0
  50. butterbot/sources/bilibili/source/base_polling_source.py +130 -0
  51. butterbot/sources/bilibili/source/bili_danmaku_source.py +230 -0
  52. butterbot/sources/bilibili/source/bili_dynamic_source.py +135 -0
  53. butterbot/sources/bilibili/source/bili_live_source.py +137 -0
  54. butterbot/sources/bilibili/types/__init__.py +11 -0
  55. butterbot/sources/bilibili/types/bili_type.py +32 -0
  56. butterbot/sources/napcat/README.md +10 -0
  57. butterbot/sources/napcat/__init__.py +20 -0
  58. butterbot/sources/napcat/api/__init__.py +3 -0
  59. butterbot/sources/napcat/api/napcat_api.py +316 -0
  60. butterbot/sources/napcat/data/__init__.py +179 -0
  61. butterbot/sources/napcat/data/event_data.py +441 -0
  62. butterbot/sources/napcat/data/segment_data.py +432 -0
  63. butterbot/sources/napcat/events.py +91 -0
  64. butterbot/sources/napcat/filters/__init__.py +19 -0
  65. butterbot/sources/napcat/filters/filters.py +202 -0
  66. butterbot/sources/napcat/source/__init__.py +5 -0
  67. butterbot/sources/napcat/source/napcat_source.py +58 -0
  68. butterbot/sources/napcat/types/__init__.py +5 -0
  69. butterbot/sources/napcat/types/napcat_type.py +61 -0
  70. butterbot/utils/README.md +15 -0
  71. butterbot/utils/__init__.py +11 -0
  72. butterbot/utils/data_pair.py +27 -0
  73. butterbot/utils/logging_config.py +521 -0
  74. butterbot/utils/terminal.py +308 -0
  75. butterbot/utils/websocket.py +1270 -0
  76. butterbot_python-3.1.0.dev1.dist-info/METADATA +769 -0
  77. butterbot_python-3.1.0.dev1.dist-info/RECORD +79 -0
  78. butterbot_python-3.1.0.dev1.dist-info/WHEEL +4 -0
  79. butterbot_python-3.1.0.dev1.dist-info/licenses/LICENSE +674 -0
@@ -0,0 +1,432 @@
1
+ """
2
+ NapCat OneBot11 消息段数据模型
3
+
4
+ 基于 OneBot11 协议定义的消息段类型,使用 BaseDataModel 实现自动分发构造
5
+ """
6
+
7
+ from typing import ClassVar, TypeVar
8
+
9
+ from butterbot.core.data import AutoDispatchList, BaseDataModel
10
+
11
+ # ==================== 嵌套数据类 ====================
12
+
13
+
14
+ class TextData(BaseDataModel):
15
+ """纯文本消息数据"""
16
+
17
+ text: str
18
+
19
+
20
+ class FaceData(BaseDataModel):
21
+ """QQ表情消息数据"""
22
+
23
+ id: str
24
+
25
+
26
+ class ImageData(BaseDataModel):
27
+ """图片消息数据"""
28
+
29
+ file: str
30
+ type: str | None = None # 'flash' 表示闪照
31
+ url: str | None = None
32
+ cache: int | None = None # 0 或 1
33
+ proxy: int | None = None # 0 或 1
34
+ timeout: int | None = None
35
+
36
+
37
+ class RecordData(BaseDataModel):
38
+ """语音消息数据"""
39
+
40
+ file: str
41
+ magic: int | None = None # 0 或 1,变声
42
+ url: str | None = None
43
+ cache: int | None = None
44
+ proxy: int | None = None
45
+ timeout: int | None = None
46
+
47
+
48
+ class VideoData(BaseDataModel):
49
+ """短视频消息数据"""
50
+
51
+ file: str
52
+ url: str | None = None
53
+ cache: int | None = None
54
+ proxy: int | None = None
55
+ timeout: int | None = None
56
+
57
+
58
+ class AtData(BaseDataModel):
59
+ """@某人消息数据"""
60
+
61
+ qq: str # QQ号 或 'all'
62
+ name: str | None = None
63
+
64
+
65
+ class PokeData(BaseDataModel):
66
+ """戳一戳消息数据"""
67
+
68
+ type: str
69
+ id: str
70
+ name: str | None = None
71
+
72
+
73
+ class ShareData(BaseDataModel):
74
+ """链接分享消息数据"""
75
+
76
+ url: str
77
+ title: str
78
+ content: str | None = None
79
+ image: str | None = None
80
+
81
+
82
+ class ContactData(BaseDataModel):
83
+ """推荐好友/群消息数据"""
84
+
85
+ type: str # 'qq' 或 'group'
86
+ id: str
87
+
88
+
89
+ class LocationData(BaseDataModel):
90
+ """位置消息数据"""
91
+
92
+ lat: str # 纬度
93
+ lon: str # 经度
94
+ title: str | None = None
95
+ content: str | None = None
96
+
97
+
98
+ class MusicData(BaseDataModel):
99
+ """音乐分享消息数据"""
100
+
101
+ type: str # 'qq', '163', 'xm' 或 'custom'
102
+ id: str | None = None # 非 custom 时使用
103
+ url: str | None = None # custom 时使用
104
+ audio: str | None = None
105
+ title: str | None = None
106
+ content: str | None = None
107
+ image: str | None = None
108
+
109
+
110
+ class ReplyData(BaseDataModel):
111
+ """回复消息数据"""
112
+
113
+ id: str | None = None # msg_id 的短ID映射
114
+ seq: int | None = None # msg_seq,优先使用
115
+
116
+
117
+ class ForwardData(BaseDataModel):
118
+ """合并转发消息数据"""
119
+
120
+ id: str
121
+
122
+
123
+ class NodeData(BaseDataModel):
124
+ """合并转发节点消息数据"""
125
+
126
+ id: str | None = None # 直接引用已有消息
127
+ user_id: str | None = None # 自定义节点
128
+ nickname: str | None = None
129
+ content: list | None = None # MessageNode[]
130
+ prompt: str | None = None
131
+ summary: str | None = None
132
+ source: str | None = None
133
+
134
+
135
+ class FileData(BaseDataModel):
136
+ """文件消息数据"""
137
+
138
+ file: str
139
+
140
+
141
+ class AnonymousData(BaseDataModel):
142
+ """匿名发消息数据"""
143
+
144
+ ignore: int | None = None # 0 或 1
145
+
146
+
147
+ class RpsData(BaseDataModel):
148
+ """猜拳魔法表情数据"""
149
+
150
+ pass
151
+
152
+
153
+ class DiceData(BaseDataModel):
154
+ """掷骰子魔法表情数据"""
155
+
156
+ pass
157
+
158
+
159
+ class ShakeData(BaseDataModel):
160
+ """窗口抖动数据"""
161
+
162
+ pass
163
+
164
+
165
+ class XmlData(BaseDataModel):
166
+ """XML消息数据"""
167
+
168
+ data: str
169
+
170
+
171
+ class JsonData(BaseDataModel):
172
+ """JSON消息数据"""
173
+
174
+ data: str
175
+
176
+
177
+ # ==================== 消息段基类与子类 ====================
178
+
179
+
180
+ class MessageNode(BaseDataModel):
181
+ """OneBot11 消息段基类
182
+
183
+ 使用 type 字段进行分发
184
+ """
185
+
186
+ discriminator_field: ClassVar[str] = "type"
187
+ type: str
188
+
189
+
190
+ MessageNodeT = TypeVar("MessageNodeT", bound=MessageNode)
191
+
192
+
193
+ class TextNode(MessageNode):
194
+ """纯文本消息段"""
195
+
196
+ discriminator_value: ClassVar[str] = "text"
197
+ type: str = "text"
198
+ data: TextData
199
+
200
+ @property
201
+ def text(self) -> str:
202
+ return self.data.text
203
+
204
+
205
+ class FaceNode(MessageNode):
206
+ """QQ表情消息段"""
207
+
208
+ discriminator_value: ClassVar[str] = "face"
209
+ type: str = "face"
210
+ data: FaceData
211
+
212
+ @property
213
+ def face_id(self) -> str:
214
+ return self.data.id
215
+
216
+
217
+ class ImageNode(MessageNode):
218
+ """图片消息段"""
219
+
220
+ discriminator_value: ClassVar[str] = "image"
221
+ type: str = "image"
222
+ data: ImageData
223
+
224
+
225
+ class RecordNode(MessageNode):
226
+ """语音消息段"""
227
+
228
+ discriminator_value: ClassVar[str] = "record"
229
+ type: str = "record"
230
+ data: RecordData
231
+
232
+
233
+ class VideoNode(MessageNode):
234
+ """短视频消息段"""
235
+
236
+ discriminator_value: ClassVar[str] = "video"
237
+ type: str = "video"
238
+ data: VideoData
239
+
240
+
241
+ class AtNode(MessageNode):
242
+ """@某人消息段"""
243
+
244
+ discriminator_value: ClassVar[str] = "at"
245
+ type: str = "at"
246
+ data: AtData
247
+
248
+ @property
249
+ def qq(self) -> str:
250
+ return self.data.qq
251
+
252
+ @property
253
+ def is_all(self) -> bool:
254
+ return self.data.qq == "all"
255
+
256
+
257
+ class RpsNode(MessageNode):
258
+ """猜拳魔法表情消息段"""
259
+
260
+ discriminator_value: ClassVar[str] = "rps"
261
+ type: str = "rps"
262
+ data: RpsData | None = None
263
+
264
+
265
+ class DiceNode(MessageNode):
266
+ """掷骰子魔法表情消息段"""
267
+
268
+ discriminator_value: ClassVar[str] = "dice"
269
+ type: str = "dice"
270
+ data: DiceData | None = None
271
+
272
+
273
+ class ShakeNode(MessageNode):
274
+ """窗口抖动消息段"""
275
+
276
+ discriminator_value: ClassVar[str] = "shake"
277
+ type: str = "shake"
278
+ data: ShakeData | None = None
279
+
280
+
281
+ class PokeNode(MessageNode):
282
+ """戳一戳消息段"""
283
+
284
+ discriminator_value: ClassVar[str] = "poke"
285
+ type: str = "poke"
286
+ data: PokeData
287
+
288
+
289
+ class AnonymousNode(MessageNode):
290
+ """匿名发消息消息段"""
291
+
292
+ discriminator_value: ClassVar[str] = "anonymous"
293
+ type: str = "anonymous"
294
+ data: AnonymousData | None = None
295
+
296
+
297
+ class ShareNode(MessageNode):
298
+ """链接分享消息段"""
299
+
300
+ discriminator_value: ClassVar[str] = "share"
301
+ type: str = "share"
302
+ data: ShareData
303
+
304
+
305
+ class ContactNode(MessageNode):
306
+ """推荐好友/群消息段"""
307
+
308
+ discriminator_value: ClassVar[str] = "contact"
309
+ type: str = "contact"
310
+ data: ContactData
311
+
312
+
313
+ class LocationNode(MessageNode):
314
+ """位置消息段"""
315
+
316
+ discriminator_value: ClassVar[str] = "location"
317
+ type: str = "location"
318
+ data: LocationData
319
+
320
+
321
+ class MusicNode(MessageNode):
322
+ """音乐分享消息段"""
323
+
324
+ discriminator_value: ClassVar[str] = "music"
325
+ type: str = "music"
326
+ data: MusicData
327
+
328
+
329
+ class ReplyNode(MessageNode):
330
+ """回复消息段"""
331
+
332
+ discriminator_value: ClassVar[str] = "reply"
333
+ type: str = "reply"
334
+ data: ReplyData
335
+
336
+
337
+ class ForwardNode(MessageNode):
338
+ """合并转发消息段"""
339
+
340
+ discriminator_value: ClassVar[str] = "forward"
341
+ type: str = "forward"
342
+ data: ForwardData
343
+
344
+
345
+ class NodeNode(MessageNode):
346
+ """合并转发节点消息段"""
347
+
348
+ discriminator_value: ClassVar[str] = "node"
349
+ type: str = "node"
350
+ data: NodeData
351
+
352
+
353
+ class XmlNode(MessageNode):
354
+ """XML消息段"""
355
+
356
+ discriminator_value: ClassVar[str] = "xml"
357
+ type: str = "xml"
358
+ data: XmlData
359
+
360
+ @property
361
+ def xml_data(self) -> str:
362
+ return self.data.data
363
+
364
+
365
+ class JsonNode(MessageNode):
366
+ """JSON消息段"""
367
+
368
+ discriminator_value: ClassVar[str] = "json"
369
+ type: str = "json"
370
+ data: JsonData
371
+
372
+ @property
373
+ def json_data(self) -> str:
374
+ return self.data.data
375
+
376
+
377
+ class FileNode(MessageNode):
378
+ """文件消息段"""
379
+
380
+ discriminator_value: ClassVar[str] = "file"
381
+ type: str = "file"
382
+ data: FileData
383
+
384
+
385
+ # ==================== 消息列表领域模型 ====================
386
+
387
+
388
+ class NapcatMessage(AutoDispatchList[MessageNode]):
389
+ """Napcat消息领域模型,包含一个消息段列表"""
390
+
391
+ # root: list[MessageNode]
392
+
393
+ @classmethod
394
+ def element_type(cls):
395
+ return MessageNode
396
+
397
+ # 可迭代对象
398
+ def __iter__(self):
399
+ return iter(self.root)
400
+
401
+ # ====== 便携方法 ======
402
+
403
+ @property
404
+ def message_list(self) -> list[MessageNode]:
405
+ """消息段列表"""
406
+ return self.root
407
+
408
+ def filter(self, node_type: type[MessageNodeT]) -> list[MessageNodeT]:
409
+ """过滤出指定类型的消息段"""
410
+ return [seg for seg in self.message_list if isinstance(seg, node_type)]
411
+
412
+ @property
413
+ def texts(self) -> list[str]:
414
+ """提取所有文本消息段的文本内容"""
415
+ return [seg.text for seg in self.filter(TextNode)]
416
+
417
+ @property
418
+ def ats(self) -> list[str]:
419
+ """提取所有@消息段的QQ号"""
420
+ return [seg.qq for seg in self.filter(AtNode)]
421
+
422
+ @property
423
+ def imgs(self) -> list[str]:
424
+ """提取所有图片消息段的URL"""
425
+ return [
426
+ seg.data.url for seg in self.filter(ImageNode) if seg.data.url is not None
427
+ ]
428
+
429
+ @property
430
+ def plain_text(self):
431
+ """提取纯文本内容,连接所有文本消息段的文本"""
432
+ return "".join(self.texts)
@@ -0,0 +1,91 @@
1
+ """Napcat 事件类型别名.
2
+
3
+ 将 ``Event[*Data]`` 包装为 ``*Event`` 类型别名,用户可直接用作类型注解:
4
+
5
+ .. code:: python
6
+
7
+ from butterbot.sources.napcat.events import NapcatGroupMessageEvent
8
+
9
+ @app.subscribe(source.uuid, NapcatType.GROUP_MESSAGE)
10
+ async def handler(event: NapcatGroupMessageEvent):
11
+ print(event.data.group_id)
12
+ """
13
+
14
+ from typing import TypeAlias
15
+
16
+ from butterbot.core.event import Event
17
+
18
+ from .data import (
19
+ NapcatData,
20
+ NapcatFriendAddNoticeData,
21
+ NapcatFriendRecallNoticeData,
22
+ NapcatFriendRequestData,
23
+ NapcatGroupAdminNoticeData,
24
+ NapcatGroupBanNoticeData,
25
+ NapcatGroupCardNoticeData,
26
+ NapcatGroupDecreaseNoticeData,
27
+ NapcatGroupEssenceNoticeData,
28
+ NapcatGroupIncreaseNoticeData,
29
+ NapcatGroupMessageData,
30
+ NapcatGroupMessageSentData,
31
+ NapcatGroupMsgEmojiLikeNoticeData,
32
+ NapcatGroupRecallNoticeData,
33
+ NapcatGroupRequestData,
34
+ NapcatGroupUploadNoticeData,
35
+ NapcatHeartbeatMetaData,
36
+ NapcatHonorNotifyData,
37
+ NapcatLifecycleMetaData,
38
+ NapcatLuckyKingNotifyData,
39
+ NapcatMessageData,
40
+ NapcatMessageSentData,
41
+ NapcatMetaData,
42
+ NapcatNoticeData,
43
+ NapcatNotifyData,
44
+ NapcatPokeNotifyData,
45
+ NapcatPrivateMessageData,
46
+ NapcatPrivateMessageSentData,
47
+ NapcatReactionNoticeData,
48
+ NapcatRequestData,
49
+ )
50
+
51
+ # ── 通配 ──
52
+ NapcatEvent: TypeAlias = Event[NapcatData]
53
+
54
+ # ── 消息事件 ──
55
+ NapcatMessageEvent: TypeAlias = Event[NapcatMessageData]
56
+ NapcatPrivateMessageEvent: TypeAlias = Event[NapcatPrivateMessageData]
57
+ NapcatGroupMessageEvent: TypeAlias = Event[NapcatGroupMessageData]
58
+
59
+ # ── 消息发送事件 ──
60
+ NapcatMessageSentEvent: TypeAlias = Event[NapcatMessageSentData]
61
+ NapcatPrivateMessageSentEvent: TypeAlias = Event[NapcatPrivateMessageSentData]
62
+ NapcatGroupMessageSentEvent: TypeAlias = Event[NapcatGroupMessageSentData]
63
+
64
+ # ── 通知事件 ──
65
+ NapcatNoticeEvent: TypeAlias = Event[NapcatNoticeData]
66
+ NapcatGroupUploadNoticeEvent: TypeAlias = Event[NapcatGroupUploadNoticeData]
67
+ NapcatGroupAdminNoticeEvent: TypeAlias = Event[NapcatGroupAdminNoticeData]
68
+ NapcatGroupDecreaseNoticeEvent: TypeAlias = Event[NapcatGroupDecreaseNoticeData]
69
+ NapcatGroupIncreaseNoticeEvent: TypeAlias = Event[NapcatGroupIncreaseNoticeData]
70
+ NapcatGroupBanNoticeEvent: TypeAlias = Event[NapcatGroupBanNoticeData]
71
+ NapcatFriendAddNoticeEvent: TypeAlias = Event[NapcatFriendAddNoticeData]
72
+ NapcatGroupRecallNoticeEvent: TypeAlias = Event[NapcatGroupRecallNoticeData]
73
+ NapcatFriendRecallNoticeEvent: TypeAlias = Event[NapcatFriendRecallNoticeData]
74
+ NapcatNotifyEvent: TypeAlias = Event[NapcatNotifyData]
75
+ NapcatPokeNotifyEvent: TypeAlias = Event[NapcatPokeNotifyData]
76
+ NapcatLuckyKingNotifyEvent: TypeAlias = Event[NapcatLuckyKingNotifyData]
77
+ NapcatHonorNotifyEvent: TypeAlias = Event[NapcatHonorNotifyData]
78
+ NapcatGroupMsgEmojiLikeNoticeEvent: TypeAlias = Event[NapcatGroupMsgEmojiLikeNoticeData]
79
+ NapcatReactionNoticeEvent: TypeAlias = Event[NapcatReactionNoticeData]
80
+ NapcatGroupEssenceNoticeEvent: TypeAlias = Event[NapcatGroupEssenceNoticeData]
81
+ NapcatGroupCardNoticeEvent: TypeAlias = Event[NapcatGroupCardNoticeData]
82
+
83
+ # ── 请求事件 ──
84
+ NapcatRequestEvent: TypeAlias = Event[NapcatRequestData]
85
+ NapcatFriendRequestEvent: TypeAlias = Event[NapcatFriendRequestData]
86
+ NapcatGroupRequestEvent: TypeAlias = Event[NapcatGroupRequestData]
87
+
88
+ # ── 元事件 ──
89
+ NapcatMetaEvent: TypeAlias = Event[NapcatMetaData]
90
+ NapcatLifecycleMetaEvent: TypeAlias = Event[NapcatLifecycleMetaData]
91
+ NapcatHeartbeatMetaEvent: TypeAlias = Event[NapcatHeartbeatMetaData]
@@ -0,0 +1,19 @@
1
+ """Napcat 预置过滤器包."""
2
+
3
+ from .filters import (
4
+ CommandFilter,
5
+ GroupFilter,
6
+ PrefixFilter,
7
+ SenderRoleFilter,
8
+ TextFilter,
9
+ UserFilter,
10
+ )
11
+
12
+ __all__ = [
13
+ "CommandFilter",
14
+ "GroupFilter",
15
+ "PrefixFilter",
16
+ "SenderRoleFilter",
17
+ "TextFilter",
18
+ "UserFilter",
19
+ ]