Skip to content

Commit 9c74d90

Browse files
authored
修复链接导入失败
1 parent 6541e9a commit 9c74d90

1 file changed

Lines changed: 90 additions & 14 deletions

File tree

汤盛碗clash generator.html

Lines changed: 90 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<head>
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6-
<title>Clash Config Generator (Full Protocol Fix)</title>
6+
<title>Clash Config Generator (Final Perfect Version)</title>
77
<style>
88
/* --- Minimalist Design --- */
99
body { font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", Arial, sans-serif; background-color: #f5f5f7; color: #1d1d1f; display: flex; justify-content: center; padding-top: 40px; min-height: 100vh; margin: 0; }
@@ -138,7 +138,8 @@ <h1>TangShengWan's Clash Config Generator</h1>
138138
if (!input) { alert("⚠️ Please paste content!"); return; }
139139

140140
// 1. Try as a link download
141-
if (input.startsWith('http')) {
141+
// [Safety Check] Skip download logic for protocol links to prevent crash
142+
if (input.startsWith('http') && !input.startsWith('hysteria2://') && !input.startsWith('vless://') && !input.startsWith('vmess://') && !input.startsWith('ss://')) {
142143
const btn = document.querySelector('#mode-batch .btn');
143144
const originalText = btn.innerText;
144145
btn.innerText = "⏳ Parsing...";
@@ -173,10 +174,14 @@ <h1>TangShengWan's Clash Config Generator</h1>
173174
proxies = yamlProxies;
174175
} else {
175176
// Strategy B: If not YAML, try parsing Base64 or vless:// links
176-
if (!content.includes('proxies:') && !content.includes('- {')) {
177+
// [Critical Fix] Do NOT try Base64 decode if it looks like a protocol link
178+
const isProtocolLink = content.startsWith('vless://') || content.startsWith('hysteria2://') || content.startsWith('vmess://') || content.startsWith('ss://');
179+
180+
if (!content.includes('proxies:') && !content.includes('- {') && !isProtocolLink) {
177181
const decoded = safeBase64Decode(content);
178182
if (decoded) content = decoded;
179183
}
184+
180185
const lines = content.split(/[\r\n]+/);
181186
let nameCount = {};
182187
lines.forEach(line => {
@@ -185,7 +190,7 @@ <h1>TangShengWan's Clash Config Generator</h1>
185190
if (line.startsWith('vless://')) result = parseVless(line);
186191
else if (line.startsWith('hysteria2://')) result = parseHysteria2(line);
187192
else if (line.startsWith('vmess://')) result = parseVmess(line);
188-
else if (line.startsWith('ss://')) result = parseSS(line); // Added ss support
193+
else if (line.startsWith('ss://')) result = parseSS(line);
189194

190195
if (result) {
191196
let finalName = result.name;
@@ -206,16 +211,15 @@ <h1>TangShengWan's Clash Config Generator</h1>
206211
const configStr = p.config.toLowerCase();
207212
const n = p.name.toLowerCase();
208213

209-
// 1. [Critical] Remove Proxy Group Types (Cause of "unsupported proxy type" error)
214+
// 1. [Critical] Remove Proxy Group Types
210215
if (configStr.includes('type: select') ||
211216
configStr.includes('type: url-test') ||
212217
configStr.includes('type: fallback') ||
213218
configStr.includes('type: load-balance')) {
214219
return false;
215220
}
216221

217-
// 2. Remove Ads/Invalid Nodes
218-
// (Keeping Chinese keywords as they filter common ad nodes from providers)
222+
// 2. Remove Ads/Invalid Nodes (Keeping Chinese keywords as most providers are CN based)
219223
if (n.includes('剩余') || n.includes('流量') || n.includes('到期') ||
220224
n.includes('官网') || n.includes('expire') || n.includes('reset') ||
221225
n.includes('🪧') || n.includes('不可用')) {
@@ -273,16 +277,88 @@ <h1>TangShengWan's Clash Config Generator</h1>
273277
} catch (e) { console.error(e); return []; }
274278
}
275279

276-
// --- Helper Tools ---
280+
// --- [Fixed] Safe Base64 Decode with try-catch ---
277281
function safeBase64Decode(str) {
278-
str = str.replace(/\s/g, '');
279-
return decodeURIComponent(escape(atob(str.replace(/-/g, '+').replace(/_/g, '/'))));
282+
try {
283+
str = str.replace(/\s/g, '');
284+
return decodeURIComponent(escape(atob(str.replace(/-/g, '+').replace(/_/g, '/'))));
285+
} catch (e) {
286+
console.warn("Base64 Decode Failed, treating as raw text.");
287+
return null;
288+
}
289+
}
290+
291+
// --- Parsers (Full Logic) ---
292+
function parseVless(line) {
293+
try {
294+
const u = new URL(line);
295+
const params = u.searchParams;
296+
const name = decodeURIComponent(u.hash.slice(1)) || u.hostname;
297+
const type = params.get('type') || 'tcp';
298+
let config = ` - name: "${name}"
299+
type: vless
300+
server: ${u.hostname}
301+
port: ${u.port}
302+
uuid: ${u.username}
303+
tls: true
304+
udp: true
305+
skip-cert-verify: true
306+
servername: ${params.get('sni') || u.hostname}
307+
network: ${type}`;
308+
if (type === 'ws') config += `\n ws-opts:\n path: "${params.get('path')||'/'}"\n headers:\n Host: ${params.get('sni')||u.hostname}`;
309+
if (params.get('flow')) config += `\n flow: ${params.get('flow')}`;
310+
return { name: name, config: config };
311+
} catch (e) { return null; }
312+
}
313+
314+
function parseHysteria2(line) {
315+
try {
316+
const u = new URL(line);
317+
const params = u.searchParams;
318+
const name = decodeURIComponent(u.hash.slice(1)) || u.hostname;
319+
let config = ` - name: "${name}"
320+
type: hysteria2
321+
server: ${u.hostname}
322+
port: ${u.port}
323+
password: ${u.username}
324+
sni: ${params.get('sni') || u.hostname}
325+
skip-cert-verify: true
326+
up: 100 Mbps
327+
down: 100 Mbps`;
328+
if (params.get('obfs') && params.get('obfs') !== 'none') {
329+
config += `\n obfs: ${params.get('obfs')}\n obfs-password: "${params.get('obfs-password')||''}"`;
330+
}
331+
return { name: name, config: config };
332+
} catch (e) { return null; }
333+
}
334+
335+
function parseVmess(line) {
336+
try {
337+
const b64 = line.replace('vmess://', '');
338+
const jsonStr = safeBase64Decode(b64);
339+
if (!jsonStr) return null;
340+
const c = JSON.parse(jsonStr);
341+
const name = c.ps || c.add;
342+
return {
343+
name: name,
344+
config: ` - name: "${name}"
345+
type: vmess
346+
server: ${c.add}
347+
port: ${c.port}
348+
uuid: ${c.id}
349+
alterId: ${c.aid || 0}
350+
cipher: ${c.scy || 'auto'}
351+
udp: true
352+
tls: ${c.tls === 'tls'}
353+
skip-cert-verify: true
354+
servername: ${c.host || ''}
355+
network: ${c.net || 'tcp'}
356+
ws-opts: { path: "${c.path || '/'}", headers: { Host: ${c.host || ''} } }`
357+
};
358+
} catch (e) { return null; }
280359
}
281360

282-
function parseVless(line) { /* Simplified placeholder */ return null; }
283-
function parseHysteria2(line) { return null; }
284-
function parseVmess(line) { return null; }
285-
function parseSS(line) { return null; } // Placeholder
361+
function parseSS(line) { return null; }
286362

287363
// Manual Assembly Logic (Simplified for Demo)
288364
function addNode() {

0 commit comments

Comments
 (0)