|  | 
| 17 | 17 | # 初始化 | 
| 18 | 18 | my = itchat.new_instance() | 
| 19 | 19 | my.auto_login(hotReload=False, enableCmdQR=-2) | 
| 20 |  | -my.global_keys = ["创业", "算法", "人工智能", "机器学习"] | 
| 21 |  | -my.to_user_name = "filehelper" | 
| 22 |  | - | 
| 23 | 20 | # my还包括的以下属性,注意用点.查看: | 
| 24 | 21 | # (1) alive 是否还活着,isLogging 是否已登陆 | 
| 25 | 22 | # (2) loginInfo 登陆信息,其中的User属性为自己的信息User字典类,包括UserName, NickName, RemarkName, Sex(1 or 2), Signature, Province, City等 | 
| 26 | 23 | # (3) memberList 通讯录列表,每一项为一个User字典类,包括UserName, NickName, RemarkName, Sex(1 or 2), Signature, Province, City等 | 
| 27 | 24 | # (4) chatroomList 群聊列表,每一项为一个Chatroom字典类,包括UserName, NickName, RemarkName, MemberCount, MemberList, Self等 | 
| 28 | 25 | # (5) mpList 订阅号列表,每一项为一个MassivePlatform字典类,包括UserName, NickName等 | 
| 29 | 26 | 
 | 
| 30 |  | -# 获取并更新通讯录: {UserName: UserInstance} | 
| 31 |  | -my.friends = {user["UserName"]: user for user in my.get_friends(update=True)} | 
|  | 27 | +my.global_keys = ["创业", "算法", "人工智能", "机器学习"] | 
|  | 28 | +my.to_user_name = "filehelper" # 消息接受者 | 
|  | 29 | +my.update_time = time.time() # 信息更新时间 | 
|  | 30 | +my.msg_store = {} # 消息存储队列 | 
|  | 31 | +my.friends = {} # 好友字典列表 | 
|  | 32 | +my.groups = {} # 群聊字典列表 | 
| 32 | 33 | 
 | 
| 33 |  | -# 消息存储队列 | 
| 34 |  | -my.msg_store = {} | 
|  | 34 | + | 
|  | 35 | +def update_my_infos(): | 
|  | 36 | + """ | 
|  | 37 | + 更新信息 | 
|  | 38 | + """ | 
|  | 39 | + # 获取并更新通讯录: {UserName: UserInstance} | 
|  | 40 | + my.friends = {user["UserName"]: user for user in my.get_friends(update=True)} | 
|  | 41 | + # 获取并更新群列表: {UserName: UserInstance} | 
|  | 42 | + my.groups = {group["UserName"]: group for group in my.get_chatrooms(update=True)} | 
|  | 43 | + return | 
|  | 44 | +update_my_infos() | 
| 35 | 45 | 
 | 
| 36 | 46 | 
 | 
| 37 |  | -# 消息提取函数 | 
| 38 |  | -def get_msg_list(msg): | 
|  | 47 | +class Message(object): | 
| 39 | 48 |  """ | 
| 40 |  | - 提取消息内容,消息来源分类: | 
| 41 |  | - (1)来自好友的消息 | 
| 42 |  | - (2)来自群的消息 | 
| 43 |  | - (3)来自文件传输助手的消息 | 
| 44 |  | - 提取消息内容,消息类型分类: | 
| 45 |  | - (1)文字(2)图片(3)语音(4)视频(5)地址(6)名片(7)提醒(8)分享(9)附件 | 
|  | 49 | + 消息类 | 
| 46 | 50 |  """ | 
| 47 |  | - # logging.warning("message: %s", msg) | 
| 48 |  | - msg_id = msg["MsgId"] # 消息ID | 
| 49 |  | - from_user_name = msg["FromUserName"] # 消息发送者ID,如果为群消息,则为群ID | 
| 50 |  | - to_user_name = msg["ToUserName"] # 消息接受者ID,如果为群消息,则为群ID | 
|  | 51 | + def __init__(self, msg): | 
|  | 52 | + """ | 
|  | 53 | + 构造函数:提取消息内容 | 
|  | 54 | + 消息来源分类: | 
|  | 55 | + (1)来自好友的消息 | 
|  | 56 | + (2)来自群的消息 | 
|  | 57 | + 提取消息内容,消息类型分类: | 
|  | 58 | + (1)文字(2)图片(3)语音(4)视频(5)地址(6)名片(7)提醒(8)分享(9)附件 | 
|  | 59 | + """ | 
|  | 60 | + # 更新信息,十分钟更新一次 | 
|  | 61 | + # logging.warning("message: %s", msg) | 
|  | 62 | + if time.time() - my.update_time > 600: | 
|  | 63 | + update_my_infos() | 
|  | 64 | + my.update_time = time.time() | 
| 51 | 65 | 
 | 
