Compare commits

...

15 Commits

Author SHA1 Message Date
armv9
adef6cd4af 4.0.1 2024-12-12 17:03:36 +09:00
armv9
399b171adf misc change 2024-12-12 17:03:32 +09:00
armv9
6e4c180428 fix: dns outbound 2024-12-12 17:02:37 +09:00
armv9
75c6496151 change: domain rule use domain_suffix 2024-12-12 17:02:14 +09:00
Integral
62c59f6fd3
refactor: replace non-empty QString constructors with QStringLiteral() 2024-11-03 12:50:41 +08:00
armv9
12d6fc24e7 4.0-beta4 2024-10-09 13:32:41 +09:00
armv9
6de7c588b6 update core 2024-10-09 13:32:41 +09:00
armv9
99c8d50943 add url test button on main window 2024-10-09 13:32:41 +09:00
极速蜗牛
2a177256ce
Add /usr/share/sing-box to core asset search path (#1350) 2024-07-20 13:23:24 +08:00
Chi_Tang
b1d1674912
fixed pkgbuild for 4.0 (#1348) 2024-07-13 17:36:39 +08:00
armv9
2dd9cf45eb update readme 2024-07-13 15:57:07 +09:00
armv9
96a6586c5e 4.0-beta3 2024-07-13 15:39:11 +09:00
armv9
375ffec58d remove v2ray_asset_dir 2024-07-13 15:37:07 +09:00
armv9
7aa863b881 remove log high light 2024-07-13 15:26:01 +09:00
armv9
79838d8679 urltest: use dns 2024-07-07 15:25:15 +09:00
37 changed files with 255 additions and 475 deletions

18
.github/workflows/update-pkgbuild.yml vendored Normal file
View File

@ -0,0 +1,18 @@
name: AUR CI
on:
push:
branches:
- main
paths-ignore:
- '**.md'
- 'LICENSE'
- '!.github/workflows/**'
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: chitang233/aur-pkgbuild-builder@main
with:
deploy_key: ${{ secrets.DEPLOY_KEY }}
package_name: 'nekoray-git'

View File

@ -353,7 +353,7 @@ namespace Qv2ray::components::proxy {
// execute and get the code // execute and get the code
const auto returnCode = QProcess::execute(action.first, action.second); const auto returnCode = QProcess::execute(action.first, action.second);
// print out the commands and result codes // print out the commands and result codes
DEBUG(QString("[%1] Program: %2, Args: %3").arg(returnCode).arg(action.first).arg(action.second.join(";"))); DEBUG(QStringLiteral("[%1] Program: %2, Args: %3").arg(returnCode).arg(action.first).arg(action.second.join(";")));
// give the code back // give the code back
results << (returnCode == QProcess::NormalExit); results << (returnCode == QProcess::NormalExit);
} }
@ -423,7 +423,7 @@ namespace Qv2ray::components::proxy {
// execute and get the code // execute and get the code
const auto returnCode = QProcess::execute(action.first, action.second); const auto returnCode = QProcess::execute(action.first, action.second);
// print out the commands and result codes // print out the commands and result codes
DEBUG(QString("[%1] Program: %2, Args: %3").arg(returnCode).arg(action.first).arg(action.second.join(";"))); DEBUG(QStringLiteral("[%1] Program: %2, Args: %3").arg(returnCode).arg(action.first).arg(action.second.join(";")));
} }
#else #else

View File

@ -1,132 +0,0 @@
#include "LogHighlighter.hpp"
#define TO_EOL "(([\\s\\S]*)|([\\d\\D]*)|([\\w\\W]*))$"
#define REGEX_IPV6_ADDR \
R"(\[\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*\])"
#define REGEX_IPV4_ADDR \
R"((\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5]))"
#define REGEX_PORT_NUMBER R"(([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-5]{2}[0-3][0-5])*)"
namespace Qv2ray::ui {
SyntaxHighlighter::SyntaxHighlighter(bool darkMode, QTextDocument *parent) : QSyntaxHighlighter(parent) {
HighlightingRule rule;
if (darkMode) {
tcpudpFormat.setForeground(QColor(0, 200, 230));
ipHostFormat.setForeground(Qt::yellow);
warningFormat.setForeground(QColor(255, 160, 15));
warningFormat2.setForeground(Qt::cyan);
} else {
ipHostFormat.setForeground(QColor(0, 52, 130));
tcpudpFormat.setForeground(QColor(0, 52, 130));
warningFormat.setBackground(QColor(255, 160, 15));
warningFormat.setForeground(Qt::white);
warningFormat2.setForeground(Qt::darkCyan);
}
const static QColor darkGreenColor(10, 180, 0);
acceptedFormat.setForeground(darkGreenColor);
acceptedFormat.setFontItalic(true);
acceptedFormat.setFontWeight(QFont::Bold);
rule.pattern = QRegularExpression("\\saccepted\\s");
rule.format = acceptedFormat;
highlightingRules.append(rule);
//
rejectedFormat.setFontWeight(QFont::Bold);
rejectedFormat.setBackground(Qt::red);
rejectedFormat.setForeground(Qt::white);
rejectedFormat.setFontWeight(QFont::Bold);
rule.pattern = QRegularExpression("\\srejected\\s" TO_EOL);
rule.format = rejectedFormat;
highlightingRules.append(rule);
//
dateFormat.setForeground(darkMode ? Qt::cyan : Qt::darkCyan);
rule.pattern = QRegularExpression("\\d\\d\\d\\d/\\d\\d/\\d\\d");
rule.format = dateFormat;
highlightingRules.append(rule);
//
timeFormat.setForeground(darkMode ? Qt::cyan : Qt::darkCyan);
rule.pattern = QRegularExpression("\\d\\d:\\d\\d:\\d\\d");
rule.format = timeFormat;
highlightingRules.append(rule);
//
debugFormat.setForeground(Qt::darkGray);
rule.pattern = QRegularExpression("\\[D[Ee][Bb][Uu].*?\\]");
rule.format = debugFormat;
highlightingRules.append(rule);
//
infoFormat.setForeground(darkMode ? Qt::lightGray : Qt::darkCyan);
rule.pattern = QRegularExpression("\\[I[Nn][Ff][Oo].*?\\]");
rule.format = infoFormat;
highlightingRules.append(rule);
//
warningFormat.setFontWeight(QFont::Bold);
warningFormat2.setFontWeight(QFont::Bold);
rule.pattern = QRegularExpression("\\[W[Aa][Rr][Nn].*?\\]");
rule.format = warningFormat2;
highlightingRules.append(rule);
//
rule.pattern = QRegularExpression("\\[E[Rr][Rr][Oo].*?\\]");
rule.format = rejectedFormat;
highlightingRules.append(rule);
//
v2rayComponentFormat.setForeground(darkMode ? darkGreenColor : Qt::darkYellow);
rule.pattern = QRegularExpression(R"( (\w+\/)+\w+: )");
rule.format = v2rayComponentFormat;
highlightingRules.append(rule);
//
failedFormat.setFontWeight(QFont::Bold);
failedFormat.setBackground(Qt::red);
failedFormat.setForeground(Qt::white);
rule.pattern = QRegularExpression("failed");
rule.format = failedFormat;
highlightingRules.append(rule);
//
rule.pattern = QRegularExpression(">>>>+");
rule.format = warningFormat;
highlightingRules.append(rule);
//
rule.pattern = QRegularExpression("<<<<+");
rule.format = warningFormat;
highlightingRules.append(rule);
{
// IP IPv6 Host;
rule.pattern = QRegularExpression(REGEX_IPV4_ADDR ":" REGEX_PORT_NUMBER);
rule.pattern.setPatternOptions(QRegularExpression::ExtendedPatternSyntaxOption);
rule.format = ipHostFormat;
highlightingRules.append(rule);
//
rule.pattern = QRegularExpression(REGEX_IPV6_ADDR ":" REGEX_PORT_NUMBER);
rule.pattern.setPatternOptions(QRegularExpression::ExtendedPatternSyntaxOption);
rule.format = ipHostFormat;
highlightingRules.append(rule);
//
rule.pattern = QRegularExpression("([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}(/|):" REGEX_PORT_NUMBER);
rule.pattern.setPatternOptions(QRegularExpression::PatternOption::ExtendedPatternSyntaxOption);
rule.format = ipHostFormat;
highlightingRules.append(rule);
}
for (const auto &pattern: {"tcp:", "udp:"}) {
tcpudpFormat.setFontWeight(QFont::Bold);
rule.pattern = QRegularExpression(pattern);
rule.format = tcpudpFormat;
highlightingRules.append(rule);
}
}
void SyntaxHighlighter::highlightBlock(const QString &text) {
for (const HighlightingRule &rule: highlightingRules) {
QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text);
while (matchIterator.hasNext()) {
QRegularExpressionMatch match = matchIterator.next();
setFormat(match.capturedStart(), match.capturedLength(), rule.format);
}
}
setCurrentBlockState(0);
}
} // namespace Qv2ray::ui

View File

