diff --git a/README.md b/README.md index 51ca5e0..0df6779 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ V2Ray 项目地址:https://github.com/v2ray/v2ray-core # v2rayL -![v2rayL](http://cloud.thinker.ink/images/v2rayLlogo.png) +![v2rayL](http://cloud.thinker.ink/images/857633d396d9f89cc606c0666194f45f.png) v2ray linux 客户端,使用pyqt5编写GUI界面,核心基于v2ray-core @@ -19,13 +19,15 @@ v2ray linux 客户端,使用pyqt5编写GUI界面,核心基于v2ray-core - 通过`vmess://`、`ss://`分享链接添加配置,通过二维码添加配置 - 导出配置、生成配置分享链接、生成分享二维码 - 最小化至托盘、测试延时、右键菜单 +- 检查更新 - ...... +其中vmess支持websocket、mKcp 目前程序可能存在一些bug但是没有测试出,若在使用过程中发现bug,请在issue中提交,以便改进。 # Usage -## 安装 +## install ``` ① 在release中下载最新版本的install.sh ``` @@ -33,7 +35,7 @@ v2ray linux 客户端,使用pyqt5编写GUI界面,核心基于v2ray-core ② 运行 ./install.sh ``` -## 更新 +## update ``` ① 在release中下载最新版本的update.sh ``` @@ -41,9 +43,9 @@ v2ray linux 客户端,使用pyqt5编写GUI界面,核心基于v2ray-core ② 运行 ./update.sh ``` -# 首页展示 +# Home page -![首页](http://cloud.thinker.ink/images/0bbd5564f4c123f24089d9134bcd6fe0.png) +![首页](http://cloud.thinker.ink/images/f366165b6daced76427a6f8a89cc4168.png) # License diff --git a/v2rayL-GUI/config.py b/v2rayL-GUI/config.py index 1347bd1..abdacad 100755 --- a/v2rayL-GUI/config.py +++ b/v2rayL-GUI/config.py @@ -3,51 +3,81 @@ # Date: 2019-08-13 conf_template = { - "log":{}, - "dns":{}, - "stats":{}, - "inbounds":[ - { - "port":"1080", - "protocol":"socks", - "settings":{ - "auth":"noauth", - "udp": True - }, - "tag":"in-0" - } - ], - "outbounds":[ - { - "protocol":"", - "settings":{}, - "tag":"out-0", - "streamSettings":{} - }, - { - "tag":"direct", - "protocol":"freedom", - "settings":{} + "dns": { + "servers": [ + "1.1.1.1" + ] + }, + "inbounds": [{ + "port": 1080, + "protocol": "socks", + "settings": { + "auth": "noauth", + "udp": True, + "userLevel": 8 + }, + "sniffing": { + "destOverride": [ + "http", + "tls" + ], + "enabled": True + }, + "tag": "socks" }, { - "tag":"blocked", - "protocol":"blackhole", - "settings":{} + "port": 1081, + "protocol": "http", + "settings": { + "userLevel": 8 + }, + "tag": "http" } ], - "routing":{ - "domainStrategy":"IPOnDemand", - "rules":[ + "log": { + "loglevel": "warning" + }, + "outbounds": [{ + "mux": { + "enabled": False + }, + "protocol": "", + "settings": {}, + "streamSettings": {}, + "tag": "proxy" + }, + { + "protocol": "freedom", + "settings": {}, + "tag": "direct" + }, { - "type":"field", - "ip":[ - "geoip:private" - ], - "outboundTag":"direct" + "protocol": "blackhole", + "settings": { + "response": { + "type": "http" + } + }, + "tag": "block" } - ] + ], + "policy": { + "levels": { + "8": { + "connIdle": 300, + "downlinkOnly": 1, + "handshake": 4, + "uplinkOnly": 1 + } + }, + "system": { + "statsInboundUplink": True, + "statsInboundDownlink": True + } + }, + "routing": { + "domainStrategy": "IPIfNonMatch", + "rules": [] }, - "policy":{}, - "reverse":{}, - "transport":{} + "stats": {} } \ No newline at end of file diff --git a/v2rayL-GUI/sub2conf_api.py b/v2rayL-GUI/sub2conf_api.py index af7fbf5..4f54894 100755 --- a/v2rayL-GUI/sub2conf_api.py +++ b/v2rayL-GUI/sub2conf_api.py @@ -43,7 +43,7 @@ def b642conf(self, prot, tp, b64str): ret = eval(base64.b64decode(b64str).decode()) region = ret['ps'] - elif prot == "ss": + elif prot == "shadowsocks": string = b64str.split("#") cf = string[0].split("@") if len(cf) == 1: @@ -75,22 +75,49 @@ def setconf(self, region): "users": [ { "id": use_conf["id"], - "alterId": use_conf["aid"] + "alterId": int(use_conf["aid"]), + "security": "auto", + "level": 8, } ] }) - - conf['outbounds'][0]["streamSettings"] = { - "network": use_conf["net"], - "wsSettings": { - "path": use_conf["path"], - "headers": { - "Host": use_conf['host'] + # webSocket 协议 + if use_conf["net"] == "ws": + conf['outbounds'][0]["streamSettings"] = { + "network": use_conf["net"], + "security": "tls" if use_conf["tls"] else "", + "tlssettings": { + "allowInsecure": True, + "serverName": use_conf["tls"] + }, + "wssettings": { + "connectionReuse": True, + "headers": { + "Host": use_conf['host'] + }, + "path": use_conf["path"] } } - } + # mKcp协议 + elif use_conf["net"] == "kcp": + conf['outbounds'][0]["streamSettings"] = { + "network": use_conf["net"], + "kcpsettings": { + "congestion": False, + "downlinkCapacity": 100, + "header": { + "type": use_conf["type"] if use_conf["type"] else "none" + }, + "mtu": 1350, + "readBufferSize": 1, + "tti": 50, + "uplinkCapacity": 12, + "writeBufferSize": 1 + }, + "security": "" + } - elif use_conf['prot'] == "ss": + elif use_conf['prot'] == "shadowsocks": conf['outbounds'][0]["protocol"] = "shadowsocks" conf['outbounds'][0]["settings"]["servers"] = list() conf['outbounds'][0]["settings"]["servers"].append({ @@ -143,7 +170,7 @@ def update(self): if ori[0] == "vmess": self.b642conf("vmess", 1, ori[1]) elif ori[0] == "ss": - self.b642conf("ss", 1, ori[1]) + self.b642conf("shadowsocks", 1, ori[1]) self.conf = dict(self.saved_conf['local'], **self.saved_conf['subs']) @@ -159,7 +186,7 @@ def add_conf_by_uri(self): if op[0] == "vmess": self.b642conf("vmess", 0, op[1]) elif op[0] == "ss": - self.b642conf("ss", 0, op[1]) + self.b642conf("shadowsocks", 0, op[1]) else: raise MyException("无法解析的链接格式") except Exception as e: diff --git a/v2rayL-GUI/v2rayL_api.py b/v2rayL-GUI/v2rayL_api.py index 0293ae3..549a67e 100755 --- a/v2rayL-GUI/v2rayL_api.py +++ b/v2rayL-GUI/v2rayL_api.py @@ -65,7 +65,7 @@ def disconnect(self): else: raise MyException("服务未开启,无需断开连接.") except Exception as e: - raise MyException(e) + raise MyException(e.args[0]) def update(self, url): if url: # 如果存在订阅地址 diff --git a/v2rayL-GUI/v2rayL_threads.py b/v2rayL-GUI/v2rayL_threads.py index 73dfbb6..40600d1 100755 --- a/v2rayL-GUI/v2rayL_threads.py +++ b/v2rayL-GUI/v2rayL_threads.py @@ -3,7 +3,11 @@ # Date: 2019-08-13 from PyQt5.QtCore import QThread, pyqtSignal +from PyQt5.QtWidgets import QMessageBox from sub2conf_api import MyException +import subprocess +import requests + class ConnectThread(QThread): @@ -23,7 +27,7 @@ def run(self): try: row = self.tableView.currentIndex().row() region = self.tableView.model().item(row, 0).text() - except Exception as e: + except AttributeError: self.sinOut.emit(("conn", "@@Fail@@", "未选中配置无法连接,请导入配置后再次连接", None)) else: try: @@ -115,5 +119,70 @@ def run(self): ret = self.v2rayL.ping(addr) except MyException as e: self.sinOut.emit(("ping", "@@Fail@@", e.args[0], None)) + except AttributeError: + self.sinOut.emit(("ping", "@@Fail@@", "请选择需要测试的配置.", None)) else: - self.sinOut.emit(("ping", "@@OK@@", ret.strip(), None)) \ No newline at end of file + self.sinOut.emit(("ping", "@@OK@@", ret.strip(), None)) + + +class CheckUpdateThread(QThread): + """ + 测试延时线程 + """ + sinOut = pyqtSignal(tuple) + + def __init__(self, version=None, parent=None): + super(CheckUpdateThread, self).__init__(parent) + self.version = version + + def __del__(self): + # 线程状态改变与线程终止 + self.wait() + + def run(self): + update_url = "https://api.github.com/repos/jiangxufeng/v2rayL/releases/latest" + try: + req = requests.get(update_url) + if req.status_code != 200: + self.sinOut.emit(("ckud", "@@Fail@@", "网络错误,请检查网络连接或稍后再试.", None)) + else: + latest = req.json()['tag_name'] + if latest == self.version: + self.sinOut.emit(("ckud", "@@OK@@", "当前版本已是最新版本.", None)) + else: + self.sinOut.emit(("ckud", "@@OK@@", "正在后台进行更新..", req)) + except Exception as e: + self.sinOut.emit(("ckud", "@@Fail@@", "网络错误,请检查网络连接或稍后再试."+e.args[0], None)) + + +class VersionUpdateThread(QThread): + """ + 测试延时线程 + """ + sinOut = pyqtSignal(tuple) + + def __init__(self, update_url=None, parent=None): + super(VersionUpdateThread, self).__init__(parent) + self.url = update_url + + def __del__(self): + # 线程状态改变与线程终止 + self.wait() + + def run(self): + try: + req = requests.get(self.url) + if req.status_code != 200: + self.sinOut.emit(("vrud", "@@Fail@@", "网络错误,请检查网络连接或稍后再试.", None)) + else: + print(1) + with open("/etc/v2rayL/update.sh", 'w') as f: + f.write(req.text) + + subprocess.call(["chmod +x /etc/v2rayL/update.sh && /etc/v2rayL/update.sh"], shell=True) + + self.sinOut.emit(("vrud", "@@OK@@", "更新完成, 重启程序生效.", None)) + + except Exception as e: + self.sinOut.emit(("vrud", "@@Fail@@", "网络错误,请检查网络连接或稍后再试."+e.args[0], None)) + diff --git a/v2rayL-GUI/v2rayLui.py b/v2rayL-GUI/v2rayLui.py index 1ba44dc..906c326 100644 --- a/v2rayL-GUI/v2rayLui.py +++ b/v2rayL-GUI/v2rayLui.py @@ -33,7 +33,14 @@ from datetime import datetime import pyzbar.pyzbar as pyzbar from PIL import Image -from v2rayL_threads import ConnectThread, DisConnectThread, UpdateSubsThread, PingThread +from v2rayL_threads import ( + ConnectThread, + DisConnectThread, + UpdateSubsThread, + PingThread, + CheckUpdateThread, + VersionUpdateThread +) @@ -68,6 +75,8 @@ def setupUi(self, MainWindow): self.menu_5.setObjectName("menu_5") self.menu_2 = QMenu(self.menubar) self.menu_2.setObjectName("menu_2") + self.menu_6 = QMenu(self.menubar) + self.menu_6.setObjectName("menu_6") MainWindow.setMenuBar(self.menubar) self.toolBar = QToolBar(MainWindow) self.toolBar.setObjectName("toolBar") @@ -94,40 +103,28 @@ def setupUi(self, MainWindow): self.qr_share_ui = QAction(QIcon("/etc/v2rayL/images/qr.png"), "生成分享二维码", self) self.toolBar.addAction(self.qr_share_ui) - self.action = QAction(MainWindow) - self.action.setObjectName("action") - self.action_2 = QAction(MainWindow) - self.action_2.setObjectName("action_2") self.action_5 = QAction(MainWindow) self.action_5.setObjectName("action_5") - self.action_5.setShortcut('Ctrl+Q') self.action_6 = QAction(MainWindow) self.action_6.setObjectName("action_6") - self.action_6.setShortcut('Ctrl+W') self.action_8 = QAction(MainWindow, checkable=True) self.action_8.setObjectName("action_8") - self.action_8.setShortcut('Ctrl+D') self.action_9 = QAction(MainWindow, checkable=True) - self.action_9.setShortcut('Ctrl+F') self.action_9.setObjectName("action_9") self.action_10 = QAction(MainWindow) self.action_10.setObjectName("action_10") - self.action_10.setShortcut('F1') self.action_24 = QAction(MainWindow) self.action_24.setObjectName("action_24") - self.action_24.setShortcut('F2') self.action_25 = QAction(MainWindow) self.action_25.setObjectName("action_25") - self.action_25.setShortcut('F3') self.action_26 = QAction(MainWindow) self.action_26.setObjectName("action_26") - self.action_26.setShortcut('Ctrl+H') self.action_27 = QAction(MainWindow) self.action_27.setObjectName("action_27") - self.action_27.setShortcut('F4') self.action_28 = QAction(MainWindow) self.action_28.setObjectName("action_28") - self.action_28.setShortcut('F5') + self.action_29 = QAction(MainWindow) + self.action_29.setObjectName("action_29") self.menu.addAction(self.action_10) self.menu.addSeparator() @@ -147,11 +144,13 @@ def setupUi(self, MainWindow): self.menu_4.addSeparator() self.menu_4.addAction(self.menu_5.menuAction()) self.menu_4.addSeparator() - self.menu_2.addSeparator() self.menu_2.addAction(self.action_26) self.menu_2.addSeparator() + self.menu_6.addAction(self.action_29) + self.menu_6.addSeparator() self.menubar.addAction(self.menu.menuAction()) self.menubar.addAction(self.menu_4.menuAction()) + self.menubar.addAction(self.menu_6.menuAction()) self.menubar.addAction(self.menu_2.menuAction()) self.rightMenu = QMenu(self) self.CN = self.rightMenu.addAction('连接') @@ -165,16 +164,15 @@ def setupUi(self, MainWindow): def retranslateUi(self, MainWindow): _translate = QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "V2rayL")) - MainWindow.setWindowIcon(QIcon("/etc/v2rayL/images/logo.png")) + MainWindow.setWindowIcon(QIcon("/etc/v2rayL/images/logo.ico")) self.menu.setTitle(_translate("MainWindow", "配置")) self.menu_3.setTitle(_translate("MainWindow", "添加")) self.menu_4.setTitle(_translate("MainWindow", "订阅")) self.menu_5.setTitle(_translate("MainWindow", "自动更新")) self.menu_2.setTitle(_translate("MainWindow", "帮助")) self.menu_1.setTitle(_translate("MainWindow", "分享")) + self.menu_6.setTitle(_translate("MainWindow", "设置")) self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar")) - self.action.setText(_translate("MainWindow", "订阅设置")) - self.action_2.setText(_translate("MainWindow", "更新订阅")) self.action_5.setText(_translate("MainWindow", "地址设置")) self.action_6.setText(_translate("MainWindow", "更新订阅")) self.action_8.setText(_translate("MainWindow", "开启")) @@ -185,6 +183,7 @@ def retranslateUi(self, MainWindow): self.action_26.setText(_translate("MainWindow", "说明")) self.action_27.setText(_translate("MainWindow", "链接分享")) self.action_28.setText(_translate("MainWindow", "二维码分享")) + self.action_29.setText(_translate("MainWindow", "检查更新")) class Ui_Subs_Dialog(object): @@ -300,7 +299,7 @@ def __init__(self, w): def initUI(self): # 设置托盘图标 - self.tp.setIcon(QIcon('/etc/v2rayL/images/logo.png')) + self.tp.setIcon(QIcon('/etc/v2rayL/images/logo.ico')) def quitApp(self): # 退出程序 @@ -322,11 +321,13 @@ def act(self, reason): self.w.show() def run(self): - a1 = QAction('&显示(Show)', triggered=self.w.show) - a2 = QAction('&退出(Exit)', triggered=self.quitApp) + a1 = QAction('恢复(Show)', triggered=self.w.show) + a2 = QAction('帮助(Help)', triggered=self.w.help) + a3 = QAction('退出(Exit)', triggered=self.quitApp) tpMenu = QMenu() tpMenu.addAction(a1) tpMenu.addAction(a2) + tpMenu.addAction(a3) self.tp.setContextMenu(tpMenu) self.tp.show() # 不调用show不会显示系统托盘消息,图标隐藏无法调用 @@ -342,7 +343,7 @@ def run(self): sys.exit(self.app.exec_()) # 持续对app的连接 -class MyMainWindow(QMainWindow, Ui_MainWindow): +class MyMainWindow(QMainWindow, Ui_MainWindow, SystemTray): def __init__(self, parent=None): super(MyMainWindow, self).__init__(parent) self.setupUi(self) @@ -358,6 +359,7 @@ def __init__(self, parent=None): self.qr_ui = QDialog() self.qr_child_ui = Ui_Qr_Dialog() self.qr_child_ui.setupUi(self.qr_ui) + self.version = "2.0.0" self.status_format = "当前状态: {}\t\t\t\t\t\t自动更新: {}" # 获取api操作 @@ -387,7 +389,6 @@ def __init__(self, parent=None): self.display_all_conf() self.status = self.status_format.format(self.v2rayL.current, ("开启" if self.v2rayL.auto else "关闭"), "NaN") self.statusbar.showMessage(self.status) - # 开启连接线程 self.conn_start = ConnectThread() @@ -398,6 +399,11 @@ def __init__(self, parent=None): self.update_subs_start = UpdateSubsThread() self.ping_start = PingThread(tv=(self.tableView, self.v2rayL)) + + # 检查版本更新线程 + self.check_update_start = CheckUpdateThread(version=self.version) + # 更新版本线程 + self.version_update_start = VersionUpdateThread() # 事件绑定 self.action_5.triggered.connect(self.subs_ui_show) # 显示订阅地址窗口 self.action_6.triggered.connect(self.update_subs) # 更新订阅 @@ -409,6 +415,7 @@ def __init__(self, parent=None): self.action_26.triggered.connect(self.help) # 显示帮助说明信息 self.action_27.triggered.connect(self.output_conf_by_uri) # 生成分享链接 self.action_28.triggered.connect(self.output_conf_by_qr) # 生成分享二维码 + self.action_29.triggered.connect(self.check_update) # 检查更新 self.subs_child_ui.pushButton_2.clicked.connect(self.subs_ui_hide) # 关闭订阅地址窗口 self.confs_child_ui.pushButton_2.clicked.connect(self.confs_ui_hide) # 显示配置窗口 self.subs_child_ui.pushButton.clicked.connect(self.change_subs_addr) # 更新订阅操作 @@ -426,22 +433,43 @@ def __init__(self, parent=None): self.update_subs_start.sinOut.connect(self.alert) # 得到反馈 self.ping_ui.triggered.connect(self.start_ping_th) # toolbar绑定ping程序 self.ping_start.sinOut.connect(self.alert) # 得到反馈 + self.check_update_start.sinOut.connect(self.alert) + self.version_update_start.sinOut.connect(self.alert) self.CN.triggered.connect(self.start_conn_th) # 右键菜单连接绑定 self.DISCN.triggered.connect(self.end_conn_th) # 右键菜单断开连接绑定 self.customContextMenuRequested.connect(self.rightMenuShow) # 显示右键菜单 # 设置最小化到托盘 - self.tray() + SystemTray(self) def help(self): QMessageBox.about(self, "说明", - self.tr("1. v2rayL当前版本:v1.1.4\n" + self.tr("1. v2rayL当前版本:v2.0.1\n" "2. github地址:https://github.com/jiangxufeng/v2rayL\n" "3. 目前支持协议有:Vmess、shadowsocks\n4. 支持通过分享链接、二维码导入和分享配置\n" "5. 双击选中配置可直接进行连接\n6. 程序可能存在未测试到的Bug,使用过程中发现Bug请在github提交")) - def tray(self): - # 创建托盘程序 - ti = SystemTray(self) + def check_update(self): + # update_url = "https://api.github.com/repos/jiangxufeng/v2rayL/releases/latest" + # try: + # req = requests.get(update_url) + # if req.status_code != 200: + # QMessageBox.critical(self, "检查更新", self.tr("网络错误,请检查网络连接或稍后再试.")) + # else: + # latest = req.json()['tag_name'] + # if latest == self.version: + # QMessageBox.information(self, "检查更新", self.tr("当前版本已是最新版本.")) + # else: + # choice = QMessageBox.question(self, "检查更新", "最新版本: v{}" + # "\n更新内容:\n{}\n是否更新?".format(req.json()['tag_name'], + # req.json()['body']), + # QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) + # if choice == QMessageBox.Yes: + # pass + # except Exception as e: + # self.statusbar.showMessage(self.status) + # QMessageBox.critical(self, "检查更新", self.tr("网络错误,请检查网络连接或稍后再试."+e.args[0])) + self.statusbar.showMessage("正在检查版本更新....") + self.check_update_start.start() def rightMenuShow(self, pos): self.rightMenu.exec_(QCursor.pos()) @@ -599,17 +627,21 @@ def del_conf(self): 移除一个配置 :return: """ - row = self.tableView.currentIndex().row() - region = self.tableView.model().item(row, 0).text() - if self.v2rayL.current == region: - QMessageBox.critical(self, "移除失败", self.tr("当前配置正在使用,无法移除.")) + try: + row = self.tableView.currentIndex().row() + region = self.tableView.model().item(row, 0).text() + except AttributeError: + QMessageBox.information(self, "移除通知", self.tr("未选择任何配置.")) else: - try: - self.v2rayL.delconf(region) - except MyException as e: - QMessageBox.critical(self, "移除失败", self.tr(e.args[0])) + if self.v2rayL.current == region: + QMessageBox.information(self, "移除通知", self.tr("当前配置正在使用,无法移除.")) else: - self.display_all_conf() + try: + self.v2rayL.delconf(region) + except MyException as e: + QMessageBox.critical(self, "移除失败", self.tr(e.args[0])) + else: + self.display_all_conf() def start_conn_th(self): """ @@ -675,11 +707,50 @@ def alert(self, tp): elif tp == "ping": self.status = self.status_format.format(self.v2rayL.current, ("开启" if self.v2rayL.auto else "关闭"))+ "\t\t\t\t\t\t所测延时: {}ms".format(ret) self.statusbar.showMessage(self.status) + + elif tp == "ckud": + if not row: + self.statusbar.showMessage(self.status) + QMessageBox.information(self, "检查更新", self.tr(ret)) + else: + + choice = QMessageBox.question(self, "检查更新", "最新版本: v{}" + "\n更新内容:\n{}\n是否更新?".format( + row.json()['tag_name'], + row.json()['body']), + QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) + if choice == QMessageBox.Yes: + self.statusbar.showMessage(ret) + self.version_update_start.url = row.json()["assets"][1]['browser_download_url'] + self.version_update_start.start() + + elif tp == "vrud": + self.statusbar.showMessage(self.status) + QMessageBox.information(self, "更新成功", self.tr(ret)) + else: - QMessageBox.critical(self, "错误", self.tr(ret)) if tp == "addr": + QMessageBox.critical(self, "地址设置错误", self.tr(ret)) self.subs_child_ui.lineEdit.setText(self.v2rayL.url) + elif tp == "conn": + QMessageBox.critical(self, "连接错误", self.tr(ret)) + self.statusbar.showMessage(self.status) + self.connect_ui.setEnabled(True) + self.disconnect_ui.setDisabled(True) + + elif tp == "disconn": + QMessageBox.critical(self, "断开连接错误", self.tr(ret)) + self.statusbar.showMessage(self.status) + + elif tp == "ckud": + self.statusbar.showMessage(self.status) + QMessageBox.critical(self, "检查更新失败", self.tr(ret)) + + elif tp == "vrud": + self.statusbar.showMessage(self.status) + QMessageBox.critical(self, "更新失败", self.tr(ret)) + def output_conf(self): """ 导出配置文件 @@ -729,33 +800,41 @@ def output_conf_by_uri(self): 输出分享链接 :return: """ - row = self.tableView.currentIndex().row() - region = self.tableView.model().item(row, 0).text() - ret = self.v2rayL.subs.conf2b64(region) - QMessageBox.information(self, "分享链接", self.tr(ret)) + try: + row = self.tableView.currentIndex().row() + region = self.tableView.model().item(row, 0).text() + except AttributeError: + QMessageBox.information(self, "分享链接", self.tr("请选择需要分享的配置.")) + else: + ret = self.v2rayL.subs.conf2b64(region) + QMessageBox.information(self, "分享链接", self.tr(ret)) def output_conf_by_qr(self): """ 输出分享二维码 :return: """ - row = self.tableView.currentIndex().row() - region = self.tableView.model().item(row, 0).text() - ret = self.v2rayL.subs.conf2b64(region) - # 生成二维码 - url = "http://api.k780.com:88/?app=qr.get&data={}".format(ret) try: - req = requests.get(url) - if req.status_code == 200: - qr = QPixmap() - qr.loadFromData(req.content) - self.qr_child_ui.label.setPixmap(qr) - self.qr_child_ui.label.setScaledContents(True) - self.qr_ui.show() - else: - QMessageBox.critical(self, "错误", self.tr("服务错误,可能原因:调用API发生错误")) - except: - QMessageBox.critical(self, "错误", self.tr("服务错误,请将错误在github中提交")) + row = self.tableView.currentIndex().row() + region = self.tableView.model().item(row, 0).text() + except AttributeError: + QMessageBox.information(self, "分享二维码", self.tr("请选择需要分享的配置.")) + else: + ret = self.v2rayL.subs.conf2b64(region) + # 生成二维码 + url = "http://api.k780.com:88/?app=qr.get&data={}".format(ret) + try: + req = requests.get(url) + if req.status_code == 200: + qr = QPixmap() + qr.loadFromData(req.content) + self.qr_child_ui.label.setPixmap(qr) + self.qr_child_ui.label.setScaledContents(True) + self.qr_ui.show() + else: + QMessageBox.critical(self, "错误", self.tr("服务错误,可能原因:调用API发生错误")) + except: + QMessageBox.critical(self, "错误", self.tr("服务错误,请将错误在github中提交")) def event(self, QEvent): """