| 52 |  | - msg_type = msg["MsgType"] # 消息类型 | 
| 53 |  | - msg_content = msg["Content"] # 消息内容 | 
| 54 |  | - msg_time = msg["CreateTime"] # 消息发送时间 | 
|  | 66 | + self.msg_id = msg["MsgId"] # 消息ID | 
|  | 67 | + self.from_user_name = msg["FromUserName"] # 消息发送者ID,如果为群消息,则为群ID | 
| 55 | 68 | 
 | 
| 56 |  | - msg_file = msg["FileName"] # 消息中所带文件的名称 | 
| 57 |  | - msg_file_length = msg["FileSize"] # 消息中所带文件的大小 | 
| 58 |  | - msg_voice_length = msg["VoiceLength"] # 消息中所带语音的长度(毫秒) | 
| 59 |  | - msg_play_length = msg["PlayLength"] # 消息中所带视频的长度(秒) | 
| 60 |  | - msg_url = msg["Url"] # 消息中所带链接的地址 | 
|  | 69 | + self.msg_type = msg["MsgType"] # 消息类型,这里参考下边的we_type | 
|  | 70 | + self.msg_content = msg["Content"] # 消息内容,这里参考下边的we_text | 
|  | 71 | + self.msg_time = msg["CreateTime"] # 消息发送时间,时间戳格式 | 
| 61 | 72 | 
 | 
| 62 |  | - wind_name = msg["User"]["RemarkName"] if msg["User"].get("RemarkName") else ( | 
| 63 |  | - msg["User"]["NickName"] if msg["User"].get("NickName") else to_user_name | 
| 64 |  | - ) # 窗口名称:群名或好友名 | 
|  | 73 | + self.msg_file = msg["FileName"] # 消息中所带文件的名称 | 
|  | 74 | + self.msg_file_length = msg["FileSize"] # 消息中所带文件的大小,字符串类型 | 
|  | 75 | + self.msg_voice_length = msg["VoiceLength"] # 消息中所带语音的长度(毫秒) | 
|  | 76 | + self.msg_play_length = msg["PlayLength"] # 消息中所带视频的长度(秒) | 
|  | 77 | + self.msg_url = msg["Url"] # 消息中所带链接的地址 | 
| 65 | 78 | 
 | 
