Skip to content

Commit 06ecdf6

Browse files
committed
整理代码
1 parent bf0017c commit 06ecdf6

File tree

82 files changed

+1385
-582
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+1385
-582
lines changed

functions/modules/utils/node-cleaner.js

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,20 @@ export function fixNodeUrlEncoding(nodeUrl) {
2020
}
2121
};
2222

23+
const decodeRepeated = (value) => {
24+
let decoded = safeDecode(value);
25+
if (decoded.includes('%')) {
26+
const decodedTwice = safeDecode(decoded);
27+
if (decodedTwice !== decoded) {
28+
decoded = decodedTwice;
29+
}
30+
}
31+
return decoded;
32+
};
33+
2334
// 辅助函数:判断是否需要保持原样(即解码后出现乱码)
2435
const shouldKeepRaw = (decoded) => {
25-
return decoded.includes('');
36+
return decoded.includes('');
2637
};
2738

2839
let fixedUrl = nodeUrl;
@@ -42,7 +53,7 @@ export function fixNodeUrlEncoding(nodeUrl) {
4253
// 修复 hash (节点名称)
4354
if (urlObj.hash) {
4455
const rawHash = urlObj.hash.substring(1);
45-
const decodedHash = safeDecode(rawHash);
56+
const decodedHash = decodeRepeated(rawHash);
4657
if (!shouldKeepRaw(decodedHash)) {
4758
urlObj.hash = '#' + encodeURIComponent(decodedHash);
4859
}
@@ -68,13 +79,29 @@ export function fixSSEncoding(nodeUrl) {
6879
if (!nodeUrl.startsWith('ss://')) return nodeUrl;
6980

7081
try {
71-
const urlObj = new URL(nodeUrl);
72-
if (urlObj.hash) {
73-
try {
74-
urlObj.hash = '#' + encodeURIComponent(decodeURIComponent(urlObj.hash.substring(1)));
75-
} catch (e) { }
82+
const hashIndex = nodeUrl.indexOf('#');
83+
const baseUrl = hashIndex === -1 ? nodeUrl : nodeUrl.substring(0, hashIndex);
84+
const hashPart = hashIndex === -1 ? '' : nodeUrl.substring(hashIndex + 1);
85+
86+
let fixedBase = baseUrl;
87+
const prefix = 'ss://';
88+
if (baseUrl.startsWith(prefix)) {
89+
const afterScheme = baseUrl.substring(prefix.length);
90+
const atIndex = afterScheme.indexOf('@');
91+
if (atIndex !== -1) {
92+
const base64Part = afterScheme.substring(0, atIndex);
93+
const rest = afterScheme.substring(atIndex);
94+
const decodedBase64 = base64Part.includes('%') ? decodeURIComponent(base64Part) : base64Part;
95+
fixedBase = `${prefix}${decodedBase64}${rest}`;
96+
}
7697
}
77-
return urlObj.toString();
98+
99+
if (!hashPart) {
100+
return fixedBase;
101+
}
102+
103+
const decodedName = decodeURIComponent(hashPart);
104+
return `${fixedBase}#${encodeURIComponent(decodedName)}`;
78105
} catch (e) {
79106
const parts = nodeUrl.split('#');
80107
if (parts.length > 1) {

public/manifest.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
"name": "MiSub - 订阅转换器",
33
"short_name": "MiSub",
44
"description": "基于 Cloudflare 的订阅转换和管理工具",
5-
"start_url": "/",
5+
"start_url": "/?source=pwa",
66
"display": "standalone",
7+
"display_override": ["standalone", "minimal-ui", "browser"],
78
"background_color": "#0f172a",
89
"theme_color": "#4f46e5",
910
"orientation": "portrait-primary",
1011
"scope": "/",
12+
"id": "/?source=pwa",
1113
"lang": "zh-CN",
1214
"categories": ["productivity", "utilities"],
1315
"icons": [

public/offline.html

Lines changed: 126 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,127 +3,207 @@
33
<head>
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<meta name="theme-color" content="#0f172a" />
67
<title>MiSub - 离线模式</title>
78
<style>
9+
:root {
10+
color-scheme: light dark;
11+
--bg: #f8fafc;
12+
--card: rgba(255, 255, 255, 0.85);
13+
--text: #0f172a;
14+
--muted: #64748b;
15+
--primary: #4f46e5;
16+
--border: rgba(148, 163, 184, 0.2);
17+
}
18+
@media (prefers-color-scheme: dark) {
19+
:root {
20+
--bg: #0b1120;
21+
--card: rgba(15, 23, 42, 0.75);
22+
--text: #f8fafc;
23+
--muted: #94a3b8;
24+
--primary: #818cf8;
25+
--border: rgba(148, 163, 184, 0.2);
26+
}
27+
}
828
body {
9-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
29+
font-family: 'Plus Jakarta Sans', 'Outfit', 'Segoe UI', sans-serif;
1030
margin: 0;
1131
padding: 0;
12-
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
1332
min-height: 100vh;
1433
display: flex;
1534
align-items: center;
1635
justify-content: center;
17-
color: white;
36+
background:
37+
radial-gradient(circle at 0% 0%, rgba(99, 102, 241, 0.12), transparent 55%),
38+
radial-gradient(circle at 100% 100%, rgba(14, 165, 233, 0.12), transparent 55%),
39+
var(--bg);
40+
color: var(--text);
1841
}
1942
.container {
2043
text-align: center;
21-
padding: 2rem;
22-
max-width: 400px;
44+
padding: 2.5rem 2.25rem;
45+
max-width: 440px;
46+
border-radius: 28px;
47+
background: var(--card);
48+
border: 1px solid var(--border);
49+
box-shadow: 0 30px 60px -40px rgba(15, 23, 42, 0.6);
50+
backdrop-filter: blur(12px);
2351
}
2452
.icon {
25-
width: 80px;
26-
height: 80px;
27-
margin: 0 auto 2rem;
28-
background: rgba(255, 255, 255, 0.2);
29-
border-radius: 50%;
53+
width: 88px;
54+
height: 88px;
55+
margin: 0 auto 1.5rem;
56+
border-radius: 24px;
3057
display: flex;
3158
align-items: center;
3259
justify-content: center;
60+
background: rgba(99, 102, 241, 0.12);
61+
color: var(--primary);
3362
}
3463
h1 {
3564
font-size: 1.5rem;
36-
margin-bottom: 1rem;
37-
font-weight: 600;
65+
margin-bottom: 0.75rem;
66+
font-weight: 700;
3867
}
3968
p {
4069
font-size: 1rem;
41-
opacity: 0.9;
70+
color: var(--muted);
4271
line-height: 1.6;
43-
margin-bottom: 2rem;
72+
margin-bottom: 1.5rem;
73+
}
74+
.actions {
75+
display: flex;
76+
gap: 0.75rem;
77+
justify-content: center;
78+
flex-wrap: wrap;
79+
margin-bottom: 1.5rem;
4480
}
4581
.btn {
46-
background: rgba(255, 255, 255, 0.2);
47-
border: 2px solid rgba(255, 255, 255, 0.3);
82+
background: var(--primary);
83+
border: none;
4884
color: white;
49-
padding: 0.75rem 1.5rem;
50-
border-radius: 0.5rem;
51-
font-size: 1rem;
85+
padding: 0.7rem 1.4rem;
86+
border-radius: 12px;
87+
font-size: 0.95rem;
5288
cursor: pointer;
53-
transition: all 0.3s ease;
89+
transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease;
5490
text-decoration: none;
55-
display: inline-block;
91+
display: inline-flex;
92+
align-items: center;
93+
justify-content: center;
94+
box-shadow: 0 12px 30px -16px rgba(79, 70, 229, 0.7);
95+
}
96+
.btn.secondary {
97+
background: transparent;
98+
border: 1px solid var(--border);
99+
color: var(--text);
100+
box-shadow: none;
56101
}
57102
.btn:hover {
58-
background: rgba(255, 255, 255, 0.3);
59103
transform: translateY(-1px);
104+
opacity: 0.95;
60105
}
61106
.features {
62-
margin-top: 2rem;
63107
text-align: left;
108+
border-top: 1px solid var(--border);
109+
padding-top: 1.25rem;
110+
margin-top: 1.25rem;
64111
}
65112
.feature {
66113
display: flex;
67114
align-items: center;
68115
margin-bottom: 0.75rem;
69116
font-size: 0.9rem;
117+
color: var(--muted);
118+
}
119+
.feature:last-child {
120+
margin-bottom: 0;
70121
}
71122
.feature-icon {
72123
width: 16px;
73124
height: 16px;
74125
margin-right: 0.5rem;
75-
opacity: 0.8;
126+
color: var(--primary);
127+
}
128+
.status {
129+
display: inline-flex;
130+
align-items: center;
131+
gap: 0.5rem;
132+
font-size: 0.85rem;
133+
color: var(--muted);
134+
}
135+
.dot {
136+
width: 8px;
137+
height: 8px;
138+
border-radius: 999px;
139+
background: #f97316;
140+
}
141+
.dot.online {
142+
background: #22c55e;
76143
}
77144
</style>
78145
</head>
79146
<body>
80147
<div class="container">
81148
<div class="icon">
82-
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
83-
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
149+
<svg width="42" height="42" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
150+
<path d="M2 12s3.5-6.5 10-6.5 10 6.5 10 6.5-3.5 6.5-10 6.5-10-6.5-10-6.5z"></path>
84151
<circle cx="12" cy="12" r="3"></circle>
85152
</svg>
86153
</div>
87-
88-
<h1>您当前处于离线状态</h1>
89-
<p>网络连接似乎出现了问题,但您仍然可以查看已缓存的内容。</p>
90-
91-
<button class="btn" onclick="window.location.reload()">重新连接</button>
92-
154+
155+
<h1>当前离线</h1>
156+
<p>网络暂不可用,但已缓存的页面仍可浏览。恢复连接后将自动同步最新数据。</p>
157+
158+
<div class="actions">
159+
<button class="btn" onclick="window.location.reload()">重新连接</button>
160+
<a class="btn secondary" href="/">返回主页</a>
161+
</div>
162+
163+
<div class="status">
164+
<span class="dot" id="statusDot"></span>
165+
<span id="statusText">离线状态</span>
166+
</div>
167+
93168
<div class="features">
94169
<div class="feature">
95170
<svg class="feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
96171
<polyline points="20,6 9,17 4,12"></polyline>
97172
</svg>
98-
离线时可查看已缓存的订阅
173+
已缓存的订阅和配置可继续查看
99174
</div>
100175
<div class="feature">
101176
<svg class="feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
102177
<polyline points="20,6 9,17 4,12"></polyline>
103178
</svg>
104-
数据会在连接恢复后同步
179+
恢复网络后自动尝试同步
105180
</div>
106181
<div class="feature">
107182
<svg class="feature-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
108183
<polyline points="20,6 9,17 4,12"></polyline>
109184
</svg>
110-
PWA应用离线体验优化
185+
建议保持应用常驻以加速更新
111186
</div>
112187
</div>
113188
</div>
114189

115190
<script>
116-
// 定期检查网络连接
117-
setInterval(() => {
118-
if (navigator.onLine) {
119-
window.location.reload();
191+
const statusDot = document.getElementById('statusDot');
192+
const statusText = document.getElementById('statusText');
193+
194+
const updateStatus = () => {
195+
const online = navigator.onLine;
196+
statusDot.classList.toggle('online', online);
197+
statusText.textContent = online ? '已恢复连接' : '离线状态';
198+
if (online) {
199+
setTimeout(() => window.location.reload(), 600);
120200
}
121-
}, 5000);
122-
123-
// 监听网络状态变化
124-
window.addEventListener('online', () => {
125-
window.location.reload();
126-
});
201+
};
202+
203+
updateStatus();
204+
window.addEventListener('online', updateStatus);
205+
window.addEventListener('offline', updateStatus);
206+
setInterval(updateStatus, 5000);
127207
</script>
128208
</body>
129-
</html>
209+
</html>

0 commit comments

Comments
 (0)