@ -1,92 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#pragma once
#include <QRegularExpression>
#include <QSyntaxHighlighter>
#include <QTextCharFormat>
#include <QTextDocument>
namespace Qv2ray {
namespace ui {
class SyntaxHighlighter : public QSyntaxHighlighter {
Q_OBJECT
public:
explicit SyntaxHighlighter(bool darkMode, QTextDocument *parent = nullptr);
protected:
void highlightBlock(const QString &text) override;
private:
struct HighlightingRule {
QRegularExpression pattern;
QTextCharFormat format;
};
QVector<HighlightingRule> highlightingRules;
QTextCharFormat tcpudpFormat;
QTextCharFormat dateFormat;
QTextCharFormat acceptedFormat;
QTextCharFormat rejectedFormat;
QTextCharFormat failedFormat;
QTextCharFormat warningFormat;
QTextCharFormat warningFormat2;
QTextCharFormat infoFormat;
QTextCharFormat debugFormat;
QTextCharFormat timeFormat;
QTextCharFormat ipHostFormat;
QTextCharFormat v2rayComponentFormat;
};
} // namespace ui
} // namespace Qv2ray
using namespace Qv2ray::ui;

View File

@ -191,13 +191,13 @@ QVariant QJsonModel::data(const QModelIndex &index, int role) const {
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole) {
if (index.column() == 0) if (index.column() == 0)
return QString("%1").arg(item->key()); return QStringLiteral("%1").arg(item->key());
if (index.column() == 1) if (index.column() == 1)
return QString("%1").arg(item->value()); return QStringLiteral("%1").arg(item->value());
} else if (Qt::EditRole == role) { } else if (Qt::EditRole == role) {
if (index.column() == 1) { if (index.column() == 1) {
return QString("%1").arg(item->value()); return QStringLiteral("%1").arg(item->value());
} }
} }

View File