| 66 |  | - msg_user_name = from_user_name # 消息发送者的ID | 
| 67 |  | - msg_nick_name = wind_name # 消息发送者的昵称 | 
| 68 |  | - if from_user_name.startswith("@@") or to_user_name.startswith("@@"): | 
| 69 |  | - msg_user_name = msg["ActualUserName"] | 
| 70 |  | - msg_nick_name = msg["ActualNickName"] if (msg_user_name not in my.friends) or (not my.friends[msg_user_name]["RemarkName"]) else my.friends[msg_user_name]["RemarkName"] | 
|  | 79 | + self.user_user_name = msg["User"].get("UserName", "") # 消息发送者ID,如果为群消息,则为群ID | 
|  | 80 | + self.user_nick_name = msg["User"].get("NickName", "") # 消息发送者昵称,如果为群消息,则为群名 | 
|  | 81 | + self.user_remark_name = msg["User"].get("RemarkName", "") # 消息发送者备注名称,如果为群消息,则为群备注名称 | 
|  | 82 | + self.wind_name = self.user_remark_name if self.user_remark_name else ( | 
|  | 83 | + self.user_nick_name if self.user_nick_name else ( | 
|  | 84 | + my.friends[self.user_user_name]["NickName"] if self.user_user_name in my.friends else ( | 
|  | 85 | + my.groups[self.user_user_name]["NickName"] if self.user_user_name in my.groups else "未知窗口" | 
|  | 86 | + ) | 
|  | 87 | + ) | 
|  | 88 | + ) | 
| 71 | 89 | 
 | 
| 72 |  | - is_at = msg.get("IsAt", None) # 是否在群内被@ | 
| 73 |  | - we_type = msg["Type"] # 消息类型 | 
| 74 |  | - we_text = msg["Text"] # 消息内容 | 
|  | 90 | + self.actual_user_name = msg.get("ActualUserName", "") # 群消息中,消息发送者的ID | 
|  | 91 | + self.actual_nick_name = msg.get("ActualNickName", "") # 群消息中,消息发送者的群昵称 | 
|  | 92 | + self.actual_remark_name = self.actual_nick_name \ | 
|  | 93 | + if (self.actual_user_name not in my.friends) or (not my.friends[self.actual_user_name]["RemarkName"]) \ | 
|  | 94 | + else my.friends[self.actual_user_name]["RemarkName"] | 
| 75 | 95 | 
 | 
| 76 |  | - logging.warning("show: msg_nick_name=%s, wind_name=%s, we_type=%s, we_text=%s", msg_nick_name, wind_name, we_type, we_text) | 
| 77 |  | - return msg_id, from_user_name, to_user_name, msg_type, msg_content, msg_time, msg_file, msg_file_length, msg_voice_length, msg_play_length, msg_url, \ | 
| 78 |  | - wind_name, msg_user_name, msg_nick_name, is_at, we_type, we_text | 
|  | 96 | +  self.is_at = msg.get("IsAt", None) # 是否在群内被@ | 
|  | 97 | +  self.we_type = msg["Type"] # 消息类型 | 
|  | 98 | + self.we_text = msg["Text"] # 消息内容 | 
| 79 | 99 | 
 | 
|  | 100 | + logging.warning("show: wind_name=%s, actual_send_name=%s, we_type=%s, we_text=%s", self.wind_name, self.actual_remark_name, self.we_type, self.we_text) | 
|  | 101 | + return | 
| 80 | 102 | 
 | 
| 81 |  | -# 消息注册,主要处理群消息 | 
| 82 |  | -@my.msg_register([TEXT, PICTURE, RECORDING, VIDEO, MAP, CARD, NOTE, SHARING, ATTACHMENT], isFriendChat=True, isGroupChat=True) | 
| 83 |  | -def text_reply(msg): | 
|  | 103 | + | 
|  | 104 | +def process_message_group(msg): | 
| 84 | 105 |  """ | 
| 85 |  | - 消息自动接收, 接受全部的消息(自己发送的消息除外) | 
|  | 106 | + 处理群消息 | 
| 86 | 107 |  """ | 
| 87 |  | - # 跳过来自自己的消息 | 
| 88 |  | - if msg["FromUserName"] == my.loginInfo["User"]["UserName"]: | 
|  | 108 | + # 消息过滤, 只监测文字、图片、语音、名片、注解、分享等 | 
|  | 109 | + if msg.we_type not in ["Text", "Picture", "Recording", "Card", "Note", "Sharing"]: | 
|  | 110 | + logging.warning("process_message_group: message type isn't included, ignored") | 
| 89 | 111 |  return | 
| 90 | 112 | 
 | 
