新增小红书、XMPP、元宝、Zalo 四个渠道扩展。 小红书渠道扩展主要模块:config, gateway, webhook, outbound, streaming, pairing, security, dedupe, media, status, window XMPP 渠道扩展主要模块:plugin, config, gateway, outbound, streaming, pairing, security, dedupe, accounts, commands, muc, rate_limiter, stanza_utils, status, monitor 元宝渠道扩展主要模块:plugin, client, config_schema, gateway, outbound(chunk/queue/transport), inbound(dispatcher), streaming, pairing, security, accounts, actions, commands, codec(biz/conn), session, shared, utils Zalo 渠道扩展主要模块:api, config, gateway, webhook, outbound, pairing, security, session, polling, monitor, status
107 lines
3.4 KiB
Python
107 lines
3.4 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
from datetime import datetime, UTC
|
|
|
|
from yuxi.channel.extensions.zalo.types import ZaloAccount, ZaloMessage
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def parse_update_to_unified(update: dict, account: ZaloAccount | dict) -> dict | None:
|
|
event_name = update.get("event_name", "")
|
|
message = update.get("message", {})
|
|
if not message:
|
|
logger.debug("Zalo update without message field, skipping")
|
|
return None
|
|
|
|
sender = message.get("from", {})
|
|
if sender.get("is_bot"):
|
|
logger.debug("Zalo skipping bot message from %s", sender.get("id"))
|
|
return None
|
|
|
|
chat = message.get("chat", {})
|
|
|
|
zm = ZaloMessage(
|
|
event_name=event_name,
|
|
message_id=message.get("message_id", ""),
|
|
from_id=sender.get("id", ""),
|
|
from_name=sender.get("name", ""),
|
|
from_display_name=sender.get("display_name", sender.get("name", "")),
|
|
from_avatar=sender.get("avatar", ""),
|
|
chat_id=chat.get("id", ""),
|
|
chat_type=chat.get("chat_type", "PRIVATE"),
|
|
date=message.get("date", 0),
|
|
text=message.get("text", ""),
|
|
photo_url=message.get("photo", ""),
|
|
caption=message.get("caption", ""),
|
|
)
|
|
|
|
return _build_unified_message(zm, account, message)
|
|
|
|
|
|
def parse_updates_to_unified(updates: list[dict], account: ZaloAccount | dict) -> list[dict]:
|
|
results = []
|
|
for update in updates:
|
|
unified = parse_update_to_unified(update, account)
|
|
if unified:
|
|
results.append(unified)
|
|
return results
|
|
|
|
|
|
def _build_unified_message(zm: ZaloMessage, account: ZaloAccount | dict, message: dict) -> dict | None:
|
|
account_id = account.get("account_id", "default") if isinstance(account, dict) else account.account_id
|
|
|
|
event_name = zm.event_name
|
|
if event_name == "message.text.received":
|
|
message_type = "TEXT"
|
|
content = zm.text
|
|
elif event_name == "message.image.received":
|
|
message_type = "IMAGE"
|
|
content = zm.caption or "[图片]"
|
|
elif event_name == "message.sticker.received":
|
|
message_type = "STICKER"
|
|
sticker_id = message.get("sticker", "")
|
|
content = f"[贴纸 {sticker_id}]"
|
|
elif event_name == "message.unsupported.received":
|
|
logger.debug("Zalo unsupported message received, skipping")
|
|
return None
|
|
else:
|
|
logger.debug("Zalo unknown event: %s, skipping", event_name)
|
|
return None
|
|
|
|
is_group = zm.chat_type == "GROUP"
|
|
timestamp = None
|
|
if zm.date:
|
|
timestamp = datetime.fromtimestamp(zm.date, tz=UTC)
|
|
|
|
media_urls = [zm.photo_url] if zm.photo_url else []
|
|
if message_type == "STICKER":
|
|
sticker_url = message.get("url", "")
|
|
if sticker_url:
|
|
media_urls.append(sticker_url)
|
|
|
|
return {
|
|
"msg_id": zm.message_id,
|
|
"channel_type": "zalo",
|
|
"account_id": account_id,
|
|
"content": content,
|
|
"message_type": message_type,
|
|
"media_urls": media_urls,
|
|
"sender": {
|
|
"id": zm.from_id,
|
|
"display_name": zm.from_display_name or zm.from_name,
|
|
"kind": "GROUP" if is_group else "DIRECT",
|
|
},
|
|
"group": {"id": zm.chat_id} if is_group else None,
|
|
"timestamp": timestamp,
|
|
"mentioned_ids": [],
|
|
"reply_to_id": None,
|
|
"raw_payload": {
|
|
"event_name": event_name,
|
|
"text": zm.text,
|
|
"photo_url": zm.photo_url,
|
|
"caption": zm.caption,
|
|
},
|
|
}
|