diff --git a/README.md b/README.md index 258532c..36c855a 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ v2ray linux 客户端,使用pyqt5编写GUI界面,核心基于v2ray-core(v2ra - 设置自动更新订阅、更换地址 - 支持协议:vmess、shadowsocks - 通过`vmess://`、`ss://`分享链接添加配置,通过二维码添加配置 +- 手动添加配置,修改本地监听端口 - 导出配置、生成配置分享链接、生成分享二维码 - 最小化至托盘、测试延时、检查更新 - ...... @@ -60,9 +61,9 @@ bash <(curl -s -L http://dl.thinker.ink/uninstall.sh) ![首页](http://cloud.thinker.ink/download/a043a08860f239f8d0cbeb2dc2a5b6d5.png) -![setting1](http://cloud.thinker.ink/download/c32e16f3b205b25c615b86a7beb8eb8d.png) +![setting1](http://cloud.thinker.ink/images/364231980b07e8881164f61cd220d0bb.png) -![setting2](http://cloud.thinker.ink/images/cc18605727deaf878cb0a2fa07ec230f.png) +![setting2](http://cloud.thinker.ink/images/8835526765d479143879c08fe1ecb8a4.png) # 感谢 diff --git a/v2rayL-GUI/new_ui.py b/v2rayL-GUI/new_ui.py index 3baabfd..d1945b0 100644 --- a/v2rayL-GUI/new_ui.py +++ b/v2rayL-GUI/new_ui.py @@ -330,10 +330,20 @@ def init_ui(self): self.share_child_ui = Ui_Share_Dialog() self.share_child_ui.setupUi(self.share_ui) - # 二维码分享配置窗口 - self.qr_ui = QDialog() - self.qr_child_ui = Ui_Qr_Dialog() - self.qr_child_ui.setupUi(self.qr_ui) + # # 二维码分享配置窗口 + # self.qr_ui = QDialog() + # self.qr_child_ui = Ui_Qr_Dialog() + # self.qr_child_ui.setupUi(self.qr_ui) + + # 添加ss窗口 + self.ss_add_ui = QDialog() + self.ss_add_child_ui = Ui_Add_Ss_Dialog() + self.ss_add_child_ui.setupUi(self.ss_add_ui) + + # 添加vmess窗口 + self.vmess_add_ui = QDialog() + self.vmess_add_child_ui = Ui_Add_Vmess_Dialog() + self.vmess_add_child_ui.setupUi(self.vmess_add_ui) self.current_page = self.first_widget self.config_setting_widget.hide() @@ -445,12 +455,9 @@ def setupUi(self, Form): self.pushButton.setStyleSheet("#pushButton{border-width: 0px; border-radius: 15px; background: #1E90FF; outline: none; font-family: Microsoft YaHei; color: white; font-size: 13px; }\n" "#pushButton:hover{ background: #5599FF;}") self.pushButton.setObjectName("pushButton") - self.label_6 = QLabel(Form) - self.label_6.setGeometry(QRect(40, 190, 141, 21)) - self.label_6.setStyleSheet("font: 13pt \"Purisa\";\n") - self.label_6.setObjectName("label_6") + self.pushButton_2 = QPushButton(Form) - self.pushButton_2.setGeometry(QRect(210, 184, 171, 31)) + self.pushButton_2.setGeometry(QRect(570, 184, 171, 31)) self.pushButton_2.setStyleSheet("#pushButton_2{border-width: 0px; border-radius: 15px; background: #1E90FF; outline: none; font-family: Microsoft YaHei; color: white; font-size: 13px; }\n" "#pushButton_2:hover{ background: #5599FF;}") self.pushButton_2.setObjectName("pushButton_2") @@ -482,6 +489,19 @@ def setupUi(self, Form): self.switchBtn = SwitchBtn(self.label_9) self.switchBtn.setGeometry(0, 0, 60, 30) + self.pushButton_vmess = QPushButton(Form) + self.pushButton_vmess.setGeometry(QRect(40, 184, 171, 31)) + self.pushButton_vmess.setStyleSheet( + "#pushButton_vmess{border-width: 0px; border-radius: 15px; background: #1E90FF; outline: none; font-family: Microsoft YaHei; color: white; font-size: 13px; }\n" + "#pushButton_vmess:hover{ background: #5599FF;}") + self.pushButton_vmess.setObjectName("pushButton_vmess") + + self.pushButton_ss = QPushButton(Form) + self.pushButton_ss.setGeometry(QRect(250, 184, 171, 31)) + self.pushButton_ss.setStyleSheet( + "#pushButton_ss{border-width: 0px; border-radius: 15px; background: #1E90FF; outline: none; font-family: Microsoft YaHei; color: white; font-size: 13px; }\n" + "#pushButton_ss:hover{ background: #5599FF;}") + self.pushButton_ss.setObjectName("pushButton_ss") self.retranslateUi(Form) QMetaObject.connectSlotsByName(Form) @@ -496,10 +516,11 @@ def retranslateUi(self, Form): self.label_4.setText(_translate("Form", "通过URI添加")) self.label_5.setText(_translate("Form", "通过二维码添加")) self.pushButton.setText(_translate("Form", "点击选择二维码")) - self.label_6.setText(_translate("Form", "导出当前完整配置")) - self.pushButton_2.setText(_translate("Form", "选择保存地址")) + self.pushButton_2.setText(_translate("Form", "导出当前完整配置")) self.label_7.setText(_translate("Form", "订阅")) self.label_8.setText(_translate("Form", "程序启动时自动更新订阅")) + self.pushButton_vmess.setText(_translate("Form", "手动配置Vmess")) + self.pushButton_ss.setText(_translate("Form", "手动配置shadowsocks")) class Ui_SystemSettings(object): @@ -519,16 +540,6 @@ def setupUi(self, SystemSettings): self.label_3.setGeometry(QRect(450, 130, 67, 17)) self.label_3.setStyleSheet("font: 14pt \"Purisa\";") self.label_3.setObjectName("label_3") - # self.socks_spinBox = QSpinBox(SystemSettings) - # self.socks_spinBox.setGeometry(QRect(530, 120, 131, 31)) - # self.socks_spinBox.setMinimum(1080) - # self.socks_spinBox.setMaximum(10000) - # self.socks_spinBox.setObjectName("socks_spinBox") - # self.socks_spinBox_2 = QSpinBox(SystemSettings) - # self.socks_spinBox_2.setGeometry(QRect(150, 120, 131, 31)) - # self.socks_spinBox_2.setMinimum(1080) - # self.socks_spinBox_2.setMaximum(10000) - # self.socks_spinBox_2.setObjectName("socks_spinBox_2") self.label_4 = QLabel(SystemSettings) self.label_4.setGeometry(QRect(310, 230, 101, 31)) self.label_4.setStyleSheet("font-size: 24px;\n" @@ -560,15 +571,17 @@ def setupUi(self, SystemSettings): self.label_8.setGeometry(QRect(320, 375, 201, 71)) self.label_8.setObjectName("label_8") - self.label_9 = QLabel(SystemSettings) - self.label_9.setGeometry(QRect(130, 130, 67, 17)) - self.label_9.setStyleSheet("font: 14pt \"Purisa\";") - self.label_9.setObjectName("label_9") + self.http_sp = QSpinBox(SystemSettings) + self.http_sp.setGeometry(QRect(130, 124, 80, 30)) + self.http_sp.setMinimum(1080) + self.http_sp.setMaximum(10080) + self.http_sp.setValue(1081) - self.label_10 = QLabel(SystemSettings) - self.label_10.setGeometry(QRect(525, 130, 67, 17)) - self.label_10.setStyleSheet("font: 14pt \"Purisa\";") - self.label_10.setObjectName("label_10") + self.socks_sp = QSpinBox(SystemSettings) + self.socks_sp.setGeometry(QRect(525, 124, 80, 30)) + self.socks_sp.setMinimum(1080) + self.socks_sp.setMaximum(10080) + self.socks_sp.setValue(1080) self.switchBtn = SwitchBtn(self.label_8, True) self.switchBtn.setGeometry(0, 0, 60, 30) @@ -585,12 +598,12 @@ def retranslateUi(self, SystemSettings): self.label_3.setText(_translate("SystemSettings", "Socks:")) self.label_4.setText(_translate("SystemSettings", "版本更新")) self.label_5.setText(_translate("SystemSettings", "当前版本:")) - self.version_label.setText(_translate("SystemSettings", "v2.0.4")) + self.version_label.setText(_translate("SystemSettings", "v2.1.0")) self.checkupdateButton.setText(_translate("SystemSettings", "检查更新")) self.label_7.setText(_translate("SystemSettings", "程序启动时自动进行检查更新")) - self.label_6.setText(_translate("SystemSettings", "**端口可选范围:1080-10000")) - self.label_9.setText(_translate("SystemSettings", "1081")) - self.label_10.setText(_translate("SystemSettings", "1080")) + self.label_6.setText(_translate("SystemSettings", "**端口可选范围:1080-10080,每次修改都将更新**")) + # self.label_9.setText(_translate("SystemSettings", "1081")) + # self.label_10.setText(_translate("SystemSettings", "1080")) class Ui_HelpUi(object): @@ -617,14 +630,15 @@ def retranslateUi(self, HelpUi): "\n" "

当前版本

\n" "

——————————————————————

\n" - "

v2.0.4

\n" + "

v2.1.0

\n" "


\n" "

说明

\n" "

——————————————————————

")) - self.label.setText(_translate("HelpUi", "1. 具有全新的V2rayL UI\n" - "2. github地址:https://github.com/jiangxufeng/v2rayL\n" - "3. 目前支持协议有:Vmess、shadowsocks\n" - "4. 支持通过分享链接、二维码导入和分享配置\n" + self.label.setText(_translate("HelpUi", + "1. github地址:https://github.com/jiangxufeng/v2rayL\n" + "2. 目前支持协议有:Vmess、shadowsocks\n" + "3. 支持通过分享链接、二维码导入和分享配置,手动配置\n" + "4. 支持修改本地监听端口,范围为1080~10080\n" "5. 开发环境为Ubuntu18.04+Python3.6,其他linux系统可能不兼容\n" "6. 程序可能存在未测试到的Bug,使用过程中发现Bug请在github提交")) @@ -776,57 +790,289 @@ def retranslateUi(self, Form): class Ui_Share_Dialog(object): + def setupUi(self, dialog): + dialog.setObjectName("dialog") + dialog.resize(565, 480) + dialog.setStyleSheet("#dialog{color:#232C51; background:white; }") + dialog.setWindowOpacity(0.95) # 设置窗口透明度 + self.label = QLabel(dialog) + self.label.setGeometry(QRect(170, 20, 200, 200)) + self.label.setText("") + self.label.setObjectName("label") + self.textBrowser = QTextBrowser(dialog) + self.textBrowser.setGeometry(QRect(20, 250, 501, 171)) + self.textBrowser.setObjectName("textBrowser") + + self.retranslateUi(dialog) + QMetaObject.connectSlotsByName(dialog) + + def retranslateUi(self, dialog): + _translate = QCoreApplication.translate + dialog.setWindowTitle(_translate("dialog", "配置分享")) + + +class Ui_Add_Ss_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(226, 171) + Dialog.resize(314, 329) + Dialog.setStyleSheet(""" + #Dialog{ + color:#232C51; + background:white; + } + """) + Dialog.setWindowOpacity(0.95) # 设置窗口透明度 + # Dialog.setAttribute(Qt.WA_TranslucentBackground) # 设置窗口背景透明 self.label = QLabel(Dialog) - self.label.setGeometry(QRect(20, 20, 191, 17)) - self.label.setStyleSheet("font: 75 13pt \"新宋体\";") + self.label.setGeometry(QRect(20, 30, 111, 20)) self.label.setObjectName("label") + self.label_2 = QLabel(Dialog) + self.label_2.setGeometry(QRect(20, 80, 121, 17)) + self.label_2.setObjectName("label_2") + self.lineEdit_2 = QLineEdit(Dialog) + self.lineEdit_2.setGeometry(QRect(70, 30, 221, 25)) + self.lineEdit_2.setStyleSheet("border-style:none none solid none;background-color:transparent;") + self.lineEdit_2.setText("") + self.lineEdit_2.setObjectName("lineEdit_2") + self.label_3 = QLabel(Dialog) + self.label_3.setGeometry(QRect(20, 130, 121, 17)) + self.label_3.setObjectName("label_3") + self.label_4 = QLabel(Dialog) + self.label_4.setGeometry(QRect(20, 180, 131, 17)) + self.label_4.setObjectName("label_4") + self.label_5 = QLabel(Dialog) + self.label_5.setGeometry(QRect(20, 230, 121, 17)) + self.label_5.setObjectName("label_5") + self.lineEdit_3 = QLineEdit(Dialog) + self.lineEdit_3.setGeometry(QRect(70, 80, 221, 25)) + self.lineEdit_3.setStyleSheet("border-style:none none solid none;background-color:transparent;") + self.lineEdit_3.setText("") + self.lineEdit_3.setObjectName("lineEdit_3") + self.lineEdit_4 = QLineEdit(Dialog) + self.lineEdit_4.setGeometry(QRect(70, 130, 221, 25)) + self.lineEdit_4.setStyleSheet("border-style:none none solid none;background-color:transparent;") + self.lineEdit_4.setText("") + self.lineEdit_4.setObjectName("lineEdit_4") + self.lineEdit_5 = QLineEdit(Dialog) + self.lineEdit_5.setGeometry(QRect(70, 180, 221, 25)) + self.lineEdit_5.setStyleSheet("border-style:none none solid none;background-color:transparent;") + self.lineEdit_5.setText("") + self.lineEdit_5.setObjectName("lineEdit_5") + self.lineEdit_5.setEchoMode(QLineEdit.Password) + self.comboBox = QComboBox(Dialog) + self.comboBox.setGeometry(QRect(100, 230, 191, 25)) + self.comboBox.setObjectName("comboBox") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.comboBox.addItem("") self.pushButton = QPushButton(Dialog) - self.pushButton.setGeometry(QRect(40, 60, 141, 31)) - self.pushButton.setStyleSheet("#pushButton{border-width: 0px; border-radius: 15px; background: #1E90FF; outline: none; font-family: Microsoft YaHei; color: white; font-size: 13px; }\n" - "#pushButton:hover{ background: #5599FF;}") + self.pushButton.setGeometry(QRect(80, 280, 151, 31)) + self.pushButton.setStyleSheet("#pushButton{border-width: 0px; border-radius: 15px; background: #1E90FF; outline: none; font-family: Microsoft YaHei; color: white; font-size: 13px; } \n" +"#pushButton:hover{ background: #5599FF;}") self.pushButton.setObjectName("pushButton") - self.pushButton_2 = QPushButton(Dialog) - self.pushButton_2.setGeometry(QRect(40, 110, 141, 31)) - self.pushButton_2.setStyleSheet("#pushButton_2{border-width: 0px; border-radius: 15px; background: #1E90FF; outline: none; font-family: Microsoft YaHei; color: white; font-size: 13px; }\n" - "#pushButton_2:hover{ background: #5599FF;}") - self.pushButton_2.setObjectName("pushButton_2") + self.line = QFrame(Dialog) + self.line.setGeometry(QRect(70, 50, 231, 16)) + self.line.setFrameShape(QFrame.HLine) + self.line.setFrameShadow(QFrame.Sunken) + self.line.setObjectName("line") + self.line_2 = QFrame(Dialog) + self.line_2.setGeometry(QRect(70, 100, 231, 16)) + self.line_2.setFrameShape(QFrame.HLine) + self.line_2.setFrameShadow(QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.line_3 = QFrame(Dialog) + self.line_3.setGeometry(QRect(70, 150, 231, 16)) + self.line_3.setFrameShape(QFrame.HLine) + self.line_3.setFrameShadow(QFrame.Sunken) + self.line_3.setObjectName("line_3") + self.line_4 = QFrame(Dialog) + self.line_4.setGeometry(QRect(70, 200, 231, 16)) + self.line_4.setFrameShape(QFrame.HLine) + self.line_4.setFrameShadow(QFrame.Sunken) + self.line_4.setObjectName("line_4") self.retranslateUi(Dialog) QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): _translate = QCoreApplication.translate - Dialog.setWindowTitle(_translate("Dialog", "配置分享")) - self.label.setText(_translate("Dialog", "请选择以下一种方式分享")) - self.pushButton.setText(_translate("Dialog", "二维码分享")) - self.pushButton_2.setText(_translate("Dialog", "链接分享")) - - -class Ui_Qr_Dialog(object): + Dialog.setWindowTitle(_translate("Dialog", "手动添加ShadowSocks配置")) + self.label.setText(_translate("Dialog", "别名:")) + self.label_2.setText(_translate("Dialog", "地址:")) + self.label_3.setText(_translate("Dialog", "端口:")) + self.label_4.setText(_translate("Dialog", "密码:")) + self.label_5.setText(_translate("Dialog", "加密方式:")) + self.comboBox.setItemText(0, _translate("Dialog", "aes-256-cfb")) + self.comboBox.setItemText(1, _translate("Dialog", "aes-128-cfb")) + self.comboBox.setItemText(2, _translate("Dialog", "chacha20")) + self.comboBox.setItemText(3, _translate("Dialog", "chacha20-ietf")) + self.comboBox.setItemText(4, _translate("Dialog", "aes-256-gcm")) + self.comboBox.setItemText(5, _translate("Dialog", "aes-128-gcm")) + self.comboBox.setItemText(6, _translate("Dialog", "chacha20-poly1305")) + self.comboBox.setItemText(7, _translate("Dialog", "chacha20-ietf-poly1305")) + self.pushButton.setText(_translate("Dialog", "确认添加")) + + +class Ui_Add_Vmess_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(218, 218) - Dialog.setMinimumSize(QSize(218, 218)) - Dialog.setMaximumSize(QSize(218, 218)) - self.gridLayout = QGridLayout(Dialog) - self.gridLayout.setObjectName("gridLayout") + Dialog.resize(465, 527) + Dialog.setStyleSheet("#Dialog{color:#232C51; background:white; }") + Dialog.setWindowOpacity(0.95) # 设置窗口透明度 self.label = QLabel(Dialog) - self.label.setEnabled(True) - self.label.setMinimumSize(QSize(200, 200)) - self.label.setMaximumSize(QSize(200, 200)) - self.label.setText("") + self.label.setGeometry(QRect(30, 35, 111, 17)) self.label.setObjectName("label") - self.gridLayout.addWidget(self.label, 0, 0, 1, 1) + self.lineEdit = QLineEdit(Dialog) + self.lineEdit.setGeometry(QRect(140, 30, 301, 25)) + self.lineEdit.setStyleSheet("border-style:none none solid none;background-color:transparent;") + self.lineEdit.setText("") + self.lineEdit.setObjectName("lineEdit") + self.label_2 = QLabel(Dialog) + self.label_2.setGeometry(QRect(30, 75, 121, 17)) + self.label_2.setObjectName("label_2") + self.lineEdit_2 = QLineEdit(Dialog) + self.lineEdit_2.setGeometry(QRect(120, 70, 321, 25)) + self.lineEdit_2.setStyleSheet("border-style:none none solid none;background-color:transparent;") + self.lineEdit_2.setText("") + self.lineEdit_2.setObjectName("lineEdit_2") + self.label_3 = QLabel(Dialog) + self.label_3.setGeometry(QRect(30, 115, 101, 17)) + self.label_3.setObjectName("label_3") + self.lineEdit_3 = QLineEdit(Dialog) + self.lineEdit_3.setGeometry(QRect(120, 110, 321, 25)) + self.lineEdit_3.setStyleSheet("border-style:none none solid none;background-color:transparent;") + self.lineEdit_3.setText("") + self.lineEdit_3.setObjectName("lineEdit_3") + self.label_4 = QLabel(Dialog) + self.label_4.setGeometry(QRect(30, 155, 91, 17)) + self.label_4.setObjectName("label_4") + self.lineEdit_4 = QLineEdit(Dialog) + self.lineEdit_4.setGeometry(QRect(120, 150, 321, 25)) + self.lineEdit_4.setStyleSheet("border-style:none none solid none;background-color:transparent;") + self.lineEdit_4.setText("") + self.lineEdit_4.setObjectName("lineEdit_4") + self.lineEdit_5 = QLineEdit(Dialog) + self.lineEdit_5.setGeometry(QRect(150, 190, 291, 25)) + self.lineEdit_5.setStyleSheet("border-style:none none solid none;background-color:transparent;") + self.lineEdit_5.setText("") + self.lineEdit_5.setObjectName("lineEdit_5") + self.label_5 = QLabel(Dialog) + self.label_5.setGeometry(QRect(30, 195, 111, 17)) + self.label_5.setObjectName("label_5") + self.label_6 = QLabel(Dialog) + self.label_6.setGeometry(QRect(30, 240, 121, 17)) + self.label_6.setObjectName("label_6") + self.label_7 = QLabel(Dialog) + self.label_7.setGeometry(QRect(30, 330, 111, 17)) + self.label_7.setObjectName("label_7") + self.comboBox = QComboBox(Dialog) + self.comboBox.setGeometry(QRect(150, 235, 86, 25)) + #self.comboBox.setStyleSheet("background-color: rgb(255, 255, 255);") + self.comboBox.setObjectName("comboBox") + self.comboBox.addItem("") + self.comboBox.addItem("") + self.label_8 = QLabel(Dialog) + self.label_8.setGeometry(QRect(30, 286, 221, 21)) + self.label_8.setObjectName("label_8") + self.comboBox_2 = QComboBox(Dialog) + self.comboBox_2.setGeometry(QRect(150, 325, 86, 25)) + #self.comboBox_2.setStyleSheet("background-color: rgb(255, 255, 255);") + self.comboBox_2.setObjectName("comboBox_2") + self.comboBox_2.addItem("") + self.comboBox_2.addItem("") + self.comboBox_2.addItem("") + self.comboBox_2.addItem("") + self.comboBox_2.addItem("") + self.comboBox_2.addItem("") + self.comboBox_2.addItem("") + self.label_9 = QLabel(Dialog) + self.label_9.setGeometry(QRect(30, 365, 121, 17)) + self.label_9.setObjectName("label_9") + self.lineEdit_6 = QLineEdit(Dialog) + self.lineEdit_6.setGeometry(QRect(150, 360, 291, 25)) + self.lineEdit_6.setStyleSheet("border-style:none none solid none;background-color:transparent;") + self.lineEdit_6.setText("") + self.lineEdit_6.setObjectName("lineEdit_6") + self.label_10 = QLabel(Dialog) + self.label_10.setGeometry(QRect(30, 410, 67, 17)) + self.label_10.setObjectName("label_10") + self.lineEdit_7 = QLineEdit(Dialog) + self.lineEdit_7.setGeometry(QRect(80, 405, 361, 25)) + self.lineEdit_7.setStyleSheet("border-style:none none solid none;background-color:transparent;") + self.lineEdit_7.setText("") + self.lineEdit_7.setObjectName("lineEdit_7") + self.line = QFrame(Dialog) + self.line.setGeometry(QRect(140, 45, 301, 16)) + self.line.setFrameShape(QFrame.HLine) + self.line.setFrameShadow(QFrame.Sunken) + self.line.setObjectName("line") + self.line_2 = QFrame(Dialog) + self.line_2.setGeometry(QRect(120, 90, 321, 16)) + self.line_2.setFrameShape(QFrame.HLine) + self.line_2.setFrameShadow(QFrame.Sunken) + self.line_2.setObjectName("line_2") + self.line_3 = QFrame(Dialog) + self.line_3.setGeometry(QRect(120, 130, 321, 16)) + self.line_3.setFrameShape(QFrame.HLine) + self.line_3.setFrameShadow(QFrame.Sunken) + self.line_3.setObjectName("line_3") + self.line_4 = QFrame(Dialog) + self.line_4.setGeometry(QRect(120, 170, 321, 16)) + self.line_4.setFrameShape(QFrame.HLine) + self.line_4.setFrameShadow(QFrame.Sunken) + self.line_4.setObjectName("line_4") + self.line_5 = QFrame(Dialog) + self.line_5.setGeometry(QRect(150, 210, 291, 20)) + self.line_5.setFrameShape(QFrame.HLine) + self.line_5.setFrameShadow(QFrame.Sunken) + self.line_5.setObjectName("line_5") + self.line_6 = QFrame(Dialog) + self.line_6.setGeometry(QRect(150, 380, 291, 20)) + self.line_6.setFrameShape(QFrame.HLine) + self.line_6.setFrameShadow(QFrame.Sunken) + self.line_6.setObjectName("line_6") + self.line_7 = QFrame(Dialog) + self.line_7.setGeometry(QRect(80, 420, 361, 20)) + self.line_7.setFrameShape(QFrame.HLine) + self.line_7.setFrameShadow(QFrame.Sunken) + self.line_7.setObjectName("line_7") + self.pushButton = QPushButton(Dialog) + self.pushButton.setGeometry(QRect(160, 464, 151, 31)) + self.pushButton.setStyleSheet("#pushButton{border-width: 0px; border-radius: 15px; background: #1E90FF; outline: none; font-family: Microsoft YaHei; color: white; font-size: 13px; }\n" +"#pushButton:hover{ background: #5599FF;}") + self.pushButton.setObjectName("pushButton") self.retranslateUi(Dialog) QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): _translate = QCoreApplication.translate - Dialog.setWindowTitle(_translate("Dialog", "二维码分享配置")) + Dialog.setWindowTitle(_translate("Dialog", "手动添加Vmess配置")) + self.label.setText(_translate("Dialog", "别名(remark):")) + self.label_2.setText(_translate("Dialog", "地址(addr):")) + self.label_3.setText(_translate("Dialog", "端口(port):")) + self.label_4.setText(_translate("Dialog", "用户ID(id):")) + self.label_5.setText(_translate("Dialog", "额外ID(alterId):")) + self.label_6.setText(_translate("Dialog", "传输协议(net):")) + self.label_7.setText(_translate("Dialog", "伪装类型(type):")) + self.comboBox.setItemText(0, _translate("Dialog", "ws")) + self.comboBox.setItemText(1, _translate("Dialog", "kcp")) + self.label_8.setText(_translate("Dialog", "下列配置无则保持默认")) + self.comboBox_2.setItemText(0, _translate("Dialog", "none")) + self.comboBox_2.setItemText(1, _translate("Dialog", "http")) + self.comboBox_2.setItemText(2, _translate("Dialog", "utp")) + self.comboBox_2.setItemText(3, _translate("Dialog", "wechat-video")) + self.comboBox_2.setItemText(4, _translate("Dialog", "dtls")) + self.comboBox_2.setItemText(5, _translate("Dialog", "strp")) + self.comboBox_2.setItemText(6, _translate("Dialog", "wireguard")) + self.label_9.setText(_translate("Dialog", "伪装域名(host):")) + self.label_10.setText(_translate("Dialog", "path:")) + self.pushButton.setText(_translate("Dialog", "确认添加")) def main(): app = QApplication(sys.argv) diff --git a/v2rayL-GUI/sub2conf_api.py b/v2rayL-GUI/sub2conf_api.py index 96aaa07..295d9eb 100755 --- a/v2rayL-GUI/sub2conf_api.py +++ b/v2rayL-GUI/sub2conf_api.py @@ -6,8 +6,9 @@ import json import pickle import requests +import copy import urllib.parse as parse -from config import conf_template as conf +from config import conf_template as tpl class Sub2Conf(object): @@ -65,8 +66,12 @@ def b642conf(self, prot, tp, b64str): region = region + "_local" self.saved_conf[["local", "subs"][tp]][region] = ret - def setconf(self, region): + def setconf(self, region, http, socks): use_conf = self.conf[region] + conf = copy.deepcopy(tpl) + conf["inbounds"][0]["port"] = socks + conf["inbounds"][1]["port"] = http + if use_conf['prot'] == "vmess": conf['outbounds'][0]["protocol"] = "vmess" conf['outbounds'][0]["settings"]["vnext"] = list() diff --git a/v2rayL-GUI/v2rayL_api.py b/v2rayL-GUI/v2rayL_api.py index 28bd580..3b86a7b 100755 --- a/v2rayL-GUI/v2rayL_api.py +++ b/v2rayL-GUI/v2rayL_api.py @@ -13,12 +13,14 @@ def __init__(self): try: with open("/etc/v2rayL/ncurrent", "rb") as f: - self.current, self.url, self.auto, self.check = pickle.load(f) + self.current, self.url, self.auto, self.check, self.http, self.socks = pickle.load(f) except: self.current = "未连接至VPN" self.url = None self.auto = False self.check = False + self.http = 1081 + self.socks = 1080 self.subs = Sub2Conf(subs_url=self.url) @@ -27,7 +29,8 @@ def __init__(self): self.subs.update() except: with open("/etc/v2rayL/ncurrent", "wb") as jf: - pickle.dump((self.current, None, False), jf) + pickle.dump(("未连接至VPN", None, False, False, + self.http, self.socks), jf) raise MyException("更新失败, 已关闭自动更新,请更新订阅地址") def auto_check(self, flag): @@ -44,14 +47,17 @@ def subscribe(self, flag): if flag: with open("/etc/v2rayL/ncurrent", "wb") as jf: self.auto = True - pickle.dump((self.current, self.url, self.auto, self.check), jf) + pickle.dump((self.current, self.url, self.auto, self.check, + self.http, self.socks), jf) else: with open("/etc/v2rayL/ncurrent", "wb") as jf: self.auto = False - pickle.dump((self.current, self.url, self.auto, self.check), jf) + pickle.dump((self.current, self.url, self.auto, self.check, + self.http, self.socks), jf) - def connect(self, region): - self.subs.setconf(region) + def connect(self, region, flag): + if not flag: + self.subs.setconf(region, self.http, self.socks) try: output = subprocess.getoutput(["sudo systemctl status v2rayL.service"]) if "Active: active" in output: @@ -66,7 +72,8 @@ def connect(self, region): else: self.current = region with open("/etc/v2rayL/ncurrent", "wb") as jf: - pickle.dump((self.current, self.url, self.auto, self.check), jf) + pickle.dump((self.current, self.url, self.auto, self.check, + self.http, self.socks), jf) def disconnect(self): try: @@ -75,12 +82,14 @@ def disconnect(self): subprocess.call(["sudo systemctl stop v2rayL.service"], shell=True) self.current = "未连接至VPN" with open("/etc/v2rayL/ncurrent", "wb") as jf: - pickle.dump((self.current, self.url, self.auto, self.check), jf) + pickle.dump((self.current, self.url, self.auto, self.check, + self.http, self.socks), jf) else: if self.current != "未连接至VPN": self.current = "未连接至VPN" with open("/etc/v2rayL/ncurrent", "wb") as jf: - pickle.dump((self.current, self.url, self.auto, self.check), jf) + pickle.dump((self.current, self.url, self.auto, self.check, + self.http, self.socks), jf) else: raise MyException("服务未开启,无需断开连接.") except Exception as e: @@ -91,7 +100,8 @@ def update(self, url): self.subs = Sub2Conf(subs_url=url) self.subs.update() with open("/etc/v2rayL/ncurrent", "wb") as jf: - pickle.dump((self.current, url, self.auto, self.check), jf) + pickle.dump((self.current, url, self.auto, self.check, + self.http, self.socks), jf) else: if self.current in self.subs.saved_conf["subs"]: @@ -101,11 +111,13 @@ def update(self, url): pass with open("/etc/v2rayL/ncurrent", "wb") as jf: - pickle.dump(("未连接至VPN", None, False), jf) + pickle.dump(("未连接至VPN", None, False, False, + self.http, self.socks), jf) else: with open("/etc/v2rayL/ncurrent", "wb") as jf: - pickle.dump((self.current, None, False), jf) + pickle.dump((self.current, None, False, False, + self.http, self.socks), jf) with open("/etc/v2rayL/data", "wb") as f: pickle.dump({"local": self.subs.saved_conf["local"], "subs": {}}, f) @@ -120,8 +132,8 @@ def delconf(self, region): def ping(self): try: proxy = { - "http": "127.0.0.1:1081", - "https": "127.0.0.1:1081" + "http": "127.0.0.1:{}".format(self.http), + "https": "127.0.0.1:{}".format(self.http) } req = requests.get("http://www.google.com", proxies=proxy, timeout=10) if req.status_code == 200: diff --git a/v2rayL-GUI/v2rayL_threads.py b/v2rayL-GUI/v2rayL_threads.py index 872d1e8..2c513c1 100755 --- a/v2rayL-GUI/v2rayL_threads.py +++ b/v2rayL-GUI/v2rayL_threads.py @@ -29,7 +29,7 @@ def run(self): self.sinOut.emit(("conn", "@@Fail@@", "未选中配置无法连接,请导入配置后再次连接", None)) else: try: - self.v2rayL.connect(region) + self.v2rayL.connect(region, False) except MyException as e: self.sinOut.emit(("conn", "@@Fail@@", e.args[0], None)) else: diff --git a/v2rayL-GUI/v2rayLui.py b/v2rayL-GUI/v2rayLui.py index 15f127f..0c06e2a 100644 --- a/v2rayL-GUI/v2rayLui.py +++ b/v2rayL-GUI/v2rayLui.py @@ -2,6 +2,9 @@ # Author: Suummmmer # Date: 2019-08-13 +import json +import random +import base64 import requests import subprocess import pickle @@ -13,9 +16,9 @@ QFileDialog, QSystemTrayIcon, qApp, - QMainWindow + QDialog ) -+from PyQt5.QtCore import Qt +from PyQt5.QtCore import Qt from PyQt5.QtGui import QIcon, QPixmap from v2rayL_api import V2rayL, MyException import pyzbar.pyzbar as pyzbar @@ -28,7 +31,7 @@ CheckUpdateThread, VersionUpdateThread ) -from new_ui import MainUi, SwitchBtn +from new_ui import MainUi, SwitchBtn, Ui_Add_Ss_Dialog, Ui_Add_Vmess_Dialog class SystemTray(object): @@ -82,7 +85,7 @@ def __init__(self, parent=None): super(MyMainWindow, self).__init__(parent) self.init_ui() - self.version = "2.0.4" + self.version = "2.1.0" # 获取api操作 self.v2rayL = V2rayL() @@ -129,7 +132,9 @@ def __init__(self, parent=None): # 填充当前订阅地址 self.config_setting_ui.lineEdit.setText(self.v2rayL.url) - # + # 端口 + self.system_setting_ui.http_sp.setValue(self.v2rayL.http) + self.system_setting_ui.socks_sp.setValue(self.v2rayL.socks) # # 显示当前所有配置 self.display_all_conf() @@ -152,7 +157,12 @@ def __init__(self, parent=None): self.ping_start.sinOut.connect(self.alert) # 得到反馈 self.check_update_start.sinOut.connect(self.alert) self.version_update_start.sinOut.connect(self.alert) - + self.system_setting_ui.http_sp.valueChanged.connect(lambda: self.value_change(True)) + self.system_setting_ui.socks_sp.valueChanged.connect(lambda: self.value_change(False)) + self.config_setting_ui.pushButton_ss.clicked.connect(self.show_add_ss_dialog) + self.config_setting_ui.pushButton_vmess.clicked.connect(self.show_add_vmess_dialog) + self.ss_add_child_ui.pushButton.clicked.connect(self.add_ss_by_input) + self.vmess_add_child_ui.pushButton.clicked.connect(self.add_vmess_by_input) # 设置最小化到托盘 SystemTray(self) @@ -361,7 +371,7 @@ def alert(self, tp): if choice == QMessageBox.Yes: shell = "notify-send -i /etc/v2rayL/images/logo.ico v2rayL {}".format(ret) subprocess.call([shell], shell=True) - self.version_update_start.url = "http://cloud.thinker.ink/update.sh" + self.version_update_start.url = "http://dl.thinker.ink/update.sh" self.version_update_start.start() elif tp == "vrud": @@ -439,8 +449,24 @@ def start_ping_th(self): self.ping_start.start() def show_share_dialog(self, region): - self.share_child_ui.pushButton.clicked.connect(lambda: self.output_conf_by_qr(region)) - self.share_child_ui.pushButton_2.clicked.connect(lambda: self.output_conf_by_uri(region)) + 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.share_child_ui.label.setPixmap(qr) + self.share_child_ui.label.setScaledContents(True) + else: + shell = "notify-send -i /etc/v2rayL/images/logo.ico v2rayL 服务错误,可能原因:调用API发生错误" + subprocess.call([shell], shell=True) + except: + shell = "notify-send -i /etc/v2rayL/images/logo.ico v2rayL 服务错误,请将错误在github中提交" + subprocess.call([shell], shell=True) + + self.share_child_ui.textBrowser.setText(ret) self.share_ui.show() def output_conf_by_uri(self, region): @@ -448,14 +474,8 @@ def output_conf_by_uri(self, region): 输出分享链接 :return: """ - # if self.v2rayL.current != "未连接至VPN": - # ret = self.v2rayL.subs.conf2b64(self.v2rayL.current) - # QMessageBox.information(self, "分享链接", self.tr(ret)) - # else: - # shell = "notify-send -i /etc/v2rayL/images/logo.ico v2rayL 请连接一个VPN后再选择分享 -t 3" - # subprocess.call([shell], shell=True) ret = self.v2rayL.subs.conf2b64(region) - QMessageBox.information(self, "分享链接", self.tr(ret)) + # QMessageBox.information(self, "分享链接", self.tr(ret)) def output_conf_by_qr(self, region): """ @@ -480,6 +500,120 @@ def output_conf_by_qr(self, region): shell = "notify-send -i /etc/v2rayL/images/logo.ico v2rayL 服务错误,请将错误在github中提交" subprocess.call([shell], shell=True) + def value_change(self, flag): + """ + 端口改变 + :param flag: true时为http, false为socks + :return: + """ + with open("/etc/v2rayL/config.json", "r") as f: + ret = json.load(f) + + if flag: + new_port = self.system_setting_ui.http_sp.value() + if new_port == ret["inbounds"][0]["port"]: + new_port = new_port + 1 if new_port < 10079 else new_port - 1 + self.system_setting_ui.http_sp.setValue(new_port) + ret["inbounds"][1]["port"] = new_port + else: + new_port = self.system_setting_ui.socks_sp.value() + if new_port == ret["inbounds"][1]["port"]: + new_port = new_port + 1 if new_port < 10079 else new_port - 1 + self.system_setting_ui.socks_sp.setValue(new_port) + ret["inbounds"][0]["port"] = new_port + + with open("/etc/v2rayL/config.json", "w") as f: + f.write(json.dumps(ret, indent=4)) + + if flag: + self.v2rayL.http = new_port + with open("/etc/v2rayL/ncurrent", "wb") as jf: + pickle.dump((self.v2rayL.current, self.v2rayL.url, self.v2rayL.auto, self.v2rayL.check, + new_port, self.v2rayL.socks), jf) + else: + self.v2rayL.socks = new_port + with open("/etc/v2rayL/ncurrent", "wb") as jf: + pickle.dump((self.v2rayL.current, self.v2rayL.url, self.v2rayL.auto, self.v2rayL.check, + self.v2rayL.http, new_port), jf) + + self.v2rayL.connect(self.v2rayL.current, True) + + def show_add_ss_dialog(self): + """ + 显示手动添加ss配置窗口 + :return: + """ + self.ss_add_ui.show() + + def show_add_vmess_dialog(self): + self.vmess_add_ui.show() + + def add_ss_by_input(self): + remark = self.ss_add_child_ui.lineEdit_2.text().strip() + addr = self.ss_add_child_ui.lineEdit_3.text().strip() + port = self.ss_add_child_ui.lineEdit_4.text().strip() + password = self.ss_add_child_ui.lineEdit_5.text().strip() + method = self.ss_add_child_ui.comboBox.currentText() + # print(remark, addr, port, password, security) + if not remark: + remark = "shadowsocks_" + str(random.choice(range(10000, 99999))) + + b64str = "ss://"+base64.b64encode("{}:{}@{}:{}".format(method, password, addr, port).encode()).decode()\ + + "#" + remark + + self.v2rayL.addconf(b64str) + shell = "notify-send -i /etc/v2rayL/images/logo.ico v2rayL 添加成功" + subprocess.call([shell], shell=True) + self.v2rayL = V2rayL() + self.display_all_conf() + self.ss_add_child_ui.lineEdit_2.setText("") + self.ss_add_child_ui.lineEdit_3.setText("") + self.ss_add_child_ui.lineEdit_4.setText("") + self.ss_add_child_ui.lineEdit_5.setText("") + self.ss_add_ui.hide() + + def add_vmess_by_input(self): + remark = self.vmess_add_child_ui.lineEdit.text().strip() + addr = self.vmess_add_child_ui.lineEdit_2.text().strip() + port = self.vmess_add_child_ui.lineEdit_3.text().strip() + uid = self.vmess_add_child_ui.lineEdit_4.text().strip() + aid = self.vmess_add_child_ui.lineEdit_5.text().strip() + net = self.vmess_add_child_ui.comboBox.currentText() + types = self.vmess_add_child_ui.comboBox_2.currentText() + host = self.vmess_add_child_ui.lineEdit_6.text().strip() + path = self.vmess_add_child_ui.lineEdit_7.text().strip() + # print(remark, addr, port, password, security) + if not remark: + remark = "vmess_" + str(random.choice(range(10000, 99999))) + conf = { + 'add': addr, + 'port': port, + 'host': host, + 'ps': remark, + 'id': uid, + 'aid': aid, + 'net': net, + 'type': types, + 'path': path, + 'tls': "", + "v": 2 + } + b64str = "vmess://" + base64.b64encode(str(conf).encode()).decode() + + self.v2rayL.addconf(b64str) + shell = "notify-send -i /etc/v2rayL/images/logo.ico v2rayL 添加成功" + subprocess.call([shell], shell=True) + self.v2rayL = V2rayL() + self.display_all_conf() + self.vmess_add_child_ui.lineEdit.setText("") + self.vmess_add_child_ui.lineEdit_2.setText("") + self.vmess_add_child_ui.lineEdit_3.setText("") + self.vmess_add_child_ui.lineEdit_4.setText("") + self.vmess_add_child_ui.lineEdit_5.setText("") + self.vmess_add_child_ui.lineEdit_6.setText("") + self.vmess_add_child_ui.lineEdit_7.setText("") + self.vmess_add_ui.hide() + if __name__ == "__main__": import sys