fix(local-music): 封面落盘 + URL 编码统一,修复持久化配额与编码边界

- 新增 src/shared/localUrl.ts 共用 local:// 编码:按路径段 encodeURIComponent,
  避免整体编码把 / 转成 %2F 引发 Chromium 解析边界差异,同时正确处理
  空格/中文/# 等特殊字符(封面落到含空格目录时 Image loader 会加载失败)
- 封面从内嵌 base64 Data URL 改为 userData/AudioCovers/<sha256>.<ext> 落盘,
  MAX_COVER_BYTES 1MB→8MB;老条目(无 coverPath 字段)扫描时一次性自愈
- playlist minify 剥离 base64 picUrl 并仅持久化 local:// 永不过期的 playMusicUrl,
  防止单张 base64 封面撑爆 localStorage 5MB 配额导致整个 playList 写入失败;
  localStorage 写入加 try/catch 兜底,避免配额超限时直接抛异常
This commit is contained in:
chengww
2026-05-17 21:36:49 +08:00
parent ee98eb0266
commit 15258f28fd
8 changed files with 129 additions and 40 deletions
+26
View File
@@ -0,0 +1,26 @@
// local:// 协议 URL 拼接工具
// 主进程与渲染进程共用,确保所有本地文件 URL 走同一套编码策略,
// 否则音频/封面/缓存/下载在 edge-case 上行为分裂。
/**
* 把绝对文件路径转成 local:// 协议 URL。
*
* 编码顺序:
* 1. \\ -> /Windows 路径规范化)
* 2. 按路径段 encodeURIComponent,再用 / 拼回去
*
* 不直接对整条路径 encodeURIComponent:它会把 / 编码成 %2F,注册为 standard 的
* local:// 协议在 Chromium 解析含 %2F 的 path 时存在边界差异。
* 按路径段编码可以保留目录分隔符,同时正确处理空格、中文、#、?、% 等特殊字符。
*
* 必须编码而不是裸拼:Image loader(含 crossOrigin='Anonymous' 时)对未编码空格
* 比 audio.src 严格——封面常落到 "Application Support" 这类含空格目录会加载失败。
*
* 主进程 fileManager 用 decodeURIComponent 还原;它是 encodeURIComponent 的逆,
* 能解码本函数产生的全部 %XX。
*/
export function filePathToLocalUrl(absPath: string): string {
const normalized = absPath.replace(/\\/g, '/');
const encoded = normalized.split('/').map(encodeURIComponent).join('/');
return `local:///${encoded}`;
}