Skip to content

添加本地歌曲扫描 - #1

Merged
imsyy merged 14 commits into
mainfrom
feat/scan-test
Apr 2, 2026
Merged

imsyy merged 14 commits into
mainfrom
feat/scan-test

Conversation

@imsyy

@imsyy imsyy commented Apr 2, 2026

Copy link
Copy Markdown
Member

No description provided.

imsyy and others added 8 commits April 1, 2026 01:51
播放控制优化:
- 播放位置从墙钟时间改为采样计数,与实际音频输出精确同步
- 主进程轮询(33ms setInterval)改为 Rust 事件驱动(ThreadsafeFunction)
- 状态变化/播放结束由 Rust 主动推送,位置更新 200ms 一次
- 前端 rAF 插值在两次同步之间保持 60fps 流畅进度条
- fade 渐变从阻塞式改为非阻塞异步线程,Mutex 持有时间从 200ms 降到微秒级
- position/status 事件分离,避免竞态覆盖播放状态

扫描优化:
- 新增 lofty 依赖,扫描时用纯 tag 解析替代 FFmpeg probe
- 扫描速度从 ~2s/文件 降到 ~20ms/文件

工程规范:
- Cargo workspace 统一 [profile.release] 和 [lints.clippy],消除构建警告
- 全 workspace cargo clippy pedantic 零警告
- 数据库文件移至 userData/Database/ 子目录

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Copilot AI review requested due to automatic review settings April 2, 2026 07:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

该 PR 主要为应用新增“本地音乐库”能力:支持配置扫描目录、后台扫描提取元数据并落库、在前端展示/搜索/右键菜单播放;同时补充“音量均衡(响度归一化)”配置,并对部分 UI 组件进行能力增强以支撑新页面交互。

Changes:

  • 新增本地音乐库:扫描目录管理、扫描进度广播、SQLite 持久化、Library 页面与 SongList 列表/菜单交互。
  • 新增音量均衡(响度归一化):前端设置项 + IPC + Rust 音频引擎实时响度/ReplayGain 支持。
  • UI 基础组件增强:DropdownMenu/ContextMenu、VirtualList empty/header、Input 圆角等。

Reviewed changes

