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