MCPcopy Index your code
hub / github.com/TeleBoxOrg/TeleBox_Plugins / getNodeInfo

Function getNodeInfo

subinfo/subinfo.ts:139–210  ·  view source on GitHub ↗
(url: string)

Source from the content-addressed store, hash-verified

137
138// 尝试解析节点信息 (节点数, 类型, 地区分布)
139async function getNodeInfo(url: string): Promise<{ node_count: number | string, type_count: Record<string, number>, regions: Record<string, number> } | null> {
140 try {
141 const res = await axios.get(url, { timeout: 10000, responseType: 'text' });
142
143 // 1. 尝试解析 YAML (Clash/Surge)
144 try {
145 const config = yaml.load(res.data);
146 if (config && (config as any).proxies) {
147 const proxies = (config as any).proxies;
148 const typeCount: Record<string, number> = {};
149 const regions: Record<string, number> = {};
150 let totalNodes = proxies.length;
151 let identified = 0;
152 for (const proxy of proxies) {
153 const type = proxy.type?.toLowerCase();
154 typeCount[type] = (typeCount[type] || 0) + 1;
155 const nameLow = proxy.name?.toLowerCase() || '';
156 for (const [region, keys] of REGION_RULES) {
157 if (keys.some(k => nameLow.includes(k.toLowerCase()))) {
158 regions[region] = (regions[region] || 0) + 1;
159 identified++;
160 break;
161 }
162 }
163 }
164 if (totalNodes - identified > 0) regions['其他'] = totalNodes - identified;
165 return {
166 node_count: totalNodes,
167 type_count: Object.fromEntries(Object.entries(typeCount).filter(([, v]) => v > 0)),
168 regions: Object.fromEntries(Object.entries(regions).filter(([, v]) => v > 0))
169 };
170 }
171 } catch { /* 忽略 YAML 解析错误 */ }
172
173 // 2. 尝试解析 Base64 (V2Ray/Shadowsocks 原始链接)
174 try {
175 const decoded = Buffer.from(res.data, 'base64').toString();
176 const typeCount: Record<string, number> = {};
177 const regions: Record<string, number> = {};
178 let nodeCount = 0;
179 let identified = 0;
180 const protocols = ['vmess://', 'trojan://', 'ss://', 'ssr://', 'vless://', 'hy2://', 'hysteria://', 'hy://', 'tuic://', 'wireguard://', 'socks5://', 'http://', 'https://', 'shadowtls://', 'naive://'];
181
182 decoded.split('\n').forEach((line: string) => {
183 if (!line.trim()) return;
184 for (const pattern of protocols) {
185 if (line.startsWith(pattern)) {
186 let t = pattern.replace('://', '');
187 typeCount[t] = (typeCount[t] || 0) + 1;
188 nodeCount++;
189 let lLow = line.toLowerCase();
190 for (const [region, keys] of REGION_RULES) {
191 if (keys.some(k => lLow.includes(k.toLowerCase()))) {
192 regions[region] = (regions[region] || 0) + 1;
193 identified++;
194 break;
195 }
196 }

Callers 1

processSubscriptionMethod · 0.85

Calls 2

loadMethod · 0.80
getMethod · 0.45

Tested by

no test coverage detected