Initial commit

This commit is contained in:
theshy
2025-08-14 23:00:16 +08:00
commit 088c3d2044
11 changed files with 1253 additions and 0 deletions

150
public/index.html Normal file
View File

@ -0,0 +1,150 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>订阅格式转换 · Xray → Clash Mihomo</title>
<style>
:root {
color-scheme: light dark;
}
html,
body {
height: 100%;
margin: 0;
font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto,
Helvetica, Arial;
}
.container {
max-width: 880px;
margin: 40px auto;
padding: 0 16px;
}
h1 {
font-size: 20px;
margin: 0 0 16px;
}
textarea {
width: 100%;
min-height: 160px;
padding: 12px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 13px;
border-radius: 8px;
border: 1px solid #8883;
background: transparent;
}
.row {
display: flex;
gap: 8px;
margin: 12px 0;
}
.row > * {
flex: 1;
}
button {
padding: 10px 14px;
border-radius: 8px;
border: 1px solid #8883;
background: #09f;
color: #fff;
cursor: pointer;
}
button.secondary {
background: transparent;
color: inherit;
}
.out {
white-space: pre;
padding: 12px;
border: 1px solid #8883;
border-radius: 8px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 13px;
min-height: 120px;
}
.hint {
color: #888;
font-size: 12px;
}
.grid {
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
gap: 8px;
}
.right {
text-align: right;
}
a {
color: inherit;
}
</style>
</head>
<body>
<div class="container">
<h1>订阅格式转换Xray 链接/订阅 → Clash Mihomo</h1>
<p class="hint">
支持 vless/vmess/trojan 链接,或整段订阅文本/订阅地址(自动识别
base64
</p>
<textarea
id="input"
placeholder="在此粘贴 vless://、vmess:// 或 trojan:// 链接,或订阅文本"
></textarea>
<div class="grid">
<div class="hint">
输出为 YAML 的 proxies 段,可作 provider 或粘贴入主配置。
</div>
<div class="right">
<button id="btnConvert">转换为 Clash (YAML)</button>
<button id="btnDownload" class="secondary">下载 proxies.yaml</button>
</div>
</div>
<div id="out" class="out"></div>
</div>
<script>
const $ = (s) => document.querySelector(s);
const inputEl = $("#input");
const outEl = $("#out");
const btnConvert = $("#btnConvert");
const btnDownload = $("#btnDownload");
async function convert() {
const val = inputEl.value.trim();
if (!val) {
outEl.textContent = "请输入内容";
return;
}
try {
const resp = await fetch("/convert/clash", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ input: val }),
});
const text = await resp.text();
if (!resp.ok) throw new Error(text);
outEl.textContent = text;
return text;
} catch (e) {
outEl.textContent =
"错误: " + (e && e.message ? e.message : String(e));
}
}
btnConvert.addEventListener("click", convert);
btnDownload.addEventListener("click", async () => {
const text = outEl.textContent || (await convert());
if (!text) return;
const blob = new Blob([text], {
type: "application/yaml;charset=utf-8",
});
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = "proxies.yaml";
a.click();
setTimeout(() => URL.revokeObjectURL(a.href), 2000);
});
</script>
</body>
</html>