| 91 |  | - # 消息提取 | 
| 92 |  | - msg_list = get_msg_list(msg) | 
| 93 |  | - msg_id, from_user_name, to_user_name, msg_type, msg_content, msg_time, msg_file, msg_file_length, msg_voice_length, msg_play_length, msg_url, \ | 
| 94 |  | - wind_name, msg_user_name, msg_nick_name, is_at, we_type, we_text = msg_list | 
|  | 113 | + # ==== 处理红包消息 ==== | 
|  | 114 | + if msg.we_type == "Note" and msg.we_text.find("收到红包,请在手机上查看") >= 0: | 
|  | 115 | + my.send("【%s】中有人发红包啦,快抢!" % msg.wind_name, toUserName=my.to_user_name) | 
|  | 116 | + | 
|  | 117 | + # ==== 处理关键词消息 ==== | 
|  | 118 | + for key in my.global_keys: | 
|  | 119 | + if msg.we_type == "Text" and msg.we_text.find(key) >= 0: | 
|  | 120 | + my.send("【%s】中【%s】提及了关键字:%s" % (msg.wind_name, msg.actual_remark_name, key), toUserName=my.to_user_name) | 
|  | 121 | + my.send(msg.we_text, toUserName=my.to_user_name) | 
|  | 122 | + break | 
|  | 123 | + | 
|  | 124 | + # ==== 群内是否被@ ==== | 
|  | 125 | + if msg.we_type == "Text" and msg.is_at: | 
|  | 126 | + my.send("【%s】中【%s】@了你" % (msg.wind_name, msg.actual_remark_name), toUserName=my.to_user_name) | 
|  | 127 | + my.send(msg.we_text, toUserName=my.to_user_name) | 
|  | 128 | + return | 
|  | 129 | + | 
| 95 | 130 | 
 | 
|  | 131 | +def process_message_revoke(msg): | 
|  | 132 | + """ | 
|  | 133 | + 处理撤回消息 | 
|  | 134 | + """ | 
| 96 | 135 |  # 消息过滤, 只监测文字、图片、语音、名片、注解、分享等 | 
| 97 |  | - if we_type not in ["Text", "Picture", "Recording", "Card", "Note", "Sharing"]: | 
| 98 |  | - logging.warning("message type isn't included, ignored") | 
|  | 136 | + if msg.we_type not in ["Text", "Picture", "Recording", "Card", "Note", "Sharing"]: | 
|  | 137 | + logging.warning("process_message_revoke: message type isn't included, ignored") | 
| 99 | 138 |  return | 
| 100 | 139 | 
 | 
| 101 | 140 |  # 消息存储,删除过期消息 | 
| 102 |  | - my.msg_store[msg_id] = msg_list | 
| 103 |  | - for _id in [_id for _id in my.msg_store if time.time() - my.msg_store[_id][5] > 120]: | 
|  | 141 | + my.msg_store[msg.msg_id] = msg | 
|  | 142 | + for _id in [_id for _id in my.msg_store if time.time() - my.msg_store[_id].msg_time > 120]: | 
| 104 | 143 |  my.msg_store.pop(_id) | 
| 105 | 144 | 
 | 
