只用表情 XML 里的 md5 + len/totallen 作为发送参数。

不再用图片文件大小、文件名等回退逻辑去“猜参数”。
发送接口不再“先返回发送中”,而是直接调用 SendEmoji 并等待结果:
成功才返回 表情发送成功
失败直接返回具体错误(不会再假成功)
This commit is contained in:
liuwei
2026-04-15 11:36:22 +08:00
parent d0fa823557
commit ee5c1ebadc
4 changed files with 55 additions and 30 deletions
+24 -27
View File
@@ -148,27 +148,24 @@ def _extract_emoji_meta(attachment_url: str, image_path: str):
md5 = ""
total_length = 0
# 优先按 XML 结构解析,避免纯正则误命中其他字段
if text.startswith("<"):
try:
root = ET.fromstring(text)
emoji_node = root.find(".//emoji")
if emoji_node is not None:
md5 = _safe_text(emoji_node.attrib.get("md5", "")).strip().lower()
for key in ("totallen", "total_len", "totalLen", "len"):
value = _safe_text(emoji_node.attrib.get(key, "")).strip()
if value.isdigit():
total_length = int(value)
break
except Exception:
pass
if not md5:
# 只接受 XML 中的参数,不做文件名或文件大小回退,避免参数污染
if not text.startswith("<"):
return "", 0
try:
root = ET.fromstring(text)
emoji_node = root.find(".//emoji")
if emoji_node is None:
return "", 0
md5 = _safe_text(emoji_node.attrib.get("md5", "")).strip().lower()
for key in ("totallen", "total_len", "totalLen", "len"):
value = _safe_text(emoji_node.attrib.get(key, "")).strip()
if value.isdigit():
total_length = int(value)
break
except Exception:
md5_match = _EMOJI_MD5_RE.search(text)
if md5_match:
md5 = md5_match.group(1).lower()
if total_length <= 0:
len_match = _EMOJI_TOTALLEN_RE.search(text)
if len_match:
try:
@@ -176,12 +173,6 @@ def _extract_emoji_meta(attachment_url: str, image_path: str):
except Exception:
total_length = 0
if not md5 and image_path:
filename = os.path.basename(_safe_text(image_path))
stem = os.path.splitext(filename)[0]
if re.fullmatch(r"[0-9a-fA-F]{16,64}", stem):
md5 = stem.lower()
return md5, total_length
@@ -684,12 +675,18 @@ def api_send_message():
return jsonify({'success': False, 'message': '表情参数格式错误'})
md5 = _safe_text(content.get('md5')).strip().lower()
total_length = int(content.get('total_length') or 0)
if not md5 or total_length <= 0:
if not re.fullmatch(r"[0-9a-f]{16,64}", md5) or total_length <= 0:
return jsonify({'success': False, 'message': '缺少表情 md5 或长度'})
send_message_in_thread(server.client.send_emoji_message, wxid, md5, total_length)
try:
loop = get_or_create_loop()
future = asyncio.run_coroutine_threadsafe(server.client.send_emoji_message(wxid, md5, total_length), loop)
future.result(timeout=20)
except Exception as e:
logger.error(f"发送表情失败 md5={md5} len={total_length} wxid={wxid}: {e}")
return jsonify({'success': False, 'message': f'表情发送失败: {str(e)}'}), 500
return jsonify({
'success': True,
'message': '消息发送中'
'message': '表情发送成功'
})
else: