跳转到内容

架构

bae 是一个 Rust 核心外加四个原生应用。定义产品的一切,即资料库模型、导入、播放、同步、加密,都在 Rust 中,并在每个平台上表现一致;每个应用只是其上的轻量原生 UI。

  • bae-core:产品本身。资料库和元数据模型,导入和识别流水线,FFmpeg 播放引擎,响度分析,导出,以及与下方 coven 的集成。导入和识别只在桌面端编译;移动端构建是同步和播放客户端。
  • coven:数据层,一个独立库。coven 拥有 SQLite 连接,捕获 bae 提交的每个更改,并通过用户的云存储端到端加密同步这些更改。它还拥有 blob 存储(音频字节、图像)、本地缓存、身份密钥和成员资格。bae 固定一个精确的 coven 修订版,并把它标记进每个二进制程序;它定义构建之间的同步兼容世代。
  • bae-bridge:UniFFI 边界。桥接类型在 Rust 中定义一次,并在构建时生成到 Swift 和 Kotlin。
  • 应用:macOS 和 iOS 上的 SwiftUI,Android 上的 Jetpack Compose,以及原生 Windows 应用。每个也实现核心请求的平台部分:音频输出、图像文字识别、媒体控制、钥匙串访问、崩溃报告。

应用旁边还有:bae-mcp(MCP 服务器)、bae-cli(命令行)和 bae-automation(二者共用的工具层)。

资料库位于 ~/.bae/libraries/<library-id>/(移动端上是平台数据目录):

~/.bae/libraries/<id>/
library.db # SQLite: catalog, credits, playback specs
config.yaml # device-local settings, never synced
storage/
local/ # blobs this device owns (covers, artist images)
cache/ # evictable copies of cloud blobs
pinned/ # pinned-for-offline copies, never evicted

数据库只通过 coven 打开,coven 会在 bae 的 schema 旁边叠加自己的记账表(sync cursors、outbox、blob state),并运行 bae 的 migrations。以非托管方式导入的音频文件完全不在 ~/.bae 下:数据库在导入路径处引用它们。

秘密永远不在这些文件中。身份密钥、资料库加密密钥、云端凭据和 API token 位于 OS keyring 中(Apple 平台上是 Keychain,并通过 iCloud Keychain 同步;其他平台使用对应机制)。

每个平台上存在两个构建时版本。bae 编译进 OAuth providers(Google Drive、Dropbox、OneDrive)、CloudKit 和 telemetry。baeium 编译掉所有这些内容:仅 S3-compatible storage,无 telemetry,依赖树中没有专有内容。两个版本是同一份源代码和同一个核心;feature flag 决定提供商列表和诊断接线。

应用按平台使用 MAJOR.MINOR 版本。major 是兼容时代,由每个应用共享:处于同一 major 的设备可以同步一个资料库。只有传输格式或磁盘格式破坏兼容时才会增加,最常见原因是固定的 coven 修订版。minor 计算每个应用的发布次数,跨平台不可比较。