添加几个功能

This commit is contained in:
liyp 2023-12-24 20:45:07 +08:00
parent a9bcd96046
commit 96518ebc5d
2 changed files with 166 additions and 14 deletions

4
.gitignore vendored
View file

@ -1 +1,3 @@
.venv .venv
main/test.py
main/test1.py

View file

@ -1,14 +1,25 @@
import sys import sys
import platform
import requests import requests
from PyQt5.QtWidgets import QApplication, QMainWindow, QSystemTrayIcon, QMenu, QAction,QActionGroup from PyQt5.QtWidgets import QApplication, QMainWindow, QSystemTrayIcon, QMenu, QAction,QActionGroup
from PyQt5.QtGui import QIcon from PyQt5.QtGui import QIcon
from PyQt5.QtCore import QTimer,pyqtSignal,QThread
import json
import aiohttp
import asyncio
class TrayIconExample(QMainWindow): class TrayIconExample(QMainWindow):
speed_data = pyqtSignal(dict)
def __init__(self): def __init__(self):
super(TrayIconExample, self).__init__() super(TrayIconExample, self).__init__()
self.init_ui() self.init_ui()
# 启动异步任务
self.worker_thread = WorkerThread(self)
self.worker_thread.data_ready.connect(self.update_speed_data)
self.worker_thread.start()
def init_ui(self): def init_ui(self):
self.setWindowTitle('Clash Tray') self.setWindowTitle('Clash Tray')
@ -23,11 +34,39 @@ class TrayIconExample(QMainWindow):
exit_action = QAction('退出', self) exit_action = QAction('退出', self)
self.tun_mode = QAction('TUN模式', self) self.tun_mode = QAction('TUN模式', self)
self.tun_mode.setCheckable(True) self.tun_mode.setCheckable(True)
# 获取环境变量
self.copy_env=QAction('复制环境变量',self)
# 创建一个 QActionGroup self.more_menu=QMenu('更多',self)
self.upload_speed=QAction('⬆️上传速度',self)
self.download_speed=QAction('⬇️下载速度',self)
self.upload_speed.setCheckable(False)
self.upload_speed.setEnabled(False)
self.download_speed.setCheckable(False)
self.download_speed.setEnabled(False)
# self.timer = QTimer(self)
# self.timer.timeout.connect(self.update_data)
# self.timer.start(1000) # 定时器间隔为1000毫秒1秒
# 更多 子菜单项设置
self.version=self.get_version()
self.show_version = QAction('内核版本:'+self.version, self)
self.show_version.setCheckable(False)
self.show_version.setEnabled(False)
self.restart_core=QAction('重启Clash',self)
self.more_menu.addAction(self.restart_core)
self.more_menu.addAction(self.show_version)
self.restart_core.triggered.connect(self.restart_clash)
# 创建代理模式 QActionGroup
proxy_mode_group = QActionGroup(self) proxy_mode_group = QActionGroup(self)
proxy_mode_group.setExclusive(True) # 设置为单选模式 proxy_mode_group.setExclusive(True) # 设置为单选模式
# 设置代理模式菜单
self.direct_mode=QAction('直连模式',self) self.direct_mode=QAction('直连模式',self)
self.rule_mode=QAction('规则模式',self) self.rule_mode=QAction('规则模式',self)
self.global_mode=QAction('全局模式',self) self.global_mode=QAction('全局模式',self)
@ -39,12 +78,20 @@ class TrayIconExample(QMainWindow):
proxy_mode_group.addAction(self.rule_mode) proxy_mode_group.addAction(self.rule_mode)
proxy_mode_group.addAction(self.global_mode) proxy_mode_group.addAction(self.global_mode)
self.tun_mode.triggered.connect(self.change_tun_mode)
exit_action.triggered.connect(self.exit_application) exit_action.triggered.connect(self.exit_application)
# 将菜单添加到托盘图标
context_menu.addAction(self.tun_mode) context_menu.addAction(self.tun_mode)
context_menu.addMenu(proxy_mode) context_menu.addMenu(proxy_mode)
context_menu.addAction(self.copy_env)
context_menu.addAction(exit_action) context_menu.addMenu(self.more_menu)
context_menu.addActions([self.upload_speed,self.download_speed,exit_action])
proxy_mode.addActions([self.direct_mode,self.rule_mode,self.global_mode]) proxy_mode.addActions([self.direct_mode,self.rule_mode,self.global_mode])
self.copy_env.triggered.connect(self.copy_env_var)
self.direct_mode.triggered.connect(lambda:self.set_proxy_mode(0)) self.direct_mode.triggered.connect(lambda:self.set_proxy_mode(0))
self.rule_mode.triggered.connect(lambda:self.set_proxy_mode(1)) self.rule_mode.triggered.connect(lambda:self.set_proxy_mode(1))
self.global_mode.triggered.connect(lambda:self.set_proxy_mode(2)) self.global_mode.triggered.connect(lambda:self.set_proxy_mode(2))
@ -57,7 +104,14 @@ class TrayIconExample(QMainWindow):
tray_icon.show() tray_icon.show()
self.get_config() self.get_config()
self.setGeometry(100, 100, 800, 600) self.setGeometry(200, 200, 1200, 800)
def restart_clash(self):
url,port=self.get_connect()
data={'path': '','payload': ''}
response=requests.post(url=url+':'+port+'/restart').json()
if response['status']=='ok':
print('重启成功')
def get_connect(self,url=None,port=None): def get_connect(self,url=None,port=None):
url='http://127.0.0.1' url='http://127.0.0.1'
@ -83,34 +137,130 @@ class TrayIconExample(QMainWindow):
self.tun_mode.setChecked(True) self.tun_mode.setChecked(True)
else: else:
self.tun_mode.setChecked(False) self.tun_mode.setChecked(False)
return response
def get_version(self):
url,port=self.get_connect()
response=requests.get(url=url+':'+port+'/version')
if response.status_code==200:
res=response.json()
print('version',res)
return res['version']
def set_proxy_mode(self,type): def set_proxy_mode(self,type):
mode=None mode=None
if type==0: if type==0:
mode='direct' mode='direct'
# self.rule_mode.setChecked(True)
elif type==1: elif type==1:
mode='rule' mode='rule'
# self.rule_mode.setChecked(True)
elif type==2: elif type==2:
mode='global' mode='global'
# self.global_mode.setChecked(True)
url,port=self.get_connect() url,port=self.get_connect()
data = {"mode": mode} data = {"mode": mode}
response=requests.patch(url=url+':'+port+'/configs?force=true',json=data) response=requests.patch(url=url+':'+port+'/configs?force=true',json=data)
if response.status_code==204: if response.status_code==204:
self.get_config() self.get_config()
def change_tun_mode(self):
url,port=self.get_connect()
print(self.tun_mode.isChecked())
data = {"tun": {"enable": False if self.tun_mode.isChecked() else True}}
print(data)
response=requests.patch(url=url+':'+port+'/configs?force=true',json=data)
if response.status_code==204:
self.get_config()
def copy_env_var(self):
sys_info=platform.uname()
clipboard = QApplication.clipboard()
env_var=''
# print(sys_info.system)
if sys_info.system == ('Linux' or 'Darwin'):
env_var='export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7890'
elif sys_info.system == 'Windows':
env_var='setx https_proxy=http://127.0.0.1:7890\nsetx http_proxy=http://127.0.0.1:7890\nsetx all_proxy=socks5://127.0.0.1:7890'
# print(env_var)
clipboard.setText(env_var)
def update_speed_data(self,data):
print(data)
upload=data['up']
down=data['down']
if upload /1024<=1024 or down /1024<=1024:
upload=round(upload/1024,2)
down=round(down/1024,2)
self.upload_speed.setText('上传速度:'+str(upload)+'KB/s')
self.download_speed.setText('下载速度:'+str(down)+'KB/s')
else:
upload=round(upload/1024/1024,2)
down=round(down/1024/1024,2)
self.upload_speed.setText('上传速度:'+str(upload)+'MB/s')
self.download_speed.setText('下载速度:'+str(down)+'MB/s')
pass
def exit_application(self): def exit_application(self):
QApplication.quit() QApplication.quit()
# async def fetch_and_output_data(self):
# url = "http://127.0.0.1:9090/traffic" # 替换为实际的 API 地址
# async with aiohttp.ClientSession() as session:
# async with session.get(url, timeout=None) as response: # timeout=None 表示不设置超时
# while True:
# partial_data = await response.content.read(100) # 每次读取100字节的数据示例
# if not partial_data:
# break # 如果没有更多数据,退出循环
# # 在此处可以进行异步加载部分数据的操作,例如使用 Qt 的异步加载机制
# # print("Partial data:", partial_data)
# # 将字节数据转换为字符串
# partial_data_str = partial_data.decode('utf-8')
# print(partial_data_str)
# # 将字符串解析为 JSON 对象
# try:
# partial_data_json = json.loads(partial_data_str)
# print("Partial data:", partial_data_json)
# self.speed_data.emit(partial_data_json)
# except json.JSONDecodeError as e:
# print(f"Error decoding JSON: {e}")
# await asyncio.sleep(1) # 休眠1秒模拟每秒输出一部分数据
class WorkerThread(QThread):
data_ready = pyqtSignal(dict)
def run(self):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(self.fetch_and_output_data())
async def fetch_and_output_data(self):
url = "http://127.0.0.1:9090/traffic"
async with aiohttp.ClientSession() as session:
async with session.get(url, timeout=None) as response:
while True:
partial_data = await response.content.read(100)
if not partial_data:
break
partial_data_str = partial_data.decode('utf-8')
try:
partial_data_json = json.loads(partial_data_str)
self.data_ready.emit(partial_data_json)
except json.JSONDecodeError as e:
print(f"解析 JSON 时出错:{e}")
await asyncio.sleep(1)
if __name__ == '__main__': if __name__ == '__main__':
app = QApplication(sys.argv) app = QApplication(sys.argv)
window = TrayIconExample() window = TrayIconExample()