Skip to content

Commit 5ee5d70

Browse files
authored
Merge pull request #73 from MuRainBot/dev
合并Dev: 修复 CommandManager 中的命令匹配逻辑,优化QQRichText解析流程
2 parents b3fa3b2 + 9c8128b commit 5ee5d70

File tree

3 files changed

+66
-62
lines changed

3 files changed

+66
-62
lines changed

murainbot/utils/CommandManager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -831,7 +831,7 @@ def match(self, event_data: CommandEvent, rules_kwargs: dict):
831831
else:
832832
priority, rules, handler, args, kwargs, handler_command_def = handler
833833

834-
if command_def and handler_command_def != command_def:
834+
if command_def and handler_command_def != command_def and handler_command_def:
835835
continue
836836

837837
try:

murainbot/utils/QQRichText.py

Lines changed: 64 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import inspect
77
import json
88
import os
9+
from typing import Generator
910
from urllib.parse import urlparse
1011

1112
from murainbot.common import save_exc_dump
@@ -1125,6 +1126,43 @@ def get_json(self):
11251126
return json.loads(self.json_data)
11261127

11271128

1129+
def _create_segment_from_dict(segment_dict: dict) -> Segment:
1130+
"""从单个字典(array格式)创建Segment对象"""
1131+
# 这个辅助函数和你代码中的对象化逻辑是一样的
1132+
segment_type = segment_dict.get("type")
1133+
if segment_type in segments_map:
1134+
try:
1135+
params = inspect.signature(segments_map[segment_type]).parameters
1136+
kwargs = {}
1137+
data = segment_dict.get("data", {})
1138+
for param in params:
1139+
if param in data:
1140+
kwargs[param] = data[param]
1141+
elif param == "id_":
1142+
kwargs[param] = data.get("id")
1143+
elif param == "type_":
1144+
kwargs[param] = data.get("type")
1145+
elif params[param].default != params[param].empty:
1146+
kwargs[param] = params[param].default
1147+
1148+
segment = segments_map[segment_type](**kwargs)
1149+
1150+
for k, v in data.items():
1151+
if k not in segment.data:
1152+
segment.set_data(k, v)
1153+
return segment
1154+
except Exception as e:
1155+
if ConfigManager.GlobalConfig().debug.save_dump:
1156+
dump_path = save_exc_dump(f"转换{segment_dict}时失败")
1157+
else:
1158+
dump_path = None
1159+
Logger.get_logger().warning(f"转换{segment_dict}时失败,报错信息: {repr(e)}"
1160+
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}",
1161+
exc_info=True)
1162+
return Segment(segment_dict)
1163+
return Segment(segment_dict)
1164+
1165+
11281166
class QQRichText:
11291167
"""
11301168
QQ富文本
@@ -1139,70 +1177,36 @@ def __init__(
11391177
Args:
11401178
*rich: 富文本内容,可为 str、dict、list、tuple、Segment、QQRichText
11411179
"""
1180+
# __init__ 现在只做一件事:消费一个生成器来构建最终的列表
1181+
self.rich_array: list[Segment] = list(self._iter_and_convert_segments(rich))
11421182

1143-
# 特判
1144-
self.rich_array: list[Segment] = []
1145-
1146-
if len(rich) == 1 and isinstance(rich[0], (list, tuple)):
1147-
rich = rich[0]
1148-
1149-
# 识别输入的是CQCode or json形式的富文本
1150-
# 如果输入的是CQCode,则转换为json形式的富文本
1183+
def _iter_and_convert_segments(self, rich_items) -> Generator[Segment, None, None]:
1184+
"""
1185+
核心优化:单遍处理所有输入,并直接 yield 最终的 Segment 对象。
1186+
这完美实现了你“合并处理”的想法。
1187+
"""
1188+
# 1. 扁平化初始输入
1189+
if len(rich_items) == 1 and isinstance(rich_items[0], (list, tuple)):
1190+
rich_items = rich_items[0]
11511191

1152-
# 处理CQCode
1153-
array = []
1154-
for item in rich:
1155-
if isinstance(item, dict):
1156-
array.append(item)
1157-
elif isinstance(item, str):
1158-
array += cq_2_array(item)
1192+
# 2. 单遍处理所有项目
1193+
for item in rich_items:
1194+
# 分类处理,直接生成并yield Segment对象
1195+
if any(isinstance(item, segment) for segment in segments) and not isinstance(item, Segment):
1196+
yield item
1197+
elif isinstance(item, Segment):
1198+
yield _create_segment_from_dict(item.array)
11591199
elif isinstance(item, QQRichText):
1160-
array += item.rich_array
1161-
else:
1162-
for segment in segments:
1163-
if isinstance(item, segment):
1164-
array.append(item.array)
1165-
break
1166-
else:
1167-
raise TypeError("QQRichText: 输入类型错误")
1168-
rich = array
1169-
1170-
# 将rich转换为的Segment
1171-
for i in range(len(rich)):
1172-
if rich[i]["type"] in segments_map:
1173-
try:
1174-
params = inspect.signature(segments_map[rich[i]["type"]]).parameters
1175-
kwargs = {}
1176-
for param in params:
1177-
if param in rich[i]["data"]:
1178-
kwargs[param] = rich[i]["data"][param]
1179-
else:
1180-
if param == "id_":
1181-
kwargs[param] = rich[i]["data"].get("id")
1182-
elif param == "type_":
1183-
kwargs[param] = rich[i]["data"].get("type")
1184-
else:
1185-
if params[param].default != params[param].empty:
1186-
kwargs[param] = params[param].default
1187-
segment = segments_map[rich[i]["type"]](**kwargs)
1188-
# 检查原cq中是否含有不在segment的data中的参数
1189-
for k, v in rich[i]["data"].items():
1190-
if k not in segment["data"]:
1191-
segment.set_data(k, v)
1192-
rich[i] = segment
1193-
except Exception as e:
1194-
if ConfigManager.GlobalConfig().debug.save_dump:
1195-
dump_path = save_exc_dump(f"转换{rich[i]}时失败")
1196-
else:
1197-
dump_path = None
1198-
Logger.get_logger().warning(f"转换{rich[i]}时失败,报错信息: {repr(e)}"
1199-
f"{f"\n已保存异常到 {dump_path}" if dump_path else ""}",
1200-
exc_info=True)
1201-
rich[i] = Segment(rich[i])
1200+
yield from item.rich_array
1201+
elif isinstance(item, str):
1202+
for arr in cq_2_array(item):
1203+
yield _create_segment_from_dict(arr)
1204+
elif isinstance(item, dict):
1205+
yield _create_segment_from_dict(item)
1206+
elif isinstance(item, (list, tuple)):
1207+
yield from self._iter_and_convert_segments(item)
12021208
else:
1203-
rich[i] = Segment(rich[i])
1204-
1205-
self.rich_array: list[Segment] = rich
1209+
raise TypeError(f"QQRichText: 不支持的输入类型 {type(item)}")
12061210

12071211
def render(self, group_id: int | None = None):
12081212
"""

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "murainbot"
7-
version = "0.1.1"
7+
version = "0.1.2"
88
authors = [
99
{ name="Xiaosu", email="xiaosu@xiaosu.icu" },
1010
]

0 commit comments

Comments
 (0)