Skip to content

Commit 6541e9a

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

1 file changed

Lines changed: 92 additions & 17 deletions

File tree

汤盛碗的clash一键配置生成器.html

Lines changed: 92 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
<!DOCTYPE html>
1+
<!DOCTYPE html>
22
<html lang="zh-CN">
33
<head>
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6-
<title>Clash 配置生成器 (全协议修复版)</title>
6+
<title>Clash 配置生成器 (最终完美版)</title>
77
<style>
88
/* --- 极简设计风 --- */
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>汤盛碗的Clash 配置生成器</h1>
138138
if (!input) { alert("⚠️ 请粘贴内容!"); return; }
139139

140140
// 1. 尝试作为链接下载
141-
if (input.startsWith('http')) {
141+
// 排除掉明确是单行节点链接的协议,避免误入下载逻辑
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 = "⏳ 解析中...";
@@ -173,10 +174,14 @@ <h1>汤盛碗的Clash 配置生成器</h1>
173174
proxies = yamlProxies;
174175
} else {
175176
// 策略 B: 如果不是 YAML,尝试解析 Base64 或 vless:// 链接
176-
if (!content.includes('proxies:') && !content.includes('- {')) {
177+
// 【重要修复】增加判断,如果是单行协议链接,绝对不要尝试 Base64 解码,否则会报错导致脚本中断
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>汤盛碗的Clash 配置生成器</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); // 新增 ss 支持 (虽然简单正则)
193+
else if (line.startsWith('ss://')) result = parseSS(line);
189194

190195
if (result) {
191196
let finalName = result.name;
@@ -206,7 +211,7 @@ <h1>汤盛碗的Clash 配置生成器</h1>
206211
const configStr = p.config.toLowerCase();
207212
const n = p.name.toLowerCase();
208213

209-
// 1. [关键] 剔除策略组类型 (这是导致 unsupported proxy type 的元凶)
214+
// 1. [关键] 剔除策略组类型
210215
if (configStr.includes('type: select') ||
211216
configStr.includes('type: url-test') ||
212217
configStr.includes('type: fallback') ||
@@ -242,9 +247,7 @@ <h1>汤盛碗的Clash 配置生成器</h1>
242247

243248
lines.forEach(line => {
244249
line = line.trim();
245-
// 核心特征:以 "- {" 开头,且包含 "name:"
246250
if (line.startsWith('- {') && line.includes('name:')) {
247-
248251
let name = "";
249252
const quoteMatch = line.match(/name:\s*['"](.*?)['"]/);
250253
if (quoteMatch) {
@@ -272,16 +275,89 @@ <h1>汤盛碗的Clash 配置生成器</h1>
272275
} catch (e) { console.error(e); return []; }
273276
}
274277

275-
// --- 辅助工具 ---
278+
// --- [修复] 辅助工具:增加错误捕获,防止解码失败导致程序崩溃 ---
276279
function safeBase64Decode(str) {
277-
str = str.replace(/\s/g, '');
278-
return decodeURIComponent(escape(atob(str.replace(/-/g, '+').replace(/_/g, '/'))));
280+
try {
281+
str = str.replace(/\s/g, '');
282+
return decodeURIComponent(escape(atob(str.replace(/-/g, '+').replace(/_/g, '/'))));
283+
} catch (e) {
284+
// 如果解码失败,返回 null 或者原字符串,保证程序继续运行
285+
console.warn("Base64 Decode Failed, treating as raw text.");
286+
return null;
287+
}
279288
}
280289

281-
function parseVless(line) { /* 简化保留 */ return null; }
282-
function parseHysteria2(line) { return null; }
283-
function parseVmess(line) { return null; }
284-
function parseSS(line) { return null; } // 占位
290+
// --- 解析函数 ---
291+
function parseVless(line) {
292+
try {
293+
const u = new URL(line);
294+
const params = u.searchParams;
295+
const name = decodeURIComponent(u.hash.slice(1)) || u.hostname;
296+
const type = params.get('type') || 'tcp';
297+
let config = ` - name: "${name}"
298+
type: vless
299+
server: ${u.hostname}
300+
port: ${u.port}
301+
uuid: ${u.username}
302+
tls: true
303+
udp: true
304+
skip-cert-verify: true
305+
servername: ${params.get('sni') || u.hostname}
306+
network: ${type}`;
307+
if (type === 'ws') config += `\n ws-opts:\n path: "${params.get('path')||'/'}"\n headers:\n Host: ${params.get('sni')||u.hostname}`;
308+
if (params.get('flow')) config += `\n flow: ${params.get('flow')}`;
309+
return { name: name, config: config };
310+
} catch (e) { return null; }
311+
}
312+
313+
function parseHysteria2(line) {
314+
try {
315+
const u = new URL(line);
316+
const params = u.searchParams;
317+
const name = decodeURIComponent(u.hash.slice(1)) || u.hostname;
318+
let config = ` - name: "${name}"
319+
type: hysteria2
320+
server: ${u.hostname}
321+
port: ${u.port}
322+
password: ${u.username}
323+
sni: ${params.get('sni') || u.hostname}
324+
skip-cert-verify: true
325+
up: 100 Mbps
326+
down: 100 Mbps`;
327+
if (params.get('obfs') && params.get('obfs') !== 'none') {
328+
config += `\n obfs: ${params.get('obfs')}\n obfs-password: "${params.get('obfs-password')||''}"`;
329+
}
330+
return { name: name, config: config };
331+
} catch (e) { return null; }
332+
}
333+
334+
function parseVmess(line) {
335+
try {
336+
const b64 = line.replace('vmess://', '');
337+
const jsonStr = safeBase64Decode(b64);
338+
if (!jsonStr) return null;
339+
const c = JSON.parse(jsonStr);
340+
const name = c.ps || c.add;
341+
return {
342+
name: name,
343+
config: ` - name: "${name}"
344+
type: vmess
345+
server: ${c.add}
346+
port: ${c.port}
347+
uuid: ${c.id}
348+
alterId: ${c.aid || 0}
349+
cipher: ${c.scy || 'auto'}
350+
udp: true
351+
tls: ${c.tls === 'tls'}
352+
skip-cert-verify: true
353+
servername: ${c.host || ''}
354+
network: ${c.net || 'tcp'}
355+
ws-opts: { path: "${c.path || '/'}", headers: { Host: ${c.host || ''} } }`
356+
};
357+
} catch (e) { return null; }
358+
}
359+
360+
function parseSS(line) { return null; }
285361

286362
// 手动组装逻辑 (简化版,仅作展示)
287363
function addNode() {
@@ -352,5 +428,4 @@ <h1>汤盛碗的Clash 配置生成器</h1>
352428
}
353429
</script>
354430
</body>
355-
</html>
356-
431+
</html>

0 commit comments

Comments
 (0)