use crate::models::SubconverterTarget;
pub struct UAProfile {
pub head: String,
pub version_match: String,
pub version_target: String,
pub target: SubconverterTarget,
pub clash_new_name: Option<bool>,
pub surge_ver: i32,
}
impl UAProfile {
pub fn new(
head: &str,
version_match: &str,
version_target: &str,
target: SubconverterTarget,
clash_new_name: Option<bool>,
surge_ver: i32,
) -> Self {
UAProfile {
head: head.to_string(),
version_match: version_match.to_string(),
version_target: version_target.to_string(),
target,
clash_new_name,
surge_ver,
}
}
}
pub fn ver_greater_equal(src_ver: &str, target_ver: &str) -> bool {
let src_parts = src_ver.split('.').collect::<Vec<&str>>();
let target_parts = target_ver.split('.').collect::<Vec<&str>>();
let min_len = src_parts.len().min(target_parts.len());
for i in 0..min_len {
let src_part = src_parts[i].parse::<i32>().unwrap_or(0);
let target_part = target_parts[i].parse::<i32>().unwrap_or(0);
if src_part > target_part {
return true;
}
else if src_part < target_part {
return false;
}
}
if src_parts.len() >= target_parts.len() {
return true;
}
false
}
pub fn match_user_agent(
user_agent: &str,
target: &mut SubconverterTarget,
clash_new_name: &mut Option<bool>,
surge_ver: &mut i32,
) {
let ua_profiles = vec![
UAProfile::new(
"clashforandroid",
"\\/([0-9.]+)",
"2.0",
SubconverterTarget::Clash,
Some(true), -1,
),
UAProfile::new(
"clashforandroid",
"\\/([0-9.]+)r",
"",
SubconverterTarget::ClashR,
Some(false), -1,
),
UAProfile::new(
"clashforandroid",
"",
"",
SubconverterTarget::Clash,
Some(false), -1,
),
UAProfile::new(
"clashforwindows",
"\\/([0-9.]+)",
"0.11",
SubconverterTarget::Clash,
Some(true), -1,
),
UAProfile::new(
"clashforwindows",
"",
"",
SubconverterTarget::Clash,
Some(false), -1,
),
UAProfile::new(
"clash-verge",
"",
"",
SubconverterTarget::Clash,
Some(true), -1,
),
UAProfile::new(
"clashx pro",
"",
"",
SubconverterTarget::Clash,
Some(true), -1,
),
UAProfile::new(
"clashx",
"\\/([0-9.]+)",
"0.13",
SubconverterTarget::Clash,
Some(true), -1,
),
UAProfile::new(
"clash",
"",
"",
SubconverterTarget::Clash,
Some(true), -1,
),
UAProfile::new(
"kitsunebi",
"",
"",
SubconverterTarget::V2Ray,
None, -1,
),
UAProfile::new(
"loon",
"",
"",
SubconverterTarget::Loon,
None, -1,
),
UAProfile::new(
"pharos",
"",
"",
SubconverterTarget::Mixed,
None, -1,
),
UAProfile::new(
"potatso",
"",
"",
SubconverterTarget::Mixed,
None, -1,
),
UAProfile::new(
"quantumult%20x",
"",
"",
SubconverterTarget::QuantumultX,
None, -1,
),
UAProfile::new(
"quantumult",
"",
"",
SubconverterTarget::Quantumult,
None, -1,
),
UAProfile::new(
"qv2ray",
"",
"",
SubconverterTarget::V2Ray,
None, -1,
),
UAProfile::new(
"shadowrocket",
"",
"",
SubconverterTarget::Mixed, None, -1,
),
UAProfile::new(
"surfboard",
"",
"",
SubconverterTarget::Surfboard,
None, -1,
),
UAProfile::new(
"surge",
"\\/([0-9.]+).*x86",
"906",
SubconverterTarget::Surge(4),
Some(false), 4,
),
UAProfile::new(
"surge",
"\\/([0-9.]+).*x86",
"368",
SubconverterTarget::Surge(3),
Some(false), 3,
),
UAProfile::new(
"surge",
"\\/([0-9.]+)",
"1419",
SubconverterTarget::Surge(4),
Some(false), 4,
),
UAProfile::new(
"surge",
"\\/([0-9.]+)",
"900",
SubconverterTarget::Surge(3),
Some(false), 3,
),
UAProfile::new(
"surge",
"",
"",
SubconverterTarget::Surge(2),
Some(false), 2,
),
UAProfile::new(
"trojan-qt5",
"",
"",
SubconverterTarget::Trojan,
None, -1,
),
UAProfile::new(
"v2rayu",
"",
"",
SubconverterTarget::V2Ray,
None, -1,
),
UAProfile::new(
"v2rayx",
"",
"",
SubconverterTarget::V2Ray,
None, -1,
),
UAProfile::new(
"sing-box",
"",
"",
SubconverterTarget::SingBox,
None, -1,
),
];
let user_agent_lower = user_agent.to_lowercase();
for profile in ua_profiles {
if user_agent_lower.contains(&profile.head) {
if !profile.version_match.is_empty() && !profile.version_target.is_empty() {
if let Some(version_pos) = user_agent_lower.find(&profile.version_match) {
let version_begin = version_pos + profile.version_match.len();
if let Some(version_end) = user_agent_lower[version_begin..].find(' ') {
let version =
&user_agent_lower[version_begin..(version_begin + version_end)];
if ver_greater_equal(version, &profile.version_target) {
*target = profile.target;
*clash_new_name = profile.clash_new_name;
*surge_ver = profile.surge_ver;
return;
}
} else {
let version = &user_agent_lower[version_begin..];
if ver_greater_equal(version, &profile.version_target) {
*target = profile.target;
*clash_new_name = profile.clash_new_name;
*surge_ver = profile.surge_ver;
return;
}
}
}
} else {
*target = profile.target;
*clash_new_name = profile.clash_new_name;
*surge_ver = profile.surge_ver;
return;
}
}
}
}