diff --git a/MainWindow.ui b/MainWindow.ui
index 5130ce8..96d9bd4 100644
--- a/MainWindow.ui
+++ b/MainWindow.ui
@@ -44,25 +44,15 @@
-
-
+
- 从文件导入IP列表。
+ 从指定来源导入IP列表。
导入
- -
-
-
- 从远程服务器上获取IP列表。
-
-
- 同步
-
-
-
-
diff --git a/README.md b/README.md
index 07d2bd4..d4264f0 100644
--- a/README.md
+++ b/README.md
@@ -62,10 +62,29 @@ python main.py
...(若有其他需求欢迎在[issues](https://github.com/GoodCoder666/GoogleTranslate_IPFinder/issues)中提出)
+## 关于在线同步功能
+
+本项目作者提供的 IP 库在打开软件时会自动导入。程序还提供了在线导入其他 IP 库的功能,地址如下:
+
+- 精简 IPv4:
+ - 官方:https://unpkg.com/@hcfy/google-translate-ip/ips.txt
+ - 备用1(ghproxy 镜像):https://ghproxy.com/https://raw.githubusercontent.com/hcfyapp/google-translate-cn-ip/master/packages/google-translate-ip/ips.txt
+ - 备用2(jsDelivr CDN):https://cdn.jsdelivr.net/npm/@hcfy/google-translate-ip/ips.txt
+- 扩展 IPv4:
+ - 官方1:https://raw.githubusercontent.com/Ponderfly/GoogleTranslateIpCheck/master/src/GoogleTranslateIpCheck/GoogleTranslateIpCheck/ip.txt
+ - 官方2:https://ghproxy.com/https://raw.githubusercontent.com/Ponderfly/GoogleTranslateIpCheck/master/src/GoogleTranslateIpCheck/GoogleTranslateIpCheck/ip.txt
+ - 备用(GitCode 镜像):https://gitcode.net/mirrors/Ponderfly/GoogleTranslateIpCheck/-/raw/master/src/GoogleTranslateIpCheck/GoogleTranslateIpCheck/ip.txt
+- 标准 IPv6:
+ - 官方1:https://raw.githubusercontent.com/Ponderfly/GoogleTranslateIpCheck/master/src/GoogleTranslateIpCheck/GoogleTranslateIpCheck/IPv6.txt
+ - 官方2:https://ghproxy.com/https://raw.githubusercontent.com/Ponderfly/GoogleTranslateIpCheck/master/src/GoogleTranslateIpCheck/GoogleTranslateIpCheck/IPv6.txt
+ - 备用(GitCode 镜像):https://gitcode.net/mirrors/Ponderfly/GoogleTranslateIpCheck/-/raw/master/src/GoogleTranslateIpCheck/GoogleTranslateIpCheck/IPv6.txt
+
+程序会自动找到可用的网址并导入 IP 库(设置备用网址是因为 raw.githubusercontent.com 访问不稳定)。导入一般需要 5-10 秒,请耐心等待。
+
+感谢 @hcfyapp 和 @Ponderfly 提供的 IP 库。
+
## 版权说明
本项目使用[GPLv3](https://github.com/GoodCoder666/GoogleTranslate_IPFinder/blob/main/LICENSE)版权许可。IP 扫描逻辑参考 [https://repo.or.cz/gscan_quic](https://repo.or.cz/gscan_quic)。
-类似的项目:[hcfyapp/google-translate-cn-ip](https://github.com/hcfyapp/google-translate-cn-ip) [Ponderfly/GoogleTranslateIpCheck](https://github.com/Ponderfly/GoogleTranslateIpCheck)
-
-特别感谢 [hcfyapp/google-translate-cn-ip](https://github.com/hcfyapp/google-translate-cn-ip) 中提供的 IP 地址列表。自动同步功能的 IP 列表地址:[https://unpkg.com/@hcfy/google-translate-ip/ips.txt](https://unpkg.com/@hcfy/google-translate-ip/ips.txt)。
+类似的项目:[hcfyapp/google-translate-cn-ip](https://github.com/hcfyapp/google-translate-cn-ip) [Ponderfly/GoogleTranslateIpCheck](https://github.com/Ponderfly/GoogleTranslateIpCheck)
\ No newline at end of file
diff --git a/dlgImport.py b/dlgImport.py
new file mode 100644
index 0000000..3ec01ca
--- /dev/null
+++ b/dlgImport.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+from PySide6.QtWidgets import QDialog, QDialogButtonBox
+from PySide6.QtCore import Slot
+from ui_dlgImport import Ui_Dialog
+
+__all__ = ['dlgImport']
+
+class dlgImport(QDialog):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+ self.ui = Ui_Dialog()
+ self.ui.setupUi(self)
+
+ self.ui.buttonBox.button(QDialogButtonBox.Ok).setText('导入')
+ self.ui.buttonBox.button(QDialogButtonBox.Cancel).setText('取消')
\ No newline at end of file
diff --git a/dlgImport.ui b/dlgImport.ui
new file mode 100644
index 0000000..8c9ceb2
--- /dev/null
+++ b/dlgImport.ui
@@ -0,0 +1,269 @@
+
+
+ Dialog
+
+
+
+ 0
+ 0
+ 266
+ 326
+
+
+
+ 导入选项
+
+
+
-
+
+
+ 导入模式
+
+
+
-
+
+
+ 添加并去重
+
+
+ true
+
+
+
+ -
+
+
+ 替换全部
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 导入来源
+
+
+
-
+
+
+ 本地文件
+
+
+
+ -
+
+
-
+
+
+ 单个 IP:
+
+
+
+ -
+
+
+ false
+
+
+
+
+
+ -
+
+
+ 在线服务:
+
+
+ true
+
+
+
+ -
+
+
+ 30
+
+
-
+
+
+ 精简 IPv4
+
+
+ true
+
+
+
+ -
+
+
+ 扩展 IPv4
+
+
+
+ -
+
+
+ 标准 IPv6
+
+
+
+
+
+ -
+
+
-
+
+
+ 自定义 URL:
+
+
+
+ -
+
+
+ false
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ Dialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ Dialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+ radioOnline
+ toggled(bool)
+ chkBox_std4
+ setEnabled(bool)
+
+
+ 126
+ 158
+
+
+ 141
+ 185
+
+
+
+
+ radioOnline
+ toggled(bool)
+ chkBox_ext4
+ setEnabled(bool)
+
+
+ 126
+ 158
+
+
+ 141
+ 211
+
+
+
+
+ radioOnline
+ toggled(bool)
+ chkBox_std6
+ setEnabled(bool)
+
+
+ 126
+ 158
+
+
+ 141
+ 237
+
+
+
+
+ radioSingleIP
+ toggled(bool)
+ singleIPEdit
+ setEnabled(bool)
+
+
+ 56
+ 131
+
+
+ 172
+ 131
+
+
+
+
+ radioCustomURL
+ toggled(bool)
+ customURLEdit
+ setEnabled(bool)
+
+
+ 68
+ 265
+
+
+ 184
+ 265
+
+
+
+
+
diff --git a/main.py b/main.py
index 11ee085..86d275c 100644
--- a/main.py
+++ b/main.py
@@ -5,9 +5,10 @@
from PySide6.QtCore import Qt, Slot
from dlgScan import dlgScan
+from dlgImport import dlgImport
from threads import ScanThread, SpeedtestThread
from ui_MainWindow import Ui_MainWindow
-from utils import DEFAULT_IPS, HOST, time_repr, read_url, SYNC_URL
+from utils import DEFAULT_IPS, HOST, time_repr, read_url
app = QApplication(sys.argv)
@@ -40,12 +41,22 @@ def __init__(self, parent=None):
self.clipboard = QApplication.clipboard()
- def __load_ips(self, filename):
+ def __replace_ips(self, ips):
self.ui.ipList.clear()
- with open(filename, 'r') as file:
- for line in file:
- if line := line.rstrip():
- self.ui.ipList.addItem(QListWidgetItem(line))
+ for ip in ips:
+ if ip := ip.rstrip():
+ self.ui.ipList.addItem(QListWidgetItem(ip))
+ self.ui.statusbar.showMessage(f'导入成功,共 {len(ips)} 条 IP。')
+
+ def __add_ips(self, ips):
+ original_ips = {self.ui.ipList.item(i).text() for i in range(self.ui.ipList.count())}
+ count = 0
+ for ip in ips:
+ ip = ip.rstrip()
+ if ip and ip not in original_ips:
+ self.ui.ipList.addItem(QListWidgetItem(ip))
+ count += 1
+ self.ui.statusbar.showMessage(f'导入成功,新增 {count} 条 IP。')
def __save_ips(self, filename):
with open(filename, 'w') as file:
@@ -53,11 +64,72 @@ def __save_ips(self, filename):
file.write(self.ui.resultTable.item(row, 0).text() + '\n')
@Slot()
- def on_btnWait_Load_clicked(self):
- filename, _ = QFileDialog.getOpenFileName(self, '导入', filter=self.SUPPORTED_FILTERS)
- if not filename: return
- self.__load_ips(filename)
- self.ui.statusbar.showMessage(f'成功导入IP列表文件 [{filename}]')
+ def on_btnWait_Import_clicked(self):
+ dlg = dlgImport(self)
+ if dlg.exec() != QDialog.Accepted:
+ return
+ new_ips = None
+ if dlg.ui.radioLocalFile.isChecked():
+ filename, _ = QFileDialog.getOpenFileName(self, '导入', filter=self.SUPPORTED_FILTERS)
+ if not filename: return
+ with open(filename, 'r') as file:
+ new_ips = file.readlines()
+ elif dlg.ui.radioSingleIP.isChecked():
+ new_ips = [dlg.ui.singleIPEdit.text()]
+ elif dlg.ui.radioCustomURL.isChecked():
+ url = dlg.ui.customURLEdit.text()
+ try:
+ new_ips = read_url(url)
+ except Exception:
+ QMessageBox.critical(self, '错误', f'{url} 获取失败。请检查网络状况,然后再试。')
+ else: # radioOnline
+ SERVICES = (
+ # (checkBox, timeout, (url, [alternative_urls]))
+ (
+ dlg.ui.chkBox_std4,
+ 3.5,
+ (
+ 'https://unpkg.com/@hcfy/google-translate-ip/ips.txt',
+ 'https://ghproxy.com/https://raw.githubusercontent.com/hcfyapp/google-translate-cn-ip/master/packages/google-translate-ip/ips.txt',
+ 'https://cdn.jsdelivr.net/npm/@hcfy/google-translate-ip/ips.txt'
+ )
+ ),
+ (
+ dlg.ui.chkBox_ext4,
+ 3.5,
+ (
+ 'https://gitcode.net/mirrors/Ponderfly/GoogleTranslateIpCheck/-/raw/master/src/GoogleTranslateIpCheck/GoogleTranslateIpCheck/ip.txt',
+ 'https://ghproxy.com/https://raw.githubusercontent.com/Ponderfly/GoogleTranslateIpCheck/master/src/GoogleTranslateIpCheck/GoogleTranslateIpCheck/ip.txt',
+ 'https://raw.githubusercontent.com/Ponderfly/GoogleTranslateIpCheck/master/src/GoogleTranslateIpCheck/GoogleTranslateIpCheck/ip.txt'
+ )
+ ),
+ (
+ dlg.ui.chkBox_std6,
+ 3.5,
+ (
+ 'https://gitcode.net/mirrors/Ponderfly/GoogleTranslateIpCheck/-/raw/master/src/GoogleTranslateIpCheck/GoogleTranslateIpCheck/IPv6.txt',
+ 'https://ghproxy.com/https://raw.githubusercontent.com/Ponderfly/GoogleTranslateIpCheck/master/src/GoogleTranslateIpCheck/GoogleTranslateIpCheck/IPv6.txt',
+ 'https://raw.githubusercontent.com/Ponderfly/GoogleTranslateIpCheck/master/src/GoogleTranslateIpCheck/GoogleTranslateIpCheck/IPv6.txt'
+ )
+ )
+ )
+ new_ips = set()
+ for checkBox, timeout, urls in SERVICES:
+ if checkBox.isChecked():
+ for url in urls:
+ try:
+ current_ips = read_url(url, timeout)
+ except Exception:
+ continue
+ break
+ else:
+ QMessageBox.critical(self, '错误', f'{checkBox.text()} 获取失败。请检查网络状况,然后再试。')
+ return
+ new_ips |= current_ips
+ if dlg.ui.radioReplace.isChecked():
+ self.__replace_ips(new_ips)
+ else:
+ self.__add_ips(new_ips)
@Slot()
def on_btnResult_Save_clicked(self):
@@ -66,18 +138,6 @@ def on_btnResult_Save_clicked(self):
self.__save_ips(filename)
self.ui.statusbar.showMessage(f'成功导出IP测速结果文件 [{filename}]')
- @Slot()
- def on_btnWait_Sync_clicked(self):
- try:
- ip_list = read_url(SYNC_URL).split()
- except:
- QMessageBox.critical(self, '错误', '同步失败,请稍后再试。')
- return
- self.ui.ipList.clear()
- for ip in ip_list:
- self.ui.ipList.addItem(QListWidgetItem(ip))
- self.ui.statusbar.showMessage(f'同步完成,共 {self.ui.ipList.count()} 条 IP。')
-
@Slot()
def on_btnResult_Copy_clicked(self):
if self.ui.resultTable.rowCount() == 0:
@@ -138,9 +198,8 @@ def __set_buttons_enabled(self, enabled):
self.ui.btnResult_Copy.setEnabled(enabled)
self.ui.btnResult_Save.setEnabled(enabled)
self.ui.btnResult_WriteHosts.setEnabled(enabled)
- self.ui.btnWait_Load.setEnabled(enabled)
+ self.ui.btnWait_Import.setEnabled(enabled)
self.ui.btnWait_Scan.setEnabled(enabled)
- self.ui.btnWait_Sync.setEnabled(enabled)
self.ui.btnWait_Test.setEnabled(enabled)
def __add_result(self, ip, seconds):
@@ -165,7 +224,7 @@ def __speedtest_finished(self):
def __test_ips(self):
self.ui.resultTable.setRowCount(0)
ips = [self.ui.ipList.item(i).text() for i in range(self.ui.ipList.count())]
- thread = SpeedtestThread(self, ips, self.__add_result, self.__found_unavailable, num_workers=16)
+ thread = SpeedtestThread(self, ips, self.__add_result, self.__found_unavailable, num_workers=24)
thread.finished.connect(self.__speedtest_finished)
thread.start()
@@ -205,7 +264,9 @@ def dragEnterEvent(self, event):
event.accept()
def dropEvent(self, event):
- self.__load_ips(event.mimeData().text()[8:]) # [8:] is to get rid of 'file:///'
+ filename = event.mimeData().text()[8:] # [8:] is to get rid of 'file:///'
+ with open(filename, 'r') as file:
+ self.__replace_ips(file.readlines())
mainform = MainWindow()
diff --git a/threads.py b/threads.py
index e265cc3..85002de 100644
--- a/threads.py
+++ b/threads.py
@@ -43,7 +43,7 @@ def run(self):
task.signals.foundAvailable.connect(self.available_callback)
task.signals.foundUnavailable.connect(self.unavailable_callback)
pool.start(task)
- self.msleep(150)
+ self.msleep(120)
pool.waitForDone()
diff --git a/ui_MainWindow.py b/ui_MainWindow.py
index b8c9fc0..4dd008d 100644
--- a/ui_MainWindow.py
+++ b/ui_MainWindow.py
@@ -48,15 +48,10 @@ def setupUi(self, MainWindow):
self.horizontalLayout.addWidget(self.btnWait_Scan)
- self.btnWait_Load = QPushButton(self.centralwidget)
- self.btnWait_Load.setObjectName(u"btnWait_Load")
+ self.btnWait_Import = QPushButton(self.centralwidget)
+ self.btnWait_Import.setObjectName(u"btnWait_Import")
- self.horizontalLayout.addWidget(self.btnWait_Load)
-
- self.btnWait_Sync = QPushButton(self.centralwidget)
- self.btnWait_Sync.setObjectName(u"btnWait_Sync")
-
- self.horizontalLayout.addWidget(self.btnWait_Sync)
+ self.horizontalLayout.addWidget(self.btnWait_Import)
self.btnWait_Test = QPushButton(self.centralwidget)
self.btnWait_Test.setObjectName(u"btnWait_Test")
@@ -136,13 +131,9 @@ def retranslateUi(self, MainWindow):
#endif // QT_CONFIG(tooltip)
self.btnWait_Scan.setText(QCoreApplication.translate("MainWindow", u"\u626b\u63cf", None))
#if QT_CONFIG(tooltip)
- self.btnWait_Load.setToolTip(QCoreApplication.translate("MainWindow", u"\u4ece\u6587\u4ef6\u5bfc\u5165IP\u5217\u8868\u3002", None))
-#endif // QT_CONFIG(tooltip)
- self.btnWait_Load.setText(QCoreApplication.translate("MainWindow", u"\u5bfc\u5165", None))
-#if QT_CONFIG(tooltip)
- self.btnWait_Sync.setToolTip(QCoreApplication.translate("MainWindow", u"\u4ece\u8fdc\u7a0b\u670d\u52a1\u5668\u4e0a\u83b7\u53d6IP\u5217\u8868\u3002", None))
+ self.btnWait_Import.setToolTip(QCoreApplication.translate("MainWindow", u"\u4ece\u6307\u5b9a\u6765\u6e90\u5bfc\u5165IP\u5217\u8868\u3002", None))
#endif // QT_CONFIG(tooltip)
- self.btnWait_Sync.setText(QCoreApplication.translate("MainWindow", u"\u540c\u6b65", None))
+ self.btnWait_Import.setText(QCoreApplication.translate("MainWindow", u"\u5bfc\u5165", None))
#if QT_CONFIG(tooltip)
self.btnWait_Test.setToolTip(QCoreApplication.translate("MainWindow", u"\u5bf9\u5217\u8868\u4e2d\u7684IP\u8fdb\u884c\u53ef\u7528\u6027\u6d4b\u8bd5\u5e76\u6309\u54cd\u5e94\u901f\u5ea6\u6392\u5e8f\u3002", None))
#endif // QT_CONFIG(tooltip)
diff --git a/ui_dlgImport.py b/ui_dlgImport.py
new file mode 100644
index 0000000..4d03985
--- /dev/null
+++ b/ui_dlgImport.py
@@ -0,0 +1,158 @@
+# -*- coding: utf-8 -*-
+
+################################################################################
+## Form generated from reading UI file 'dlgImport.ui'
+##
+## Created by: Qt User Interface Compiler version 6.4.0
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
+ QMetaObject, QObject, QPoint, QRect,
+ QSize, QTime, QUrl, Qt)
+from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
+ QFont, QFontDatabase, QGradient, QIcon,
+ QImage, QKeySequence, QLinearGradient, QPainter,
+ QPalette, QPixmap, QRadialGradient, QTransform)
+from PySide6.QtWidgets import (QAbstractButton, QApplication, QCheckBox, QDialog,
+ QDialogButtonBox, QGroupBox, QHBoxLayout, QLineEdit,
+ QRadioButton, QSizePolicy, QVBoxLayout, QWidget)
+
+class Ui_Dialog(object):
+ def setupUi(self, Dialog):
+ if not Dialog.objectName():
+ Dialog.setObjectName(u"Dialog")
+ Dialog.resize(266, 326)
+ self.verticalLayout = QVBoxLayout(Dialog)
+ self.verticalLayout.setObjectName(u"verticalLayout")
+ self.groupBox_Mode = QGroupBox(Dialog)
+ self.groupBox_Mode.setObjectName(u"groupBox_Mode")
+ self.horizontalLayout = QHBoxLayout(self.groupBox_Mode)
+ self.horizontalLayout.setObjectName(u"horizontalLayout")
+ self.radioAppend = QRadioButton(self.groupBox_Mode)
+ self.radioAppend.setObjectName(u"radioAppend")
+ self.radioAppend.setChecked(True)
+
+ self.horizontalLayout.addWidget(self.radioAppend)
+
+ self.radioReplace = QRadioButton(self.groupBox_Mode)
+ self.radioReplace.setObjectName(u"radioReplace")
+
+ self.horizontalLayout.addWidget(self.radioReplace)
+
+
+ self.verticalLayout.addWidget(self.groupBox_Mode)
+
+ self.groupBox_Source = QGroupBox(Dialog)
+ self.groupBox_Source.setObjectName(u"groupBox_Source")
+ sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.groupBox_Source.sizePolicy().hasHeightForWidth())
+ self.groupBox_Source.setSizePolicy(sizePolicy)
+ self.verticalLayout_3 = QVBoxLayout(self.groupBox_Source)
+ self.verticalLayout_3.setObjectName(u"verticalLayout_3")
+ self.radioLocalFile = QRadioButton(self.groupBox_Source)
+ self.radioLocalFile.setObjectName(u"radioLocalFile")
+
+ self.verticalLayout_3.addWidget(self.radioLocalFile)
+
+ self.horizontalLayout_2 = QHBoxLayout()
+ self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
+ self.radioSingleIP = QRadioButton(self.groupBox_Source)
+ self.radioSingleIP.setObjectName(u"radioSingleIP")
+
+ self.horizontalLayout_2.addWidget(self.radioSingleIP)
+
+ self.singleIPEdit = QLineEdit(self.groupBox_Source)
+ self.singleIPEdit.setObjectName(u"singleIPEdit")
+ self.singleIPEdit.setEnabled(False)
+
+ self.horizontalLayout_2.addWidget(self.singleIPEdit)
+
+
+ self.verticalLayout_3.addLayout(self.horizontalLayout_2)
+
+ self.radioOnline = QRadioButton(self.groupBox_Source)
+ self.radioOnline.setObjectName(u"radioOnline")
+ self.radioOnline.setChecked(True)
+
+ self.verticalLayout_3.addWidget(self.radioOnline)
+
+ self.verticalLayout_2 = QVBoxLayout()
+ self.verticalLayout_2.setObjectName(u"verticalLayout_2")
+ self.verticalLayout_2.setContentsMargins(30, -1, -1, -1)
+ self.chkBox_std4 = QCheckBox(self.groupBox_Source)
+ self.chkBox_std4.setObjectName(u"chkBox_std4")
+ self.chkBox_std4.setChecked(True)
+
+ self.verticalLayout_2.addWidget(self.chkBox_std4)
+
+ self.chkBox_ext4 = QCheckBox(self.groupBox_Source)
+ self.chkBox_ext4.setObjectName(u"chkBox_ext4")
+
+ self.verticalLayout_2.addWidget(self.chkBox_ext4)
+
+ self.chkBox_std6 = QCheckBox(self.groupBox_Source)
+ self.chkBox_std6.setObjectName(u"chkBox_std6")
+
+ self.verticalLayout_2.addWidget(self.chkBox_std6)
+
+
+ self.verticalLayout_3.addLayout(self.verticalLayout_2)
+
+ self.horizontalLayout_3 = QHBoxLayout()
+ self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
+ self.radioCustomURL = QRadioButton(self.groupBox_Source)
+ self.radioCustomURL.setObjectName(u"radioCustomURL")
+
+ self.horizontalLayout_3.addWidget(self.radioCustomURL)
+
+ self.customURLEdit = QLineEdit(self.groupBox_Source)
+ self.customURLEdit.setObjectName(u"customURLEdit")
+ self.customURLEdit.setEnabled(False)
+
+ self.horizontalLayout_3.addWidget(self.customURLEdit)
+
+
+ self.verticalLayout_3.addLayout(self.horizontalLayout_3)
+
+
+ self.verticalLayout.addWidget(self.groupBox_Source)
+
+ self.buttonBox = QDialogButtonBox(Dialog)
+ self.buttonBox.setObjectName(u"buttonBox")
+ self.buttonBox.setOrientation(Qt.Horizontal)
+ self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok)
+
+ self.verticalLayout.addWidget(self.buttonBox)
+
+
+ self.retranslateUi(Dialog)
+ self.buttonBox.accepted.connect(Dialog.accept)
+ self.buttonBox.rejected.connect(Dialog.reject)
+ self.radioOnline.toggled.connect(self.chkBox_std4.setEnabled)
+ self.radioOnline.toggled.connect(self.chkBox_ext4.setEnabled)
+ self.radioOnline.toggled.connect(self.chkBox_std6.setEnabled)
+ self.radioSingleIP.toggled.connect(self.singleIPEdit.setEnabled)
+ self.radioCustomURL.toggled.connect(self.customURLEdit.setEnabled)
+
+ QMetaObject.connectSlotsByName(Dialog)
+ # setupUi
+
+ def retranslateUi(self, Dialog):
+ Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"\u5bfc\u5165\u9009\u9879", None))
+ self.groupBox_Mode.setTitle(QCoreApplication.translate("Dialog", u"\u5bfc\u5165\u6a21\u5f0f", None))
+ self.radioAppend.setText(QCoreApplication.translate("Dialog", u"\u6dfb\u52a0\u5e76\u53bb\u91cd", None))
+ self.radioReplace.setText(QCoreApplication.translate("Dialog", u"\u66ff\u6362\u5168\u90e8", None))
+ self.groupBox_Source.setTitle(QCoreApplication.translate("Dialog", u"\u5bfc\u5165\u6765\u6e90", None))
+ self.radioLocalFile.setText(QCoreApplication.translate("Dialog", u"\u672c\u5730\u6587\u4ef6", None))
+ self.radioSingleIP.setText(QCoreApplication.translate("Dialog", u"\u5355\u4e2a IP\uff1a", None))
+ self.radioOnline.setText(QCoreApplication.translate("Dialog", u"\u5728\u7ebf\u670d\u52a1\uff1a", None))
+ self.chkBox_std4.setText(QCoreApplication.translate("Dialog", u"\u7cbe\u7b80 IPv4", None))
+ self.chkBox_ext4.setText(QCoreApplication.translate("Dialog", u"\u6269\u5c55 IPv4", None))
+ self.chkBox_std6.setText(QCoreApplication.translate("Dialog", u"\u6807\u51c6 IPv6", None))
+ self.radioCustomURL.setText(QCoreApplication.translate("Dialog", u"\u81ea\u5b9a\u4e49 URL\uff1a", None))
+ # retranslateUi
+
diff --git a/utils.py b/utils.py
index 4f0e964..f62f9c6 100644
--- a/utils.py
+++ b/utils.py
@@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
+import ssl
+from gzip import GzipFile
from json import JSONDecoder
from time import time
from urllib.request import Request, urlopen
-import ssl
-__all__ = ['test_ip', 'check_ip', 'time_repr', 'dns_query', 'HOST', 'DEFAULT_IPS']
+__all__ = ['read_url', 'test_ip', 'check_ip', 'time_repr', 'dns_query', 'HOST', 'DEFAULT_IPS']
HOST = 'translate.googleapis.com'
TESTIP_FORMAT = 'https://{}/translate_a/single?client=gtx&sl=en&tl=fr&q=a'
@@ -56,9 +57,16 @@ def dns_query(name=HOST, server='1.1.1.1', type='A', path='/dns-query'):
reply = JSONDecoder().decode(content)
return [] if 'Answer' not in reply else [_['data'] for _ in reply['Answer']]
-SYNC_URL = 'https://unpkg.com/@hcfy/google-translate-ip/ips.txt'
-def read_url(url):
- with urlopen(url) as response:
- return response.read().decode('utf-8')
+def read_url(url, timeout=3.5):
+ request = Request(url)
+ request.add_header('Accept-Encoding', 'gzip')
+ with urlopen(request, timeout=timeout) as response:
+ # Handle gzip
+ cs = response.getheader('Content-Type')
+ cs = cs[cs.rfind('=') + 1:]
+ if response.getheader('Content-Encoding') == 'gzip':
+ with GzipFile(fileobj=response) as gz:
+ return {s.decode('utf-8').strip() for s in gz}
+ return {s.decode('utf-8').strip() for s in response}
-DEFAULT_IPS = ['172.217.204.90', '172.253.58.90', '142.250.189.206', '142.250.28.90', '142.251.107.90', '142.250.11.90', '142.250.185.238', '142.250.159.90', '142.250.31.90', '142.250.1.90', '172.217.0.46', '142.250.103.90', '142.251.40.174', '142.251.160.90', '142.250.9.90', '108.177.122.90', '142.250.128.90', '142.251.116.90', '172.253.112.90', '142.251.10.138', '142.250.126.90', '172.253.115.90', '108.177.111.90', '142.251.117.90', '142.250.107.90', '216.58.214.14', '142.250.111.90', '142.251.15.90', '142.250.185.174', '142.251.16.185', '142.250.101.90', '172.253.124.90', '172.217.203.90', '142.250.138.90', '142.250.98.90', '142.250.157.183', '142.251.18.90', '172.253.113.90', '142.250.113.90', '142.251.10.90', '142.250.157.184', '142.250.125.185', '172.217.215.90', '142.250.158.90', '142.250.114.90', '142.250.153.90', '108.177.125.186', '216.58.227.66', '172.217.195.90', '142.251.1.90', '172.253.122.90', '216.58.227.65', '142.250.145.90', '172.253.119.90', '142.251.8.90', '142.250.125.90', '108.177.127.90', '142.250.157.90', '142.251.2.90', '142.251.9.90', '142.250.8.90', '142.250.152.90', '142.250.105.90', '142.250.102.90', '142.250.217.185', '142.251.175.90', '142.251.171.90', '142.251.120.90', '172.217.222.90', '172.253.114.90', '216.58.227.67', '142.250.96.90', '142.250.4.185', '142.250.136.90', '172.253.126.90', '142.250.13.90', '142.251.166.90', '172.253.127.90', '142.250.30.90', '142.250.100.90', '142.250.157.186', '142.251.116.101', '108.177.97.100', '172.253.63.90', '142.250.218.14', '142.250.110.90', '142.250.0.90', '142.251.12.90', '142.250.112.90', '142.250.12.90', '172.217.16.46', '142.251.162.90', '172.217.214.90', '172.253.117.90', '142.250.141.90', '172.217.31.142', '142.250.123.90', '142.251.111.90', '142.251.172.90', '216.58.220.142', '142.250.10.90', '172.253.116.90', '142.251.0.90', '142.251.4.90', '142.250.4.90', '172.217.13.142', '142.250.203.142', '142.251.5.90', '142.251.163.90', '172.253.125.90', '142.251.112.90', '172.253.123.90', '142.250.142.90', '142.250.27.90', '142.251.12.185', '108.177.126.90', '142.250.99.90', '142.250.97.90', '142.251.16.90', '142.250.115.90', '142.251.6.90', '216.58.209.174', '172.217.192.90', '172.253.62.90', '172.253.118.90', '142.251.161.90']
\ No newline at end of file
+DEFAULT_IPS = ['108.177.111.90', '108.177.122.90', '108.177.125.186', '108.177.126.90', '108.177.127.90', '108.177.97.100', '142.250.0.90', '142.250.1.90', '142.250.10.90', '142.250.100.90', '142.250.101.90', '142.250.102.90', '142.250.103.90', '142.250.105.90', '142.250.107.90', '142.250.11.90', '142.250.110.90', '142.250.111.90', '142.250.112.90', '142.250.113.90', '142.250.114.90', '142.250.115.90', '142.250.12.90', '142.250.123.90', '142.250.125.185', '142.250.125.90', '142.250.126.90', '142.250.128.90', '142.250.13.90', '142.250.136.90', '142.250.138.90', '142.250.141.90', '142.250.142.90', '142.250.145.90', '142.250.152.90', '142.250.153.90', '142.250.157.183', '142.250.157.184', '142.250.157.186', '142.250.157.90', '142.250.158.90', '142.250.159.90', '142.250.185.174', '142.250.185.238', '142.250.189.206', '142.250.203.142', '142.250.217.185', '142.250.218.14', '142.250.27.90', '142.250.28.90', '142.250.30.90', '142.250.31.90', '142.250.4.185', '142.250.4.90', '142.250.8.90', '142.250.9.90', '142.250.96.90', '142.250.97.90', '142.250.98.90', '142.250.99.90', '142.251.0.90', '142.251.1.90', '142.251.10.138', '142.251.10.90', '142.251.107.90', '142.251.111.90', '142.251.112.90', '142.251.116.101', '142.251.116.90', '142.251.117.90', '142.251.12.185', '142.251.12.90', '142.251.120.90', '142.251.15.90', '142.251.16.185', '142.251.16.90', '142.251.160.90', '142.251.161.90', '142.251.162.90', '142.251.163.90', '142.251.166.90', '142.251.171.90', '142.251.172.90', '142.251.175.90', '142.251.18.90', '142.251.2.90', '142.251.4.90', '142.251.40.174', '142.251.5.90', '142.251.6.90', '142.251.8.90', '142.251.9.90', '172.217.0.46', '172.217.13.142', '172.217.16.46', '172.217.192.90', '172.217.195.90', '172.217.203.90', '172.217.204.90', '172.217.214.90', '172.217.215.90', '172.217.218.90', '172.217.222.90', '172.217.31.142', '172.253.112.90', '172.253.113.90', '172.253.114.90', '172.253.115.90', '172.253.116.90', '172.253.117.90', '172.253.118.90', '172.253.119.90', '172.253.122.90', '172.253.123.90', '172.253.124.90', '172.253.125.90', '172.253.126.90', '172.253.127.90', '172.253.58.90', '172.253.62.90', '172.253.63.90', '216.239.32.40', '216.58.209.174', '216.58.214.14', '216.58.220.142', '216.58.227.65', '216.58.227.66', '216.58.227.67', '64.233.189.191', '74.125.196.113']
\ No newline at end of file