| 106 |  | - # 保存消息中的内容(图片、语音等),不保存动态图片 | 
| 107 |  | - if (we_type in ["Picture", "Recording"]) and (not msg_file.endswith(".gif")): | 
|  | 145 | + # 保存消息中的内容(图片、语音等) | 
|  | 146 | + if msg.we_type in ["Picture", "Recording"]: | 
| 108 | 147 |  try: | 
| 109 |  | - we_text(".Cache/" + msg_file) | 
| 110 |  | - logging.warning("downloading %s to .Cache/", msg_file) | 
|  | 148 | + msg.we_text(".Cache/" + msg.msg_file) | 
|  | 149 | + logging.warning("process_message_revoke: download %s to .Cache/", msg.msg_file) | 
| 111 | 150 |  except Exception as excep: | 
| 112 |  | - logging.error("downloading %s to .Cache/ error: %s", msg_file, excep) | 
| 113 |  | - | 
| 114 |  | - # ==== 处理群消息 ==== | 
| 115 |  | - if from_user_name.startswith("@@"): | 
| 116 |  | - # ==== 处理红包消息 ==== | 
| 117 |  | - if we_type == "Note" and we_text.find("收到红包,请在手机上查看") >= 0: | 
| 118 |  | - my.send("【%s】中有人发红包啦,快抢!" % wind_name, toUserName=my.to_user_name) | 
| 119 |  | - # ==== 处理关键词消息 ==== | 
| 120 |  | - for key in my.global_keys: | 
| 121 |  | - if we_type == "Text" and we_text.find(key) >= 0: | 
| 122 |  | - my.send("【%s】中【%s】提及了关键字:%s" % (wind_name, msg_nick_name, key), toUserName=my.to_user_name) | 
| 123 |  | - my.send(we_text, toUserName=my.to_user_name) | 
| 124 |  | - break | 
| 125 |  | - # ==== 群内是否被@ ==== | 
| 126 |  | - if we_type == "Text" and is_at: | 
| 127 |  | - my.send("【%s】中【%s】@了你" % (wind_name, msg_nick_name), toUserName=my.to_user_name) | 
| 128 |  | - my.send(we_text, toUserName=my.to_user_name) | 
|  | 151 | + logging.error("process_message_revoke: download %s to .Cache/ error: %s", msg.msg_file, excep) | 
| 129 | 152 | 
 | 
| 130 | 153 |  # ==== 撤回消息处理(必须为最后一步) ==== | 
| 131 |  | - if we_type == "Note" and we_text.find("撤回了一条消息") >= 0: | 
| 132 |  | - msg_list = my.msg_store.get(msg_content[msg_content.find("<msgid>")+7: msg_content.find("</msgid>")]) | 
| 133 |  | - if not msg_list: | 
| 134 |  | - logging.warning("not message id in my.msg_store") | 
|  | 154 | + if msg.we_type == "Note" and msg.we_text.find("撤回了一条消息") >= 0: | 
|  | 155 | + old_msg = my.msg_store.get(msg.msg_content[msg.msg_content.find("<msgid>")+7: msg.msg_content.find("</msgid>")]) | 
|  | 156 | + if not old_msg: | 
|  | 157 | + logging.warning("process_message_revoke: no message id in my.msg_store") | 
| 135 | 158 |  return | 
| 136 | 159 | 
 | 
