diff --git a/liveMan.py b/liveMan.py index c57b6e7..1d8197d 100644 --- a/liveMan.py +++ b/liveMan.py @@ -28,6 +28,24 @@ from ws_server import push_to_frontend import asyncio from dataclasses import asdict +# TTS 播报引擎(全局只初始化一次) +tts_engine = pyttsx3.init() +tts_engine.setProperty('rate', 170) +tts_engine.setProperty('volume', 1.0) + +# 加锁防止多线程同时播报冲突 +tts_lock = threading.Lock() + +def speak(text: str): + """线程安全地进行语音播报""" + try: + with tts_lock: + tts_engine.say(text) + tts_engine.runAndWait() + except Exception as e: + print("【X】TTS 播报失败:", e) + + @contextmanager def patched_popen_encoding(encoding='utf-8'): original_popen_init = subprocess.Popen.__init__ @@ -306,14 +324,34 @@ class DouyinLiveWebFetcher: user_name = message.user.nick_name gift_name = message.gift.name gift_cnt = message.combo_count - print(f"【礼物msg】{user_name} 送出了 {gift_name}x{gift_cnt}") + print('送了礼物呀') + # print(f"【礼物msg】{user_name} 送出了 {gift_name}x{gift_cnt}") + user_data = asdict(message.user) + try: + speak(f"谢谢{user_name}送的小星星") + push_to_frontend(user_data,'gift') + except Exception as e: + print("【礼物播报失败:", e) def _parseLikeMsg(self, payload): '''点赞消息''' - message = LikeMessage().parse(payload) + # message = LikeMessage().parse(payload) user_name = message.user.nick_name - count = message.count - print(f"【点赞msg】{user_name} 点了{count}个赞") + # count = message.count + # print('点了攒') + # # print(f"【点赞msg】{user_name} 点了{count}个赞") + # user_data = asdict(message.user) + try: + message = LikeMessage().parse(payload) + user_name = message.user.nick_name + count = message.count + print('点了攒') + # print(f"【点赞msg】{user_name} 点了{count}个赞") + user_data = asdict(message.user) + speak(f"谢谢{user_name}点赞") + push_to_frontend(user_data,'like') + except Exception as e: + print("【点赞播报失败:", e) # def _parseMemberMsg(self, payload): # '''进入直播间消息''' @@ -326,26 +364,14 @@ class DouyinLiveWebFetcher: '''进入直播间消息''' message = MemberMessage().parse(payload) user_name = message.user.nick_name - user_id = message.user.id - gender = ["女", "男"][message.user.gender] - # avatar = message.user.avatar + print(f"【进场msg】{user_name} 进入了直播间") user_data = asdict(message.user) - # user_data = { - # "user_id": user_id, - # "user_name": user_name, - # "gender": gender, - # } - # ✅ 播放语音播报 try: - # engine = pyttsx3.init() - # engine.setProperty('rate', 170) # 语速,建议范围 120-200 - # engine.setProperty('volume', 1.0) # 音量 0.0 ~ 1.0 - # # engine.say(f"{gender}观众 {user_name} 进入了直播间") - # engine.say(f"{user_name}进入了直播间") - # engine.runAndWait() + # ✅ 播放语音播报 + speak(f"{user_name}进入了直播间") # 推送给 WebSocket 客户端 - push_to_frontend(user_data) + push_to_frontend(user_data,'join') except Exception as e: print("【X】TTS 播报失败:", e) diff --git a/main.py b/main.py index 78c0d4f..e16a16b 100644 --- a/main.py +++ b/main.py @@ -26,6 +26,8 @@ time.sleep(1) # ✅ 主程序启动直播监听 if __name__ == '__main__': live_id = '9638535297' + # live_id = '262648053209' + room = DouyinLiveWebFetcher(live_id) room.get_room_status() room.start() diff --git a/ws_server.py b/ws_server.py index 7fe2cc6..70a6241 100644 --- a/ws_server.py +++ b/ws_server.py @@ -17,10 +17,10 @@ async def ws_handler(websocket): connected_clients.remove(websocket) # 推送消息到所有前端 -async def push_to_all_clients(user_data: dict): +async def push_to_all_clients(user_data: dict,type: str = "join"): # ✅ 直接发送结构化 JSON message = { - "type": "join", + "type": type, "data": user_data } for client in connected_clients.copy(): @@ -35,12 +35,12 @@ async def ws_main(): await asyncio.Future() # 永远挂起,保持服务运行 # 主线程中调用这个方法推送消息 -def push_to_frontend(user_data): +def push_to_frontend(user_data, type: str = "join"): loop = asyncio.get_event_loop() if loop.is_running(): - asyncio.run_coroutine_threadsafe(push_to_all_clients(user_data), loop) + asyncio.run_coroutine_threadsafe(push_to_all_clients(user_data, type), loop) else: - loop.run_until_complete(push_to_all_clients(user_data)) + loop.run_until_complete(push_to_all_clients(user_data, type)) # 在线程中启动服务 def start_ws_server():