From 706b32e1f2bcf5b71bf0b00122e083e02d853fcb Mon Sep 17 00:00:00 2001 From: LFeng Date: Sat, 12 Sep 2026 15:59:28 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E9=99=A4=20MUSIC=5FMODULE=5FREVIEW.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MUSIC_MODULE_REVIEW.md | 465 ----------------------------------------- 1 file changed, 465 deletions(-) delete mode 100644 MUSIC_MODULE_REVIEW.md diff --git a/MUSIC_MODULE_REVIEW.md b/MUSIC_MODULE_REVIEW.md deleted file mode 100644 index 2ed3cf3..0000000 --- a/MUSIC_MODULE_REVIEW.md +++ /dev/null @@ -1,465 +0,0 @@ -# 音乐模块全链路审查报告 - -> 审查范围:数据请求(搜索/歌单解析/下载/解析真实链接)、播放控制(试听、播放器内核、队列、歌词、缓存)、状态管理(musicStore / feiniuStore)、UI 交互与视觉。 -> 覆盖文件(前端 11 个 + Rust 4 个): -> `src/stores/musicStore.ts`、`src/stores/feiniuStore.ts`、`src/modules/music/MusicModule.vue`、`components/PlayerBar.vue`、`components/PlayerFull.vue`、`components/MyMusicLibrary.vue`、`components/TrackItem.vue`、`components/settings/ConnectionsSettings.vue`、`components/settings/CacheSettings.vue`、`SourcePicker.vue`、`sources.ts`、`index.ts`、`src/App.vue`、`src/components/layout/ModuleContainer.vue`、`src-tauri/src/music/{mod,commands}.rs`、`src-tauri/src/music/feiniu/{mod,proxy}.rs` - ---- - -## 0. 结论摘要 - -整体架构是清晰的:**搜索/下载走 Python 桥接(musicdl)**,**播放走飞牛 NAS 本地流代理(Rust axum,支持 Range 透传)**,两个 store 职责分离,流代理与缓存设计是对的。问题集中在三类: - -| 类别 | 数量 | 代表问题 | -|---|---|---| -| P0 功能性失效 | 3 | 飞牛曲库搜索框完全无效;重启后播放键无响应;两个音频引擎可同时发声 | -| P1 逻辑/状态缺陷 | 12 | shuffle 自动切歌不随机;缓存开关状态不同步;队列被单曲播放重置;任务持久化写入 `rawSearch` 撑爆 localStorage | -| P2 性能瓶颈 | 9 | 拖动进度条即发 Range 请求;歌词/队列无虚拟滚动;全屏模糊背景;每行 2 个 Tooltip | -| P3 界面与交互缺陷 | 25 | 播放条未贴底且离开模块即消失;左右内边距不对称;三套切换控件;徽标 5 色抢戏;列表变卡片堆 | - -**最需要优先决策的一件事**:把 `PlayerBar` / `PlayerFull` 从 `MusicModule.vue` 提升到 `App.vue` 全局层。当前它们挂载在音乐模块内部,而模块容器是 `:key="activeModule"` 重挂载(`App.vue:36-41`)——**切到任何其他模块,播放条和"正在播放"大屏整体卸载,但音频仍在后台播放,用户完全失去控制入口**。这是当前体验上最严重的问题。 - ---- - -## 1. P0 功能性失效(必须修) - -### 1.1 飞牛曲库搜索框完全无效 -**现象**:输入关键词、回车,曲库列表纹丝不动。 - -**根因**:`MyMusicLibrary.vue:21` 定义了本地 `keywordInput`,`onSearchInput`(:24-29)只做了防抖后调用 `store.loadTracks(1)`,而 `loadTracks` 读的是 **store 里的 `keyword`**(`feiniuStore.ts:381`)。检查全仓:`store.keyword` **从未被任何 UI 赋值**。 - -```ts -// feiniuStore.ts:375-382 -const data = await invoke('feiniu_list_tracks', { - page: p, size: 50, - keyword: keyword.value.trim() || null // ← keyword 永远是 '' -}) -``` - -**修复**:把输入直接接到 store 字段,去掉中间层。 - -```vue - - -``` -```ts -// onSearchInput 里补一句:清空关键词时立即回全量 -function onSearchInput() { - clearTimeout(searchTimer) - searchTimer = setTimeout(() => store.loadTracks(1).catch(e => toast.error(String(e))), 400) -} -``` - ---- - -### 1.2 应用重启后,播放键点了没反应 -**现象**:重启应用,底部播放条显示着上次的歌,点播放键没任何反应,也没有提示。 - -**根因**:`restoreQueue()`(`feiniuStore.ts:644-655`)只恢复了 `queue` / `queueIndex`,**没有给 audio 设置 `src`**。此时点击播放走 `toggle()`(:564-568): - -```ts -function toggle() { - const a = ensureAudio() - if (a.paused) a.play().catch(() => {}) // ← 无 src,play() 直接 reject,被静默吞掉 - else a.pause() -} -``` - -`ensureAudio()` 新建的 `Audio()` 没有 `src`,`play()` 抛 `NotSupportedError`,被空 catch 吞掉。点「上一首/下一首」反而能用(走 `playCurrent()` 会设 src),所以表现为"只有播放键坏了"。 - -**修复**:`toggle()` 检测无 src 时先走一次 `playCurrent()`;同时给失败加可见提示。 - -```ts -function toggle() { - const a = ensureAudio() - if (!a.src) { // 恢复队列后首次播放 - if (current.value) playCurrent() - return - } - if (a.paused) a.play().catch(err => { playing.value = false; logger.error(`播放失败: ${err}`) }) - else a.pause() -} -``` -另外建议 `startPlayback` 的 catch 里落一条 `toast.error('播放失败:' + err.message)`,当前 `:558-561` 是先 catch 再静默,用户拿不到任何信息。 - ---- - -### 1.3 两个独立音频引擎,可同时发声 -**现象**:在「发现音乐」点某首歌试听,再回到播放器播另一首 → 两首歌同时响;或者试听中点播放器播放,两路声音叠加。 - -**根因**:存在两个互不知晓的 `