improve and support filter by country code

This commit is contained in:
parhelia512 2025-10-09 20:04:40 +08:00
parent a67b0fe5e2
commit 9e82c19451
13 changed files with 306 additions and 70 deletions

View File

@ -65,6 +65,7 @@ set(PROJECT_SOURCES
src/global/Utils.cpp
src/global/HTTPRequestHelper.cpp
src/global/DeviceDetailsHelper.cpp
src/global/CountryHelper.cpp
3rdparty/base64.cpp
3rdparty/qrcodegen.cpp

View File

@ -111,7 +111,6 @@ message SpeedTestResult {
optional string server_name = 6 [default = ""];
optional string server_country = 7 [default = ""];
optional bool cancelled = 8 [default = false];
optional string server_country_emoji = 9 [default = ""];
}
message SpeedTestResponse {

View File

@ -4,7 +4,6 @@ go 1.23.6
require (
github.com/Mahdi-zarei/speedtest-go v1.7.12
github.com/biter777/countries v1.7.5
github.com/chai2010/protorpc v0.0.0-00010101000000-000000000000
github.com/dustin/go-humanize v1.0.1
github.com/gofrs/uuid/v5 v5.3.2

View File

@ -12,8 +12,6 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/anytls/sing-anytls v0.0.11 h1:w8e9Uj1oP3m4zxkyZDewPk0EcQbvVxb7Nn+rapEx4fc=
github.com/anytls/sing-anytls v0.0.11/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8=
github.com/biter777/countries v1.7.5 h1:MJ+n3+rSxWQdqVJU8eBy9RqcdH6ePPn4PJHocVWUa+Q=
github.com/biter777/countries v1.7.5/go.mod h1:1HSpZ526mYqKJcpT5Ti1kcGQ0L0SrXWIaptUWjFfv2E=
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/caddyserver/certmagic v0.23.0 h1:CfpZ/50jMfG4+1J/u2LV6piJq4HOfO6ppOnOf7DkFEU=

View File

@ -1,25 +0,0 @@
package internal
import "github.com/biter777/countries"
var countryMap map[string]*countries.Country
func init() {
countryMap = make(map[string]*countries.Country)
allCountries := countries.AllInfo()
for _, country := range allCountries {
countryMap[country.Name] = country
}
}
func GetCountryByName(name string) *countries.Country {
return countryMap[name]
}
func GetCountryEmojiByName(name string) string {
country, ok := countryMap[name]
if !ok {
return ""
}
return country.Emoji
}

View File

@ -355,7 +355,6 @@ func (s *server) SpeedTest(in *gen.SpeedTestRequest, out *gen.SpeedTestResponse)
Error: To(errStr),
ServerName: To(data.ServerName),
ServerCountry: To(data.ServerCountry),
ServerCountryEmoji: To(data.ServerCountryEmoji),
Cancelled: To(data.Cancelled),
})
}
@ -378,7 +377,6 @@ func (s *server) QuerySpeedTest(in *gen.EmptyReq, out *gen.QuerySpeedTestRespons
Error: To(errStr),
ServerName: To(res.ServerName),
ServerCountry: To(res.ServerCountry),
ServerCountryEmoji: To(res.ServerCountryEmoji),
Cancelled: To(res.Cancelled),
}
out.IsRunning = To(isRunning)

View File

