diff --git a/functions/modules/utils/node-cleaner.js b/functions/modules/utils/node-cleaner.js index 2b4aff08..47bbb409 100644 --- a/functions/modules/utils/node-cleaner.js +++ b/functions/modules/utils/node-cleaner.js @@ -20,9 +20,20 @@ export function fixNodeUrlEncoding(nodeUrl) { } }; + const decodeRepeated = (value) => { + let decoded = safeDecode(value); + if (decoded.includes('%')) { + const decodedTwice = safeDecode(decoded); + if (decodedTwice !== decoded) { + decoded = decodedTwice; + } + } + return decoded; + }; + // 辅助函数:判断是否需要保持原样(即解码后出现乱码) const shouldKeepRaw = (decoded) => { - return decoded.includes(''); + return decoded.includes('�'); }; let fixedUrl = nodeUrl; @@ -42,7 +53,7 @@ export function fixNodeUrlEncoding(nodeUrl) { // 修复 hash (节点名称) if (urlObj.hash) { const rawHash = urlObj.hash.substring(1); - const decodedHash = safeDecode(rawHash); + const decodedHash = decodeRepeated(rawHash); if (!shouldKeepRaw(decodedHash)) { urlObj.hash = '#' + encodeURIComponent(decodedHash); } @@ -68,13 +79,29 @@ export function fixSSEncoding(nodeUrl) { if (!nodeUrl.startsWith('ss://')) return nodeUrl; try { - const urlObj = new URL(nodeUrl); - if (urlObj.hash) { - try { - urlObj.hash = '#' + encodeURIComponent(decodeURIComponent(urlObj.hash.substring(1))); - } catch (e) { } + const hashIndex = nodeUrl.indexOf('#'); + const baseUrl = hashIndex === -1 ? nodeUrl : nodeUrl.substring(0, hashIndex); + const hashPart = hashIndex === -1 ? '' : nodeUrl.substring(hashIndex + 1); + + let fixedBase = baseUrl; + const prefix = 'ss://'; + if (baseUrl.startsWith(prefix)) { + const afterScheme = baseUrl.substring(prefix.length); + const atIndex = afterScheme.indexOf('@'); + if (atIndex !== -1) { + const base64Part = afterScheme.substring(0, atIndex); + const rest = afterScheme.substring(atIndex); + const decodedBase64 = base64Part.includes('%') ? decodeURIComponent(base64Part) : base64Part; + fixedBase = `${prefix}${decodedBase64}${rest}`; + } } - return urlObj.toString(); + + if (!hashPart) { + return fixedBase; + } + + const decodedName = decodeURIComponent(hashPart); + return `${fixedBase}#${encodeURIComponent(decodedName)}`; } catch (e) { const parts = nodeUrl.split('#'); if (parts.length > 1) { diff --git a/public/manifest.json b/public/manifest.json index 24705373..0381e26d 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -2,12 +2,14 @@ "name": "MiSub - 订阅转换器", "short_name": "MiSub", "description": "基于 Cloudflare 的订阅转换和管理工具", - "start_url": "/", + "start_url": "/?source=pwa", "display": "standalone", + "display_override": ["standalone", "minimal-ui", "browser"], "background_color": "#0f172a", "theme_color": "#4f46e5", "orientation": "portrait-primary", "scope": "/", + "id": "/?source=pwa", "lang": "zh-CN", "categories": ["productivity", "utilities"], "icons": [ diff --git a/public/offline.html b/public/offline.html index 1db570df..b75229cb 100644 --- a/public/offline.html +++ b/public/offline.html @@ -3,127 +3,207 @@
+网络连接似乎出现了问题,但您仍然可以查看已缓存的内容。
- - - + +网络暂不可用,但已缓存的页面仍可浏览。恢复连接后将自动同步最新数据。
+ +