Copilot reviewed 55 out of 60 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/utils/time.ts 抽出通用时间格式化工具供播放器/列表复用
src/utils/format.ts 新增文件大小格式化工具供本地库列表展示
src/stores/library.ts 新增 library store:曲目/目录加载、扫描控制、进度订阅
src/settings/schema.ts 新增 loudnessNormalization 设置项
src/router/index.ts 新增 /library 路由入口
src/pages/Library.vue 新增本地音乐库页面:扫描、目录管理、搜索、播放全部
src/pages/Home.vue 精简 Home 测试页内容与标题调整
src/layouts/MainLayout.vue 顶栏样式调整(去除底边框)
src/layouts/components/SideBar.vue 侧边栏新增“本地音乐”入口
src/layouts/components/NavHeader.vue 顶部新增下拉菜单:主题切换/重载/DevTools/全局设置
src/i18n/locales/zh-CN.json 新增 library/songList/nav 相关中文文案与设置项文案
src/i18n/locales/en-US.json 新增 library/songList/nav 相关英文文案与设置项文案
src/core/player.ts 播放器核心:新增 togglePlay/playNow;playFrom/insertToQueue 行为调整;初始化应用归一化配置
src/composables/useTrackMenu.ts 新增歌曲右键/下拉共用操作菜单(播放/下一首/显示/复制路径)
src/components/ui/SVirtualList.vue 支持 empty/header 插槽与可选禁用位移动画
src/components/ui/SInput.vue 支持 round 外观与输入高度调整
src/components/ui/SImg.vue fallback 改为打包资源导入(避免硬编码路径)
src/components/ui/SDropdownMenu.vue 新增通用下拉菜单组件(Reka UI)
src/components/ui/SDialog.vue 标题/描述布局微调以统一间距
src/components/ui/SContextMenu.vue 新增通用右键菜单组件(Reka UI)
src/components/player/FullPlayer/PlayerBar.vue 复用 formatTime 工具;播放按钮改用 player.togglePlay
src/components/player/FullPlayer/PlayerBackground.vue 默认封面改用打包资源导入
src/components/player/FullPlayer/index.vue 复用 formatTime 工具;播放按钮改用 player.togglePlay
src/components/list/SongList.vue 新增通用歌曲列表:虚拟列表 + 搜索 + 右键菜单 + 音质/大小展示
src/assets/images/song.jpg 新增默认歌曲封面资源
shared/types/settings.ts SystemConfig 增加 library 配置;PlayerSettings 增加 loudnessNormalization
shared/types/player.ts Track 扩展本地文件字段;PlayerApi 增加 setNormalizationEnabled 并移除 probe
shared/types/library.ts 新增 LibraryApi 与 ScanProgress 类型
shared/defaults/settings.ts 默认配置增加 loudnessNormalization 与 library.scanDirs
public/fonts/font.css logo 字体路径调整为根路径引用
pnpm-lock.yaml 锁文件更新:引入 better-sqlite3 及相关依赖
package.json 引入 better-sqlite3 / @types;pnpm onlyBuiltDependencies 增加 better-sqlite3
native/media-ctrl/src/model.rs Debug 输出补充 cover_url 字段
native/media-ctrl/Cargo.toml lints 配置切到 workspace 统一管理
native/audio-engine/src/shared.rs Shared 增加归一化增益/开关的原子字段与访问方法
native/audio-engine/src/scanner.rs 新增目录扫描器:WalkDir + FFmpeg probe + 增量比对 + 批量回调
native/audio-engine/src/player.rs 播放器内部同步归一化开关;seek 逻辑调整;输出流字段命名调整
native/audio-engine/src/metadata.rs 抽出 stream info/tags/replaygain/thumbnail 工具供 scanner/decoder 复用
native/audio-engine/src/loudness.rs 新增实时响度分析器(RMS)用于无 ReplayGain 的动态增益
native/audio-engine/src/lib.rs 暴露 set/get_normalization;新增 scan_dirs/cancel_scan N-API 接口;静默 FFmpeg 日志
native/audio-engine/src/decoder.rs 接入 ReplayGain 与实时响度;seek API 签名调整;复用 metadata 工具
native/audio-engine/Cargo.toml 引入 walkdir;lints 配置切到 workspace
electron/preload/index.ts 暴露 system/library API;player 增加 setNormalizationEnabled
electron/preload/index.d.ts Window.api 类型补齐 system/library
electron/main/utils/nativeLoader.ts loadNativeModule 改为 const 泛型箭头函数写法
electron/main/utils/logger.ts 新增 libraryLog scope
electron/main/utils/config.ts 缓存目录结构调整:app-cache/covers
electron/main/services/scanner.ts 新增主进程扫描编排:调用 Rust 扫描 + 批量 upsert DB + 进度广播
electron/main/services/engine.ts 抽出 native engine/player 单例管理;提供 setNormalizationEnabled 同步
electron/main/services/database.ts 新增 SQLite 库:建表/索引、增量记录、upsert/search/delete
electron/main/ipc/system.ts 新增 IPC:toggleDevTools / showInExplorer
electron/main/ipc/player.ts 移除 probe IPC;接入 engine.ts;新增 setNormalizationEnabled IPC;事件类型改用 JsPlayerEvent
electron/main/ipc/library.ts 新增音乐库 IPC:扫描/目录管理/曲目查询与搜索
electron/main/ipc/index.ts 注册 library IPC handlers
electron/main/ipc/config.ts 配置变更副作用:同步 loudnessNormalization 到 native player
electron/main/core/index.ts 启动时 initDatabase;设置封面缓存 env;退出时 closeDatabase
electron-builder.config.ts 打包 files 规则调整(包含 public/out,排除更多源目录)
components.d.ts 自动组件声明补齐:ContextMenu/DropdownMenu/SongList 与新图标
Cargo.toml workspace 统一 lints/profile 配置
Cargo.lock Rust 依赖锁:audio-engine 引入 walkdir
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (1)

