From 1b08ff46b753b53ad41832df2333b4d81af8a79d Mon Sep 17 00:00:00 2001 From: haosicheng Date: Wed, 22 Oct 2025 14:50:36 +0800 Subject: [PATCH] =?UTF-8?q?[patch]=20DY=E6=97=A5=E5=BF=97=E4=BC=98?= =?UTF-8?q?=E5=8C=962?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Utils/Dy/DyUtils.py | 173 ++++++++++++++------------------------------ config.py | 2 +- 2 files changed, 57 insertions(+), 118 deletions(-) diff --git a/Utils/Dy/DyUtils.py b/Utils/Dy/DyUtils.py index d92d272..7002bac 100644 --- a/Utils/Dy/DyUtils.py +++ b/Utils/Dy/DyUtils.py @@ -1022,21 +1022,12 @@ class DouYinMessageHandler: try: message = blackboxprotobuf.decode_message(content)[0] - # 解析二进制数据 - decoded_message_readable = self.decode_binary_data(message) - print(f"\n📨 收到消息: {decoded_message_readable}") - + # 解析用户Token(静默处理) user, token = self.code_parse(message=message) if user and token: receiver_id = int(user.split(":")[0]) self._init_user_info(receiver_id, token) - print(f"✅ 获取到用户Token: 用户ID={receiver_id}") - - # 获取消息类型 - msg_type = message.get('1') - print(f"📋 消息类型: {msg_type}") - # 获取内部消息结构 inner_msg = message.get('8', {}) @@ -1044,48 +1035,46 @@ class DouYinMessageHandler: if isinstance(inner_msg, bytes): try: inner_msg = blackboxprotobuf.decode_message(inner_msg)[0] - print(f"🔄 解析内部消息字节成功") - except Exception as e: - print(f"⚠️ 无法解析内部消息字节: {e}") + except Exception: + # 无法解析的消息静默忽略 return if not inner_msg or not isinstance(inner_msg, dict): - print("⚠️ 消息结构不完整") + # 消息结构不完整,静默忽略 return # 获取内部消息类型 inner_type = inner_msg.get('1') inner_data = inner_msg.get('6', {}) - # 首先检查是否是心跳响应 + # 处理不同类型的消息 + if inner_type == 610: # Token消息 + self._log(f"🔑 收到Token消息,开始处理", "DEBUG") + self._handle_token_message(inner_data) + + elif inner_type == 500: # 聊天消息(真正的用户消息) + self._handle_chat_message(inner_data, message) + + elif inner_type == 200: # 心跳消息 + pass # 静默忽略 + + # 检查是否是心跳响应(放在最后,避免干扰其他消息类型) if "5" in message: kv_pairs = message["5"] if isinstance(kv_pairs, list): for pair in kv_pairs: if isinstance(pair, dict) and pair.get("1") == b"code" and pair.get("2") == b"0": - self._log("💓 心跳响应正常", "DEBUG") + self._log("Heartbeat OK", "INFO") return - print(f"📋 内部消息类型: {inner_type}") - print(f"📋 内部消息数据键: {list(inner_data.keys()) if isinstance(inner_data, dict) else type(inner_data)}") - # 处理不同类型的消息 - if inner_type == 610: # Token消息 - print("🔑 处理Token消息") - self._handle_token_message(inner_data) - - elif inner_type == 500: # 聊天消息 - print("💬 处理聊天消息") - self._handle_chat_message(inner_data, message) - - elif inner_type == 200: # 心跳消息 - print("💓 收到心跳消息") - - else: - print(f"❓ 未知内部消息类型: {inner_type}") + # 其他未知消息类型静默忽略 except Exception as e: - print(f"❌ 解析消息时出错: {e}") - traceback.print_exc() + # 只记录真正的错误,忽略解析失败 + if "decode" not in str(e).lower(): + self._log(f"Error processing message: {e}", "ERROR") + import traceback + self._log(f"Error details: {traceback.format_exc()}", "DEBUG") async def _process_pending_message(self, sender_id, message_content): """处理待发送的消息""" @@ -1152,11 +1141,10 @@ class DouYinMessageHandler: self._log(f"❌ 无法解析用户ID: {user}", "ERROR") return - self._log(f"✅ 成功解析Token - 用户: {receiver_id}", "SUCCESS") + self._log(f"✅ 成功解析Token - 用户: {receiver_id}", "INFO") # 确保用户信息存在并保存token if receiver_id not in self.user_tokens: - self._log(f"🆕 创建用户信息: {receiver_id}", "DEBUG") self.user_tokens[receiver_id] = { "token": None, "last_sent": 0, @@ -1168,7 +1156,7 @@ class DouYinMessageHandler: # 保存token self.user_tokens[receiver_id]["token"] = token - self._log(f"✅ 已保存用户 {receiver_id} 的Token", "DEBUG") + self._log(f"✅ 已保存用户 {receiver_id} 的Token (长度: {len(token)})", "INFO") # 处理待发送的消息 if "pending_messages" in self.user_tokens[receiver_id]: @@ -1293,10 +1281,8 @@ class DouYinMessageHandler: return None def _extract_message_text(self, msg_content): - """从消息内容中提取文本和图片URL""" + """从消息内容中提取文本和图片URL(静默解析)""" try: - print("🔍 开始提取消息内容...") - # 初始化返回结果 result = { 'text': None, @@ -1311,27 +1297,22 @@ class DouYinMessageHandler: # 方法1: 处理文本消息(从'8'字段获取) text_content = msg_content.get('8') if text_content: - print(f"📄 检测到文本内容") if isinstance(text_content, bytes): try: decoded = text_content.decode('utf-8') result['text'] = decoded - self._log(f"✅ UTF-8解码成功: {decoded}", "SUCCESS") except UnicodeDecodeError: try: decoded = text_content.decode('gbk') result['text'] = decoded - self._log(f"✅ GBK解码成功: {decoded}", "SUCCESS") except: - self._log("⚠️ 无法解码文本内容", "DEBUG") + pass elif isinstance(text_content, str): result['text'] = text_content - self._log(f"✅ 直接使用文本内容: {text_content}") - # 方法2: 统一处理'9'字段中的数据(包括文本和图片、消息、视频 + # 方法2: 统一处理'9'字段中的数据(包括文本和图片、消息、视频) meta_data = msg_content.get('9', []) if meta_data: - print(f"🔍 检测到消息元数据") for item in meta_data: if not isinstance(item, dict): continue @@ -1344,17 +1325,13 @@ class DouYinMessageHandler: # 处理所有类型的URL if key == 'avatar_uri': result['avatar'] = value - self._log(f"✅ 找到头像URL: {value}", "SUCCESS") elif key == 'imageUrl': result['image_url'] = value - self._log(f"✅ 找到图片URL: {value}", "SUCCESS") elif key == 'thumbnailUrl': result['thumbnail_url'] = value - self._log(f"✅ 找到缩略图URL: {value}", "SUCCESS") elif key == 'goods_id': goods_id = value result['goods_id'] = goods_id - self._log(f"✅ 找到商品ID: {goods_id}", "SUCCESS") elif key == 'msg_render_model': try: video_info = json.loads(value) @@ -1364,22 +1341,17 @@ class DouYinMessageHandler: viedo_url = render_body.get('coverURL') viedo_vid = render_body.get('vid') if viedo_vid and viedo_url: - self._log(f"✅ 找到视频原始vid: {viedo_vid}", "SUCCESS") - # 解析获取视频播放地址 play_url = self.parse_video(viedo_vid) if play_url: result['video_url'] = play_url else: - # 如果解析失败 在打印对应的日志后 使用备用封面图片作为地址 + # 如果解析失败,使用备用封面图片作为地址 if '\\u0026' in viedo_url: viedo_url = viedo_url.replace('\\u0026', '&') result['video_url'] = viedo_url - self._log("⚠️ 使用视频封面作为备选", "WARNING") - else: - self._log("⚠️ 未找到视频核心id 可能出现新的数据存放地址", "DEBUG") - except json.JSONDecodeError as e: - self._log(f"解析视频信息失败: {e}", "ERROR") + except json.JSONDecodeError: + pass elif key == 'sku_order_id': # 取到了对应的订单号 id order_id = value @@ -1390,9 +1362,8 @@ class DouYinMessageHandler: break # 方法3: 兼容处理旧的'9-1'字段(如果存在) - image_data = msg_content.get('9-1', []) # 如果没有拿到这个arrayList那么就不需要在对里面的数据进行解析了 + image_data = msg_content.get('9-1', []) if image_data != []: - print(f"📸 检测到旧的图片数据格式", "DEBUG") for item in image_data: if not isinstance(item, dict): continue @@ -1404,17 +1375,13 @@ class DouYinMessageHandler: if key == 'avatar_uri' and not result['avatar']: result['avatar'] = value - self._log(f"✅ 找到头像URL: {value}", "SUCCESS") elif key == 'imageUrl' and not result['image_url']: result['image_url'] = value - self._log(f"✅ 找到图片URL: {value}", "SUCCESS") elif key == 'thumbnailUrl' and not result['thumbnail_url']: result['thumbnail_url'] = value - self._log(f"✅ 找到缩略图URL: {value}", "SUCCESS") elif key == 'goods_id': goods_id = value result['goods_id'] = goods_id - self._log(f"✅ 找到商品ID: {goods_id}", "SUCCESS") elif key == 'msg_render_model': try: video_info = json.loads(value) @@ -1424,62 +1391,39 @@ class DouYinMessageHandler: viedo_url = render_body.get('coverURL') viedo_vid = render_body.get('vid') if viedo_vid and viedo_url: - self._log(f"✅ 找到视频原始vid: {viedo_vid}", "SUCCESS") - # 解析获取视频播放地址 play_url = self.parse_video(viedo_vid) if play_url: result['video_url'] = play_url else: - # 如果解析失败 在打印对应的日志后 使用备用封面图片作为地址 + # 如果解析失败,使用备用封面图片作为地址 if '\\u0026' in viedo_url: viedo_url = viedo_url.replace('\\u0026', '&') result['video_url'] = viedo_url - self._log("⚠️ 使用视频封面作为备选", "WARNING") - else: - self._log("⚠️ 未找到视频核心id 可能出现新的数据存放地址", "DEBUG") - except json.JSONDecodeError as e: - self._log(f"解析视频信息失败: {e}", "ERROR") + except json.JSONDecodeError: + pass elif key == 'sku_order_id': # 取到了对应的订单号 id order_id = value result['order_id'] = order_id - # 如果都没找到内容,打印调试信息 - if not any(result.values()): - print("🔍 未找到有效内容,打印所有字段:") - for key, value in msg_content.items(): - if isinstance(value, bytes): - try: - decoded = value.decode('utf-8', errors='ignore') - print(f" {key}: {decoded[:100]}...") - except: - print(f" {key}: [无法解码的字节数据,长度: {len(value)}]") - elif isinstance(value, list): - print(f" {key}: [列表数据,长度: {len(value)}]") - else: - print(f" {key}: {value}") - return result except Exception as e: - self._log(f"❌ 提取消息内容时出错: {e}", "ERROR") - traceback.print_exc() + # 静默处理异常,返回空结果 return { 'text': None, 'avatar': None, 'image_url': None, 'thumbnail_url': None, 'goods_id': None, - 'viedo_url': None, + 'video_url': None, 'order_id': None } def _handle_chat_message(self, message, msg_type): """处理聊天消息 - 修改版本,支持多种消息类型""" try: - self._log(f"🔍 开始解析{message} 消息结构", "DEBUG") - msg_500 = message.get('500', {}) if not msg_500: return @@ -1490,30 +1434,27 @@ class DouYinMessageHandler: # 从消息内容中获取类型和发送者ID inner_msg_type = msg_content.get("6", 0) - sender_id = msg_content.get("7", 0) - - self._log(f"📊 内部消息类型: {inner_msg_type}, 发送者ID: {sender_id}", "DEBUG") - - print("会不会到这里来呢") + sender_id_raw = msg_content.get("7", 0) + + # 关键修复:确保sender_id是int类型,避免与token保存时的key类型不匹配 + try: + sender_id = int(sender_id_raw) if sender_id_raw else 0 + except (ValueError, TypeError): + sender_id = 0 # 处理不同类型的消息 if inner_msg_type == 1000 and sender_id and sender_id != int(self.cookie['PIGEON_CID']): - # 用户文本消息 - 处理AI回复 - self._log("✅ 检测到1000状态的有效消息", "INFO") + # 用户文本消息 - 处理AI回复(只有这里会输出日志) self._handle_user_text_message(msg_content, sender_id) elif inner_msg_type == 50002 and sender_id and sender_id != int(self.cookie['PIGEON_CID']): - # 系统消息 - 触发token请求 - self._log("✅ 检测到50002类型的系统消息", "INFO") + # 系统消息 - 触发token请求(静默处理) self._handle_system_message(msg_content, sender_id) - else: - # 忽略其他消息 - self._log(f"🔍 忽略消息类型: {inner_msg_type}", "DEBUG") + # 其他消息类型静默忽略 except Exception as e: - self._log(f"❌ 处理聊天消息失败: {e}", "ERROR") - self._log(f"❌ 错误详情: {traceback.format_exc()}", "DEBUG") + self._log(f"Error handling chat message: {e}", "ERROR") def _handle_user_text_message(self, msg_content, sender_id): """处理用户文本消息""" @@ -1564,18 +1505,14 @@ class DouYinMessageHandler: self._log(f"❌ 处理用户文本消息失败: {e}", "ERROR") def _handle_system_message(self, msg_content, sender_id): - """处理系统消息 - 触发token请求""" + """处理系统消息 - 触发token请求(静默处理)""" try: # 提取会话信息 talk_id = msg_content.get("20", 0) p_id = msg_content.get("5", 0) - self._log(f"📝 系统消息会话信息 - TalkID: {talk_id}, PID: {p_id}", "DEBUG") - # 检查是否已经有该用户的token if sender_id not in self.user_tokens or not self.user_tokens[sender_id].get("token"): - self._log(f"🆕 用户 {sender_id} 无token,请求token", "INFO") - # 存储会话信息 if sender_id not in self.user_tokens: self.user_tokens[sender_id] = { @@ -1593,11 +1530,9 @@ class DouYinMessageHandler: # 请求token self._request_user_token(sender_id, p_id) - else: - self._log(f"✅ 用户 {sender_id} 已有token", "DEBUG") except Exception as e: - self._log(f"❌ 处理系统消息失败: {e}", "ERROR") + self._log(f"Error handling system message: {e}", "ERROR") def _parse_message_content(self, msg_data): """解析消息内容""" @@ -1644,19 +1579,23 @@ class DouYinMessageHandler: # 检查是否已有token,如果没有则先请求 if sender_id not in self.user_tokens or not self.user_tokens[sender_id].get("token"): self._log(f"🆕 用户 {sender_id} 无token,先请求token", "INFO") + # 创建用户对象(与旧版本保持一致,直接覆盖) self.user_tokens[sender_id] = { "token": None, "last_sent": 0, "session_initialized": False, "talk_id": talk_id, "p_id": p_id, - "pending_messages": [] # 存储等待发送的消息 + "pending_messages": [] } + # 请求token self._request_user_token(sender_id, p_id) - # 将当前消息加入待处理队列 self.user_tokens[sender_id]["pending_messages"].append(message_dict) return + else: + # 用户已有token,直接发送消息到后端 + self._log(f"✅ 用户 {sender_id} 已有token (长度: {len(self.user_tokens[sender_id]['token'])})", "DEBUG") # 预先定义默认值 (避免后续因为没有成功走到对应分支里产生的错误) # msg_type = "text" diff --git a/config.py b/config.py index d2b33e3..238defc 100644 --- a/config.py +++ b/config.py @@ -10,7 +10,7 @@ import json # 用于将令牌保存为 JSON 格式 # 后端服务器配置 # BACKEND_HOST = "192.168.5.233" # BACKEND_HOST = "192.168.5.106" -BACKEND_HOST = "192.168.5.140" +BACKEND_HOST = "192.168.5.12" # BACKEND_HOST = "shuidrop.com" # BACKEND_HOST = "test.shuidrop.com" BACKEND_PORT = "8000"