@ -59,7 +59,6 @@ type SpeedTestResult struct {
Latency int32
ServerName string
ServerCountry string
ServerCountryEmoji string
Error error
Cancelled bool
}
@ -296,12 +295,6 @@ func speedTestWithDialer(ctx context.Context, dialer func(ctx context.Context, n
}
res.ServerName = srv[0].Name
res.ServerCountry = srv[0].Country
countryEmoji := internal.GetCountryEmojiByName(srv[0].Country)
if countryEmoji == "" {
fmt.Println("Failed to get country emoji for", srv[0].Name)
} else {
res.ServerCountryEmoji = countryEmoji
}
done := make(chan struct{})

View File

@ -4,6 +4,9 @@
#include "include/stats/traffic/TrafficData.hpp"
#include "include/configs/proxy/AbstractBean.hpp"
#include "include/configs/proxy/ExtraCore.h"
#ifndef Q_MOC_RUN
#include "include/global/CountryHelper.hpp"
#endif
namespace Configs {
class SocksHttpBean;
@ -41,7 +44,7 @@ namespace Configs {
int latency = 0;
QString dl_speed;
QString ul_speed;
QString test_country_emoji;
QString test_country;
std::shared_ptr<Configs::AbstractBean> bean;
std::shared_ptr<Stats::TrafficData> traffic_data = std::make_shared<Stats::TrafficData>("");

View File

@ -0,0 +1,255 @@
#pragma once
#include <QMap>
static const QMap<QString, QString> CountryMap = {
{ "Afghanistan", "AF" },
{ "Aland Islands", "AX" },
{ "Albania", "AL" },
{ "Algeria", "DZ" },
{ "American Samoa", "AS" },
{ "Andorra", "AD" },
{ "Angola", "AO" },
{ "Anguilla", "AI" },
{ "Antarctica", "AQ" },
{ "Antigua And Barbuda", "AG" },
{ "Argentina", "AR" },
{ "Armenia", "AM" },
{ "Netherlands Antilles", "AN" },
{ "Aruba", "AW" },
{ "Australia", "AU" },
{ "Austria", "AT" },
{ "Azerbaijan", "AZ" },
{ "Bahamas", "BS" },
{ "Bahrain", "BH" },
{ "Bangladesh", "BD" },
{ "Barbados", "BB" },
{ "Belarus", "BY" },
{ "Belgium", "BE" },
{ "Belize", "BZ" },
{ "Benin", "BJ" },
{ "Bermuda", "BM" },
{ "Bhutan", "BT" },
{ "Bolivia", "BO" },
{ "Bosnia And Herzegovina", "BA" },
{ "Botswana", "BW" },
{ "Bouvet Island", "BV" },
{ "Brazil", "BR" },
{ "British Indian Ocean Territory", "IO" },
{ "Brunei Darussalam", "BN" },
{ "Bulgaria", "BG" },
{ "Burkina Faso", "BF" },
{ "Burundi", "BI" },
{ "Cambodia", "KH" },
{ "Cameroon", "CM" },
{ "Canada", "CA" },
{ "Cape Verde", "CV" },
{ "Cayman Islands", "KY" },
{ "Central African Republic", "CF" },
{ "Chad", "TD" },
{ "Chile", "CL" },
{ "China", "CN" },
{ "Christmas Island", "CX" },
{ "Cocos (Keeling) Islands", "CC" },
{ "Colombia", "CO" },
{ "Comoros", "KM" },
{ "Congo", "CG" },
{ "Congo, Democratic Republic", "CD" },
{ "Cook Islands", "CK" },
{ "Costa Rica", "CR" },
{ "Cote D\"Ivoire", "CI" },
{ "Croatia", "HR" },
{ "Cuba", "CU" },
{ "Cyprus", "CY" },
{ "Czech Republic", "CZ" },
{ "Denmark", "DK" },
{ "Djibouti", "DJ" },
{ "Dominica", "DM" },
{ "Dominican Republic", "DO" },
{ "Ecuador", "EC" },
{ "Egypt", "EG" },
{ "El Salvador", "SV" },
{ "Equatorial Guinea", "GQ" },
{ "Eritrea", "ER" },
{ "Estonia", "EE" },
{ "Ethiopia", "ET" },
{ "Falkland Islands (Malvinas)", "FK" },
{ "Faroe Islands", "FO" },
{ "Fiji", "FJ" },
{ "Finland", "FI" },
{ "France", "FR" },
{ "French Guiana", "GF" },
{ "French Polynesia", "PF" },
{ "French Southern Territories", "TF" },
{ "Gabon", "GA" },
{ "Gambia", "GM" },
{ "Georgia", "GE" },
{ "Germany", "DE" },
{ "Ghana", "GH" },
{ "Gibraltar", "GI" },
{ "Greece", "GR" },
{ "Greenland", "GL" },
{ "Grenada", "GD" },
{ "Guadeloupe", "GP" },
{ "Guam", "GU" },
{ "Guatemala", "GT" },
{ "Guernsey", "GG" },
{ "Guinea", "GN" },
{ "Guinea-Bissau", "GW" },
{ "Guyana", "GY" },
{ "Haiti", "HT" },
{ "Heard Island & Mcdonald Islands", "HM" },
{ "Holy See (Vatican City State)", "VA" },
{ "Honduras", "HN" },
{ "Hong Kong", "HK" },
{ "Hungary", "HU" },
{ "Iceland", "IS" },
{ "India", "IN" },
{ "Indonesia", "ID" },
{ "Iran, Islamic Republic Of", "IR" },
{ "Iraq", "IQ" },
{ "Ireland", "IE" },
{ "Isle Of Man", "IM" },
{ "Israel", "IL" },
{ "Italy", "IT" },
{ "Jamaica", "JM" },
{ "Japan", "JP" },
{ "Jersey", "JE" },
{ "Jordan", "JO" },
{ "Kazakhstan", "KZ" },
{ "Kenya", "KE" },
{ "Kiribati", "KI" },
{ "Korea", "KR" },
{ "Kuwait", "KW" },
{ "Kyrgyzstan", "KG" },
{ "Lao People\"s Democratic Republic", "LA" },
{ "Latvia", "LV" },
{ "Lebanon", "LB" },
{ "Lesotho", "LS" },
{ "Liberia", "LR" },
{ "Libyan Arab Jamahiriya", "LY" },
{ "Liechtenstein", "LI" },
{ "Lithuania", "LT" },
{ "Luxembourg", "LU" },
{ "Macao", "MO" },
{ "Macedonia", "MK" },
{ "Madagascar", "MG" },
{ "Malawi", "MW" },
{ "Malaysia", "MY" },
{ "Maldives", "MV" },
{ "Mali", "ML" },
{ "Malta", "MT" },
{ "Marshall Islands", "MH" },
{ "Martinique", "MQ" },
{ "Mauritania", "MR" },
{ "Mauritius", "MU" },
{ "Mayotte", "YT" },
{ "Mexico", "MX" },
{ "Micronesia, Federated States Of", "FM" },
{ "Moldova", "MD" },
{ "Monaco", "MC" },
{ "Mongolia", "MN" },
{ "Montenegro", "ME" },
{ "Montserrat", "MS" },
{ "Morocco", "MA" },
{ "Mozambique", "MZ" },
{ "Myanmar", "MM" },
{ "Namibia", "NA" },
{ "Nauru", "NR" },
{ "Nepal", "NP" },
{ "Netherlands", "NL" },
{ "Netherlands Antilles", "AN" },
{ "New Caledonia", "NC" },
{ "New Zealand", "NZ" },
{ "Nicaragua", "NI" },
{ "Niger", "NE" },
{ "Nigeria", "NG" },
{ "Niue", "NU" },
{ "Norfolk Island", "NF" },
{ "Northern Mariana Islands", "MP" },
{ "Norway", "NO" },
{ "Oman", "OM" },
{ "Pakistan", "PK" },
{ "Palau", "PW" },
{ "Palestinian Territory, Occupied", "PS" },
{ "Panama", "PA" },
{ "Papua New Guinea", "PG" },
{ "Paraguay", "PY" },
{ "Peru", "PE" },
{ "Philippines", "PH" },
{ "Pitcairn", "PN" },
{ "Poland", "PL" },
{ "Portugal", "PT" },
{ "Puerto Rico", "PR" },
{ "Qatar", "QA" },
{ "Reunion", "RE" },
{ "Romania", "RO" },
{ "Russian Federation", "RU" },
{ "Rwanda", "RW" },
{ "Saint Barthelemy", "BL" },
{ "Saint Helena", "SH" },
{ "Saint Kitts And Nevis", "KN" },
{ "Saint Lucia", "LC" },
{ "Saint Martin", "MF" },
{ "Saint Pierre And Miquelon", "PM" },
{ "Saint Vincent And Grenadines", "VC" },
{ "Samoa", "WS" },
{ "San Marino", "SM" },
{ "Sao Tome And Principe", "ST" },
{ "Saudi Arabia", "SA" },
{ "Senegal", "SN" },
{ "Serbia", "RS" },
{ "Seychelles", "SC" },
{ "Sierra Leone", "SL" },
{ "Singapore", "SG" },
{ "Slovakia", "SK" },
{ "Slovenia", "SI" },
{ "Solomon Islands", "SB" },
{ "Somalia", "SO" },
{ "South Africa", "ZA" },
{ "South Georgia And Sandwich Isl.", "GS" },
{ "Spain", "ES" },
{ "Sri Lanka", "LK" },
{ "Sudan", "SD" },
{ "Suriname", "SR" },
{ "Svalbard And Jan Mayen", "SJ" },
{ "Swaziland", "SZ" },
{ "Sweden", "SE" },
{ "Switzerland", "CH" },
{ "Syrian Arab Republic", "SY" },
{ "Taiwan", "TW" },
{ "Tajikistan", "TJ" },
{ "Tanzania", "TZ" },
{ "Thailand", "TH" },
{ "Timor-Leste", "TL" },
{ "Togo", "TG" },
{ "Tokelau", "TK" },
{ "Tonga", "TO" },
{ "Trinidad And Tobago", "TT" },
{ "Tunisia", "TN" },
{ "Turkey", "TR" },
{ "Turkmenistan", "TM" },
{ "Turks And Caicos Islands", "TC" },
{ "Tuvalu", "TV" },
{ "Uganda", "UG" },
{ "Ukraine", "UA" },
{ "United Arab Emirates", "AE" },
{ "United Kingdom", "GB" },
{ "United States", "US" },
{ "United States Outlying Islands", "UM" },
{ "Uruguay", "UY" },
{ "Uzbekistan", "UZ" },
{ "Vanuatu", "VU" },
{ "Venezuela", "VE" },
{ "Viet Nam", "VN" },
{ "Virgin Islands, British", "VG" },
{ "Virgin Islands, U.S.", "VI" },
{ "Wallis And Futuna", "WF" },
{ "Western Sahara", "EH" },
{ "Yemen", "YE" },
{ "Zambia", "ZM" },
};
QString CountryNameToCode(const QString& countryName);
QString CountryCodeToFlag(const QString& countryCode);

View File

@ -12,7 +12,7 @@ namespace Configs
_add(new configItem("dl", &dl_speed, itemType::string));
_add(new configItem("ul", &ul_speed, itemType::string));
_add(new configItem("report", &full_test_report, itemType::string));
_add(new configItem("country_emoji", &test_country_emoji, itemType::string));
_add(new configItem("country", &test_country, itemType::string));
if (bean != nullptr) {
this->bean = std::shared_ptr<Configs::AbstractBean>(bean);
@ -26,7 +26,7 @@ namespace Configs
if (latency < 0) {
result = "Unavailable";
} else if (latency > 0) {
if (!test_country_emoji.isEmpty()) result += UNICODE_LRO + test_country_emoji + " ";
if (!test_country.isEmpty()) result += UNICODE_LRO + CountryCodeToFlag(test_country) + " ";
result += QString("%1 ms").arg(latency);
}
if (!dl_speed.isEmpty() && dl_speed != "N/A") result += "" + dl_speed;

View File

@ -0,0 +1,13 @@
#include "include/global/CountryHelper.hpp"
QString CountryNameToCode(const QString& countryName) {
return CountryMap.value(countryName, "");
}
QString CountryCodeToFlag(const QString& countryCode) {
QVector<uint> ucs4 = countryCode.toUcs4();
for (uint& code : ucs4) {
code += 0x1F1A5;
}
return QString::fromUcs4(ucs4.data(), countryCode.length());
}

View File

@ -1158,7 +1158,7 @@ void MainWindow::UpdateDataView(bool force)
).arg(currentSptProfileName,
currentTestResult.dl_speed.value().c_str(),
currentTestResult.ul_speed.value().c_str(),
currentTestResult.server_country_emoji.value().c_str(),
CountryCodeToFlag(CountryNameToCode(QString::fromStdString(currentTestResult.server_country.value()))),
currentTestResult.server_country.value().c_str(),
currentTestResult.server_name.value().c_str());
}
@ -1325,7 +1325,9 @@ QList<std::shared_ptr<Configs::ProxyEntity>> MainWindow::filterProfilesList(cons
MW_show_log("Null profile, maybe data is corrupted");
continue;
}
if (searchString.isEmpty() || profile->bean->name.contains(searchString, Qt::CaseInsensitive) || profile->bean->serverAddress.contains(searchString, Qt::CaseInsensitive)) res.append(profile);
if (searchString.isEmpty() || profile->bean->name.contains(searchString, Qt::CaseInsensitive) || profile->bean->serverAddress.contains(searchString, Qt::CaseInsensitive)
|| (searchString.startsWith("CODE:") && searchString.mid(5) == profile->test_country))
res.append(profile);
}
return res;
}