src/components/ui/SInput.vue:43

  • SInput 根节点移除了 w-full,这会改变默认布局行为:例如 SettingsSearch.vue 中未显式指定宽度时,输入框可能收缩为内容宽度而不是铺满容器。若希望保持向后兼容,建议保留 w-full(或至少通过 prop/默认 class 确保在常见场景下占满可用宽度)。

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +54 to +57
/** 右键菜单 */
const contextIndex = ref(-1);
const contextTrack = computed(() => props.items[contextIndex.value]);
const { items: contextMenuItems, handleSelect: onContextMenu } = useTrackMenu(contextTrack);

Copilot AI Apr 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

contextTrack 基于 props.items[contextIndex] 取值,但 contextIndex 是从(可能已过滤的)列表渲染索引传入的。开启搜索过滤后,右键菜单会指向错误的歌曲(header/操作都会错)。建议让 contextTrack 基于 filteredItems 取值,或在设置 contextIndex 时保存实际 track 引用/ID。

Copilot uses AI. Check for mistakes.
Comment thread src/core/player.ts Resolved
Comment thread src/stores/library.ts Resolved
Comment thread native/audio-engine/src/player.rs Outdated
Comment on lines +592 to +593
d.seek(position_secs);
true

Copilot AI Apr 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seek_ok 现在只要 decoder_data 存在就恒为 true(DecoderData::seek 已改为返回 (),且内部 seek 失败也被吞掉)。这会导致 FFmpeg seek 失败时不再触发回退到 load() 的逻辑,用户可能看到 seek 不生效/卡住且没有恢复路径。建议让 DecoderData::seek 返回 Result<()>/bool 并在此处据此决定是否回退。

Suggested change
d.seek(position_secs);
true
// 使用 DecoderData::seek 的返回值判断是否 seek 成功
d.seek(position_secs).is_ok()

Copilot uses AI. Check for mistakes.
Comment thread src/composables/useTrackMenu.ts Resolved
Comment thread electron/preload/index.ts Outdated
Comment on lines +96 to +104
onScanProgress: (callback: (progress: unknown) => void) => {
ipcRenderer.removeAllListeners("library:scanProgress");
const handler = (_event: Electron.IpcRendererEvent, data: unknown): void => {
callback(data);
};
ipcRenderer.on("library:scanProgress", handler);
return () => {
ipcRenderer.removeListener("library:scanProgress", handler);
};

Copilot AI Apr 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onScanProgress 内部使用 ipcRenderer.removeAllListeners('library:scanProgress') 会移除该 channel 上所有监听器(包括其它模块/窗口可能注册的监听),容易造成隐式耦合问题。建议仅移除当前订阅创建的 handler(或使用 once/维护订阅引用),避免全量清空。

Copilot uses AI. Check for mistakes.
@imsyy

imsyy commented Apr 2, 2026

Copy link
Copy Markdown
Member Author

@copilot 重新审查

Copilot AI commented Apr 2, 2026 •

Copy link
Copy Markdown
Contributor

@copilot 重新审查

已按“重新审查”处理并补充修复:onScanProgress 改为仅解绑当前 handler,避免 removeAllListeners 影响其他监听;同时修正了队列长度读取的类型错误并完成针对性校验(pnpm typecheck:web、相关 eslint)。对应提交:a49b727。

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • npmmirror.com
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node node install.js (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot finished work on behalf of imsyy April 2, 2026 07:47
@imsyy
imsyy merged commit 9245278 into main Apr 2, 2026
@imsyy
imsyy deleted the feat/scan-test branch April 2, 2026 16:39
roarrabbit pushed a commit to roarrabbit/SPlayer-Next that referenced this pull request Aug 27, 2026
@Neclyon Neclyon mentioned this pull request Sep 11, 2026
5 tasks done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants