初始化提交

This commit is contained in:
2025-09-23 16:23:15 +08:00
commit 877b18a70f
590 changed files with 53617 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
import 'package:get/get.dart';
import 'kr_outbound_item.dart';
/// 表示服务器分组的模型类
class KRGroupOutboundList {
final String tag; // 标签
String icon = ""; // 图标
final List<KROutboundItem> outboundList; // 出站项列表
/// 构造函数,初始化标签和出站项列表
KRGroupOutboundList({
required this.tag,
required this.outboundList,
});
}
class KRCountryOutboundList {
final String country;
final List<KROutboundItem> outboundList;
//// 是否展开
RxBool isExpand = false.obs;
KRCountryOutboundList({
required this.country,
required this.outboundList,
});
}
+207
View File
@@ -0,0 +1,207 @@
import 'dart:convert';
import 'package:get/get.dart';
import 'package:kaer_with_panels/app/modules/kr_main/views/kr_main_view.dart';
import '../response/kr_node_list.dart';
/// 表示出站项的模型类
class KROutboundItem {
String id = ""; // 标签
String tag = ""; // 标签
String serverAddr = ""; // 服务器地址
/// 初始化配置
Map<String, dynamic> config = {}; // 配置项
String city = ""; // 城市
String country = ""; // 国家
double latitude = 0.0;
double longitude = 0.0;
String protocol = "";
/// 延迟
RxInt urlTestDelay = 0.obs;
/// URL
String url = "";
/// 服务器类型
/// 构造函数,接受 KrNodeListItem 对象并初始化 KROutboundItem
KROutboundItem(KrNodeListItem nodeListItem) {
id = nodeListItem.id.toString();
protocol = nodeListItem.protocol;
latitude = nodeListItem.latitude;
longitude = nodeListItem.longitude;
tag = nodeListItem.name; // 设置标签
serverAddr = nodeListItem.serverAddr; // 设置服务器地址
// 将 config 字符串转换为 Map<String, dynamic>
city = nodeListItem.city; // 设置城市
country = nodeListItem.country; // 设置国家
final json = jsonDecode(nodeListItem.config);
switch (nodeListItem.protocol) {
case "vless":
final securityConfig =
json["security_config"] as Map<String, dynamic>? ?? {};
// 智能设置 server_name
String serverName = securityConfig["sni"] ?? "";
if (serverName.isEmpty) {
serverName = nodeListItem.serverAddr;
}
config = {
"type": "vless",
"tag": nodeListItem.name,
"server": nodeListItem.serverAddr,
"server_port": json["port"],
"uuid": nodeListItem.uuid,
if (json["flow"] != null && json["flow"] != "none")
"flow": json["flow"],
if (json["transport"] != null && json["transport"] != "tcp")
"transport": _buildTransport(json),
"tls": {
"enabled": json["security"] == "tls",
"server_name": serverName,
"insecure": securityConfig["allow_insecure"] ?? false,
"utls": {
"enabled": true,
"fingerprint": securityConfig["fingerprint"] ?? "chrome"
}
}
};
break;
case "vmess":
final securityConfig =
json["security_config"] as Map<String, dynamic>? ?? {};
// 智能设置 server_name
String serverName = securityConfig["sni"] ?? "";
if (serverName.isEmpty) {
serverName = nodeListItem.serverAddr;
}
config = {
"type": "vmess",
"tag": nodeListItem.name,
"server": nodeListItem.serverAddr,
"server_port": json["port"],
"uuid": nodeListItem.uuid,
"alter_id": 0,
"security": "auto",
if (json["transport"] != null && json["transport"] != "tcp")
"transport": _buildTransport(json),
"tls": {
"enabled": json["security"] == "tls",
"server_name": serverName,
"insecure": securityConfig["allow_insecure"] ?? false,
"utls": {"enabled": true, "fingerprint": "chrome"}
}
};
break;
case "shadowsocks":
config = {
"type": "shadowsocks",
"tag": nodeListItem.name,
"server": nodeListItem.serverAddr,
"server_port": json["port"],
"method": json["method"],
"password": nodeListItem.uuid
};
break;
case "hysteria2":
final securityConfig =
json["security_config"] as Map<String, dynamic>? ?? {};
config = {
"type": "hysteria2",
"tag": nodeListItem.name,
"server": nodeListItem.serverAddr,
"server_port": json["port"],
"password": nodeListItem.uuid,
"up_mbps": 100,
"down_mbps": 100,
"obfs": {
"type": "salamander",
"password": json["obfs_password"] ?? nodeListItem.uuid
},
"tls": {
"enabled": true,
"server_name": securityConfig["sni"] ?? "",
"insecure": securityConfig["allow_insecure"] ?? false,
"alpn": ["h3"]
}
};
break;
case "trojan":
final securityConfig =
json["security_config"] as Map<String, dynamic>? ?? {};
// 智能设置 server_name
String serverName = securityConfig["sni"] ?? "";
if (serverName.isEmpty) {
// 如果没有配置 SNI,使用服务器地址
serverName = nodeListItem.serverAddr;
}
config = {
"type": "trojan",
"tag": nodeListItem.name,
"server": nodeListItem.serverAddr,
"server_port": json["port"],
"password": nodeListItem.uuid,
"tls": {
"enabled": json["security"] == "tls",
"server_name": serverName,
"insecure": securityConfig["allow_insecure"] ?? false,
"utls": {"enabled": true, "fingerprint": "chrome"}
}
};
break;
}
// 检查 relayNode 是否为 JSON 字符串并解析
if (nodeListItem.relayNode.isNotEmpty && nodeListItem.relayMode != "none") {
final relayNodeJson = jsonDecode(nodeListItem.relayNode);
if (relayNodeJson is List && nodeListItem.relayMode != "none") {
// 随机选择一个元素
final randomNode = (relayNodeJson..shuffle()).first;
config["server"] = randomNode["host"]; // 提取 host
config["server_port"] = randomNode["port"]; // 提取 port
}
}
// 解析配置
}
/// 构建传输配置
Map<String, dynamic> _buildTransport(Map<String, dynamic> json) {
final transportType = json["transport"] as String?;
final transportConfig =
json["transport_config"] as Map<String, dynamic>? ?? {};
switch (transportType) {
case "ws":
return {
"type": "ws",
"path": transportConfig["path"] ?? "/",
if (transportConfig["host"] != null)
"headers": {"Host": transportConfig["host"]}
};
case "grpc":
return {
"type": "grpc",
"service_name": transportConfig["service_name"] ?? ""
};
case "http":
return {
"type": "http",
"host": [transportConfig["host"] ?? ""],
"path": transportConfig["path"] ?? "/"
};
default:
return {};
}
}
}
+87
View File
@@ -0,0 +1,87 @@
import '../response/kr_node_group_list.dart';
import 'kr_group_outbound_list.dart';
import '../response/kr_node_list.dart';
import 'kr_outbound_item.dart';
/// 表示出站项列表的模型类
class KrOutboundsList {
/// 服务器分组
final List<KRGroupOutboundList> groupOutboundList = []; // 存储服务器分组的列表
/// 国家分组,包含所有国家
final List<KRCountryOutboundList> countryOutboundList = []; // 存储国家分组的列表
/// 全部列表
final List<KROutboundItem> allList = []; // 存储国家分组的列表
// 配置json
final List<Map<String,dynamic>> configJsonList = [];
/// 标签列表
final Map<String,KROutboundItem> keyList = {}; // 存储国家分组的列表
/// 处理出站项并将其分组
/// [list] 是要处理的出站项列表
void processOutboundItems(List<KrNodeListItem> list,List<KRNodeGroupListItem> groupList) {
final Map<String, List<KROutboundItem>> tagGroups = {};
final Map<String, List<KROutboundItem>> countryGroups = {};
// 用于追踪已使用的标签
final Map<String, int> tagCounter = {};
for (var element in list) {
// 生成唯一标签
var baseName = element.name;
if (tagCounter.containsKey(baseName)) {
tagCounter[baseName] = tagCounter[baseName]! + 1;
element.name = "${baseName}_${tagCounter[baseName]}";
} else {
tagCounter[baseName] = 0;
}
final KROutboundItem item = KROutboundItem(element);
allList.add(item);
// 根据标签分组出站项
for (var tag in element.tags) {
tagGroups.putIfAbsent(tag, () => []);
tagGroups[tag]?.add(item);
}
// 根据国家分组出站项
countryGroups.putIfAbsent(element.country, () => []);
countryGroups[element.country]?.add(item);
configJsonList.add(item.config);
keyList[item.tag] = item;
}
// 将标签分组转换为 KRGroupOutboundList 并添加到 groupOutboundList
for (var tag in tagGroups.keys) {
final item = KRGroupOutboundList(
tag: tag, outboundList: tagGroups[tag]!);
for (var group in groupList) {
if (item.tag == group.name) {
item.icon = group.icon;
break;
}
}
groupOutboundList.add(item); // 添加标签分组到列表
}
// 将国家分组转换为 KRCountryOutboundList 并添加到 countryOutboundList
for (var country in countryGroups.keys) {
countryOutboundList.add(KRCountryOutboundList(
country: country,
outboundList: countryGroups[country]!)); // 添加国家分组到列表
}
}
}