From 7945853fd1bccd4d29f509879037f6f9d7a67e03 Mon Sep 17 00:00:00 2001 From: UnCLAS-Prommer Date: Thu, 1 May 2025 21:05:48 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=B3=A8=E8=A7=A3=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8E=9F=E7=94=9F=E8=A1=A8=E6=83=85=E8=A7=A3?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 13 ++- src/qq_emoji_list.py | 250 +++++++++++++++++++++++++++++++++++++++++++ src/recv_handler.py | 46 +++++--- src/utils.py | 2 +- 4 files changed, 290 insertions(+), 21 deletions(-) create mode 100644 src/qq_emoji_list.py diff --git a/main.py b/main.py index 549db97..c3d96a9 100644 --- a/main.py +++ b/main.py @@ -61,12 +61,10 @@ async def graceful_shutdown(): await mmc_stop_com() tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()] for task in tasks: - if not task.done(): - task.cancel() + task.cancel() await asyncio.gather(*tasks, return_exceptions=True) - except Exception as e: - logger.error(f"Adapter关闭失败: {e}") + logger.error(f"Adapter关闭中出现错误: {e}") if __name__ == "__main__": @@ -79,7 +77,8 @@ if __name__ == "__main__": loop.run_until_complete(graceful_shutdown()) except Exception as e: logger.exception(f"主程序异常: {str(e)}") - if loop and not loop.is_closed(): - loop.run_until_complete(graceful_shutdown()) - loop.close() sys.exit(1) + finally: + if loop and not loop.is_closed(): + loop.close() + sys.exit(0) diff --git a/src/qq_emoji_list.py b/src/qq_emoji_list.py new file mode 100644 index 0000000..51c3232 --- /dev/null +++ b/src/qq_emoji_list.py @@ -0,0 +1,250 @@ +qq_face: dict = { + "0": "[表情:惊讶]", + "1": "[表情:撇嘴]", + "2": "[表情:色]", + "3": "[表情:发呆]", + "4": "[表情:得意]", + "5": "[表情:流泪]", + "6": "[表情:害羞]", + "7": "[表情:闭嘴]", + "8": "[表情:睡]", + "9": "[表情:大哭]", + "10": "[表情:尴尬]", + "11": "[表情:发怒]", + "12": "[表情:调皮]", + "13": "[表情:呲牙]", + "14": "[表情:微笑]", + "15": "[表情:难过]", + "16": "[表情:酷]", + "18": "[表情:抓狂]", + "19": "[表情:吐]", + "20": "[表情:偷笑]", + "21": "[表情:可爱]", + "22": "[表情:白眼]", + "23": "[表情:傲慢]", + "24": "[表情:饥饿]", + "25": "[表情:困]", + "26": "[表情:惊恐]", + "27": "[表情:流汗]", + "28": "[表情:憨笑]", + "29": "[表情:悠闲]", + "30": "[表情:奋斗]", + "31": "[表情:咒骂]", + "32": "[表情:疑问]", + "33": "[表情: 嘘]", + "34": "[表情:晕]", + "35": "[表情:折磨]", + "36": "[表情:衰]", + "37": "[表情:骷髅]", + "38": "[表情:敲打]", + "39": "[表情:再见]", + "41": "[表情:发抖]", + "42": "[表情:爱情]", + "43": "[表情:跳跳]", + "46": "[表情:猪头]", + "49": "[表情:拥抱]", + "53": "[表情:蛋糕]", + "56": "[表情:刀]", + "59": "[表情:便便]", + "60": "[表情:咖啡]", + "63": "[表情:玫瑰]", + "64": "[表情:凋谢]", + "66": "[表情:爱心]", + "67": "[表情:心碎]", + "74": "[表情:太阳]", + "75": "[表情:月亮]", + "76": "[表情:赞]", + "77": "[表情:踩]", + "78": "[表情:握手]", + "79": "[表情:胜利]", + "85": "[表情:飞吻]", + "86": "[表情:怄火]", + "89": "[表情:西瓜]", + "96": "[表情:冷汗]", + "97": "[表情:擦汗]", + "98": "[表情:抠鼻]", + "99": "[表情:鼓掌]", + "100": "[表情:糗大了]", + "101": "[表情:坏笑]", + "102": "[表情:左哼哼]", + "103": "[表情:右哼哼]", + "104": "[表情:哈欠]", + "105": "[表情:鄙视]", + "106": "[表情:委屈]", + "107": "[表情:快哭了]", + "108": "[表情:阴险]", + "109": "[表情:左亲亲]", + "110": "[表情:吓]", + "111": "[表情:可怜]", + "112": "[表情:菜刀]", + "114": "[表情:篮球]", + "116": "[表情:示爱]", + "118": "[表情:抱拳]", + "119": "[表情:勾引]", + "120": "[表情:拳头]", + "121": "[表情:差劲]", + "123": "[表情:NO]", + "124": "[表情:OK]", + "125": "[表情:转圈]", + "129": "[表情:挥手]", + "137": "[表情:鞭炮]", + "144": "[表情:喝彩]", + "146": "[表情:爆筋]", + "147": "[表情:棒棒糖]", + "169": "[表情:手枪]", + "171": "[表情:茶]", + "172": "[表情:眨眼睛]", + "173": "[表情:泪奔]", + "174": "[表情:无奈]", + "175": "[表情:卖萌]", + "176": "[表情:小纠结]", + "177": "[表情:喷血]", + "178": "[表情:斜眼笑]", + "179": "[表情:doge]", + "181": "[表情:戳一戳]", + "182": "[表情:笑哭]", + "183": "[表情:我最美]", + "185": "[表情:羊驼]", + "187": "[表情:幽灵]", + "201": "[表情:点赞]", + "212": "[表情:托腮]", + "262": "[表情:脑阔疼]", + "263": "[表情:沧桑]", + "264": "[表情:捂脸]", + "265": "[表情:辣眼睛]", + "266": "[表情:哦哟]", + "267": "[表情:头秃]", + "268": "[表情:问号脸]", + "269": "[表情:暗中观察]", + "270": "[表情:emm]", + "271": "[表情:吃 瓜]", + "272": "[表情:呵呵哒]", + "273": "[表情:我酸了]", + "277": "[表情:汪汪]", + "281": "[表情:无眼笑]", + "282": "[表情:敬礼]", + "283": "[表情:狂笑]", + "284": "[表情:面无表情]", + "285": "[表情:摸鱼]", + "286": "[表情:魔鬼笑]", + "287": "[表情:哦]", + "289": "[表情:睁眼]", + "293": "[表情:摸锦鲤]", + "294": "[表情:期待]", + "295": "[表情:拿到红包]", + "297": "[表情:拜谢]", + "298": "[表情:元宝]", + "299": "[表情:牛啊]", + "300": "[表情:胖三斤]", + "302": "[表情:左拜年]", + "303": "[表情:右拜年]", + "305": "[表情:右亲亲]", + "306": "[表情:牛气冲天]", + "307": "[表情:喵喵]", + "311": "[表情:打call]", + "312": "[表情:变形]", + "314": "[表情:仔细分析]", + "317": "[表情:菜汪]", + "318": "[表情:崇拜]", + "319": "[表情: 比心]", + "320": "[表情:庆祝]", + "323": "[表情:嫌弃]", + "324": "[表情:吃糖]", + "325": "[表情:惊吓]", + "326": "[表情:生气]", + "332": "[表情:举牌牌]", + "333": "[表情:烟花]", + "334": "[表情:虎虎生威]", + "336": "[表情:豹富]", + "337": "[表情:花朵脸]", + "338": "[表情:我想开了]", + "339": "[表情:舔屏]", + "341": "[表情:打招呼]", + "342": "[表情:酸Q]", + "343": "[表情:我方了]", + "344": "[表情:大怨种]", + "345": "[表情:红包多多]", + "346": "[表情:你真棒棒]", + "347": "[表情:大展宏兔]", + "349": "[表情:坚强]", + "350": "[表情:贴贴]", + "351": "[表情:敲敲]", + "352": "[表情:咦]", + "353": "[表情:拜托]", + "354": "[表情:尊嘟假嘟]", + "355": "[表情:耶]", + "356": "[表情:666]", + "357": "[表情:裂开]", + "392": "[表情:龙年 快乐]", + "393": "[表情:新年中龙]", + "394": "[表情:新年大龙]", + "395": "[表情:略略略]", + "😊": "[表情:嘿嘿]", + "😌": "[表情:羞涩]", + "😚": "[ 表情:亲亲]", + "😓": "[表情:汗]", + "😰": "[表情:紧张]", + "😝": "[表情:吐舌]", + "😁": "[表情:呲牙]", + "😜": "[表情:淘气]", + "☺": "[表情:可爱]", + "😍": "[表情:花痴]", + "😔": "[表情:失落]", + "😄": "[表情:高兴]", + "😏": "[表情:哼哼]", + "😒": "[表情:不屑]", + "😳": "[表情:瞪眼]", + "😘": "[表情:飞吻]", + "😭": "[表情:大哭]", + "😱": "[表情:害怕]", + "😂": "[表情:激动]", + "💪": "[表情:肌肉]", + "👊": "[表情:拳头]", + "👍": "[表情 :厉害]", + "👏": "[表情:鼓掌]", + "👎": "[表情:鄙视]", + "🙏": "[表情:合十]", + "👌": "[表情:好的]", + "👆": "[表情:向上]", + "👀": "[表情:眼睛]", + "🍜": "[表情:拉面]", + "🍧": "[表情:刨冰]", + "🍞": "[表情:面包]", + "🍺": "[表情:啤酒]", + "🍻": "[表情:干杯]", + "☕": "[表情:咖啡]", + "🍎": "[表情:苹果]", + "🍓": "[表情:草莓]", + "🍉": "[表情:西瓜]", + "🚬": "[表情:吸烟]", + "🌹": "[表情:玫瑰]", + "🎉": "[表情:庆祝]", + "💝": "[表情:礼物]", + "💣": "[表情:炸弹]", + "✨": "[表情:闪光]", + "💨": "[表情:吹气]", + "💦": "[表情:水]", + "🔥": "[表情:火]", + "💤": "[表情:睡觉]", + "💩": "[表情:便便]", + "💉": "[表情:打针]", + "📫": "[表情:邮箱]", + "🐎": "[表情:骑马]", + "👧": "[表情:女孩]", + "👦": "[表情:男孩]", + "🐵": "[表情:猴]", + "🐷": "[表情:猪]", + "🐮": "[表情:牛]", + "🐔": "[表情:公鸡]", + "🐸": "[表情:青蛙]", + "👻": "[表情:幽灵]", + "🐛": "[表情:虫]", + "🐶": "[表情:狗]", + "🐳": "[表情:鲸鱼]", + "👢": "[表情:靴子]", + "☀": "[表情:晴天]", + "❔": "[表情:问号]", + "🔫": "[表情:手枪]", + "💓": "[表情:爱 心]", + "🏪": "[表情:便利店]", +} diff --git a/src/recv_handler.py b/src/recv_handler.py index f282f40..33f98b9 100644 --- a/src/recv_handler.py +++ b/src/recv_handler.py @@ -1,5 +1,6 @@ from .logger import logger from .config import global_config +from .qq_emoji_list import qq_face import time import asyncio import json @@ -209,7 +210,7 @@ class RecvHandler: logger.info("发送到Maibot处理信息") await self.message_process(message_base) - async def handle_real_message(self, raw_message: dict, in_reply: bool = False) -> List[Seg]: + async def handle_real_message(self, raw_message: dict, in_reply: bool = False) -> List[Seg] | None: """ 处理实际消息 Parameters: @@ -232,7 +233,11 @@ class RecvHandler: else: logger.warning("text处理失败") case RealMessageType.face: - pass + ret_seg = await self.handle_face_message(sub_message) + if ret_seg: + seg_message.append(ret_seg) + else: + logger.warning("face处理失败或不支持") case RealMessageType.reply: if not in_reply: ret_seg = await self.handle_reply_message(sub_message) @@ -278,7 +283,11 @@ class RecvHandler: logger.warning("暂时不支持链接解析") pass case RealMessageType.forward: - forward_message_id = sub_message.get("data").get("id") + forward_message_data = sub_message.get("data") + if not forward_message_data: + logger.warning("转发消息内容为空") + return None + forward_message_id = forward_message_data.get("id") request_uuid = str(uuid.uuid4()) payload = json.dumps( { @@ -336,15 +345,25 @@ class RecvHandler: seg_data = Seg(type=RealMessageType.text, data=plain_text) return seg_data - async def handle_face_message(self) -> None: + async def handle_face_message(self, raw_message: dict) -> Seg | None: """ 处理表情消息 - - 支持未完成 + Parameters: + raw_message: dict: 原始消息 + Returns: + seg_data: Seg: 处理后的消息段 """ - pass + message_data: dict = raw_message.get("data") + face_raw_id: str = message_data.get("id") + if str(face_raw_id) in qq_face: + face_content: str = qq_face.get(face_raw_id) + seg_data = Seg(type="text", data=face_content) + return seg_data + else: + logger.warning(f"不支持的表情:{face_raw_id}") + return None - async def handle_image_message(self, raw_message: dict) -> Seg: + async def handle_image_message(self, raw_message: dict) -> Seg | None: """ 处理图片消息与表情包消息 Parameters: @@ -368,7 +387,7 @@ class RecvHandler: seg_data = Seg(type="emoji", data=image_base64) return seg_data - async def handle_at_message(self, raw_message: dict, self_id: int, group_id: int) -> Seg: + async def handle_at_message(self, raw_message: dict, self_id: int, group_id: int) -> Seg | None: """ 处理at消息 Parameters: @@ -399,12 +418,13 @@ class RecvHandler: else: return None - async def handle_reply_message(self, raw_message: dict) -> Seg: + async def handle_reply_message(self, raw_message: dict) -> Seg | None: """ 处理回复消息 """ raw_message_data: dict = raw_message.get("data") + message_id: int = None if raw_message_data: message_id = raw_message_data.get("id") else: @@ -522,7 +542,7 @@ class RecvHandler: logger.info("发送到Maibot处理通知信息") await self.message_process(message_base) - async def handle_poke_notify(self, raw_message: dict) -> Seg: + async def handle_poke_notify(self, raw_message: dict) -> Seg | None: self_info: dict = await get_self_info(self.server_connection) if not self_info: logger.error("自身信息获取失败") @@ -564,7 +584,7 @@ class RecvHandler: ) return seg_data - async def handle_forward_message(self, message_list: list) -> Seg: + async def handle_forward_message(self, message_list: list) -> Seg | None: """ 递归处理转发消息,并按照动态方式确定图片处理方式 Parameters: @@ -629,7 +649,7 @@ class RecvHandler: else: return seg_data - async def _handle_forward_message(self, message_list: list, layer: int) -> Tuple[Seg, int]: + async def _handle_forward_message(self, message_list: list, layer: int) -> Tuple[Seg, int] | Tuple[None, int]: """ 递归处理实际转发消息 Parameters: diff --git a/src/utils.py b/src/utils.py index 784e9d9..c699d8d 100644 --- a/src/utils.py +++ b/src/utils.py @@ -1,4 +1,4 @@ -import websockets.asyncio.server as Server +import websockets as Server import json import base64 import uuid