View File

@ -323,7 +323,7 @@ void MainWindow::runSpeedTest(const QString& config, bool useDefault, bool testC
if (!res.result.value().dl_speed.value().empty()) profile->dl_speed = QString::fromStdString(res.result.value().dl_speed.value());
if (!res.result.value().ul_speed.value().empty()) profile->ul_speed = QString::fromStdString(res.result.value().ul_speed.value());
if (profile->latency <= 0 && res.result.value().latency.value() > 0) profile->latency = res.result.value().latency.value();
if (!res.result->server_country_emoji.value().empty()) profile->test_country_emoji = QString::fromStdString(res.result.value().server_country_emoji.value());
if (!res.result->server_country.value().empty()) profile->test_country = CountryNameToCode(QString::fromStdString(res.result.value().server_country.value()));
refresh_proxy_list(profile->id);
lastProxyListUpdate = QDateTime::currentDateTime();
}
@ -365,12 +365,12 @@ void MainWindow::runSpeedTest(const QString& config, bool useDefault, bool testC
ent->dl_speed = QString::fromStdString(res.dl_speed.value());
ent->ul_speed = QString::fromStdString(res.ul_speed.value());
if (ent->latency <= 0 && res.latency.value() > 0) ent->latency = res.latency.value();
if (!res.server_country_emoji.value().empty()) ent->test_country_emoji = QString::fromStdString(res.server_country_emoji.value());
if (!res.server_country.value().empty()) ent->test_country = CountryNameToCode(QString::fromStdString(res.server_country.value()));
} else {
ent->dl_speed = "N/A";
ent->ul_speed = "N/A";
ent->latency = -1;
ent->test_country_emoji = "";
ent->test_country = "";
MW_show_log(tr("[%1] speed test error: %2").arg(ent->bean->DisplayTypeAndName(), QString::fromStdString(res.error.value())));
}
ent->Save();