Skip to content

完整本地音乐库支持#166

Open
YUCLing wants to merge 8 commits into
mainfrom
feat/full-music-library-support
Open

完整本地音乐库支持#166
YUCLing wants to merge 8 commits into
mainfrom
feat/full-music-library-support

Conversation

@YUCLing

@YUCLing YUCLing commented Jun 13, 2026

Copy link
Copy Markdown
Owner

close #161

@YUCLing YUCLing self-assigned this Jun 13, 2026
@YUCLing YUCLing added the implementation Implementation adds/fixes label Jun 13, 2026
@YUCLing YUCLing moved this from Todo to In Progress in Open Orpheus Development Jun 13, 2026
@YUCLing YUCLing marked this pull request as ready for review June 16, 2026 10:29
@greptile-apps

greptile-apps Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

本 PR 为本地音乐库添加了完整支持:增量扫描(基于文件大小与修改时间的变更检测)、从 NCM 格式 ID3 标签提取元数据、新增 removeLibrary 处理器,以及将加密/解密逻辑提取到独立的 id3.ts 模块中。同时修复了数据库类型声明,将 exec/execNamed/executeSql/executeTransaction 的返回类型从 Record<string, string> 更正为 Record<string, string>[],以匹配 Rust 侧的实际行为。

  • 增量扫描addLibrary 不再每次全量重建,而是先加载已有记录到内存 Map,按文件大小和 mtime 判断是否需要重新索引,扫描结束后清除已不存在于磁盘的陈旧条目。
  • ID3 元数据提取trackEntryFromFile 现在读取 NCM 格式的加密 comment,并将艺术家、专辑封面、时长等字段填入数据库记录;对于没有 NCM 标签的普通本地文件,回落到 music-tag-native 读取的原始 ID3 字段。
  • 数据库导出方式变更getMusicLibraryDb() 等 getter 函数被替换为直接导出 let 变量,调用方代码随之更新。

Confidence Score: 5/5

改动逻辑清晰,增量扫描、元数据解析和 removeLibrary 处理均实现正确,可以合并。

增量扫描的变更检测逻辑(文件大小 + mtime vs 索引时间戳)正确;陈旧条目清理通过 existingMap 差集实现,无遗漏;removeLibrary 的 onremovelibrary 事件在 try-catch 之外,保证无论 db.exec 是否抛出都会触发;数据库类型声明修正与 Rust 实现一致;id3.ts 模块各函数均有完整的边界检查。

无需特别关注的文件,所有改动均已仔细验证。

Important Files Changed

Filename Overview
src/main/calls/musiclibrary.ts 核心改动:增量扫描逻辑、NCM ID3 元数据解析、新增 removeLibrary 处理器;逻辑正确,变更检测和陈旧条目清理均处理到位。
src/main/id3.ts 新增模块,将加密 comment 的编解码逻辑从 storage.ts 中提取出来;三个函数均有完整的边界检查和异常捕获。
src/main/database.ts 将 getter 函数替换为直接导出 let 变量;TypeScript CommonJS 输出中赋值语句同步更新 exports,调用方在 initializeDatabases() 之后使用均安全。
modules/database/index.d.ts 修正 exec/execNamed/executeSql/executeTransaction 返回类型为 Record<string, string>[],与 Rust 实现一致。
src/main/calls/storage.ts ID3 处理逻辑改用 id3.ts 模块;readDownloadedMusicInfo 在 catch 块中新增 return,修复了之前返回 comment 为空字符串的静默错误语义。

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant R as 渲染进程
    participant H as addLibrary 处理器
    participant DB as musicLibraryDb
    participant FS as 文件系统

    R->>H: musiclibrary.addLibrary(library)
    H-->>R: [true](同步返回)

    H->>DB: "SELECT file,filesize,timestamp WHERE dir=library"
    DB-->>H: existingRows[]

    H->>FS: "readdir(libPath, {recursive:true})"
    FS-->>H: entries[]

    loop 逐个音乐文件
        alt 文件不在 DB 中(新文件)
            H->>FS: stat + readFile(via trackEntryFromFile)
            H->>DB: DELETE + INSERT
        else 文件已在 DB 中
            H->>FS: stat(变更检测)
            alt 大小或 mtime 有变化
                H->>FS: stat + readFile(via trackEntryFromFile)
                H->>DB: DELETE + INSERT
            else 无变化
                Note over H: 跳过,从 existingMap 移除
            end
        end
        H-->>R: onaddprogress(每10个)
    end

    loop existingMap 中剩余的陈旧条目
        H->>DB: "DELETE WHERE file=staleFile"
    end

    H-->>R: musiclibrary.onaddend
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant R as 渲染进程
    participant H as addLibrary 处理器
    participant DB as musicLibraryDb
    participant FS as 文件系统

    R->>H: musiclibrary.addLibrary(library)
    H-->>R: [true](同步返回)

    H->>DB: "SELECT file,filesize,timestamp WHERE dir=library"
    DB-->>H: existingRows[]

    H->>FS: "readdir(libPath, {recursive:true})"
    FS-->>H: entries[]

    loop 逐个音乐文件
        alt 文件不在 DB 中(新文件)
            H->>FS: stat + readFile(via trackEntryFromFile)
            H->>DB: DELETE + INSERT
        else 文件已在 DB 中
            H->>FS: stat(变更检测)
            alt 大小或 mtime 有变化
                H->>FS: stat + readFile(via trackEntryFromFile)
                H->>DB: DELETE + INSERT
            else 无变化
                Note over H: 跳过,从 existingMap 移除
            end
        end
        H-->>R: onaddprogress(每10个)
    end

    loop existingMap 中剩余的陈旧条目
        H->>DB: "DELETE WHERE file=staleFile"
    end

    H-->>R: musiclibrary.onaddend
Loading

Reviews (3): Last reviewed commit: "chore/db: use live binding to get direct..." | Re-trigger Greptile

Comment thread src/main/calls/musiclibrary.ts
Comment thread src/main/id3.ts
Comment thread src/main/calls/musiclibrary.ts
Comment thread src/main/calls/musiclibrary.ts
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Comment thread src/main/calls/storage.ts Outdated
Comment thread src/main/calls/musiclibrary.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

implementation Implementation adds/fixes

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

(Flatpak)本地歌曲问题

1 participant