| 137 |  | - msg_id, from_user_name, to_user_name, msg_type, msg_content, msg_time, msg_file, msg_file_length, msg_voice_length, msg_play_length, msg_url, \ | 
| 138 |  | - wind_name, msg_user_name, msg_nick_name, is_at, we_type, we_text = msg_list | 
| 139 |  | - my.send("【%s】中【%s】撤回了自己发送的消息:\nType: %s\nTime: %s\n%s" % (wind_name, msg_nick_name, we_type, msg_time, msg_file), toUserName=my.to_user_name) | 
|  | 160 | + if old_msg.from_user_name.startswith("@@"): | 
|  | 161 | + my.send("【%s】中【%s】撤回了自己发送的消息:\nType: %s\nTime: %s\n%s" % | 
|  | 162 | + (old_msg.wind_name, old_msg.actual_remark_name, old_msg.we_type, old_msg.msg_time, old_msg.msg_file), toUserName=my.to_user_name) | 
|  | 163 | + else: | 
|  | 164 | + my.send("【%s】撤回了自己发送的消息:\nType: %s\nTime: %s\n%s" % | 
|  | 165 | + (old_msg.wind_name, old_msg.we_type, old_msg.msg_time, old_msg.msg_file), toUserName=my.to_user_name) | 
|  | 166 | + | 
|  | 167 | + if old_msg.we_type in ["Text", "Card"]: | 
|  | 168 | + my.send(str(old_msg.we_text), toUserName=my.to_user_name) | 
|  | 169 | + elif old_msg.we_type == "Sharing": | 
|  | 170 | + my.send(old_msg.we_text + "\n" + old_msg.msg_url, toUserName=my.to_user_name) | 
|  | 171 | + elif old_msg.we_type == "Picture": | 
|  | 172 | + my.send_image(".Cache/" + old_msg.msg_file, toUserName=my.to_user_name) | 
|  | 173 | + elif old_msg.we_type == "Recording": | 
|  | 174 | + my.send_file(".Cache/" + old_msg.msg_file, toUserName=my.to_user_name) | 
|  | 175 | + return | 
|  | 176 | + | 
|  | 177 | + | 
|  | 178 | +@my.msg_register([TEXT, PICTURE, RECORDING, VIDEO, MAP, CARD, NOTE, SHARING, ATTACHMENT], isFriendChat=True, isGroupChat=True) | 
|  | 179 | +def text_reply(msg): | 
|  | 180 | + """ | 
|  | 181 | + 消息自动接收, 接受全部的消息(自己发送的消息除外) | 
|  | 182 | + """ | 
|  | 183 | + # 跳过来自自己的消息 | 
|  | 184 | + if msg["FromUserName"] == my.loginInfo["User"]["UserName"]: | 
|  | 185 | + return | 
|  | 186 | + | 
|  | 187 | + # 消息提取 | 
|  | 188 | + msg = Message(msg) | 
| 140 | 189 | 
 | 
| 141 |  | - if we_type in ["Text", "Card"]: | 
| 142 |  | - my.send(str(we_text), toUserName=my.to_user_name) | 
| 143 |  | - elif we_type == "Sharing": | 
| 144 |  | - my.send(we_text + "\n" + msg_url, toUserName=my.to_user_name) | 
| 145 |  | - elif we_type == "Recording": | 
| 146 |  | - my.send_file(".Cache/" + msg_file, toUserName=my.to_user_name) | 
| 147 |  | - elif we_type == "Picture" and (not msg_file.endswith(".gif")): | 
| 148 |  | - my.send_image(".Cache/" + msg_file, toUserName=my.to_user_name) | 
|  | 190 | + # 处理群消息 | 
|  | 191 | + if msg.from_user_name.startswith("@@"): | 
|  | 192 | + process_message_group(msg) | 
| 149 | 193 | 
 | 
|  | 194 | + # 处理撤回消息 | 
|  | 195 | + process_message_revoke(msg) | 
| 150 | 196 |  return | 
| 151 | 197 | 
 | 
| 152 | 198 | 
 | 
| @@ -332,4 +378,75 @@ def text_reply(msg): | 
| 332 | 378 |  'Type': 'Text', | 
| 333 | 379 |  'Text': '就是那个,那个协议我们手上有吗' | 
| 334 | 380 | } | 
|  | 381 | +
 | 
