feat: 新增跨平台消息互通插件及适配器优化
refactor(discord_adapter): 优化音频处理与心跳机制 feat(plugins/discord-cross): 实现QQ与Discord消息互通功能 fix(events/base): 添加platform字段到基础事件模型
This commit is contained in:
165
plugins/discord-cross/sender.py
Normal file
165
plugins/discord-cross/sender.py
Normal file
@@ -0,0 +1,165 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
跨平台消息互通插件发送器模块
|
||||
"""
|
||||
import json
|
||||
from typing import List
|
||||
from core.utils.logger import logger
|
||||
from core.managers.redis_manager import redis_manager
|
||||
from .config import config
|
||||
from .translator import translate_with_deepseek
|
||||
from .parser import format_discord_to_qq_content, format_qq_to_discord_content
|
||||
|
||||
async def send_to_discord(channel_id: int, content: str, attachments: List[dict] = None, embed: dict = None):
|
||||
"""发送消息到 Discord 频道"""
|
||||
try:
|
||||
publish_data = {
|
||||
"type": "send_message",
|
||||
"channel_id": channel_id,
|
||||
"content": content,
|
||||
"attachments": attachments or [],
|
||||
"embed": embed
|
||||
}
|
||||
await redis_manager.redis.publish("neobot_discord_send", json.dumps(publish_data))
|
||||
logger.info(f"[CrossPlatform] 消息已发布到 Redis 供 Discord 适配器发送: {channel_id}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[CrossPlatform] 发送消息到 Discord 失败: {e}")
|
||||
|
||||
async def send_to_qq(group_id: int, content: str, attachments: List[dict] = None):
|
||||
"""发送消息到 QQ 群"""
|
||||
try:
|
||||
from core.managers.bot_manager import bot_manager
|
||||
from models.message import MessageSegment
|
||||
|
||||
all_bots = bot_manager.get_all_bots()
|
||||
|
||||
if not all_bots:
|
||||
logger.error(f"[CrossPlatform] 没有可用的 QQ 机器人实例")
|
||||
return
|
||||
|
||||
logger.debug(f"[CrossPlatform] 找到 {len(all_bots)} 个 QQ 机器人实例")
|
||||
|
||||
for bot in all_bots:
|
||||
try:
|
||||
message = content
|
||||
|
||||
if attachments:
|
||||
full_message = []
|
||||
if content:
|
||||
full_message.append(MessageSegment.text(content))
|
||||
for attachment in attachments:
|
||||
if isinstance(attachment, dict):
|
||||
att_type = attachment.get("type", "image")
|
||||
attachment_url = attachment.get("url", "")
|
||||
|
||||
if att_type == "image":
|
||||
full_message.append(MessageSegment.image(attachment_url, cache=True, proxy=True, timeout=30))
|
||||
elif att_type == "record":
|
||||
full_message.append(MessageSegment.record(attachment_url, cache=True, proxy=True, timeout=30))
|
||||
elif att_type == "video":
|
||||
full_message.append(MessageSegment.video(attachment_url))
|
||||
else:
|
||||
attachment_url = str(attachment)
|
||||
if attachment_url.lower().endswith(('.mp4', '.avi', '.mkv', '.mov', '.flv', '.wmv')):
|
||||
full_message.append(MessageSegment.video(attachment_url))
|
||||
elif attachment_url.lower().endswith(('.amr', '.silk', '.mp3', '.wav', '.ogg', '.m4a')):
|
||||
full_message.append(MessageSegment.record(attachment_url, cache=True, proxy=True, timeout=30))
|
||||
else:
|
||||
full_message.append(MessageSegment.image(attachment_url, cache=True, proxy=True, timeout=30))
|
||||
|
||||
logger.debug(f"[CrossPlatform] 准备发送消息到 QQ 群 {group_id}: {full_message}")
|
||||
await bot.send_group_msg(group_id, full_message)
|
||||
logger.info(f"[CrossPlatform] 消息已发送到 QQ 群 {group_id}")
|
||||
else:
|
||||
await bot.send_group_msg(group_id, message)
|
||||
logger.info(f"[CrossPlatform] 消息已发送到 QQ 群 {group_id}")
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"[CrossPlatform] 发送消息到 QQ 群 {group_id} 失败: {e}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[CrossPlatform] 发送消息到 QQ 失败: {e}")
|
||||
|
||||
async def forward_discord_to_qq(
|
||||
discord_username: str,
|
||||
discord_discriminator: str,
|
||||
content: str,
|
||||
channel_id: int,
|
||||
attachments: List[dict] = None
|
||||
):
|
||||
"""将 Discord 消息转发到所有映射的 QQ 群"""
|
||||
if channel_id not in config.CROSS_PLATFORM_MAP:
|
||||
logger.warning(f"[CrossPlatform] 未找到 Discord 频道 {channel_id} 的映射配置")
|
||||
return
|
||||
|
||||
group_info = config.CROSS_PLATFORM_MAP[channel_id]
|
||||
target_qq_group = group_info["qq_group_id"]
|
||||
|
||||
formatted_content, image_list = await format_discord_to_qq_content(
|
||||
discord_username,
|
||||
discord_discriminator,
|
||||
content,
|
||||
channel_id,
|
||||
attachments
|
||||
)
|
||||
|
||||
if formatted_content:
|
||||
translated_content = await translate_with_deepseek(formatted_content, "zh-CN", channel_id, "en2zh")
|
||||
if translated_content != formatted_content:
|
||||
formatted_content = f"{formatted_content}\n\n━━━━━ 翻译 ━━━━━\n{translated_content}"
|
||||
|
||||
await send_to_qq(target_qq_group, formatted_content, image_list)
|
||||
logger.success(f"[CrossPlatform] Discord 频道 {channel_id} -> QQ 群 {target_qq_group}")
|
||||
|
||||
async def forward_qq_to_discord(
|
||||
qq_nickname: str,
|
||||
qq_user_id: int,
|
||||
group_name: str,
|
||||
group_id: int,
|
||||
content: str,
|
||||
attachments: List[dict] = None
|
||||
):
|
||||
"""将 QQ 消息转发到所有映射的 Discord 频道"""
|
||||
target_channels = []
|
||||
for discord_channel_id, info in config.CROSS_PLATFORM_MAP.items():
|
||||
if info["qq_group_id"] == group_id:
|
||||
target_channels.append(discord_channel_id)
|
||||
|
||||
if not target_channels:
|
||||
logger.warning(f"[CrossPlatform] 未找到 QQ 群 {group_id} 的映射配置")
|
||||
return
|
||||
|
||||
formatted_content, image_list, embed = await format_qq_to_discord_content(
|
||||
qq_nickname,
|
||||
qq_user_id,
|
||||
group_name,
|
||||
group_id,
|
||||
content,
|
||||
attachments
|
||||
)
|
||||
|
||||
if embed and embed.get("description"):
|
||||
original_text = embed["description"]
|
||||
translated_text = await translate_with_deepseek(original_text, "en", group_id, "zh2en")
|
||||
if translated_text != original_text:
|
||||
embed["description"] = f"{original_text}\n\n**Translation:**\n{translated_text}"
|
||||
|
||||
for channel_id in target_channels:
|
||||
await send_to_discord(channel_id, formatted_content, image_list, embed)
|
||||
|
||||
logger.success(f"[CrossPlatform] QQ 群 {group_id} -> Discord 频道 {target_channels}")
|
||||
|
||||
async def publish_to_redis(platform: str, data: dict):
|
||||
"""通过 Redis 发布跨平台消息"""
|
||||
try:
|
||||
if redis_manager.redis:
|
||||
publish_data = {
|
||||
"platform": platform,
|
||||
"data": data,
|
||||
"timestamp": int(__import__('time').time())
|
||||
}
|
||||
await redis_manager.redis.publish(config.CROSS_PLATFORM_CHANNEL, json.dumps(publish_data))
|
||||
logger.debug(f"[CrossPlatform] 已通过 Redis 发布消息: platform={platform}")
|
||||
except Exception as e:
|
||||
logger.error(f"[CrossPlatform] Redis 发布失败: {e}")
|
||||
Reference in New Issue
Block a user