pyxllib 0.3.197__py3-none-any.whl → 0.3.200__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 (126) hide show
  1. pyxllib/__init__.py +21 -21
  2. pyxllib/algo/__init__.py +8 -8
  3. pyxllib/algo/disjoint.py +54 -54
  4. pyxllib/algo/geo.py +541 -541
  5. pyxllib/algo/intervals.py +964 -964
  6. pyxllib/algo/matcher.py +389 -389
  7. pyxllib/algo/newbie.py +166 -166
  8. pyxllib/algo/pupil.py +629 -629
  9. pyxllib/algo/shapelylib.py +67 -67
  10. pyxllib/algo/specialist.py +241 -241
  11. pyxllib/algo/stat.py +494 -494
  12. pyxllib/algo/treelib.py +149 -149
  13. pyxllib/algo/unitlib.py +66 -66
  14. pyxllib/autogui/__init__.py +5 -5
  15. pyxllib/autogui/activewin.py +246 -246
  16. pyxllib/autogui/all.py +9 -9
  17. pyxllib/autogui/autogui.py +852 -852
  18. pyxllib/autogui/uiautolib.py +362 -362
  19. pyxllib/autogui/virtualkey.py +102 -102
  20. pyxllib/autogui/wechat.py +827 -827
  21. pyxllib/autogui/wechat_msg.py +421 -421
  22. pyxllib/autogui/wxautolib.py +84 -84
  23. pyxllib/cv/__init__.py +5 -5
  24. pyxllib/cv/expert.py +267 -267
  25. pyxllib/cv/imfile.py +159 -159
  26. pyxllib/cv/imhash.py +39 -39
  27. pyxllib/cv/pupil.py +9 -9
  28. pyxllib/cv/rgbfmt.py +1525 -1525
  29. pyxllib/cv/slidercaptcha.py +137 -137
  30. pyxllib/cv/trackbartools.py +251 -251
  31. pyxllib/cv/xlcvlib.py +1040 -1040
  32. pyxllib/cv/xlpillib.py +423 -423
  33. pyxllib/data/echarts.py +240 -240
  34. pyxllib/data/jsonlib.py +89 -89
  35. pyxllib/data/oss.py +72 -72
  36. pyxllib/data/pglib.py +1127 -1127
  37. pyxllib/data/sqlite.py +568 -568
  38. pyxllib/data/sqllib.py +297 -297
  39. pyxllib/ext/JLineViewer.py +505 -505
  40. pyxllib/ext/__init__.py +6 -6
  41. pyxllib/ext/demolib.py +246 -246
  42. pyxllib/ext/drissionlib.py +277 -277
  43. pyxllib/ext/kq5034lib.py +12 -12
  44. pyxllib/ext/old.py +663 -663
  45. pyxllib/ext/qt.py +449 -449
  46. pyxllib/ext/robustprocfile.py +497 -497
  47. pyxllib/ext/seleniumlib.py +76 -76
  48. pyxllib/ext/tk.py +173 -173
  49. pyxllib/ext/unixlib.py +827 -827
  50. pyxllib/ext/utools.py +351 -351
  51. pyxllib/ext/webhook.py +124 -119
  52. pyxllib/ext/win32lib.py +40 -40
  53. pyxllib/ext/wjxlib.py +88 -88
  54. pyxllib/ext/wpsapi.py +124 -124
  55. pyxllib/ext/xlwork.py +9 -9
  56. pyxllib/ext/yuquelib.py +1105 -1105
  57. pyxllib/file/__init__.py +17 -17
  58. pyxllib/file/docxlib.py +761 -761
  59. pyxllib/file/gitlib.py +309 -309
  60. pyxllib/file/libreoffice.py +165 -165
  61. pyxllib/file/movielib.py +148 -148
  62. pyxllib/file/newbie.py +10 -10
  63. pyxllib/file/onenotelib.py +1469 -1469
  64. pyxllib/file/packlib/__init__.py +330 -330
  65. pyxllib/file/packlib/zipfile.py +2441 -2441
  66. pyxllib/file/pdflib.py +426 -426
  67. pyxllib/file/pupil.py +185 -185
  68. pyxllib/file/specialist/__init__.py +685 -685
  69. pyxllib/file/specialist/dirlib.py +799 -799
  70. pyxllib/file/specialist/download.py +193 -193
  71. pyxllib/file/specialist/filelib.py +2829 -2829
  72. pyxllib/file/xlsxlib.py +3131 -3131
  73. pyxllib/file/xlsyncfile.py +341 -341
  74. pyxllib/prog/__init__.py +5 -5
  75. pyxllib/prog/cachetools.py +64 -64
  76. pyxllib/prog/deprecatedlib.py +233 -233
  77. pyxllib/prog/filelock.py +42 -42
  78. pyxllib/prog/ipyexec.py +253 -253
  79. pyxllib/prog/multiprogs.py +940 -940
  80. pyxllib/prog/newbie.py +451 -451
  81. pyxllib/prog/pupil.py +1197 -1197
  82. pyxllib/prog/sitepackages.py +33 -33
  83. pyxllib/prog/specialist/__init__.py +391 -391
  84. pyxllib/prog/specialist/bc.py +203 -203
  85. pyxllib/prog/specialist/browser.py +497 -497
  86. pyxllib/prog/specialist/common.py +347 -347
  87. pyxllib/prog/specialist/datetime.py +198 -198
  88. pyxllib/prog/specialist/tictoc.py +240 -240
  89. pyxllib/prog/specialist/xllog.py +180 -180
  90. pyxllib/prog/xlosenv.py +108 -108
  91. pyxllib/stdlib/__init__.py +17 -17
  92. pyxllib/stdlib/tablepyxl/__init__.py +10 -10
  93. pyxllib/stdlib/tablepyxl/style.py +303 -303
  94. pyxllib/stdlib/tablepyxl/tablepyxl.py +130 -130
  95. pyxllib/text/__init__.py +8 -8
  96. pyxllib/text/ahocorasick.py +39 -39
  97. pyxllib/text/airscript.js +744 -744
  98. pyxllib/text/charclasslib.py +121 -121
  99. pyxllib/text/jiebalib.py +267 -267
  100. pyxllib/text/jinjalib.py +32 -32
  101. pyxllib/text/jsa_ai_prompt.md +271 -271
  102. pyxllib/text/jscode.py +922 -922
  103. pyxllib/text/latex/__init__.py +158 -158
  104. pyxllib/text/levenshtein.py +303 -303
  105. pyxllib/text/nestenv.py +1215 -1215
  106. pyxllib/text/newbie.py +300 -300
  107. pyxllib/text/pupil/__init__.py +8 -8
  108. pyxllib/text/pupil/common.py +1121 -1121
  109. pyxllib/text/pupil/xlalign.py +326 -326
  110. pyxllib/text/pycode.py +47 -47
  111. pyxllib/text/specialist/__init__.py +8 -8
  112. pyxllib/text/specialist/common.py +112 -112
  113. pyxllib/text/specialist/ptag.py +186 -186
  114. pyxllib/text/spellchecker.py +172 -172
  115. pyxllib/text/templates/echart_base.html +10 -10
  116. pyxllib/text/templates/highlight_code.html +16 -16
  117. pyxllib/text/templates/latex_editor.html +102 -102
  118. pyxllib/text/vbacode.py +17 -17
  119. pyxllib/text/xmllib.py +747 -747
  120. pyxllib/xl.py +42 -39
  121. pyxllib/xlcv.py +17 -17
  122. {pyxllib-0.3.197.dist-info → pyxllib-0.3.200.dist-info}/METADATA +1 -1
  123. pyxllib-0.3.200.dist-info/RECORD +126 -0
  124. {pyxllib-0.3.197.dist-info → pyxllib-0.3.200.dist-info}/licenses/LICENSE +190 -190
  125. pyxllib-0.3.197.dist-info/RECORD +0 -126
  126. {pyxllib-0.3.197.dist-info → pyxllib-0.3.200.dist-info}/WHEEL +0 -0
