diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/AppConfig.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/AppConfig.kt index 09e3a9d5..05369040 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/AppConfig.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/AppConfig.kt @@ -57,6 +57,7 @@ object AppConfig { const val PREF_DELAY_TEST_URL = "pref_delay_test_url" const val PREF_LOGLEVEL = "pref_core_loglevel" const val PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD = "pref_outbound_domain_resolve_method" + const val PREF_INTELLIGENT_SELECTION_METHOD = "pref_intelligent_selection_method" const val PREF_MODE = "pref_mode" const val PREF_IS_BOOTED = "pref_is_booted" const val PREF_CHECK_UPDATE_PRE_RELEASE = "pref_check_update_pre_release" diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/SubscriptionItem.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/SubscriptionItem.kt index 8957df78..8a38e6db 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/SubscriptionItem.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/SubscriptionItem.kt @@ -11,6 +11,7 @@ data class SubscriptionItem( var prevProfile: String? = null, var nextProfile: String? = null, var filter: String? = null, + var intelligentSelectionFilter: String? = null, var allowInsecureUrl: Boolean = false, ) diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt index 155be104..4393bd70 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt @@ -496,14 +496,14 @@ data class V2rayConfig( var domainStrategy: String, var domainMatcher: String? = null, var rules: ArrayList, - val balancers: List? = null + var balancers: List? = null ) { data class RulesBean( var type: String = "field", var ip: ArrayList? = null, var domain: ArrayList? = null, - var outboundTag: String = "", + var outboundTag: String? = null, var balancerTag: String? = null, var port: String? = null, val sourcePort: String? = null, @@ -515,6 +515,32 @@ data class V2rayConfig( val attrs: String? = null, val domainMatcher: String? = null ) + + data class BalancerBean( + val tag: String, + val selector: List, + val fallbackTag: String? = null, + val strategy: StrategyObject? = null + ) + + data class StrategyObject( + val type: String = "random", // "random" | "roundRobin" | "leastPing" | "leastLoad" + val settings: StrategySettingsObject? = null + ) + + data class StrategySettingsObject( + val expected: Int? = null, + val maxRTT: String? = null, + val tolerance: Double? = null, + val baselines: List? = null, + val costs: List? = null + ) + + data class CostObject( + val regexp: Boolean = false, + val match: String, + val value: Double + ) } data class PolicyBean( @@ -532,6 +558,26 @@ data class V2rayConfig( ) } + data class ObservatoryObject( + val subjectSelector: List, + val probeUrl: String, + val probeInterval: String, + val enableConcurrency: Boolean = false + ) + + data class BurstObservatoryObject( + val subjectSelector: List, + val pingConfig: PingConfigObject + ) { + data class PingConfigObject( + val destination: String, + val connectivity: String? = null, + val interval: String, + val sampling: Int, + val timeout: String? = null + ) + } + data class FakednsBean( var ipPool: String = "198.18.0.0/15", var poolSize: Int = 10000 diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/AngConfigManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/AngConfigManager.kt index b8d42ed7..320f3693 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/AngConfigManager.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/AngConfigManager.kt @@ -490,4 +490,31 @@ object AngConfigManager { MmkvManager.encodeSubscription("", subItem) return 1 } + + /** + * Creates an intelligent selection configuration based on multiple server configurations. + * + * @param context The application context used for configuration generation. + * @param guidList The list of server GUIDs to be included in the intelligent selection. + * Each GUID represents a server configuration that will be combined. + * @param subid The subscription ID to associate with the generated configuration. + * This helps organize the configuration under a specific subscription. + * @return The GUID key of the newly created intelligent selection configuration, + * or null if the operation fails (e.g., empty guidList or configuration parsing error). + */ + fun createIntelligentSelection( + context: Context, + guidList: List, + subid: String + ): String? { + if (guidList.isEmpty()) { + return null + } + val result = V2rayConfigManager.genV2rayConfig(context, guidList) ?: return null + val config = CustomFmt.parse(JsonUtil.toJson(result)) ?: return null + config.subscriptionId = subid + val key = MmkvManager.encodeServerConfig("", config) + MmkvManager.encodeServerRaw(key, JsonUtil.toJsonPretty(result) ?: "") + return key + } } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2rayConfigManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2rayConfigManager.kt index f53697bb..d004e640 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2rayConfigManager.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2rayConfigManager.kt @@ -4,6 +4,7 @@ import android.content.Context import android.text.TextUtils import android.util.Log import com.v2ray.ang.AppConfig +import com.v2ray.ang.R import com.v2ray.ang.dto.ConfigResult import com.v2ray.ang.dto.EConfigType import com.v2ray.ang.dto.NetworkType @@ -15,6 +16,7 @@ import com.v2ray.ang.dto.V2rayConfig.OutboundBean.OutSettingsBean import com.v2ray.ang.dto.V2rayConfig.OutboundBean.StreamSettingsBean import com.v2ray.ang.dto.V2rayConfig.RoutingBean.RulesBean import com.v2ray.ang.extension.isNotNullEmpty +import com.v2ray.ang.fmt.CustomFmt import com.v2ray.ang.fmt.HttpFmt import com.v2ray.ang.fmt.ShadowsocksFmt import com.v2ray.ang.fmt.SocksFmt @@ -52,6 +54,27 @@ object V2rayConfigManager { } } + /** + * Generates a V2ray configuration from multiple server profiles. + * + * @param context The context of the caller. + * @param guidList A list of server GUIDs to be included in the generated configuration. + * Each GUID represents a unique server profile stored in the system. + * @return A V2rayConfig object containing the combined configuration of all specified servers, + * or null if the operation fails (e.g., no valid configurations found, parsing errors) + */ + fun genV2rayConfig(context: Context, guidList: List): V2rayConfig? { + try { + val configList = guidList.mapNotNull { guid -> + MmkvManager.decodeServerConfig(guid) + } + return genV2rayMultipleConfig(context, configList) + } catch (e: Exception) { + Log.e(AppConfig.TAG, "Failed to generate V2ray config", e) + return null + } + } + /** * Retrieves the speedtest V2ray configuration for the given GUID. * @@ -142,6 +165,80 @@ object V2rayConfigManager { return result } + private fun genV2rayMultipleConfig(context: Context, configList: List): V2rayConfig? { + val validConfigs = configList.asSequence().filter { it.server.isNotNullEmpty() } + .filter { !Utils.isPureIpAddress(it.server!!) || Utils.isValidUrl(it.server!!) } + .filter { it.configType != EConfigType.CUSTOM } + .filter { it.configType != EConfigType.HYSTERIA2 } + .filter { config -> + if (config.subscriptionId.isEmpty()) { + return@filter true + } + val subItem = MmkvManager.decodeSubscription(config.subscriptionId) + if (subItem?.intelligentSelectionFilter.isNullOrEmpty() || config.remarks.isEmpty()) { + return@filter true + } + Regex(pattern = subItem?.intelligentSelectionFilter!!).containsMatchIn(input = config.remarks) + }.toList() + + if (validConfigs.isEmpty()) { + Log.w(AppConfig.TAG, "All configs are invalid") + return null + } + + val v2rayConfig = initV2rayConfig(context) ?: return null + v2rayConfig.log.loglevel = MmkvManager.decodeSettingsString(AppConfig.PREF_LOGLEVEL) ?: "warning" + + val subIds = configList.map { it.subscriptionId }.toHashSet() + val remarks = if (subIds.size == 1 && subIds.first().isNotEmpty()) { + val sub = MmkvManager.decodeSubscription(subIds.first()) + (sub?.remarks ?: "") + context.getString(R.string.intelligent_selection) + } else { + context.getString(R.string.intelligent_selection) + } + + v2rayConfig.remarks = remarks + + getInbounds(v2rayConfig) + + v2rayConfig.outbounds.removeAt(0) + val outboundsList = mutableListOf() + var index = 0 + for (config in validConfigs) { + index++ + val outbound = convertProfile2Outbound(config) ?: continue + val ret = updateOutboundWithGlobalSettings(outbound) + if (!ret) continue + outbound.tag = "proxy-$index" + outboundsList.add(outbound) + } + outboundsList.addAll(v2rayConfig.outbounds) + v2rayConfig.outbounds = ArrayList(outboundsList) + + getRouting(v2rayConfig) + + getFakeDns(v2rayConfig) + + getDns(v2rayConfig) + + getBalance(v2rayConfig) + + if (MmkvManager.decodeSettingsBool(AppConfig.PREF_LOCAL_DNS_ENABLED) == true) { + getCustomLocalDns(v2rayConfig) + } + if (MmkvManager.decodeSettingsBool(AppConfig.PREF_SPEED_ENABLED) != true) { + v2rayConfig.stats = null + v2rayConfig.policy = null + } + + //Resolve and add to DNS Hosts + if (MmkvManager.decodeSettingsString(AppConfig.PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD, "1") == "1") { + resolveOutboundDomainsToHosts(v2rayConfig) + } + + return v2rayConfig + } + /** * Retrieves the normal V2ray configuration for speedtest. * @@ -741,6 +838,60 @@ object V2rayConfigManager { return true } + /** + * Configures load balancing settings for the V2ray configuration. + * + * @param v2rayConfig The V2ray configuration object to be modified with balancing settings + */ + private fun getBalance(v2rayConfig: V2rayConfig) + { + try { + v2rayConfig.routing.rules.forEach { rule -> + if (rule.outboundTag == "proxy") { + rule.outboundTag = null + rule.balancerTag = "proxy-round" + } + } + + if (MmkvManager.decodeSettingsString(AppConfig.PREF_INTELLIGENT_SELECTION_METHOD, "0") == "0") { + val balancer = V2rayConfig.RoutingBean.BalancerBean( + tag = "proxy-round", + selector = listOf("proxy-"), + strategy = V2rayConfig.RoutingBean.StrategyObject( + type = "leastPing" + ) + ) + v2rayConfig.routing.balancers = listOf(balancer) + v2rayConfig.observatory = V2rayConfig.ObservatoryObject( + subjectSelector = listOf("proxy-"), + probeUrl = MmkvManager.decodeSettingsString(AppConfig.PREF_DELAY_TEST_URL) ?: AppConfig.DELAY_TEST_URL, + probeInterval = "3m", + enableConcurrency = true + ) + } else { + val balancer = V2rayConfig.RoutingBean.BalancerBean( + tag = "proxy-round", + selector = listOf("proxy-"), + strategy = V2rayConfig.RoutingBean.StrategyObject( + type = "leastLoad" + ) + ) + v2rayConfig.routing.balancers = listOf(balancer) + v2rayConfig.burstObservatory = V2rayConfig.BurstObservatoryObject( + subjectSelector = listOf("proxy-"), + pingConfig = V2rayConfig.BurstObservatoryObject.PingConfigObject( + destination = MmkvManager.decodeSettingsString(AppConfig.PREF_DELAY_TEST_URL) ?: AppConfig.DELAY_TEST_URL, + interval = "5m", + sampling = 2, + timeout = "30s" + ) + ) + } + } catch (e: Exception) { + Log.e(AppConfig.TAG, "Failed to configure balance", e) + } + } + /** * Updates the outbound with fragment settings for traffic optimization. * diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/MainActivity.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/MainActivity.kt index 0c7584d8..610af8ec 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/MainActivity.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/MainActivity.kt @@ -385,6 +385,11 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList true } + R.id.intelligent_selection_all -> { + mainViewModel.createIntelligentSelectionAll() + true + } + R.id.service_restart -> { restartV2Ray() true diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/SettingsActivity.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/SettingsActivity.kt index 6af64e3a..ef20f6b3 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/SettingsActivity.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/SettingsActivity.kt @@ -258,6 +258,7 @@ class SettingsActivity : BaseActivity() { AppConfig.PREF_UI_MODE_NIGHT, AppConfig.PREF_LOGLEVEL, AppConfig.PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD, + AppConfig.PREF_INTELLIGENT_SELECTION_METHOD, AppConfig.PREF_MODE ).forEach { key -> if (MmkvManager.decodeSettingsString(key) != null) { diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/SubEditActivity.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/SubEditActivity.kt index f85382f1..46f2afc0 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/SubEditActivity.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/SubEditActivity.kt @@ -45,6 +45,7 @@ class SubEditActivity : BaseActivity() { binding.etRemarks.text = Utils.getEditable(subItem.remarks) binding.etUrl.text = Utils.getEditable(subItem.url) binding.etFilter.text = Utils.getEditable(subItem.filter) + binding.etIntelligentSelectionFilter.text = Utils.getEditable(subItem.intelligentSelectionFilter) binding.chkEnable.isChecked = subItem.enabled binding.autoUpdateCheck.isChecked = subItem.autoUpdate binding.allowInsecureUrl.isChecked = subItem.allowInsecureUrl @@ -60,6 +61,7 @@ class SubEditActivity : BaseActivity() { binding.etRemarks.text = null binding.etUrl.text = null binding.etFilter.text = null + binding.etIntelligentSelectionFilter.text = null binding.chkEnable.isChecked = true binding.etPreProfile.text = null binding.etNextProfile.text = null @@ -75,6 +77,7 @@ class SubEditActivity : BaseActivity() { subItem.remarks = binding.etRemarks.text.toString() subItem.url = binding.etUrl.text.toString() subItem.filter = binding.etFilter.text.toString() + subItem.intelligentSelectionFilter = binding.etIntelligentSelectionFilter.text.toString() subItem.enabled = binding.chkEnable.isChecked subItem.autoUpdate = binding.autoUpdateCheck.isChecked subItem.prevProfile = binding.etPreProfile.text.toString() diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/MainViewModel.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/MainViewModel.kt index ec5cb7ee..f9323c98 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/MainViewModel.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/MainViewModel.kt @@ -384,6 +384,29 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { MmkvManager.encodeServerList(serverList) } + /** + * Creates an intelligent selection configuration containing all currently filtered servers. + */ + fun createIntelligentSelectionAll() { + viewModelScope.launch(Dispatchers.IO) { + val key = AngConfigManager.createIntelligentSelection( + getApplication(), + serversCache.map { it.guid }.toList(), + subscriptionId + ) + + launch(Dispatchers.Main) { + if (key.isNullOrEmpty()) { + getApplication().toastError(R.string.toast_failure) + } else { + getApplication().toastSuccess(R.string.toast_success) + MmkvManager.setSelectServer(key) + reloadServerList() + } + } + } + } + /** * Initializes assets. * @param assets The asset manager. diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/SettingsViewModel.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/SettingsViewModel.kt index 7ac5d60f..fe108ea6 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/SettingsViewModel.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/SettingsViewModel.kt @@ -50,6 +50,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application AppConfig.PREF_SOCKS_PORT, AppConfig.PREF_LOGLEVEL, AppConfig.PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD, + AppConfig.PREF_INTELLIGENT_SELECTION_METHOD, AppConfig.PREF_LANGUAGE, AppConfig.PREF_UI_MODE_NIGHT, AppConfig.PREF_ROUTING_DOMAIN_STRATEGY, diff --git a/V2rayNG/app/src/main/res/layout/activity_sub_edit.xml b/V2rayNG/app/src/main/res/layout/activity_sub_edit.xml index af5d70cd..baf3edb1 100644 --- a/V2rayNG/app/src/main/res/layout/activity_sub_edit.xml +++ b/V2rayNG/app/src/main/res/layout/activity_sub_edit.xml @@ -93,6 +93,25 @@ + + + + + + + + + \ No newline at end of file diff --git a/V2rayNG/app/src/main/res/values-ar/strings.xml b/V2rayNG/app/src/main/res/values-ar/strings.xml index d74011e9..ace91940 100644 --- a/V2rayNG/app/src/main/res/values-ar/strings.xml +++ b/V2rayNG/app/src/main/res/values-ar/strings.xml @@ -269,6 +269,7 @@ تحديث الاشتراك (أول خطوة) Tcping لجميع الإعدادات اختبر جميع الإعدادات (3) + Creating Intelligent Selection Current Group Configuration Asset files الفرز حسب نتائج الاختبار (5) تصفية ملف التكوين @@ -363,5 +364,12 @@ Resolve and add to DNS Hosts Resolve and replace domain + Intelligent Selection + Remarks Intelligent Selection regular filter + Intelligent Selection Method + + Least Ping + Least Load + diff --git a/V2rayNG/app/src/main/res/values-bn/strings.xml b/V2rayNG/app/src/main/res/values-bn/strings.xml index f36c9d3a..3067fd81 100644 --- a/V2rayNG/app/src/main/res/values-bn/strings.xml +++ b/V2rayNG/app/src/main/res/values-bn/strings.xml @@ -269,6 +269,7 @@ সাবস্ক্রিপশন আপডেট সব কনফিগারেশন TCPing সব কনফিগারেশন প্রকৃত বিলম্ব + Creating Intelligent Selection Current Group Configuration Asset files টেস্ট ফলাফল দ্বারা সাজানো কনফিগারেশন ফাইল ফিল্টার করুন @@ -368,5 +369,12 @@ Resolve and add to DNS Hosts Resolve and replace domain + Intelligent Selection + Remarks Intelligent Selection regular filter + Intelligent Selection Method + + Least Ping + Least Load + \ No newline at end of file diff --git a/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml b/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml index 90e5cc26..913015c8 100644 --- a/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml +++ b/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml @@ -269,6 +269,7 @@ ورۊ کردن اشتراک جرگه سکویی Tcping کانفیگا جرگه سکویی تئخیر واقعی کانفیگا جرگه سکویی + Creating Intelligent Selection Current Group Configuration فایلا بونچک جوقرافیایی ترتیب و ری نتیجه یل آزمایش فیلتر کردن کانفیگا @@ -378,5 +379,12 @@ هل وو ٱووردن و میزبووݩ یل دامنه DNS هل وو جایونی دامنه + Intelligent Selection + Remarks Intelligent Selection regular filter + Intelligent Selection Method + + Least Ping + Least Load + diff --git a/V2rayNG/app/src/main/res/values-fa/strings.xml b/V2rayNG/app/src/main/res/values-fa/strings.xml index 081571a3..dc8ca573 100644 --- a/V2rayNG/app/src/main/res/values-fa/strings.xml +++ b/V2rayNG/app/src/main/res/values-fa/strings.xml @@ -266,6 +266,7 @@ به‌روزرسانی گروه فعلی اشتراک TCPING کانفیگ های گروه فعلی تاخیر واقعی کانفیگ های گروه فعلی + Creating Intelligent Selection Current Group Configuration فایل های منبع جغرافیایی مرتب‌ سازی بر اساس نتایج آزمایش فیلتر کردن کانفیگ‌ها @@ -377,5 +378,12 @@ Resolve and add to DNS Hosts Resolve and replace domain + Intelligent Selection + Remarks Intelligent Selection regular filter + Intelligent Selection Method + + Least Ping + Least Load + diff --git a/V2rayNG/app/src/main/res/values-ru/strings.xml b/V2rayNG/app/src/main/res/values-ru/strings.xml index 0d716598..036746a3 100644 --- a/V2rayNG/app/src/main/res/values-ru/strings.xml +++ b/V2rayNG/app/src/main/res/values-ru/strings.xml @@ -268,6 +268,7 @@ Обновить подписку группы Проверить профили группы Время отклика профилей группы + Creating Intelligent Selection Current Group Configuration Файлы ресурсов Сортировать по результатам теста Фильтр групп @@ -377,5 +378,12 @@ Определять и добавлять к узлам DNS Определять и заменять домен + Intelligent Selection + Remarks Intelligent Selection regular filter + Intelligent Selection Method + + Least Ping + Least Load + diff --git a/V2rayNG/app/src/main/res/values-vi/strings.xml b/V2rayNG/app/src/main/res/values-vi/strings.xml index 86238b79..302b78fb 100644 --- a/V2rayNG/app/src/main/res/values-vi/strings.xml +++ b/V2rayNG/app/src/main/res/values-vi/strings.xml @@ -269,6 +269,7 @@ Cập nhật các gói đăng ký Ping tất cả máy chủ Kiểm tra HTTP tất cả máy chủ + Creating Intelligent Selection Current Group Configuration Asset files Sắp xếp lại theo lần kiểm tra cuối cùng Lọc cấu hình theo các gói đăng ký @@ -365,5 +366,12 @@ Resolve and add to DNS Hosts Resolve and replace domain + Intelligent Selection + Remarks Intelligent Selection regular filter + Intelligent Selection Method + + Least Ping + Least Load + diff --git a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml index a8eec856..2a6911a2 100644 --- a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml +++ b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml @@ -266,6 +266,7 @@ 更新当前组订阅 测试当前组配置 Tcping 测试当前组配置真连接 + 生成当前组智能选择配置 资源文件 按测试结果排序 过滤配置文件 @@ -369,5 +370,12 @@ 解析后添加至 DNS Hosts 解析后替换原域名 + 智能选择 + 别名智能选择正则过滤 + 智能选择方式 + + 最低延迟 + 最稳定 + diff --git a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml index f8b938c5..09824a12 100644 --- a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml +++ b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml @@ -267,6 +267,7 @@ 更新目前群組訂閱 偵測目前群組設定 Tcping 偵測目前群組設定真延遲 + Creating Intelligent Selection Current Group Configuration 資源檔案 依偵測結果排序 過濾設定 @@ -369,5 +370,12 @@ 解析後加入 DNS Hosts 解析後替換原網域名稱 + Intelligent Selection + Remarks Intelligent Selection regular filter + Intelligent Selection Method + + Least Ping + Least Load + diff --git a/V2rayNG/app/src/main/res/values/arrays.xml b/V2rayNG/app/src/main/res/values/arrays.xml index 27f0846e..63ca4c6d 100644 --- a/V2rayNG/app/src/main/res/values/arrays.xml +++ b/V2rayNG/app/src/main/res/values/arrays.xml @@ -208,4 +208,9 @@ 2 + + 0 + 1 + + \ No newline at end of file diff --git a/V2rayNG/app/src/main/res/values/strings.xml b/V2rayNG/app/src/main/res/values/strings.xml index 57106306..b9388f54 100644 --- a/V2rayNG/app/src/main/res/values/strings.xml +++ b/V2rayNG/app/src/main/res/values/strings.xml @@ -270,6 +270,7 @@ Update current group subscription Tcping current group configuration Real delay current group configuration + Creating Intelligent Selection Current Group Configuration Asset files Sorting by test results Filter configuration file @@ -379,5 +380,12 @@ Resolve and add to DNS Hosts Resolve and replace domain + Intelligent Selection + Remarks Intelligent Selection regular filter + Intelligent Selection Method + + Least Ping + Least Load + diff --git a/V2rayNG/app/src/main/res/xml/pref_settings.xml b/V2rayNG/app/src/main/res/xml/pref_settings.xml index b5ee7aab..a2f179d7 100644 --- a/V2rayNG/app/src/main/res/xml/pref_settings.xml +++ b/V2rayNG/app/src/main/res/xml/pref_settings.xml @@ -230,6 +230,14 @@ android:summary="%s" android:title="@string/title_outbound_domain_resolve_method" /> + +