From b6ebcf4f5041f87ebe8b80ada79a030b660f4215 Mon Sep 17 00:00:00 2001 From: EFrostBlade <3171264475@qq.com> Date: Sun, 16 Jun 2024 18:12:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E4=B8=80=E4=B8=AApy?= =?UTF-8?q?thon=20demo=EF=BC=8C=E5=88=9B=E5=BB=BA=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E7=AA=97=E5=8F=A3=EF=BC=8C=E8=A7=A3=E6=9E=90=E5=B9=B6?= =?UTF-8?q?=E5=9C=A8=E7=AA=97=E5=8F=A3=E4=B8=AD=E6=98=BE=E7=A4=BA=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E5=90=8E=E7=9A=84=E7=9B=B4=E6=92=AD=E9=97=B4=E6=B6=88?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Demos/Python/LogWindow.py | 291 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 Demos/Python/LogWindow.py diff --git a/Demos/Python/LogWindow.py b/Demos/Python/LogWindow.py new file mode 100644 index 0000000..22e911d --- /dev/null +++ b/Demos/Python/LogWindow.py @@ -0,0 +1,291 @@ +# ruff: noqa: F401,F403,F405,E402,F541,E722 +import asyncio +import websockets +import json +import os +import ctypes +import sys +import time +import winreg +import tkinter as tk +from tkinter import ttk +import customtkinter +import subprocess +import random +import threading +import atexit +import psutil +import queue + +# 创建一个队列 +gui_queue = queue.Queue() + +# 创建一个线程安全的标志 +stop_flag = threading.Event() + + +def is_admin(): + try: + return ctypes.windll.shell32.IsUserAnAdmin() + except: + return False + + +def disable_proxy(): + internet_settings = winreg.OpenKey( + winreg.HKEY_CURRENT_USER, + r"Software\Microsoft\Windows\CurrentVersion\Internet Settings", + 0, + winreg.KEY_ALL_ACCESS, + ) + + # 设置代理使能为0(禁用) + winreg.SetValueEx(internet_settings, "ProxyEnable", 0, winreg.REG_DWORD, 0) + # 清空代理服务器信息 + winreg.SetValueEx(internet_settings, "ProxyServer", 0, winreg.REG_SZ, "") + + winreg.CloseKey(internet_settings) + print("Proxy disabled.") + + +def initGame(): + print("Init game.") + pass + + +class App(customtkinter.CTk): + def __init__(self): + super().__init__() + + self.title("dy-barrage-grab-log-window") + self.geometry("800x600") + self.grid_columnconfigure((0, 1), weight=1) + self.grid_rowconfigure(0, weight=1) + self.LogFrame = LogFrame(self) + self.LogFrame.grid(row=0, column=0, sticky="nsew") + + +class LogFrame(customtkinter.CTkFrame): + def __init__(self, master): + super().__init__(master) + + # 创建一个Frame来包含treeview和滚动条 + self.tree_frame = ttk.Frame(self) + self.tree_frame.grid(row=0, column=0, sticky="nsew", padx=50, pady=50) + + # 创建一个滚动条 + self.scrollbar = customtkinter.CTkScrollbar(self.tree_frame) + self.scrollbar.grid(row=0, column=1, sticky="ns") + + self.treeview = ttk.Treeview( + self.tree_frame, + columns=("Type", "User ID", "User Nickname", "Content"), + show="headings", + height=20, + yscrollcommand=self.scrollbar.set, # 将滚动条与treeview关联 + ) + self.treeview.grid(row=0, column=0, sticky="nsew") + + # 设置滚动条的命令为移动treeview + self.scrollbar.configure(command=self.treeview.yview) + + # 设置列宽 + self.treeview.column("Type", width=50) + self.treeview.column("User ID", width=100) + self.treeview.column("User Nickname", width=100) + self.treeview.column("Content", width=450) + + self.treeview.heading("Type", text="Type") + self.treeview.heading("User ID", text="User ID") + self.treeview.heading("User Nickname", text="User Nickname") + self.treeview.heading("Content", text="Content") + + # 设置不同类型的颜色 + self.treeview.tag_configure("type1", foreground="black") + self.treeview.tag_configure("type2", foreground="cyan") + self.treeview.tag_configure("type3", foreground="gold") + self.treeview.tag_configure("type4", foreground="blue") + self.treeview.tag_configure("type5", foreground="red") + self.treeview.tag_configure("type6", foreground="purple") + self.treeview.tag_configure("type7", foreground="green") + self.treeview.tag_configure("type8", foreground="orange") + self.treeview.tag_configure("type9", foreground="gray") + # 添加更多类型的颜色配置... + + def display_message(self, message): + parsed_message = json.loads(message) + message_type = parsed_message.get("Type") + + data_str = parsed_message.get("Data", "{}") + try: + data = json.loads(data_str) + except json.JSONDecodeError: + print(f"Cannot parse 'Data' as JSON: {data_str}") + return + user = data.get("User", {}) + if user is None: + # print(f"'User' is None in 'Data': {data_str}") + user = {"Id": "无", "Nickname": "无"} + user_id = user.get("Id", "") + user_nickname = user.get("Nickname", "") + content = data.get("Content", "") + # 根据类型设置颜色 + color_tag = f"type{message_type}" + message_type_str = [ + "无", + "弹幕", + "点赞", + "进房", + "关注", + "礼物", + "统计", + "粉团", + "分享", + "下播", + ] + self.treeview.insert( + "", + "end", + values=( + message_type_str[message_type], + user_id, + user_nickname, + content, + ), + tags=(color_tag,), + ) + + +# async def send_ping(websocket): +# while True: +# try: +# if websocket.open: +# await websocket.ping() +# await asyncio.sleep(5) +# else: +# break +# except websockets.exceptions.ConnectionClosedOK: +# # 连接已关闭,尝试重新连接 +# websocket = await websockets.connect("ws://127.0.0.1:8888") + + +async def receive_messages(): + while True: + try: + async with websockets.connect( + "ws://127.0.0.1:8888", ping_timeout=None, ping_interval=None + ) as websocket: + while True: + message = await websocket.recv() + if message is not None: + try: + json.loads(message) + app.LogFrame.display_message(message) + except json.JSONDecodeError: + print( + f"Received a message that could not be parsed as JSON: {message}" + ) + except ( + websockets.ConnectionClosed, + websockets.exceptions.ConnectionClosedError, + websockets.exceptions.ConnectionClosedOK, + ) as e: + print(f"Connection closed, retrying...{e}") + continue + except Exception as e: + print(f"An error occurred on ws server: {e}") + continue + + +def main(): + global listener_process + global app + # Check if the process is already running + for proc in psutil.process_iter(): + if proc.name() == "WssBarrageServer.exe": + print("The process is already running.") + proc.kill() + time.sleep(1) + + # Start a new process + # 将WssBarrageServer.exe放至同目录下dy-barrage-grab文件夹 + # 获取当前脚本的绝对路径 + script_dir = os.path.dirname(os.path.realpath(__file__)) + # 构建WssBarrageServer.exe的绝对路径 + exe_path = os.path.join(script_dir, "dy-barrage-grab", "WssBarrageServer.exe") + + # 使用绝对路径启动进程 + listener_process = subprocess.Popen(exe_path) + # 创建一个新的事件循环 + loop = asyncio.new_event_loop() + # 设置这个事件循环为当前线程的事件循环 + asyncio.set_event_loop(loop) + app = App() + + # 点击关闭按钮时调用的函数 + def on_close(): + print("Closing...") + # 设置停止标志 + stop_flag.set() + # 关闭WssBarrageServer + listener_process.terminate() + # 关闭代理 + disable_proxy() + # 退出程序 + os._exit(0) + + # 设置关闭按钮的回调函数 + app.protocol("WM_DELETE_WINDOW", on_close) + # 在事件循环中创建新的异步任务 + loop.create_task(receive_messages()) + + def update(): + # 更新Tkinter的界面 + app.update() + # 在事件循环中定期调用update方法 + loop.call_soon(update) + + # 检查队列中是否有任务 + while not gui_queue.empty(): + # 获取任务并执行 + task = gui_queue.get() + task() + + # 在事件循环中定期调用update方法 + loop.call_soon(update) + try: + # 运行事件循环 + loop.run_forever() + except Exception as e: + print(f"An error occurred in loop: {e}") + finally: + # 关闭事件循环 + loop.close() + + +if __name__ == "__main__": + if is_admin(): + # 如果已经是管理员权限,那么直接运行你的代码 + print("Running as administrator.") + pass + else: + # 如果不是管理员权限,那么以管理员权限重新启动程序 + print("Running as non-administrator.") + ctypes.windll.shell32.ShellExecuteW( + None, "runas", sys.executable, " ".join(sys.argv), None, 1 + ) + # try: + main() +# except Exception as e: +# print(f"An error occurred: {e}") +# finally: +# # 这里结束进程 +# listener_process.terminate() + + +# 注册一个函数,在程序结束时调用 +def on_exit(): + listener_process.terminate() + + +atexit.register(on_exit)