@@ -1,421 +1,421 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- # @Author : 陈坤泽
4
- # @Email : 877362867@qq.com
5
- # @Date : 2024/11/05
6
-
7
- """
8
- 微信 消息框中不同消息结构的解析器 工具
9
-
10
- todo 这个文件很多值可以写成枚举类型更规范?
11
- """
12
-
13
- import re
14
- import json
15
-
16
- # 定义全局字典
17
- msg_parsers = {}
18
-
19
-
20
- # 定义装饰器
21
- def register_tool(key):
22
- def decorator(func):
23
- # 将函数添加到全局字典中,键为传入的key参数
24
- msg_parsers[key] = func
25
- return func
26
-
27
- return decorator
28
-
29
-
30
- def fmt_text(text):
31
- return text.replace('\n', ' ')
32
-
33
-
34
- def parse_time_string(time_str):
35
- """
36
- 解析不同格式的时间字符串为标准的 Python datetime 类型。
37
-
38
- 支持以下格式:
39
- 1. 完整的日期和时间,如 "2024年10月31日 22:03",解析为对应的 datetime 对象。
40
- 2. 仅包含时间的字符串,如 "19:18",会被解析为当天的时间点,日期部分设为当前日期。
41
- 3. 特殊字符串 "以下为新消息",解析为当前时间的 datetime 对象。
42
-
43
- 示例输入:
44
- - "2024年10月31日 22:03"
45
- - "2024年11月1日 20:09"
46
- - "2024年11月1日 21:08"
47
- - "19:18"
48
- - "20:16"
49
- - "以下为新消息"
50
- """
51
- from datetime import datetime
52
-
53
- # 定义当前日期
54
- now = datetime.now()
55
-
56
- # 定义不同的正则表达式模式
57
- full_date_pattern = r"(\d{4})年(\d{1,2})月(\d{1,2})日\s+(\d{1,2}):(\d{2})"
58
- partial_time_pattern = r"^(\d{1,2}):(\d{2})$"
59
- new_message_pattern = r"^以下为新消息$"
60
-
61
- # 解析完整的日期时间
62
- match = re.match(full_date_pattern, time_str)
63
- if match:
64
- year, month, day, hour, minute = map(int, match.groups())
65
- return datetime(year, month, day, hour, minute)
66
-
67
- # 解析只有时间(小时:分钟),默认当天的日期
68
- match = re.match(partial_time_pattern, time_str)
69
- if match:
70
- hour, minute = map(int, match.groups())
71
- return datetime(now.year, now.month, now.day, hour, minute)
72
-
73
- # 解析 "以下为新消息" 为当前时间
74
- if re.match(new_message_pattern, time_str):
75
- return now
76
-
77
- # 如果未匹配到任何模式,返回 None 表示无法解析
78
- return None
79
-
80
-
81
- @register_tool("1b2p3p3b3p")
82
- def 系统_查看更多消息(node):
83
- node.msg_type = 'system'
84
- node.content_type = 'button_more'
85
- node.render_text = f'⚙️: 点击此处可 {node.text}'
86
-
87
-
88
- @register_tool("1l2t")
89
- def 系统_时间标签(node):
90
- node.msg_type = 'system'
91
- node.content_type = 'time'
92
- node.time = parse_time_string(node.text)
93
- node.render_text = f'⚙️: {node.text}'
94
-
95
-
96
- # 刚刚发送的特殊时间标签
97
- @register_tool("1l2p3p3p3t3p3p")
98
- def 系统_时间标签2(node):
99
- node.msg_type = 'system'
100
- node.content_type = 'time'
101
- node.time = parse_time_string(node.text)
102
- node.render_text = f'⚙️: {node.text}'
103
-
104
-
105
- @register_tool("1l2p3p3t3p")
106
- def 系统_撤回消息(node):
107
- node.msg_type = 'system'
108
-
109
- if node.text.endswith('撤回了一条消息'):
110
- node.content_type = 'recall'
111
- if node.text == '你撤回了一条消息':
112
- node.user = node.user2 = '你'
113
- else:
114
- node.user = re.search(r'"(.+)"', node.text).group(1)
115
- node.user2 = node.user
116
- node.render_text = f'⚙️: {node.text}'
117
- elif node.text.endswith('现在可以开始聊天了。'):
118
- node.content_type = 'add_friend'
119
- node.user = re.search(r'你已添加了(.+?),现在可以开始聊天了。', node.text).group(1)
120
- node.user2 = node.user
121
- node.render_text = f'⚙️: {node.text}'
122
- else:
123
- raise ValueError
124
-
125
-
126
- @register_tool("1l2p3p3p4p5p6p7t3b")
127
- def 发送_文本(node):
128
- node.msg_type = 'send'
129
- node.content_type = 'text'
130
- node.user = node[0][2].text
131
- node.render_text = f'↑{node.user}: {fmt_text(node.text)}'
132
-
133
-
134
- @register_tool("1l2p3p3p4p5p6p7p7p8p8b3b")
135
- def 发送_图片(node):
136
- node.msg_type = 'send'
137
- node.content_type = 'image'
138
- node.user = node[0][2].text
139
-
140
-
141
- @register_tool("1l2p3p3p4p5p6p7p7p8p9t9p9b8b3b")
142
- def 发送_视频(node):
143
- node.msg_type = 'send'
144
- node.content_type = 'video'
145
- node.user = node[0][2].text
146
-
147
-
148
- @register_tool("1l2p3p3p4p5p6p7p7p8p9p10p11t6p7p8p9p10p11t7b3b")
149
- def 发送_文本_引用文本(node):
150
- node.msg_type = 'send'
151
- node.content_type = 'text'
152
- node.user = node[0][2].text
153
- quoted_node = node[0][1][0][0] # 引用的层级结构
154
- node.text = quoted_node[0][1][0][0][0][0].text
155
- node.cite_text = quoted_node[1][0][0][0][0][0].text
156
-
157
-
158
- @register_tool("1l2p3p3p4p5p6p7p7p8p9p10p11t6p7p8p9p10p11t11t11p12b7b3b")
159
- def 发送_文本_引用图片(node):
160
- node.msg_type = 'send'
161
- node.content_type = 'text'
162
- node.user = node[0][2].text
163
- quoted_node = node[0][1][0][0]
164
- node.text = quoted_node[0][1][0][0][0][0].text
165
- node.cite_text = f'{quoted_node[1][0][0][0][0][0].text} : [图片]'
166
-
167
-
168
- # 引用文件
169
- @register_tool("1l2p3p3p4p5p6p7p7p8p9p10p11t6p7p8p9p10p11p12t11p12b7b3b")
170
- def 发送_文本_引用文件(node):
171
- node.msg_type = 'send'
172
- node.content_type = 'text'
173
- node.user = node[0][2].text
174
- quoted_node = node[0][1][0][0]
175
- node.text = quoted_node[0][1][0][0][0][0].text
176
- node.cite_text = f'[文件] {quoted_node[1][0][0][0][0][0][0].text}'
177
-
178
-
179
- # 发送文件
180
- @register_tool("1l2p3p3p4p5p6p7p8p9p10t10p11t11t9p10p10p8p9t7b7b3b")
181
- def 发送_文本_引用文件(node):
182
- node.msg_type = 'send'
183
- node.content_type = 'file'
184
- node.user = node[0][2].text
185
- file_node = node[0][1][0][0][0][0]
186
- desc = {
187
- 'name': file_node[0][0][0].text,
188
- 'size': file_node[0][0][1][0].text,
189
- 'platform': file_node[1][0].text
190
- }
191
- node.text = json.dumps(desc, ensure_ascii=False)
192
-
193
-
194
- # 发送链接
195
- @register_tool("1l2p3p3p4p5p6p7p8t8p9t9p9b8p9b9t7b3b")
196
- def 发送_链接(node):
197
- node.msg_type = 'send'
198
- node.content_type = 'link'
199
- node.user = node[0][2].text
200
- link_node = node[0][1][0][0]
201
- desc = {
202
- 'title': link_node[0][0][0].text,
203
- 'head': link_node[0][0][1][0].text,
204
- 'author': link_node[0][0][2][1].text
205
- }
206
- node.text = json.dumps(desc, ensure_ascii=False)
207
-
208
-
209
- # 转发消息
210
- @register_tool("1l2p3p3p4p5p6p7p8t8p9t9t9t8p9p9t7b3b")
211
- def 发送_转发消息(node):
212
- node.msg_type = 'send'
213
- node.content_type = 'messages'
214
- node.user = node[0][2].text
215
-
216
-
217
- @register_tool("1l2p3b3p4p5p6p7t3p")
218
- def 接收_文本(node):
219
- node.msg_type = 'receive'
220
- node.content_type = 'text'
221
- node.user = node[0][0].text
222
- node.render_text = f'↓{node.user}: {fmt_text(node.text)}'
223
-
224
-
225
- @register_tool("1l2p3b3p4p5p6p7p7b3p")
226
- def 接收_图片(node):
227
- node.msg_type = 'receive'
228
- node.content_type = 'image'
229
- node.user = node[0][0].text
230
- node.render_text = f'↓{node.user}: [图片]'
231
-
232
-
233
- @register_tool("1l2p3b3p4p5p6p7p8p9p10t10p11t11t9p10p10p8p9t7b7b3p")
234
- def 接收_文件(node):
235
- node.msg_type = 'receive'
236
- node.content_type = 'file'
237
- node.user = node[0][0].text
238
- node.render_text = f'↓{node.user}: {fmt_text(node.text)}'
239
-
240
-
241
- @register_tool("1l2p3b3p4p5p6p7p8b8p8t7b3p")
242
- def 接收_语音(node):
243
- node.msg_type = 'receive'
244
- node.content_type = 'voice'
245
- node.user = node[0][0].text
246
-
247
-
248
- @register_tool("1l2p3b3p4p5p6p7p8t8p9t9p9b8p9b9t7b3p")
249
- def 接收_链接(node):
250
- node.msg_type = 'receive'
251
- node.content_type = 'link'
252
- node.user = node[0][0].text
253
- link_node = node[0][1][0][0][0][0] # 链接内容的层级结构
254
- desc = {
255
- 'title': link_node[0].text,
256
- 'head': link_node[1][0].text, # 文章开头部分
257
- 'author': link_node[2][1].text
258
- }
259
- node.text = json.dumps(desc, ensure_ascii=False)
260
-
261
-
262
- @register_tool("1l2p3b3p4p5t4p5p6p7t3p")
263
- def 群接收_文本(node):
264
- node.msg_type = 'receive'
265
- node.content_type = 'text'
266
- node.user = node[0][0].text
267
- node.user2 = node[0][1][0][0].text
268
-
269
-
270
- @register_tool("1l2p3b3p4p5t4p5p6p7p7b3p")
271
- def 群接收_图片(node):
272
- node.msg_type = 'receive'
273
- node.content_type = 'image'
274
- node.user = node[0][0].text
275
- node.user2 = node[0][1][0][0].text
276
-
277
-
278
- @register_tool("1l2p3b3p4p5t4p5p6p7p8p9p10t10p11t11t9p10p10p7b7b3p")
279
- def 群接收_文件(node):
280
- node.msg_type = 'receive'
281
- node.content_type = 'file'
282
- node.user = node[0][0].text
283
- file_node = node[0][1] # 文件信息的节点
284
- node.user2 = file_node[0][0].text
285
- file_info_node = file_node[1][0][0][0][0]
286
- desc = {
287
- 'name': file_info_node[0][0].text,
288
- 'size': file_info_node[0][1][0].text
289
- }
290
- node.text = json.dumps(desc, ensure_ascii=False)
291
-
292
-
293
- @register_tool("1l2p3b3p4p5t4p5p6p7p8p9p10t10p11t11t9p10p10p8p9t7b7b3p")
294
- def 群接收_文件2(node):
295
- node.msg_type = 'receive'
296
- node.content_type = 'file'
297
- node.user = node[0][0].text
298
- node.user2 = node[0][1][0][0].text
299
- file_info_node = node[0][1][1][0][0][0]
300
- desc = {
301
- 'name': file_info_node[0][0][0].text,
302
- 'size': file_info_node[0][0][1][0].text,
303
- 'platform': file_info_node[1][0].text
304
- }
305
- node.text = json.dumps(desc, ensure_ascii=False)
306
-
307
-
308
- @register_tool("1l2p3b3p4p5t4p5p6p7b3p")
309
- def 群接收_动画表情(node):
310
- node.msg_type = 'receive'
311
- node.content_type = 'emoji'
312
- node.user = node[0][0].text
313
- node.user2 = node[0][1][0][0].text
314
-
315
-
316
- @register_tool("1l2p3b3p4p5t4p5p6p7p8t8p9t9p9b8p9b9t7b3p")
317
- def 群接收_链接_有公众号作者名(node):
318
- node.msg_type = 'receive'
319
- node.content_type = 'link'
320
- node.user = node[0][0].text
321
- link_node = node[0][1]
322
- node.user2 = link_node[0][0].text
323
- link_info_node = link_node[1][0][0][0]
324
- desc = {
325
- 'title': link_info_node[0].text,
326
- 'head': link_info_node[1][0].text, # 文章开头的一小部分
327
- 'author': link_info_node[2][0].text
328
- }
329
- node.text = json.dumps(desc, ensure_ascii=False)
330
-
331
-
332
- @register_tool("1l2p3b3p4p5t4p5p6p7p8t8p9t9p9b7b3p")
333
- def 群接收_链接_无公众号作者名(node):
334
- node.msg_type = 'receive'
335
- node.content_type = 'link'
336
- node.user = node[0][0].text
337
- link_node = node[0][1]
338
- node.user2 = link_node[0][0].text
339
- link_info_node = link_node[1][0][0][0]
340
- desc = {
341
- 'title': link_info_node[0].text,
342
- 'head': link_info_node[1][0].text # 文章开头的一小部分
343
- }
344
- node.text = json.dumps(desc, ensure_ascii=False)
345
-
346
-
347
- @register_tool("1l2p3b3p4p5t4p5p6p7p8b8p9p8p9p10p10t8p9p7b3p")
348
- def 群接收_视频(node):
349
- node.msg_type = 'receive'
350
- node.content_type = 'video'
351
- node.user = node[0][0].text
352
- video_node = node[0][1]
353
- node.user2 = video_node[0][0].text
354
- video_info_node = video_node[1][0][0][0]
355
- desc = {
356
- 'author': video_info_node[2][0][1].text
357
- }
358
- node.text = json.dumps(desc, ensure_ascii=False)
359
-
360
-
361
- @register_tool("1l2p3b3p4p5t4p5p6p7p8t8p9t8t7b3p")
362
- def 群接收_视频2(node):
363
- node.msg_type = 'receive'
364
- node.content_type = 'video'
365
- node.user = node[0][0].text
366
- video_node = node[0][1]
367
- node.user2 = video_node[0][0].text
368
- video_info_node = video_node[1][0][0][0]
369
- desc = {
370
- 'title': video_info_node[0].text,
371
- 'head': video_info_node[1][0].text,
372
- 'duration': video_info_node[2].text
373
- }
374
- node.text = json.dumps(desc, ensure_ascii=False)
375
-
376
-
377
- @register_tool("1l2p3b3p4p5t4p5p6p7p8p9b9t8t8b8p9t9t7b3p")
378
- def 群接收_小程序(node):
379
- node.msg_type = 'receive'
380
- node.content_type = 'applet'
381
- node.user = node[0][0].text
382
- applet_node = node[0][1]
383
- node.user2 = applet_node[0][0].text
384
- applet_info_node = applet_node[1][0][0][0]
385
- desc = {
386
- 'name': applet_info_node[0][1].text,
387
- 'title': applet_info_node[1].text,
388
- 'footnote': applet_info_node[3][1].text
389
- }
390
- node.text = json.dumps(desc, ensure_ascii=False)
391
-
392
-
393
- @register_tool("1l2p3p3p4p5l6p7p7t7p3p")
394
- def 群接收_拍一拍(node):
395
- node.msg_type = 'receive'
396
- node.content_type = 'shake'
397
- node.text = node[0][1][0][0].text
398
- node.user = re.search(r'"(.+?)" 拍了拍 "', node.text).group(1)
399
-
400
-
401
- @register_tool("1l2p3b3p4p5t4p5p6p7p8t4p5p6p7p8p9t5b3p")
402
- def 群接收_引用消息(node):
403
- node.msg_type = 'receive'
404
- node.content_type = 'text'
405
- node.user = node[0][0].text
406
- quoted_node = node[0][1]
407
- node.user2 = quoted_node[0][0].text
408
- node.text = quoted_node[1][0][0][0][0].text
409
- node.cite_text = quoted_node[2][0][0][0][0][0].text
410
-
411
-
412
- @register_tool("1l2p3b3p4p5t4p5p6p7p8t4p5p6p7p8p9p10t9p10b5b3p")
413
- def 群接收_引用文件(node):
414
- node.msg_type = 'receive'
415
- node.content_type = 'text'
416
- node.user = node[0][0].text
417
- quoted_node = node[0][1]
418
- node.user2 = quoted_node[0][0].text
419
- node.text = quoted_node[1][0][0][0][0].text
420
- file_node = quoted_node[2][0][0][0][0][0][0]
421
- node.cite_text = f'[文件] {file_node.text}'
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # @Author : 陈坤泽
4
+ # @Email : 877362867@qq.com
5
+ # @Date : 2024/11/05
6
+
7
+ """
8
+ 微信 消息框中不同消息结构的解析器 工具
9
+
10
+ todo 这个文件很多值可以写成枚举类型更规范?
11
+ """
12
+
13
+ import re
14
+ import json
15
+
16
+ # 定义全局字典
17
+ msg_parsers = {}
18
+
19
+
20
+ # 定义装饰器
21
+ def register_tool(key):
22
+ def decorator(func):
23
+ # 将函数添加到全局字典中,键为传入的key参数
24
+ msg_parsers[key] = func
25
+ return func
26
+
27
+ return decorator
28
+
29
+
30
+ def fmt_text(text):
31
+ return text.replace('\n', ' ')
32
+
33
+
34
+ def parse_time_string(time_str):
35
+ """
36
+ 解析不同格式的时间字符串为标准的 Python datetime 类型。
37
+
38
+ 支持以下格式:
39
+ 1. 完整的日期和时间,如 "2024年10月31日 22:03",解析为对应的 datetime 对象。
40
+ 2. 仅包含时间的字符串,如 "19:18",会被解析为当天的时间点,日期部分设为当前日期。
41
+ 3. 特殊字符串 "以下为新消息",解析为当前时间的 datetime 对象。
42
+
43
+ 示例输入:
44
+ - "2024年10月31日 22:03"
45
+ - "2024年11月1日 20:09"
46
+ - "2024年11月1日 21:08"
47
+ - "19:18"
48
+ - "20:16"
49
+ - "以下为新消息"
50
+ """
51
+ from datetime import datetime
52
+
53
+ # 定义当前日期
54
+ now = datetime.now()
55
+
56
+ # 定义不同的正则表达式模式
57
+ full_date_pattern = r"(\d{4})年(\d{1,2})月(\d{1,2})日\s+(\d{1,2}):(\d{2})"
58
+ partial_time_pattern = r"^(\d{1,2}):(\d{2})$"
59
+ new_message_pattern = r"^以下为新消息$"
60
+
61
+ # 解析完整的日期时间
62
+ match = re.match(full_date_pattern, time_str)
63
+ if match:
64
+ year, month, day, hour, minute = map(int, match.groups())
65
+ return datetime(year, month, day, hour, minute)
66
+
67
+ # 解析只有时间(小时:分钟),默认当天的日期
68
+ match = re.match(partial_time_pattern, time_str)
69
+ if match:
70
+ hour, minute = map(int, match.groups())
71
+ return datetime(now.year, now.month, now.day, hour, minute)
72
+
73
+ # 解析 "以下为新消息" 为当前时间
74
+ if re.match(new_message_pattern, time_str):
75
+ return now
76
+
77
+ # 如果未匹配到任何模式,返回 None 表示无法解析
78
+ return None
79
+
80
+
81
+ @register_tool("1b2p3p3b3p")
82
+ def 系统_查看更多消息(node):
83
+ node.msg_type = 'system'
84
+ node.content_type = 'button_more'
85
+ node.render_text = f'⚙️: 点击此处可 {node.text}'
86
+
87
+
88
+ @register_tool("1l2t")
89
+ def 系统_时间标签(node):
90
+ node.msg_type = 'system'
91
+ node.content_type = 'time'
92
+ node.time = parse_time_string(node.text)
93
+ node.render_text = f'⚙️: {node.text}'
94
+
95
+
96
+ # 刚刚发送的特殊时间标签
97
+ @register_tool("1l2p3p3p3t3p3p")
98
+ def 系统_时间标签2(node):
99
+ node.msg_type = 'system'
100
+ node.content_type = 'time'
101
+ node.time = parse_time_string(node.text)
102
+ node.render_text = f'⚙️: {node.text}'
103
+
104
+
105
+ @register_tool("1l2p3p3t3p")
106
+ def 系统_撤回消息(node):
107
+ node.msg_type = 'system'
108
+
109
+ if node.text.endswith('撤回了一条消息'):
110
+ node.content_type = 'recall'
111
+ if node.text == '你撤回了一条消息':
112
+ node.user = node.user2 = '你'
113
+ else:
114
+ node.user = re.search(r'"(.+)"', node.text).group(1)
115
+ node.user2 = node.user
116
+ node.render_text = f'⚙️: {node.text}'
117
+ elif node.text.endswith('现在可以开始聊天了。'):
118
+ node.content_type = 'add_friend'
119
+ node.user = re.search(r'你已添加了(.+?),现在可以开始聊天了。', node.text).group(1)
120
+ node.user2 = node.user
121
+ node.render_text = f'⚙️: {node.text}'
122
+ else:
123
+ raise ValueError
124
+
125
+
126
+ @register_tool("1l2p3p3p4p5p6p7t3b")
127
+ def 发送_文本(node):
128
+ node.msg_type = 'send'
129
+ node.content_type = 'text'
130
+ node.user = node[0][2].text
131
+ node.render_text = f'↑{node.user}: {fmt_text(node.text)}'
132
+
133
+
134
+ @register_tool("1l2p3p3p4p5p6p7p7p8p8b3b")
135
+ def 发送_图片(node):
136
+ node.msg_type = 'send'
137
+ node.content_type = 'image'
138
+ node.user = node[0][2].text
139
+
140
+
141
+ @register_tool("1l2p3p3p4p5p6p7p7p8p9t9p9b8b3b")
142
+ def 发送_视频(node):
143
+ node.msg_type = 'send'
144
+ node.content_type = 'video'
145
+ node.user = node[0][2].text
146
+
147
+
148
+ @register_tool("1l2p3p3p4p5p6p7p7p8p9p10p11t6p7p8p9p10p11t7b3b")
149
+ def 发送_文本_引用文本(node):
150
+ node.msg_type = 'send'
151
+ node.content_type = 'text'
152
+ node.user = node[0][2].text
153
+ quoted_node = node[0][1][0][0] # 引用的层级结构
154
+ node.text = quoted_node[0][1][0][0][0][0].text
155
+ node.cite_text = quoted_node[1][0][0][0][0][0].text
156
+
157
+
158
+ @register_tool("1l2p3p3p4p5p6p7p7p8p9p10p11t6p7p8p9p10p11t11t11p12b7b3b")
159
+ def 发送_文本_引用图片(node):
160
+ node.msg_type = 'send'
161
+ node.content_type = 'text'
162
+ node.user = node[0][2].text
163
+ quoted_node = node[0][1][0][0]
164
+ node.text = quoted_node[0][1][0][0][0][0].text
165
+ node.cite_text = f'{quoted_node[1][0][0][0][0][0].text} : [图片]'
166
+
167
+
168
+ # 引用文件
169
+ @register_tool("1l2p3p3p4p5p6p7p7p8p9p10p11t6p7p8p9p10p11p12t11p12b7b3b")
170
+ def 发送_文本_引用文件(node):
171
+ node.msg_type = 'send'
172
+ node.content_type = 'text'
173
+ node.user = node[0][2].text
174
+ quoted_node = node[0][1][0][0]
175
+ node.text = quoted_node[0][1][0][0][0][0].text
176
+ node.cite_text = f'[文件] {quoted_node[1][0][0][0][0][0][0].text}'
177
+
178
+
179
+ # 发送文件
180
+ @register_tool("1l2p3p3p4p5p6p7p8p9p10t10p11t11t9p10p10p8p9t7b7b3b")
181
+ def 发送_文本_引用文件(node):
182
+ node.msg_type = 'send'
183
+ node.content_type = 'file'
184
+ node.user = node[0][2].text
185
+ file_node = node[0][1][0][0][0][0]
186
+ desc = {
187
+ 'name': file_node[0][0][0].text,
188
+ 'size': file_node[0][0][1][0].text,
189
+ 'platform': file_node[1][0].text
190
+ }
191
+ node.text = json.dumps(desc, ensure_ascii=False)
192
+
193
+
194
+ # 发送链接
195
+ @register_tool("1l2p3p3p4p5p6p7p8t8p9t9p9b8p9b9t7b3b")
196
+ def 发送_链接(node):
197
+ node.msg_type = 'send'
198
+ node.content_type = 'link'
199
+ node.user = node[0][2].text
200
+ link_node = node[0][1][0][0]
201
+ desc = {
202
+ 'title': link_node[0][0][0].text,
203
+ 'head': link_node[0][0][1][0].text,
204
+ 'author': link_node[0][0][2][1].text
205
+ }
206
+ node.text = json.dumps(desc, ensure_ascii=False)
207
+
208
+
209
+ # 转发消息
210
+ @register_tool("1l2p3p3p4p5p6p7p8t8p9t9t9t8p9p9t7b3b")
211
+ def 发送_转发消息(node):
212
+ node.msg_type = 'send'
213
+ node.content_type = 'messages'
214
+ node.user = node[0][2].text
215
+
216
+
217
+ @register_tool("1l2p3b3p4p5p6p7t3p")
218
+ def 接收_文本(node):
219
+ node.msg_type = 'receive'
220
+ node.content_type = 'text'
221
+ node.user = node[0][0].text
222
+ node.render_text = f'↓{node.user}: {fmt_text(node.text)}'
223
+
224
+
225
+ @register_tool("1l2p3b3p4p5p6p7p7b3p")
226
+ def 接收_图片(node):
227
+ node.msg_type = 'receive'
228
+ node.content_type = 'image'
229
+ node.user = node[0][0].text
230
+ node.render_text = f'↓{node.user}: [图片]'
231
+
232
+
233
+ @register_tool("1l2p3b3p4p5p6p7p8p9p10t10p11t11t9p10p10p8p9t7b7b3p")
234
+ def 接收_文件(node):
235
+ node.msg_type = 'receive'
236
+ node.content_type = 'file'
237
+ node.user = node[0][0].text
238
+ node.render_text = f'↓{node.user}: {fmt_text(node.text)}'
239
+
240
+
241
+ @register_tool("1l2p3b3p4p5p6p7p8b8p8t7b3p")
242
+ def 接收_语音(node):
243
+ node.msg_type = 'receive'
244
+ node.content_type = 'voice'
245
+ node.user = node[0][0].text
246
+
247
+
248
+ @register_tool("1l2p3b3p4p5p6p7p8t8p9t9p9b8p9b9t7b3p")
249
+ def 接收_链接(node):
250
+ node.msg_type = 'receive'
251
+ node.content_type = 'link'
252
+ node.user = node[0][0].text
253
+ link_node = node[0][1][0][0][0][0] # 链接内容的层级结构
254
+ desc = {
255
+ 'title': link_node[0].text,
256
+ 'head': link_node[1][0].text, # 文章开头部分
257
+ 'author': link_node[2][1].text
258
+ }
259
+ node.text = json.dumps(desc, ensure_ascii=False)
260
+
261
+
262
+ @register_tool("1l2p3b3p4p5t4p5p6p7t3p")
263
+ def 群接收_文本(node):
264
+ node.msg_type = 'receive'
265
+ node.content_type = 'text'
266
+ node.user = node[0][0].text
267
+ node.user2 = node[0][1][0][0].text
268
+
269
+
270
+ @register_tool("1l2p3b3p4p5t4p5p6p7p7b3p")
271
+ def 群接收_图片(node):
272
+ node.msg_type = 'receive'
273
+ node.content_type = 'image'
274
+ node.user = node[0][0].text
275
+ node.user2 = node[0][1][0][0].text
276
+
277
+
278
+ @register_tool("1l2p3b3p4p5t4p5p6p7p8p9p10t10p11t11t9p10p10p7b7b3p")
279
+ def 群接收_文件(node):
280
+ node.msg_type = 'receive'
281
+ node.content_type = 'file'
282
+ node.user = node[0][0].text
283
+ file_node = node[0][1] # 文件信息的节点
284
+ node.user2 = file_node[0][0].text
285
+ file_info_node = file_node[1][0][0][0][0]
286
+ desc = {
287
+ 'name': file_info_node[0][0].text,
288
+ 'size': file_info_node[0][1][0].text
289
+ }
290
+ node.text = json.dumps(desc, ensure_ascii=False)
291
+
292
+
293
+ @register_tool("1l2p3b3p4p5t4p5p6p7p8p9p10t10p11t11t9p10p10p8p9t7b7b3p")
294
+ def 群接收_文件2(node):
295
+ node.msg_type = 'receive'
296
+ node.content_type = 'file'
297
+ node.user = node[0][0].text
298
+ node.user2 = node[0][1][0][0].text
299
+ file_info_node = node[0][1][1][0][0][0]
300
+ desc = {
301
+ 'name': file_info_node[0][0][0].text,
302
+ 'size': file_info_node[0][0][1][0].text,
303
+ 'platform': file_info_node[1][0].text
304
+ }
305
+ node.text = json.dumps(desc, ensure_ascii=False)
306
+
307
+
308
+ @register_tool("1l2p3b3p4p5t4p5p6p7b3p")
309
+ def 群接收_动画表情(node):
310
+ node.msg_type = 'receive'
311
+ node.content_type = 'emoji'
312
+ node.user = node[0][0].text
313
+ node.user2 = node[0][1][0][0].text
314
+
315
+
316
+ @register_tool("1l2p3b3p4p5t4p5p6p7p8t8p9t9p9b8p9b9t7b3p")
317
+ def 群接收_链接_有公众号作者名(node):
318
+ node.msg_type = 'receive'
319
+ node.content_type = 'link'
320
+ node.user = node[0][0].text
321
+ link_node = node[0][1]
322
+ node.user2 = link_node[0][0].text
323
+ link_info_node = link_node[1][0][0][0]
324
+ desc = {
325
+ 'title': link_info_node[0].text,
326
+ 'head': link_info_node[1][0].text, # 文章开头的一小部分
327
+ 'author': link_info_node[2][0].text
328
+ }
329
+ node.text = json.dumps(desc, ensure_ascii=False)
330
+
331
+
332
+ @register_tool("1l2p3b3p4p5t4p5p6p7p8t8p9t9p9b7b3p")
333
+ def 群接收_链接_无公众号作者名(node):
334
+ node.msg_type = 'receive'
335
+ node.content_type = 'link'
336
+ node.user = node[0][0].text
337
+ link_node = node[0][1]
338
+ node.user2 = link_node[0][0].text
339
+ link_info_node = link_node[1][0][0][0]
340
+ desc = {
341
+ 'title': link_info_node[0].text,
342
+ 'head': link_info_node[1][0].text # 文章开头的一小部分
343
+ }
344
+ node.text = json.dumps(desc, ensure_ascii=False)
345
+
346
+
347
+ @register_tool("1l2p3b3p4p5t4p5p6p7p8b8p9p8p9p10p10t8p9p7b3p")
348
+ def 群接收_视频(node):
349
+ node.msg_type = 'receive'
350
+ node.content_type = 'video'
351
+ node.user = node[0][0].text
352
+ video_node = node[0][1]
353
+ node.user2 = video_node[0][0].text
354
+ video_info_node = video_node[1][0][0][0]
355
+ desc = {
356
+ 'author': video_info_node[2][0][1].text
357
+ }
358
+ node.text = json.dumps(desc, ensure_ascii=False)
359
+
360
+
361
+ @register_tool("1l2p3b3p4p5t4p5p6p7p8t8p9t8t7b3p")
362
+ def 群接收_视频2(node):
363
+ node.msg_type = 'receive'
364
+ node.content_type = 'video'
365
+ node.user = node[0][0].text
366
+ video_node = node[0][1]
367
+ node.user2 = video_node[0][0].text
368
+ video_info_node = video_node[1][0][0][0]
369
+ desc = {
370
+ 'title': video_info_node[0].text,
371
+ 'head': video_info_node[1][0].text,
372
+ 'duration': video_info_node[2].text
373
+ }
374
+ node.text = json.dumps(desc, ensure_ascii=False)
375
+
376
+
377
+ @register_tool("1l2p3b3p4p5t4p5p6p7p8p9b9t8t8b8p9t9t7b3p")
378
+ def 群接收_小程序(node):
379
+ node.msg_type = 'receive'
380
+ node.content_type = 'applet'
381
+ node.user = node[0][0].text
382
+ applet_node = node[0][1]
383
+ node.user2 = applet_node[0][0].text
384
+ applet_info_node = applet_node[1][0][0][0]
385
+ desc = {
386
+ 'name': applet_info_node[0][1].text,
387
+ 'title': applet_info_node[1].text,
388
+ 'footnote': applet_info_node[3][1].text
389
+ }
390
+ node.text = json.dumps(desc, ensure_ascii=False)
391
+
392
+
393
+ @register_tool("1l2p3p3p4p5l6p7p7t7p3p")
394
+ def 群接收_拍一拍(node):
395
+ node.msg_type = 'receive'
396
+ node.content_type = 'shake'
397
+ node.text = node[0][1][0][0].text
398
+ node.user = re.search(r'"(.+?)" 拍了拍 "', node.text).group(1)
399
+
400
+
401
+ @register_tool("1l2p3b3p4p5t4p5p6p7p8t4p5p6p7p8p9t5b3p")
402
+ def 群接收_引用消息(node):
403
+ node.msg_type = 'receive'
404
+ node.content_type = 'text'
405
+ node.user = node[0][0].text
406
+ quoted_node = node[0][1]
407
+ node.user2 = quoted_node[0][0].text
408
+ node.text = quoted_node[1][0][0][0][0].text
409
+ node.cite_text = quoted_node[2][0][0][0][0][0].text
410
+
411
+
412
+ @register_tool("1l2p3b3p4p5t4p5p6p7p8t4p5p6p7p8p9p10t9p10b5b3p")
413
+ def 群接收_引用文件(node):
414
+ node.msg_type = 'receive'
415
+ node.content_type = 'text'
416
+ node.user = node[0][0].text
417
+ quoted_node = node[0][1]
418
+ node.user2 = quoted_node[0][0].text
419
+ node.text = quoted_node[1][0][0][0][0].text
420
+ file_node = quoted_node[2][0][0][0][0][0][0]
421
+ node.cite_text = f'[文件] {file_node.text}'