|  | 382 | +警示消息:好友类 | 
|  | 383 | +{ | 
|  | 384 | + 'MsgId': '1529895072288746571', | 
|  | 385 | + 'FromUserName': '@4076708be2e09ef83f249f168553d0dd55b4f734aee7d276e92ddbe98625476a', | 
|  | 386 | + 'ToUserName': '@f97583d8ffbaee6189854116897c677f', | 
|  | 387 | + 'MsgType': 10000, | 
|  | 388 | + 'Content': '你已添加了呼啸而过的小青春,现在可以开始聊天了。', | 
|  | 389 | + 'Status': 4, | 
|  | 390 | + 'ImgStatus': 1, | 
|  | 391 | + 'CreateTime': 1498533407, | 
|  | 392 | + 'VoiceLength': 0, | 
|  | 393 | + 'PlayLength': 0, | 
|  | 394 | + 'FileName': '', | 
|  | 395 | + 'FileSize': '', | 
|  | 396 | + 'MediaId': '', | 
|  | 397 | + 'Url': '', | 
|  | 398 | + 'AppMsgType': 0, | 
|  | 399 | + 'StatusNotifyCode': 0, | 
|  | 400 | + 'StatusNotifyUserName': '', | 
|  | 401 | + 'HasProductId': 0, | 
|  | 402 | + 'Ticket': '', | 
|  | 403 | + 'ImgHeight': 0, | 
|  | 404 | + 'ImgWidth': 0, | 
|  | 405 | + 'SubMsgType': 0, | 
|  | 406 | + 'NewMsgId': 1529895072288746571, | 
|  | 407 | + 'OriContent': '', | 
|  | 408 | + 'User': <User: { | 
|  | 409 | + 'userName': '@4076708be2e09ef83f249f168553d0dd55b4f734aee7d276e92ddbe98625476a', | 
|  | 410 | + 'MemberList': <ContactList: []> | 
|  | 411 | + }>, | 
|  | 412 | + 'Type': 'Note', | 
|  | 413 | + 'Text': '你已添加了呼啸而过的小青春,现在可以开始聊天了。' | 
|  | 414 | +} | 
|  | 415 | +
 | 
|  | 416 | +警示消息:群类 | 
|  | 417 | +{ | 
|  | 418 | + 'MsgId': '1049646282086057263', | 
|  | 419 | + 'FromUserName': '@@300f57b68ca7ef593ae3221eef7dba5377466c86122aaa15a8ffc1031310e210', | 
|  | 420 | + 'ToUserName': '@006f63e8086ab07fcbe3771dc824c4a6', | 
|  | 421 | + 'MsgType': 10000, | 
|  | 422 | + 'Content': '你邀请"大姐"加入了群聊', | 
|  | 423 | + 'Status': 3, | 
|  | 424 | + 'ImgStatus': 1, | 
|  | 425 | + 'CreateTime': 1498533901, | 
|  | 426 | + 'VoiceLength': 0, | 
|  | 427 | + 'PlayLength': 0, | 
|  | 428 | + 'FileName': '', | 
|  | 429 | + 'FileSize': '', | 
|  | 430 | + 'MediaId': '', | 
|  | 431 | + 'Url': '', | 
|  | 432 | + 'AppMsgType': 0, | 
|  | 433 | + 'StatusNotifyCode': 0, | 
|  | 434 | + 'StatusNotifyUserName': '', | 
|  | 435 | + 'HasProductId': 0, | 
|  | 436 | + 'Ticket': '', | 
|  | 437 | + 'ImgHeight': 0, | 
|  | 438 | + 'ImgWidth': 0, | 
|  | 439 | + 'SubMsgType': 0, | 
|  | 440 | + 'NewMsgId': 1049646282086057263, | 
|  | 441 | + 'OriContent': '', | 
|  | 442 | + 'ActualUserName': '@006f63e8086ab07fcbe3771dc824c4a6', | 
|  | 443 | + 'ActualNickName': '某某某', | 
|  | 444 | + 'IsAt': False, | 
|  | 445 | + 'User': <Chatroom: { | 
|  | 446 | + 'UserName': '@@300f57b68ca7ef593ae3221eef7dba5377466c86122aaa15a8ffc1031310e210', | 
|  | 447 | + 'MemberList': <ContactList: []> | 
|  | 448 | + }>, | 
|  | 449 | + 'Type': 'Note', | 
|  | 450 | + 'Text': '你邀请"大姐"加入了群聊' | 
|  | 451 | +} | 
| 335 | 452 | """ | 
0 commit comments