@ -131,7 +131,6 @@ set(PROJECT_SOURCES
3rdparty/qrcodegen.cpp 3rdparty/qrcodegen.cpp
3rdparty/QtExtKeySequenceEdit.cpp 3rdparty/QtExtKeySequenceEdit.cpp
3rdparty/qv2ray/v2/ui/LogHighlighter.cpp
3rdparty/qv2ray/v2/ui/QvAutoCompleteTextEdit.cpp 3rdparty/qv2ray/v2/ui/QvAutoCompleteTextEdit.cpp
3rdparty/qv2ray/v2/components/proxy/QvProxyConfigurator.cpp 3rdparty/qv2ray/v2/components/proxy/QvProxyConfigurator.cpp
3rdparty/qv2ray/v2/ui/widgets/common/QJsonModel.cpp 3rdparty/qv2ray/v2/ui/widgets/common/QJsonModel.cpp

View File

@ -8,16 +8,6 @@ Support Windows / Linux out of the box now.
目前支持 Windows / Linux 开箱即用 目前支持 Windows / Linux 开箱即用
## 4.x 开发计划
软件定位:电脑端节点调试软件。更新频率随机,可用性无保证。机场订阅用户建议使用 Clash Verge Rev 等。
1. 移除 Xray 核心,更新 sing-box。
2. 移除一些没用的功能。
3. 更新文档。
4. 更新部分依赖
5. 移除 macos 遗留
## 下载 / Download ## 下载 / Download
### GitHub Releases (Portable ZIP) ### GitHub Releases (Portable ZIP)

View File

@ -22,30 +22,48 @@ namespace NekoGui {
} }
QString genTunName() { QString genTunName() {
auto tun_name = "nekobox-tun"; auto tun_name = "neko-tun";
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
tun_name = "utun9"; tun_name = "utun9";
#endif #endif
return tun_name; return tun_name;
} }
void MergeJson(const QJsonObject &custom, QJsonObject &outbound) { void MergeJson(QJsonObject &dst, const QJsonObject &src) {
// 合并 // 合并
if (custom.isEmpty()) return; if (src.isEmpty()) return;
for (const auto &key: custom.keys()) { for (const auto &key: src.keys()) {
if (outbound.contains(key)) { auto v_src = src[key];
auto v = custom[key]; if (dst.contains(key)) {
auto v_orig = outbound[key]; auto v_dst = dst[key];
if (v.isObject() && v_orig.isObject()) { // isObject 则合并? if (v_src.isObject() && v_dst.isObject()) { // isObject 则合并?
auto vo = v.toObject(); auto v_src_obj = v_src.toObject();
QJsonObject vo_orig = v_orig.toObject(); auto v_dst_obj = v_dst.toObject();
MergeJson(vo, vo_orig); MergeJson(v_dst_obj, v_src_obj);
outbound[key] = vo_orig; dst[key] = v_dst_obj;
} else { } else {
outbound[key] = v; dst[key] = v_src;
}
} else if (v_src.isArray()) {
if (key.startsWith("+")) {
auto key2 = SubStrAfter(key, "+");
auto v_dst = dst[key2];
auto v_src_arr = v_src.toArray();
auto v_dst_arr = v_dst.toArray();
QJSONARRAY_ADD(v_src_arr, v_dst_arr)
dst[key2] = v_src_arr;
} else if (key.endsWith("+")) {
auto key2 = SubStrBefore(key, "+");
auto v_dst = dst[key2];
auto v_src_arr = v_src.toArray();
auto v_dst_arr = v_dst.toArray();
QJSONARRAY_ADD(v_dst_arr, v_src_arr)
dst[key2] = v_dst_arr;
} else {
dst[key] = v_src;
} }
} else { } else {
outbound[key] = custom[key]; dst[key] = v_src;
} }
} }
} }
@ -68,7 +86,7 @@ namespace NekoGui {
} }
// apply custom config // apply custom config
MergeJson(QString2QJsonObject(ent->bean->custom_config), result->coreConfig); MergeJson(result->coreConfig, QString2QJsonObject(ent->bean->custom_config));
return result; return result;
} }
@ -76,7 +94,7 @@ namespace NekoGui {
QString BuildChain(int chainId, const std::shared_ptr<BuildConfigStatus> &status) { QString BuildChain(int chainId, const std::shared_ptr<BuildConfigStatus> &status) {
auto group = profileManager->GetGroup(status->ent->gid); auto group = profileManager->GetGroup(status->ent->gid);
if (group == nullptr) { if (group == nullptr) {
status->result->error = QString("This profile is not in any group, your data may be corrupted."); status->result->error = QStringLiteral("This profile is not in any group, your data may be corrupted.");
return {}; return {};
} }
@ -88,11 +106,11 @@ namespace NekoGui {
for (auto id: list) { for (auto id: list) {
resolved += profileManager->GetProfile(id); resolved += profileManager->GetProfile(id);
if (resolved.last() == nullptr) { if (resolved.last() == nullptr) {
status->result->error = QString("chain missing ent: %1").arg(id); status->result->error = QStringLiteral("chain missing ent: %1").arg(id);
break; break;
} }
if (resolved.last()->type == "chain") { if (resolved.last()->type == "chain") {
status->result->error = QString("chain in chain is not allowed: %1").arg(id); status->result->error = QStringLiteral("chain in chain is not allowed: %1").arg(id);
break; break;
} }
} }
@ -109,7 +127,7 @@ namespace NekoGui {
if (group->front_proxy_id >= 0) { if (group->front_proxy_id >= 0) {
auto fEnt = profileManager->GetProfile(group->front_proxy_id); auto fEnt = profileManager->GetProfile(group->front_proxy_id);
if (fEnt == nullptr) { if (fEnt == nullptr) {
status->result->error = QString("front proxy ent not found."); status->result->error = QStringLiteral("front proxy ent not found.");
return {}; return {};
} }
ents += resolveChain(fEnt); ents += resolveChain(fEnt);
@ -342,7 +360,7 @@ namespace NekoGui {
} }
// apply custom outbound settings // apply custom outbound settings
MergeJson(QString2QJsonObject(ent->bean->custom_outbound), outbound); MergeJson(outbound, QString2QJsonObject(ent->bean->custom_outbound));
// Bypass Lookup for the first profile // Bypass Lookup for the first profile
auto serverAddress = ent->bean->serverAddress; auto serverAddress = ent->bean->serverAddress;
@ -486,7 +504,7 @@ namespace NekoGui {
} else if (item.startsWith("keyword:")) { } else if (item.startsWith("keyword:")) {
domain_keyword += item.replace("keyword:", "").toLower(); domain_keyword += item.replace("keyword:", "").toLower();
} else { } else {
domain_full += item.toLower(); domain_subdomain += item.toLower();
} }
} }
} }
@ -523,21 +541,22 @@ namespace NekoGui {
}; };
// Direct // Direct
auto directDNSAddress = dataStore->routing->direct_dns; QJsonObject directObj{
if (!status->forTest) { {"tag", "dns-direct"},
QJsonObject directObj{ {"address_resolver", "dns-local"},
{"tag", "dns-direct"}, {"strategy", dataStore->routing->direct_dns_strategy},
{"address_resolver", "dns-local"}, {"address", dataStore->routing->direct_dns},
{"strategy", dataStore->routing->direct_dns_strategy}, {"detour", "direct"},
{"address", directDNSAddress.replace("+local://", "://")}, };
{"detour", "direct"}, if (dataStore->routing->dns_final_out == "bypass") {
}; dnsServers.prepend(directObj);
if (dataStore->routing->dns_final_out == "bypass") { } else {
dnsServers.prepend(directObj); dnsServers.append(directObj);
} else {
dnsServers.append(directObj);
}
} }
dnsRules.append(QJsonObject{
{"outbound", "any"},
{"server", "dns-direct"},
});
// block // block
if (!status->forTest) if (!status->forTest)
@ -687,7 +706,7 @@ namespace NekoGui {
QJSONARRAY_ADD(routingRules, status->routingRules) QJSONARRAY_ADD(routingRules, status->routingRules)
auto routeObj = QJsonObject{ auto routeObj = QJsonObject{
{"rules", routingRules}, {"rules", routingRules},
{"auto_detect_interface", dataStore->spmode_vpn}, {"auto_detect_interface", dataStore->spmode_vpn}, // TODO force enable?
{ {
"geoip", "geoip",
QJsonObject{ QJsonObject{
@ -725,8 +744,8 @@ namespace NekoGui {
QString WriteVPNSingBoxConfig() { QString WriteVPNSingBoxConfig() {
// tun user rule // tun user rule
auto match_out = dataStore->vpn_rule_white ? "nekobox-socks" : "direct"; auto match_out = dataStore->vpn_rule_white ? "neko-socks" : "direct";
auto no_match_out = dataStore->vpn_rule_white ? "direct" : "nekobox-socks"; auto no_match_out = dataStore->vpn_rule_white ? "direct" : "neko-socks";
QString process_name_rule = dataStore->vpn_rule_process.trimmed(); QString process_name_rule = dataStore->vpn_rule_process.trimmed();
if (!process_name_rule.isEmpty()) { if (!process_name_rule.isEmpty()) {

View File

@ -42,7 +42,7 @@ namespace NekoGui {
// Load Proxys // Load Proxys
QList<int> delProfile; QList<int> delProfile;
for (auto id: profilesIdOrder) { for (auto id: profilesIdOrder) {
auto ent = LoadProxyEntity(QString("profiles/%1.json").arg(id)); auto ent = LoadProxyEntity(QStringLiteral("profiles/%1.json").arg(id));
// Corrupted profile? // Corrupted profile?
if (ent == nullptr || ent->bean == nullptr || ent->bean->version == -114514) { if (ent == nullptr || ent->bean == nullptr || ent->bean->version == -114514) {
delProfile << id; delProfile << id;
@ -58,7 +58,7 @@ namespace NekoGui {
auto loadedOrder = groupsTabOrder; auto loadedOrder = groupsTabOrder;
groupsTabOrder = {}; groupsTabOrder = {};
for (auto id: groupsIdOrder) { for (auto id: groupsIdOrder) {
auto ent = LoadGroup(QString("groups/%1.json").arg(id)); auto ent = LoadGroup(QStringLiteral("groups/%1.json").arg(id));
// Corrupted group? // Corrupted group?
if (ent->id != id) { if (ent->id != id) {
continue; continue;
@ -103,7 +103,7 @@ namespace NekoGui {
auto newId = i++; auto newId = i++;
profile->id = newId; profile->id = newId;
profile->gid = gidOld2New[gid]; profile->gid = gidOld2New[gid];
profile->fn = QString("profiles/%1.json").arg(newId); profile->fn = QStringLiteral("profiles/%1.json").arg(newId);
profile->Save(); profile->Save();
newProfiles[newId] = profile; newProfiles[newId] = profile;
newProfilesIdOrder << newId; newProfilesIdOrder << newId;
@ -122,7 +122,7 @@ namespace NekoGui {
auto group = groups[oldGid]; auto group = groups[oldGid];
QFile::remove(group->fn); QFile::remove(group->fn);
group->id = newId; group->id = newId;
group->fn = QString("groups/%1.json").arg(newId); group->fn = QStringLiteral("groups/%1.json").arg(newId);
group->Save(); group->Save();
newGroups[newId] = group; newGroups[newId] = group;
newGroupsIdOrder << newId; newGroupsIdOrder << newId;
@ -227,7 +227,7 @@ namespace NekoGui {
if (latency < 0) { if (latency < 0) {
return QObject::tr("Unavailable"); return QObject::tr("Unavailable");
} else if (latency > 0) { } else if (latency > 0) {
return UNICODE_LRO + QString("%1 ms").arg(latency); return UNICODE_LRO + QStringLiteral("%1 ms").arg(latency);
} else { } else {
return ""; return "";
} }
@ -268,7 +268,7 @@ namespace NekoGui {
profiles[ent->id] = ent; profiles[ent->id] = ent;
profilesIdOrder.push_back(ent->id); profilesIdOrder.push_back(ent->id);
ent->fn = QString("profiles/%1.json").arg(ent->id); ent->fn = QStringLiteral("profiles/%1.json").arg(ent->id);
ent->Save(); ent->Save();
return true; return true;
} }
@ -278,7 +278,7 @@ namespace NekoGui {
if (dataStore->started_id == id) return; if (dataStore->started_id == id) return;
profiles.erase(id); profiles.erase(id);
profilesIdOrder.removeAll(id); profilesIdOrder.removeAll(id);
QFile(QString("profiles/%1.json").arg(id)).remove(); QFile(QStringLiteral("profiles/%1.json").arg(id)).remove();
} }
void ProfileManager::MoveProfile(const std::shared_ptr<ProxyEntity> &ent, int gid) { void ProfileManager::MoveProfile(const std::shared_ptr<ProxyEntity> &ent, int gid) {
@ -342,7 +342,7 @@ namespace NekoGui {
groupsIdOrder.push_back(ent->id); groupsIdOrder.push_back(ent->id);
groupsTabOrder.push_back(ent->id); groupsTabOrder.push_back(ent->id);
ent->fn = QString("groups/%1.json").arg(ent->id); ent->fn = QStringLiteral("groups/%1.json").arg(ent->id);
ent->Save(); ent->Save();
return true; return true;
} }
@ -359,7 +359,7 @@ namespace NekoGui {
groups.erase(gid); groups.erase(gid);
groupsIdOrder.removeAll(gid); groupsIdOrder.removeAll(gid);
groupsTabOrder.removeAll(gid); groupsTabOrder.removeAll(gid);
QFile(QString("groups/%1.json").arg(gid)).remove(); QFile(QStringLiteral("groups/%1.json").arg(gid)).remove();
} }
std::shared_ptr<Group> ProfileManager::GetGroup(int id) { std::shared_ptr<Group> ProfileManager::GetGroup(int id) {

View File

@ -29,12 +29,12 @@ namespace NekoGui_traffic {
} }
[[nodiscard]] QString DisplaySpeed() const { [[nodiscard]] QString DisplaySpeed() const {
return UNICODE_LRO + QString("%1↑ %2↓").arg(ReadableSize(uplink_rate), ReadableSize(downlink_rate)); return UNICODE_LRO + QStringLiteral("%1↑ %2↓").arg(ReadableSize(uplink_rate), ReadableSize(downlink_rate));
} }
[[nodiscard]] QString DisplayTraffic() const { [[nodiscard]] QString DisplayTraffic() const {
if (downlink + uplink == 0) return ""; if (downlink + uplink == 0) return "";
return UNICODE_LRO + QString("%1↑ %2↓").arg(ReadableSize(uplink), ReadableSize(downlink)); return UNICODE_LRO + QStringLiteral("%1↑ %2↓").arg(ReadableSize(uplink), ReadableSize(downlink));
} }
}; };
} // namespace NekoGui_traffic } // namespace NekoGui_traffic

View File

@ -38,7 +38,7 @@ namespace NekoGui_fmt {
} }
QString AbstractBean::DisplayTypeAndName() { QString AbstractBean::DisplayTypeAndName() {
return QString("[%1] %2").arg(DisplayType(), DisplayName()); return QStringLiteral("[%1] %2").arg(DisplayType(), DisplayName());
} }
void AbstractBean::ResolveDomainToIP(const std::function<void()> &onFinished) { void AbstractBean::ResolveDomainToIP(const std::function<void()> &onFinished) {

View File

@ -9,7 +9,7 @@
#define WriteTempFile(fn, data) \ #define WriteTempFile(fn, data) \
QDir dir; \ QDir dir; \
if (!dir.exists("temp")) dir.mkdir("temp"); \ if (!dir.exists("temp")) dir.mkdir("temp"); \
QFile f(QString("temp/") + fn); \ QFile f(QStringLiteral("temp/") + fn); \
bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate); \ bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate); \
if (ok) { \ if (ok) { \
f.write(data); \ f.write(data); \
@ -50,7 +50,7 @@ namespace NekoGui_fmt {
return 1; return 1;
}; };
if (!forceExternal && (proxy_type == proxy_TUIC || hopPort.trimmed().isEmpty())) { if (!forceExternal) {
// sing-box support // sing-box support
return 0; return 0;
} else { } else {

View File

@ -13,7 +13,7 @@ namespace NekoGui_fmt {
url.setScheme("http"); url.setScheme("http");
} }
} else { } else {
url.setScheme(QString("socks%1").arg(socks_http_type)); url.setScheme(QStringLiteral("socks%1").arg(socks_http_type));
} }
if (!name.isEmpty()) url.setFragment(name); if (!name.isEmpty()) url.setFragment(name);
if (!username.isEmpty()) url.setUserName(username); if (!username.isEmpty()) url.setUserName(username);

View File

@ -40,6 +40,7 @@ require (
github.com/libdns/cloudflare v0.1.1 // indirect github.com/libdns/cloudflare v0.1.1 // indirect
github.com/libdns/libdns v0.2.2 // indirect github.com/libdns/libdns v0.2.2 // indirect
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
github.com/metacubex/tfo-go v0.0.0-20240821025650-e9be0afd5e7d // indirect
github.com/mholt/acmez v1.2.0 // indirect github.com/mholt/acmez v1.2.0 // indirect
github.com/miekg/dns v1.1.59 // indirect github.com/miekg/dns v1.1.59 // indirect
github.com/onsi/ginkgo/v2 v2.9.7 // indirect github.com/onsi/ginkgo/v2 v2.9.7 // indirect
@ -52,19 +53,18 @@ require (
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 // indirect github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 // indirect
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f // indirect github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f // indirect
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba // indirect github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba // indirect
github.com/sagernet/quic-go v0.45.1-beta.2 // indirect github.com/sagernet/quic-go v0.47.0-beta.2 // indirect
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
github.com/sagernet/sing v0.4.1 // indirect github.com/sagernet/sing v0.4.3 // indirect
github.com/sagernet/sing-dns v0.2.1-0.20240624030536-ca4a5f7afb65 // indirect github.com/sagernet/sing-dns v0.2.3 // indirect
github.com/sagernet/sing-mux v0.2.0 // indirect github.com/sagernet/sing-mux v0.2.0 // indirect
github.com/sagernet/sing-quic v0.2.0-beta.12 // indirect github.com/sagernet/sing-quic v0.2.2 // indirect
github.com/sagernet/sing-shadowsocks v0.2.6 // indirect github.com/sagernet/sing-shadowsocks v0.2.7 // indirect
github.com/sagernet/sing-shadowsocks2 v0.2.0 // indirect github.com/sagernet/sing-shadowsocks2 v0.2.0 // indirect
github.com/sagernet/sing-shadowtls v0.1.4 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect
github.com/sagernet/sing-tun v0.3.2 // indirect github.com/sagernet/sing-tun v0.3.3 // indirect
github.com/sagernet/sing-vmess v0.1.8 // indirect github.com/sagernet/sing-vmess v0.1.12 // indirect
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 // indirect
github.com/sagernet/utls v1.5.4 // indirect github.com/sagernet/utls v1.5.4 // indirect
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 // indirect github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 // indirect
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect
@ -80,16 +80,16 @@ require (
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
golang.org/x/mod v0.18.0 // indirect golang.org/x/mod v0.18.0 // indirect
golang.org/x/net v0.25.0 // indirect golang.org/x/net v0.25.0 // indirect
golang.org/x/sync v0.7.0 // indirect golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.21.0 // indirect golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.16.0 // indirect golang.org/x/text v0.18.0 // indirect
golang.org/x/time v0.5.0 // indirect golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 // indirect golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/grpc v1.63.2 // indirect google.golang.org/grpc v1.63.2 // indirect
google.golang.org/protobuf v1.33.0 // indirect google.golang.org/protobuf v1.33.0 // indirect
lukechampine.com/blake3 v1.2.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect
) )
replace grpc_server => ../../grpc_server replace grpc_server => ../../grpc_server
@ -98,7 +98,7 @@ replace github.com/matsuridayo/libneko => ../../../../libneko
replace github.com/sagernet/sing-box => ../../../../sing-box replace github.com/sagernet/sing-box => ../../../../sing-box
// replace github.com/sagernet/sing-quic => ../../../../sing-quic replace github.com/sagernet/sing-quic => ../../../../sing-quic
// replace github.com/sagernet/sing => ../../../../sing // replace github.com/sagernet/sing => ../../../../sing

View File

@ -94,6 +94,8 @@ github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/metacubex/tfo-go v0.0.0-20240821025650-e9be0afd5e7d h1:j9LtzkYstLFoNvXW824QQeN7Y26uPL5249kzWKbzO9U=
github.com/metacubex/tfo-go v0.0.0-20240821025650-e9be0afd5e7d/go.mod h1:c7bVFM9f5+VzeZ/6Kg77T/jrg1Xp8QpqlSHvG/aXVts=
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30= github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE= github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
@ -125,33 +127,29 @@ github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f h1:NkhuupzH5ch7b/Y
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f/go.mod h1:KXmw+ouSJNOsuRpg4wgwwCQuunrGz4yoAqQjsLjc6N0= github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f/go.mod h1:KXmw+ouSJNOsuRpg4wgwwCQuunrGz4yoAqQjsLjc6N0=
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba h1:EY5AS7CCtfmARNv2zXUOrsEMPFDGYxaw65JzA2p51Vk= github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba h1:EY5AS7CCtfmARNv2zXUOrsEMPFDGYxaw65JzA2p51Vk=
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
github.com/sagernet/quic-go v0.45.1-beta.2 h1:zkEeCbhdFFkrxKcuIRBtXNKci/1t2J/39QSG/sPvlmc= github.com/sagernet/quic-go v0.47.0-beta.2 h1:1tCGWFOSaXIeuQaHrwOMJIYvlupjTcaVInGQw5ArULU=
github.com/sagernet/quic-go v0.45.1-beta.2/go.mod h1:+N3FqM9DAzOWfe64uxXuBejVJwX7DeW7BslzLO6N/xI= github.com/sagernet/quic-go v0.47.0-beta.2/go.mod h1:bLVKvElSEMNv7pu7SZHscW02TYigzQ5lQu3Nh4wNh8Q=
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU= github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
github.com/sagernet/sing v0.4.1 h1:zVlpE+7k7AFoC2pv6ReqLf0PIHjihL/jsBl5k05PQFk= github.com/sagernet/sing v0.4.3 h1:Ty/NAiNnVd6844k7ujlL5lkzydhcTH5Psc432jXA4Y8=
github.com/sagernet/sing v0.4.1/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls= github.com/sagernet/sing v0.4.3/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls=
github.com/sagernet/sing-dns v0.2.1-0.20240624030536-ca4a5f7afb65 h1:lcCe7E1csuyUA3RCvpFcIYOy6FIifDthKaCrUjLG4xA= github.com/sagernet/sing-dns v0.2.3 h1:YzeBUn2tR38F7HtvGEQ0kLRLmZWMEgi/+7wqa4Twb1k=
github.com/sagernet/sing-dns v0.2.1-0.20240624030536-ca4a5f7afb65/go.mod h1:dArgyPZmK8+zDBVRMjV3r12zHgnTara0ahrWwSe/eQE= github.com/sagernet/sing-dns v0.2.3/go.mod h1:BJpJv6XLnrUbSyIntOT6DG9FW0f4fETmPAHvNjOprLg=
github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo= github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo=
github.com/sagernet/sing-mux v0.2.0/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ= github.com/sagernet/sing-mux v0.2.0/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ=
github.com/sagernet/sing-quic v0.2.0-beta.12 h1:BhvA5mmrDFEyDUQB5eeu+9UhF+ieyuNJ5Rsb0dAG3QY= github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
github.com/sagernet/sing-quic v0.2.0-beta.12/go.mod h1:YVpLfVi8BvYM7NMrjmnvcRm3E8iMETf1gFQmTQDN9jI= github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
github.com/sagernet/sing-shadowsocks v0.2.6 h1:xr7ylAS/q1cQYS8oxKKajhuQcchd5VJJ4K4UZrrpp0s=
github.com/sagernet/sing-shadowsocks v0.2.6/go.mod h1:j2YZBIpWIuElPFL/5sJAj470bcn/3QQ5lxZUNKLDNAM=
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg= github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
github.com/sagernet/sing-tun v0.3.2 h1:z0bLUT/YXH9RrJS9DsIpB0Bb9afl2hVJOmHd0zA3HJY= github.com/sagernet/sing-tun v0.3.3 h1:LZnQNmfGcNG2KPTPkLgc+Lo7k606QJVkPp2DnjriwUk=
github.com/sagernet/sing-tun v0.3.2/go.mod h1:DxLIyhjWU/HwGYoX0vNGg2c5QgTQIakphU1MuERR5tQ= github.com/sagernet/sing-tun v0.3.3/go.mod h1:DxLIyhjWU/HwGYoX0vNGg2c5QgTQIakphU1MuERR5tQ=
github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc= github.com/sagernet/sing-vmess v0.1.12 h1:2gFD8JJb+eTFMoa8FIVMnknEi+vCSfaiTXTfEYAYAPg=
github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA= github.com/sagernet/sing-vmess v0.1.12/go.mod h1:luTSsfyBGAc9VhtCqwjR+dt1QgqBhuYBCONB/POhF8I=
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 h1:z3SJQhVyU63FT26Wn/UByW6b7q8QKB0ZkPqsyqcz2PI=
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6/go.mod h1:73xRZuxwkFk4aiLw28hG8W6o9cr2UPrGL9pdY2UTbvY=
github.com/sagernet/utls v1.5.4 h1:KmsEGbB2dKUtCNC+44NwAdNAqnqQ6GA4pTO0Yik56co= github.com/sagernet/utls v1.5.4 h1:KmsEGbB2dKUtCNC+44NwAdNAqnqQ6GA4pTO0Yik56co=
github.com/sagernet/utls v1.5.4/go.mod h1:CTGxPWExIloRipK3XFpYv0OVyhO8kk3XCGW/ieyTh1s= github.com/sagernet/utls v1.5.4/go.mod h1:CTGxPWExIloRipK3XFpYv0OVyhO8kk3XCGW/ieyTh1s=
github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 h1:R0OMYAScomNAVpTfbHFpxqJpvwuhxSRi+g6z7gZhABs= github.com/sagernet/wireguard-go v0.0.0-20231215174105-89dec3b2f3e8 h1:R0OMYAScomNAVpTfbHFpxqJpvwuhxSRi+g6z7gZhABs=
@ -229,8 +227,8 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -245,15 +243,15 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -296,5 +294,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=

View File

@ -18,6 +18,16 @@ popd
#### ####
if [ ! -d "sing-quic" ]; then
git clone --no-checkout https://github.com/MatsuriDayo/sing-quic.git
fi
pushd sing-quic
git checkout "$COMMIT_SING_QUIC"
popd
####
if [ ! -d "libneko" ]; then if [ ! -d "libneko" ]; then
git clone --no-checkout https://github.com/MatsuriDayo/libneko.git git clone --no-checkout https://github.com/MatsuriDayo/libneko.git
fi fi

View File

@ -1,2 +1,3 @@
export COMMIT_SING_BOX="cf36758f11b7c144e1211801753cc91f06ff2906" export COMMIT_SING_BOX="06557f6cef23160668122a17a818b378b5a216b5"
export COMMIT_SING_QUIC="b49ce60d9b3622d5238fee96bfd3c5f6e3915b42"
export COMMIT_LIBNEKO="1c47a3af71990a7b2192e03292b4d246c308ef0b" export COMMIT_LIBNEKO="1c47a3af71990a7b2192e03292b4d246c308ef0b"

View File

@ -51,7 +51,7 @@ namespace NekoGui_network {
for (const auto &err: errors) { for (const auto &err: errors) {
error_str << err.errorString(); error_str << err.errorString();
} }
MW_show_log(QString("SSL Errors: %1 %2").arg(error_str.join(","), NekoGui::dataStore->sub_insecure ? "(Ignored)" : "")); MW_show_log(QStringLiteral("SSL Errors: %1 %2").arg(error_str.join(","), NekoGui::dataStore->sub_insecure ? "(Ignored)" : ""));
}); });
// Wait for response // Wait for response
auto abortTimer = new QTimer; auto abortTimer = new QTimer;

View File

@ -247,7 +247,6 @@ namespace NekoGui {
_add(new configItem("theme", &theme, itemType::string)); _add(new configItem("theme", &theme, itemType::string));
_add(new configItem("custom_inbound", &custom_inbound, itemType::string)); _add(new configItem("custom_inbound", &custom_inbound, itemType::string));
_add(new configItem("custom_route", &custom_route_global, itemType::string)); _add(new configItem("custom_route", &custom_route_global, itemType::string));
_add(new configItem("v2ray_asset_dir", &v2ray_asset_dir, itemType::string));
_add(new configItem("sub_use_proxy", &sub_use_proxy, itemType::boolean)); _add(new configItem("sub_use_proxy", &sub_use_proxy, itemType::boolean));
_add(new configItem("remember_id", &remember_id, itemType::integer)); _add(new configItem("remember_id", &remember_id, itemType::integer));
_add(new configItem("remember_enable", &remember_enable, itemType::boolean)); _add(new configItem("remember_enable", &remember_enable, itemType::boolean));
@ -350,7 +349,7 @@ namespace NekoGui {
} }
QString Routing::DisplayRouting() const { QString Routing::DisplayRouting() const {
return QString("[Proxy] %1\n[Proxy] %2\n[Direct] %3\n[Direct] %4\n[Block] %5\n[Block] %6\n[Default Outbound] %7\n[DNS] %8") return QStringLiteral("[Proxy] %1\n[Proxy] %2\n[Direct] %3\n[Direct] %4\n[Block] %5\n[Block] %6\n[Default Outbound] %7\n[DNS] %8")
.arg(SplitLinesSkipSharp(proxy_domain).join(","), 10) .arg(SplitLinesSkipSharp(proxy_domain).join(","), 10)
.arg(SplitLinesSkipSharp(proxy_ip).join(","), 10) .arg(SplitLinesSkipSharp(proxy_ip).join(","), 10)
.arg(SplitLinesSkipSharp(direct_domain).join(","), 10) .arg(SplitLinesSkipSharp(direct_domain).join(","), 10)
@ -416,16 +415,13 @@ namespace NekoGui {
// System Utils // System Utils
QString FindCoreAsset(const QString &name) { QString FindCoreAsset(const QString &name) {
QStringList search{NekoGui::dataStore->v2ray_asset_dir}; QStringList search{};
search << QApplication::applicationDirPath(); search << QApplication::applicationDirPath();
search << "/usr/share/sing-geoip"; search << "/usr/share/sing-geoip";
search << "/usr/share/sing-geosite"; search << "/usr/share/sing-geosite";
search << "/usr/share/xray"; search << "/usr/share/sing-box";
search << "/usr/local/share/xray"; search << "/usr/lib/nekobox";
search << "/opt/xray"; search << "/usr/share/nekobox";
search << "/usr/share/v2ray";
search << "/usr/local/share/v2ray";
search << "/opt/v2ray";
for (const auto &dir: search) { for (const auto &dir: search) {
if (dir.isEmpty()) continue; if (dir.isEmpty()) continue;
QFileInfo asset(dir + "/" + name); QFileInfo asset(dir + "/" + name);

View File

@ -17,5 +17,5 @@ namespace NekoGui {
bool IsAdmin(); bool IsAdmin();
} // namespace NekoGui } // namespace NekoGui
#define ROUTES_PREFIX_NAME QString("routes_box") #define ROUTES_PREFIX_NAME QStringLiteral("routes_box")
#define ROUTES_PREFIX QString(ROUTES_PREFIX_NAME + "/") #define ROUTES_PREFIX QString(ROUTES_PREFIX_NAME + "/")

View File

@ -107,7 +107,6 @@ namespace NekoGui {
int mux_concurrency = 8; int mux_concurrency = 8;
bool mux_default_on = false; bool mux_default_on = false;
QString theme = "0"; QString theme = "0";
QString v2ray_asset_dir = "";
int language = 0; int language = 0;
QString mw_size = ""; QString mw_size = "";
bool check_include_pre = false; bool check_include_pre = false;

View File

@ -1 +1 @@
4.0-beta2-2024-07-05 4.0.1-2024-12-12

View File

@ -12,7 +12,7 @@
{ {
"tag": "dns-remote", "tag": "dns-remote",
"address": "8.8.8.8", "address": "8.8.8.8",
"detour": "nekoray-socks" "detour": "neko-socks"
}, },
{ {
"tag": "dns-direct", "tag": "dns-direct",
@ -75,7 +75,7 @@
"outbounds": [ "outbounds": [
{ {
"type": "socks", "type": "socks",
"tag": "nekoray-socks", "tag": "neko-socks",
"udp_fragment": true, "udp_fragment": true,
//%SOCKS_USER_PASS% //%SOCKS_USER_PASS%
"server": "127.0.0.1", "server": "127.0.0.1",

View File

@ -205,7 +205,7 @@ namespace NekoGui_rpc {
#define NOT_OK \ #define NOT_OK \
*rpcOK = false; \ *rpcOK = false; \
onError(QString("QNetworkReply::NetworkError code: %1\n").arg(status)); onError(QStringLiteral("QNetworkReply::NetworkError code: %1\n").arg(status));
void Client::Exit() { void Client::Exit() {
libcore::EmptyReq request; libcore::EmptyReq request;

View File

@ -141,13 +141,7 @@ namespace NekoGui_sys {
void CoreProcess::Start() { void CoreProcess::Start() {
show_stderr = false; show_stderr = false;
// set extra env // cwd: same as GUI, at ./config
auto v2ray_asset_dir = NekoGui::FindCoreAsset("geoip.dat");
if (!v2ray_asset_dir.isEmpty()) {
v2ray_asset_dir = QFileInfo(v2ray_asset_dir).absolutePath();
env << "XRAY_LOCATION_ASSET=" + v2ray_asset_dir;
}
//
ExternalProcess::Start(); ExternalProcess::Start();
write((NekoGui::dataStore->core_token + "\n").toUtf8()); write((NekoGui::dataStore->core_token + "\n").toUtf8());
} }

View File

@ -56,7 +56,7 @@ LONG __stdcall CreateCrashHandler(EXCEPTION_POINTERS *pException) {
} }
// 创建消息提示 // 创建消息提示
QMessageBox::warning(NULL, "Application crashed", QMessageBox::warning(NULL, "Application crashed",
QString("ErrorCode: %1 ErrorAddr:%2 ErrorFlag: %3 ErrorPara: %4\nVersion: %5\nDump file at %6") QStringLiteral("ErrorCode: %1 ErrorAddr:%2 ErrorFlag: %3 ErrorPara: %4\nVersion: %5\nDump file at %6")
.arg(errCode) .arg(errCode)
.arg(errAddr) .arg(errAddr)
.arg(errFlag) .arg(errFlag)

View File

@ -63,14 +63,6 @@
<source>Custom Inbound</source> <source>Custom Inbound</source>
<translation>ورودی سفارشی</translation> <translation>ورودی سفارشی</translation>
</message> </message>
<message>
<source>Asset Location</source>
<translation>مکان دارایی</translation>
</message>
<message>
<source>Default: dir of &quot;nekoray&quot;</source>
<translation type="unfinished">مسیر پیش فرض &quot;nekoray&quot;</translation>
</message>
<message> <message>
<source>Concurrent</source> <source>Concurrent</source>
<translation>هم زمان</translation> <translation>هم زمان</translation>
@ -1500,6 +1492,10 @@ End: %2</source>
<source>Stop Testing</source> <source>Stop Testing</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>URL Test</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ProxyItem</name> <name>ProxyItem</name>
@ -1640,6 +1636,10 @@ Direct: %2</source>
<source>Default</source> <source>Default</source>
<translation type="unfinished">پیش فرض</translation> <translation type="unfinished">پیش فرض</translation>
</message> </message>
<message>
<source>The last speed test did not exit completely, please wait. If it persists, please restart the program.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name> <name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name>

View File

@ -107,14 +107,6 @@
<source>Core</source> <source>Core</source>
<translation>Ядро</translation> <translation>Ядро</translation>
</message> </message>
<message>
<source>Asset Location</source>
<translation>Расположение файлов</translation>
</message>
<message>
<source>Default: dir of &quot;nekoray&quot;</source>
<translation>По умолчанию: текущая папка nekoray</translation>
</message>
<message> <message>
<source>Select</source> <source>Select</source>
<translation>Выбрать</translation> <translation>Выбрать</translation>
@ -1506,6 +1498,10 @@ End: %2</source>
<source>Stop Testing</source> <source>Stop Testing</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>URL Test</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>ProxyItem</name> <name>ProxyItem</name>
@ -1653,6 +1649,10 @@ Release note:
<source>Default</source> <source>Default</source>
<translation>По умолчанию</translation> <translation>По умолчанию</translation>
</message> </message>
<message>
<source>The last speed test did not exit completely, please wait. If it persists, please restart the program.</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name> <name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name>

View File

@ -63,14 +63,6 @@
<source>Custom Inbound</source> <source>Custom Inbound</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>Asset Location</source>
<translation></translation>
</message>
<message>
<source>Default: dir of &quot;nekoray&quot;</source>
<translation> nekoray </translation>
</message>
<message> <message>
<source>Concurrent</source> <source>Concurrent</source>
<translation></translation> <translation></translation>
@ -1496,7 +1488,7 @@ Split by line.</source>
</message> </message>
<message> <message>
<source>In and Out IP</source> <source>In and Out IP</source>
<translation>IP</translation> <translation> IP</translation>
</message> </message>
<message> <message>
<source>Test Options</source> <source>Test Options</source>
@ -1506,6 +1498,10 @@ Split by line.</source>
<source>Stop Testing</source> <source>Stop Testing</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>URL Test</source>
<translation>URL </translation>
</message>
</context> </context>
<context> <context>
<name>ProxyItem</name> <name>ProxyItem</name>
@ -1653,6 +1649,10 @@ Release note:
<source>Default</source> <source>Default</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>The last speed test did not exit completely, please wait. If it persists, please restart the program.</source>
<translation>退</translation>
</message>
</context> </context>
<context> <context>
<name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name> <name>Qv2ray::ui::widgets::AutoCompleteTextEdit</name>

View File

@ -59,7 +59,7 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
// Common // Common
ui->log_level->addItems(QString("trace debug info warn error fatal panic").split(" ")); ui->log_level->addItems(QStringLiteral("trace debug info warn error fatal panic").split(" "));
ui->mux_protocol->addItems({"h2mux", "smux", "yamux"}); ui->mux_protocol->addItems({"h2mux", "smux", "yamux"});
refresh_auth(); refresh_auth();
@ -155,7 +155,6 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
// Core // Core
ui->groupBox_core->setTitle(software_core_name); ui->groupBox_core->setTitle(software_core_name);
ui->core_v2ray_asset->setText(NekoGui::dataStore->v2ray_asset_dir);
// //
CACHE.extraCore = QString2QJsonObject(NekoGui::dataStore->extraCore->core_map); CACHE.extraCore = QString2QJsonObject(NekoGui::dataStore->extraCore->core_map);
if (!CACHE.extraCore.contains("naive")) CACHE.extraCore.insert("naive", ""); if (!CACHE.extraCore.contains("naive")) CACHE.extraCore.insert("naive", "");
@ -167,16 +166,6 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
extra_core_layout->addWidget(new ExtraCoreWidget(&CACHE.extraCore, s)); extra_core_layout->addWidget(new ExtraCoreWidget(&CACHE.extraCore, s));
} }
// //
connect(ui->core_v2ray_asset, &QLineEdit::textChanged, this, [=] {
CACHE.needRestart = true;
});
connect(ui->core_v2ray_asset_pick, &QPushButton::clicked, this, [=] {
auto fn = QFileDialog::getExistingDirectory(this, tr("Select"), QDir::currentPath(),
QFileDialog::Option::ShowDirsOnly | QFileDialog::Option::ReadOnly);
if (!fn.isEmpty()) {
ui->core_v2ray_asset->setText(fn);
}
});
connect(ui->extra_core_add, &QPushButton::clicked, this, [=] { connect(ui->extra_core_add, &QPushButton::clicked, this, [=] {
bool ok; bool ok;
auto s = QInputDialog::getText(nullptr, tr("Add"), auto s = QInputDialog::getText(nullptr, tr("Add"),
@ -278,7 +267,6 @@ void DialogBasicSettings::accept() {
// Core // Core
NekoGui::dataStore->v2ray_asset_dir = ui->core_v2ray_asset->text();
NekoGui::dataStore->extraCore->core_map = QJsonObject2QString(CACHE.extraCore, true); NekoGui::dataStore->extraCore->core_map = QJsonObject2QString(CACHE.extraCore, true);
// Mux // Mux
@ -293,7 +281,7 @@ void DialogBasicSettings::accept() {
NekoGui::dataStore->utlsFingerprint = ui->utlsFingerprint->currentText(); NekoGui::dataStore->utlsFingerprint = ui->utlsFingerprint->currentText();
// 关闭连接统计,停止刷新前清空记录。 // 关闭连接统计,停止刷新前清空记录。
if (NekoGui::dataStore->traffic_loop_interval == 0 || NekoGui::dataStore->connection_statistics == false) { if (NekoGui::dataStore->traffic_loop_interval == 0 || !NekoGui::dataStore->connection_statistics) {
MW_dialog_message("", "ClearConnectionList"); MW_dialog_message("", "ClearConnectionList");
} }

View File

@ -566,39 +566,7 @@
<item> <item>
<widget class="QWidget" name="assest_group" native="true"> <widget class="QWidget" name="assest_group" native="true">
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Asset Location</string>
</property>
</widget>
</item>
<item row="0" column="1"> <item row="0" column="1">
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="MyLineEdit" name="core_v2ray_asset">
<property name="placeholderText">
<string>Default: dir of &quot;nekoray&quot;</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="core_v2ray_asset_pick">
<property name="text">
<string>Select</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string notr="true">Loglevel</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="log_level"> <widget class="QComboBox" name="log_level">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
@ -608,14 +576,21 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label_6"> <widget class="QLabel" name="label_6">
<property name="text"> <property name="text">
<string>Multiplex (mux)</string> <string>Multiplex (mux)</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string notr="true">Loglevel</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<widget class="QComboBox" name="mux_protocol"/> <widget class="QComboBox" name="mux_protocol"/>

View File

@ -25,7 +25,7 @@ DialogManageRoutes::DialogManageRoutes(QWidget *parent) : QDialog(parent), ui(ne
// //
ui->outbound_domain_strategy->addItems(Preset::SingBox::DomainStrategy); ui->outbound_domain_strategy->addItems(Preset::SingBox::DomainStrategy);
ui->domainStrategyCombo->addItems(Preset::SingBox::DomainStrategy); ui->domainStrategyCombo->addItems(Preset::SingBox::DomainStrategy);
qsValue += QString("prefer_ipv4 prefer_ipv6 ipv4_only ipv6_only").split(" "); qsValue += QStringLiteral("prefer_ipv4 prefer_ipv6 ipv4_only ipv6_only").split(" ");
ui->dns_object->setPlaceholderText(DecodeB64IfValid("ewogICJzZXJ2ZXJzIjogW10sCiAgInJ1bGVzIjogW10sCiAgImZpbmFsIjogIiIsCiAgInN0cmF0ZWd5IjogIiIsCiAgImRpc2FibGVfY2FjaGUiOiBmYWxzZSwKICAiZGlzYWJsZV9leHBpcmUiOiBmYWxzZSwKICAiaW5kZXBlbmRlbnRfY2FjaGUiOiBmYWxzZSwKICAicmV2ZXJzZV9tYXBwaW5nIjogZmFsc2UsCiAgImZha2VpcCI6IHt9Cn0=")); ui->dns_object->setPlaceholderText(DecodeB64IfValid("ewogICJzZXJ2ZXJzIjogW10sCiAgInJ1bGVzIjogW10sCiAgImZpbmFsIjogIiIsCiAgInN0cmF0ZWd5IjogIiIsCiAgImRpc2FibGVfY2FjaGUiOiBmYWxzZSwKICAiZGlzYWJsZV9leHBpcmUiOiBmYWxzZSwKICAiaW5kZXBlbmRlbnRfY2FjaGUiOiBmYWxzZSwKICAicmV2ZXJzZV9tYXBwaW5nIjogZmFsc2UsCiAgImZha2VpcCI6IHt9Cn0="));
dnsHelpDocumentUrl = "https://sing-box.sagernet.org/configuration/dns/"; dnsHelpDocumentUrl = "https://sing-box.sagernet.org/configuration/dns/";
// //

View File

@ -118,7 +118,7 @@ void EditCustom::onStart(std::shared_ptr<NekoGui::ProxyEntity> _ent) {
auto command = QStringList{extR->program}; auto command = QStringList{extR->program};
command += extR->arguments; command += extR->arguments;
auto btn = QMessageBox::information(this, tr("Preview config"), auto btn = QMessageBox::information(this, tr("Preview config"),
QString("Command: %1\n\n%2").arg(QStringList2Command(command), extR->config_export), QStringLiteral("Command: %1\n\n%2").arg(QStringList2Command(command), extR->config_export),
"OK", "Copy", "", 0, 0); "OK", "Copy", "", 0, 0);
if (btn == 1) { if (btn == 1) {
QApplication::clipboard()->setText(extR->config_export); QApplication::clipboard()->setText(extR->config_export);

View File

@ -21,7 +21,6 @@
#include "3rdparty/qrcodegen.hpp" #include "3rdparty/qrcodegen.hpp"
#include "3rdparty/VT100Parser.hpp" #include "3rdparty/VT100Parser.hpp"
#include "3rdparty/qv2ray/v2/components/proxy/QvProxyConfigurator.hpp" #include "3rdparty/qv2ray/v2/components/proxy/QvProxyConfigurator.hpp"
#include "3rdparty/qv2ray/v2/ui/LogHighlighter.hpp"
#ifndef NKR_NO_ZXING #ifndef NKR_NO_ZXING
#include "3rdparty/ZxingQtReader.hpp" #include "3rdparty/ZxingQtReader.hpp"
@ -102,12 +101,12 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
ui->toolButton_server->setMenu(ui->menu_server); ui->toolButton_server->setMenu(ui->menu_server);
ui->menubar->setVisible(false); ui->menubar->setVisible(false);
connect(ui->toolButton_document, &QToolButton::clicked, this, [=] { QDesktopServices::openUrl(QUrl("https://matsuridayo.github.io/")); }); connect(ui->toolButton_document, &QToolButton::clicked, this, [=] { QDesktopServices::openUrl(QUrl("https://matsuridayo.github.io/")); });
connect(ui->toolButton_ads, &QToolButton::clicked, this, [=] { QDesktopServices::openUrl(QUrl("https://matsuricom.pages.dev/")); }); connect(ui->toolButton_ads, &QToolButton::clicked, this, [=] { QDesktopServices::openUrl(QUrl("https://neko-box.pages.dev/喵")); });
connect(ui->toolButton_update, &QToolButton::clicked, this, [=] { runOnNewThread([=] { CheckUpdate(); }); }); connect(ui->toolButton_update, &QToolButton::clicked, this, [=] { runOnNewThread([=] { CheckUpdate(); }); });
connect(ui->toolButton_url_test, &QToolButton::clicked, this, [=] { speedtest_current_group(1, true); });
// Setup log UI // Setup log UI
ui->splitter->restoreState(DecodeB64IfValid(NekoGui::dataStore->splitter_state)); ui->splitter->restoreState(DecodeB64IfValid(NekoGui::dataStore->splitter_state));
new SyntaxHighlighter(false, qvLogDocument);
qvLogDocument->setUndoRedoEnabled(false); qvLogDocument->setUndoRedoEnabled(false);
ui->masterLogBrowser->setUndoRedoEnabled(false); ui->masterLogBrowser->setUndoRedoEnabled(false);
ui->masterLogBrowser->setDocument(qvLogDocument); ui->masterLogBrowser->setDocument(qvLogDocument);
@ -335,10 +334,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
neko_set_spmode_vpn(false); neko_set_spmode_vpn(false);
}); });
connect(ui->menu_qr, &QAction::triggered, this, [=]() { display_qr_link(false); }); connect(ui->menu_qr, &QAction::triggered, this, [=]() { display_qr_link(false); });
connect(ui->menu_tcp_ping, &QAction::triggered, this, [=]() { speedtest_current_group(0); }); connect(ui->menu_tcp_ping, &QAction::triggered, this, [=]() { speedtest_current_group(0, false); });
connect(ui->menu_url_test, &QAction::triggered, this, [=]() { speedtest_current_group(1); }); connect(ui->menu_url_test, &QAction::triggered, this, [=]() { speedtest_current_group(1, false); });
connect(ui->menu_full_test, &QAction::triggered, this, [=]() { speedtest_current_group(2); }); connect(ui->menu_full_test, &QAction::triggered, this, [=]() { speedtest_current_group(2, false); });
connect(ui->menu_stop_testing, &QAction::triggered, this, [=]() { speedtest_current_group(114514); }); connect(ui->menu_stop_testing, &QAction::triggered, this, [=]() { speedtest_current_group(114514, false); });
// //
auto set_selected_or_group = [=](int mode) { auto set_selected_or_group = [=](int mode) {
// 0=group 1=select 2=unknown(menu is hide) // 0=group 1=select 2=unknown(menu is hide)
@ -479,7 +478,7 @@ void MainWindow::show_group(int gid) {
auto group = NekoGui::profileManager->GetGroup(gid); auto group = NekoGui::profileManager->GetGroup(gid);
if (group == nullptr) { if (group == nullptr) {
MessageBoxWarning(tr("Error"), QString("No such group: %1").arg(gid)); MessageBoxWarning(tr("Error"), QStringLiteral("No such group: %1").arg(gid));
NekoGui::dataStore->refreshing_group = false; NekoGui::dataStore->refreshing_group = false;
return; return;
} }
@ -630,7 +629,7 @@ void MainWindow::on_commitDataRequest() {
// //
if (!isMaximized()) { if (!isMaximized()) {
auto olds = NekoGui::dataStore->mw_size; auto olds = NekoGui::dataStore->mw_size;
auto news = QString("%1x%2").arg(size().width()).arg(size().height()); auto news = QStringLiteral("%1x%2").arg(size().width()).arg(size().height());
if (olds != news) { if (olds != news) {
NekoGui::dataStore->mw_size = news; NekoGui::dataStore->mw_size = news;
} }
@ -833,12 +832,12 @@ void MainWindow::refresh_status(const QString &traffic_update) {
if (last_test_time.addSecs(2) < QTime::currentTime()) { if (last_test_time.addSecs(2) < QTime::currentTime()) {
auto txt = running == nullptr ? tr("Not Running") auto txt = running == nullptr ? tr("Not Running")
: QString("[%1] %2").arg(group_name, running->bean->DisplayName()).left(30); : QStringLiteral("[%1] %2").arg(group_name, running->bean->DisplayName()).left(30);
ui->label_running->setText(txt); ui->label_running->setText(txt);
} }
// //
auto display_socks = DisplayAddress(NekoGui::dataStore->inbound_address, NekoGui::dataStore->inbound_socks_port); auto display_socks = DisplayAddress(NekoGui::dataStore->inbound_address, NekoGui::dataStore->inbound_socks_port);
auto inbound_txt = QString("Mixed: %1").arg(display_socks); auto inbound_txt = QStringLiteral("Mixed: %1").arg(display_socks);
ui->label_inbound->setText(inbound_txt); ui->label_inbound->setText(inbound_txt);
// //
ui->checkBox_VPN->setChecked(NekoGui::dataStore->spmode_vpn); ui->checkBox_VPN->setChecked(NekoGui::dataStore->spmode_vpn);
@ -1168,7 +1167,7 @@ void MainWindow::on_menu_profile_debug_info_triggered() {
if (ents.count() != 1) return; if (ents.count() != 1) return;
auto btn = QMessageBox::information(this, software_name, ents.first()->ToJsonBytes(), "OK", "Edit", "Reload", 0, 0); auto btn = QMessageBox::information(this, software_name, ents.first()->ToJsonBytes(), "OK", "Edit", "Reload", 0, 0);
if (btn == 1) { if (btn == 1) {
QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(QString("profiles/%1.json").arg(ents.first()->id)).absoluteFilePath())); QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(QStringLiteral("profiles/%1.json").arg(ents.first()->id)).absoluteFilePath()));
} else if (btn == 2) { } else if (btn == 2) {
NekoGui::dataStore->Load(); NekoGui::dataStore->Load();
NekoGui::profileManager->LoadManager(); NekoGui::profileManager->LoadManager();
@ -1209,23 +1208,23 @@ void MainWindow::on_menu_export_config_triggered() {
if (ent->bean->DisplayCoreType() != software_core_name) return; if (ent->bean->DisplayCoreType() != software_core_name) return;
auto result = BuildConfig(ent, false, true); auto result = BuildConfig(ent, false, true);
QString config_core = QJsonObject2QString(result->coreConfig, true); QString config_core = QJsonObject2QString(result->coreConfig, false);
QApplication::clipboard()->setText(config_core); QApplication::clipboard()->setText(config_core);
QMessageBox msg(QMessageBox::Information, tr("Config copied"), config_core); QMessageBox msg(QMessageBox::Information, tr("Config copied"), tr("Config copied"));
msg.addButton("Copy core config", QMessageBox::YesRole); msg.addButton("Copy core config", QMessageBox::YesRole);
msg.addButton("Copy test config", QMessageBox::YesRole); msg.addButton("Copy test config", QMessageBox::NoRole);
msg.addButton(QMessageBox::Ok); msg.addButton(QMessageBox::Ok);
msg.setEscapeButton(QMessageBox::Ok); msg.setEscapeButton(QMessageBox::Ok);
msg.setDefaultButton(QMessageBox::Ok); msg.setDefaultButton(QMessageBox::Ok);
auto ret = msg.exec(); auto ret = msg.exec();
if (ret == 0) { if (ret == 2) {
result = BuildConfig(ent, false, false); result = BuildConfig(ent, false, false);
config_core = QJsonObject2QString(result->coreConfig, true); config_core = QJsonObject2QString(result->coreConfig, false);
QApplication::clipboard()->setText(config_core); QApplication::clipboard()->setText(config_core);
} else if (ret == 1) { } else if (ret == 3) {
result = BuildConfig(ent, true, false); result = BuildConfig(ent, true, false);
config_core = QJsonObject2QString(result->coreConfig, true); config_core = QJsonObject2QString(result->coreConfig, false);
QApplication::clipboard()->setText(config_core); QApplication::clipboard()->setText(config_core);
} }
} }
@ -1801,7 +1800,7 @@ bool MainWindow::StartVPNProcess() {
// //
vpn_process->setProcessChannelMode(QProcess::ForwardedChannels); vpn_process->setProcessChannelMode(QProcess::ForwardedChannels);
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
vpn_process->start("osascript", {"-e", QString("do shell script \"%1\" with administrator privileges") vpn_process->start("osascript", {"-e", QStringLiteral("do shell script \"%1\" with administrator privileges")
.arg("bash " + scriptPath)}); .arg("bash " + scriptPath)});
#else #else
vpn_process->start("pkexec", {"bash", scriptPath}); vpn_process->start("pkexec", {"bash", scriptPath});
@ -1824,7 +1823,7 @@ bool MainWindow::StopVPNProcess(bool unconditional) {
#else #else
QProcess p; QProcess p;
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
p.start("osascript", {"-e", QString("do shell script \"%1\" with administrator privileges") p.start("osascript", {"-e", QStringLiteral("do shell script \"%1\" with administrator privileges")
.arg("pkill -2 -U 0 nekobox_core")}); .arg("pkill -2 -U 0 nekobox_core")});
#else #else
if (unconditional) { if (unconditional) {

View File

@ -185,7 +185,7 @@ private:
static void setup_grpc(); static void setup_grpc();
void speedtest_current_group(int mode); void speedtest_current_group(int mode, bool test_group);
void speedtest_current(); void speedtest_current();

View File

@ -205,6 +205,19 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QToolButton" name="toolButton_url_test">
<property name="text">
<string>URL Test</string>
</property>
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextUnderIcon</enum>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>
@ -665,7 +678,7 @@
<string notr="true">Tcp Ping</string> <string notr="true">Tcp Ping</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+Shift+T</string> <string notr="true">Ctrl+Alt+T</string>
</property> </property>
</action> </action>
<action name="menu_url_test"> <action name="menu_url_test">
@ -673,7 +686,7 @@
<string notr="true">Url Test</string> <string notr="true">Url Test</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+Shift+U</string> <string notr="true">Ctrl+Alt+U</string>
</property> </property>
</action> </action>
<action name="menu_clear_test_result"> <action name="menu_clear_test_result">
@ -681,7 +694,7 @@
<string>Clear Test Result</string> <string>Clear Test Result</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+Shift+C</string> <string notr="true">Ctrl+Alt+C</string>
</property> </property>
</action> </action>
<action name="menu_export_config"> <action name="menu_export_config">
@ -726,7 +739,7 @@
<string>Remove Duplicates</string> <string>Remove Duplicates</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+Shift+D</string> <string notr="true">Ctrl+Alt+D</string>
</property> </property>
</action> </action>
<action name="actionfake"> <action name="actionfake">
@ -774,7 +787,7 @@
<string>Remove Unavailable</string> <string>Remove Unavailable</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+Shift+R</string> <string notr="true">Ctrl+Alt+R</string>
</property> </property>
</action> </action>
<action name="menu_full_test"> <action name="menu_full_test">
@ -782,7 +795,7 @@
<string>Full Test</string> <string>Full Test</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+Shift+F</string> <string notr="true">Ctrl+Alt+F</string>
</property> </property>
</action> </action>
<action name="menu_hotkey_settings"> <action name="menu_hotkey_settings">
@ -803,7 +816,7 @@
<string>Copy links of selected (Neko Links)</string> <string>Copy links of selected (Neko Links)</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+Alt+C</string> <string notr="true">Ctrl+N</string>
</property> </property>
</action> </action>
<action name="actionfake_2"> <action name="actionfake_2">
@ -859,7 +872,7 @@
<string>Resolve domain</string> <string>Resolve domain</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string notr="true">Ctrl+Shift+I</string> <string notr="true">Ctrl+Alt+I</string>
</property> </property>
</action> </action>
<action name="menu_vpn_settings"> <action name="menu_vpn_settings">
@ -902,6 +915,9 @@
<property name="text"> <property name="text">
<string>Stop Testing</string> <string>Stop Testing</string>
</property> </property>
<property name="shortcut">
<string notr="true">Ctrl+Alt+S</string>
</property>
</action> </action>
</widget> </widget>
<customwidgets> <customwidgets>

View File

@ -58,8 +58,14 @@ void MainWindow::setup_grpc() {
inline bool speedtesting = false; inline bool speedtesting = false;
inline QList<QThread *> speedtesting_threads = {}; inline QList<QThread *> speedtesting_threads = {};
void MainWindow::speedtest_current_group(int mode) { void MainWindow::speedtest_current_group(int mode, bool test_group) {
if (speedtesting) {
MessageBoxWarning(software_name, QObject::tr("The last speed test did not exit completely, please wait. If it persists, please restart the program."));
return;
}
auto profiles = get_selected_or_group(); auto profiles = get_selected_or_group();
if (test_group) profiles = NekoGui::profileManager->CurrentGroup()->ProfilesWithOrder();
if (profiles.isEmpty()) return; if (profiles.isEmpty()) return;
auto group = NekoGui::profileManager->CurrentGroup(); auto group = NekoGui::profileManager->CurrentGroup();
if (group->archive) return; if (group->archive) return;
@ -75,11 +81,6 @@ void MainWindow::speedtest_current_group(int mode) {
} }
#ifndef NKR_NO_GRPC #ifndef NKR_NO_GRPC
if (speedtesting) {
MessageBoxWarning(software_name, "The last speed test did not exit completely, please wait. If it persists, please restart the program.");
return;
}
QStringList full_test_flags; QStringList full_test_flags;
if (mode == libcore::FullTest) { if (mode == libcore::FullTest) {
auto w = new QDialog(this); auto w = new QDialog(this);
@ -150,7 +151,7 @@ void MainWindow::speedtest_current_group(int mode) {
// //
libcore::TestReq req; libcore::TestReq req;
req.set_mode((libcore::TestMode) mode); req.set_mode((libcore::TestMode) mode);
req.set_timeout(5000); req.set_timeout(10 * 1000);
req.set_url(NekoGui::dataStore->test_latency_url.toStdString()); req.set_url(NekoGui::dataStore->test_latency_url.toStdString());
// //
@ -181,7 +182,7 @@ void MainWindow::speedtest_current_group(int mode) {
} }
// //
auto config = new libcore::LoadConfigReq; auto config = new libcore::LoadConfigReq;
config->set_core_config(QJsonObject2QString(c->coreConfig, true).toStdString()); config->set_core_config(QJsonObject2QString(c->coreConfig, false).toStdString());
req.set_allocated_config(config); req.set_allocated_config(config);
req.set_in_address(profile->bean->serverAddress.toStdString()); req.set_in_address(profile->bean->serverAddress.toStdString());
@ -238,6 +239,7 @@ void MainWindow::speedtest_current_group(int mode) {
lock_return.lock(); lock_return.lock();
lock_return.unlock(); lock_return.unlock();
speedtesting = false; speedtesting = false;
MW_show_log(QObject::tr("Speedtest finished."));
}); });
#endif #endif
} }
@ -250,7 +252,7 @@ void MainWindow::speedtest_current() {
runOnNewThread([=] { runOnNewThread([=] {
libcore::TestReq req; libcore::TestReq req;
req.set_mode(libcore::UrlTest); req.set_mode(libcore::UrlTest);
req.set_timeout(5000); req.set_timeout(10 * 1000);
req.set_url(NekoGui::dataStore->test_latency_url.toStdString()); req.set_url(NekoGui::dataStore->test_latency_url.toStdString());
bool rpcOK; bool rpcOK;
@ -262,12 +264,12 @@ void MainWindow::speedtest_current() {
runOnUiThread([=] { runOnUiThread([=] {
if (!result.error().empty()) { if (!result.error().empty()) {
MW_show_log(QString("UrlTest error: %1").arg(result.error().c_str())); MW_show_log(QStringLiteral("UrlTest error: %1").arg(result.error().c_str()));
} }
if (latency <= 0) { if (latency <= 0) {
ui->label_running->setText(tr("Test Result") + ": " + tr("Unavailable")); ui->label_running->setText(tr("Test Result") + ": " + tr("Unavailable"));
} else if (latency > 0) { } else if (latency > 0) {
ui->label_running->setText(tr("Test Result") + ": " + QString("%1 ms").arg(latency)); ui->label_running->setText(tr("Test Result") + ": " + QStringLiteral("%1 ms").arg(latency));
} }
}); });
}); });
@ -306,7 +308,7 @@ void MainWindow::neko_start(int _id) {
auto neko_start_stage2 = [=] { auto neko_start_stage2 = [=] {
#ifndef NKR_NO_GRPC #ifndef NKR_NO_GRPC
libcore::LoadConfigReq req; libcore::LoadConfigReq req;
req.set_core_config(QJsonObject2QString(result->coreConfig, true).toStdString()); req.set_core_config(QJsonObject2QString(result->coreConfig, false).toStdString());
req.set_enable_nekoray_connections(NekoGui::dataStore->connection_statistics); req.set_enable_nekoray_connections(NekoGui::dataStore->connection_statistics);
if (NekoGui::dataStore->traffic_loop_interval > 0) { if (NekoGui::dataStore->traffic_loop_interval > 0) {
req.add_stats_outbounds("proxy"); req.add_stats_outbounds("proxy");