1use base64::{engine::general_purpose::URL_SAFE, Engine as _};
2use regex::Regex;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Serialize, Deserialize)]
8pub struct VLess {
9 pub host: String,
11 pub port: u32,
13 pub id: String,
15 #[serde(flatten)]
17 pub parameters: Option<HashMap<String, String>>,
18}
19
20impl VLess {
21 pub fn to_url(&self) -> String {
37 let url_encoded_parameters = serde_urlencoded::to_string(&self.parameters).unwrap();
38 format!(
39 "vless://{}@{}:{}?{}",
40 self.id, self.host, self.port, url_encoded_parameters
41 )
42 }
43
44 pub fn scrape(source: &str) -> Vec<Self> {
54 let source = crate::utils::seperate_links(source);
55 let mut proxy_list: Vec<VLess> = Vec::new();
56 let regex = Regex::new(r#"vless://([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})@((.+):(\d+))\?(.+)#"#).unwrap();
57
58 for captures in regex.captures_iter(&source) {
59 let uuid = captures.get(1).map(|id| id.as_str()).unwrap_or("");
60 let host = captures.get(3).map(|host| host.as_str()).unwrap_or("");
61 let port = captures.get(4).map(|port| port.as_str()).unwrap_or("");
62 let url_parameters = captures.get(5).map(|params| params.as_str()).unwrap_or("");
63
64 if uuid.is_empty() || host.is_empty() || port.is_empty() || url_parameters.is_empty() {
65 continue;
66 }
67
68 let parameters: HashMap<String, String> =
69 serde_urlencoded::from_str(&url_parameters).unwrap();
70
71 let vless_proxy = VLess {
72 host: host.to_string(),
73 port: port.parse::<u32>().unwrap_or(0),
74 id: uuid.to_string(),
75 parameters: Some(parameters),
76 };
77
78 proxy_list.push(vless_proxy);
79 }
80
81 proxy_list
82 }
83}