Skip to content

MusicBox 架构说明

本文描述 MusicBox 当前代码结构和主要运行链路。它以仓库现状为准:主进程和渲染进程都已经从早期全局对象模式迁移到更明确的 controller/service/composition 分层,渲染进程旧 core/services/ 目录现在仅作为兼容转发层保留。

总览

MusicBox 是一个 Electron 桌面应用,由四个主要部分组成:

text
Electron main process
  src/main/main.ts
  src/main/core/Application.ts
  src/main/controllers/*.ts
  src/main/services/**
        |
        | contextBridge + ipcRenderer/ipcMain
        v
Preload boundary
  src/main/preload.ts exposes window.electronAPI
        |
        v
Renderer process
  src/renderer/src/app/**
  src/renderer/src/features/**
  src/renderer/src/ui/**
  src/renderer/src/infrastructure/electron/**
        |
        v
Native/helper modules
  native/ Rust N-API audio engine
  src/main/metadata_editor.py packaged as metadata_editor executable

核心原则:

  • 主进程负责系统能力、窗口、文件、网络磁盘、音乐库缓存、插件安装、原生音频和安全校验。
  • preload 只暴露白名单 API 到 window.electronAPI,renderer 不直接访问 Node/Electron。
  • renderer 负责 UI、播放运行时、功能编排和插件 host。
  • Rust N-API 模块提供 WASAPI shared/exclusive 等原生音频能力,Web Audio 作为 renderer 内可用的播放引擎。
  • Python helper 只处理音频元数据写入相关任务,构建时打包到 dist/main

启动流程

  1. src/main/main.ts 创建 Application,在 app.whenReady() 后启动。
  2. Application.applyConfiguration() 根据用户配置处理硬件加速和 GC 标志。
  3. Application.initializeCoreServices() 注册核心服务,但尽量延迟实例化重型服务。
  4. Application.registerStartupControllers() 在窗口创建前注册 IPC controller,确保 renderer 首屏加载时 preload API 可用。
  5. WindowManager.createMainWindow() 创建无边框主窗口并加载 src/renderer/public/index.html
  6. 主窗口显示后,后台加载音乐库缓存并向 renderer 发送 library:updated
  7. renderer 入口 src/renderer/src/app/bootstrap/main.ts 加载基础工具、API、插件框架、UI component 和应用启动代码。
  8. createAppComposition() 组装生命周期、路由、播放、音乐库、插件、快捷键和 UI facade。

主进程结构

src/main/ 是 Electron main process 的 TypeScript 源码。

text
src/main/
  main.ts                  Electron app lifecycle 入口
  preload.ts               contextBridge 白名单 API
  controllers/             IPC controller
  core/                    应用生命周期、配置、窗口、服务容器
  services/                主进程业务服务
  utils/                   路径安全、文件搜索、元数据等工具
  metadata_editor.py       元数据编辑 helper 源码

core

  • Application.ts:启动、关闭、服务注册、controller 注册、后台初始化。
  • WindowManager.ts:主窗口和桌面歌词窗口创建、窗口尺寸持久化、托盘关闭行为、窗口间消息转发。
  • ServiceContainer.ts:轻量服务容器,支持延迟实例化。
  • ConfigManager.ts:读取和保存 app.getPath('userData') 下的 JSON 配置。

controllers

controller 使用 @Controller@IpcHandle@IpcOn 装饰器声明 IPC 通道,并继承 BaseController 统一注册和注销。

典型 controller:

  • AppControllerWindowControllerDialogController:应用、窗口、对话框能力。
  • LibraryController:本地/网络音乐扫描、缓存、歌单、元数据。
  • NativeAudioController:Rust N-API 音频引擎桥接。
  • NetworkController:SMB / WebDAV 挂载、状态、目录结构。
  • ExtensionsController:插件安装、启用禁用、文件读取、插件存储。
  • DesktopLyricsControllerTrayControllerGlobalShortcutsController:桌面歌词、托盘、全局快捷键。

services

  • services/library/LibraryCacheManager.ts 管理 music-library-cache.json、歌单、忽略列表和缓存校验。
  • services/library/MetadataHandler.ts 负责元数据读取/写入相关处理。
  • services/network/NetworkDriveManager.tsNetworkFileAdapter.ts 抽象 SMB / WebDAV 文件访问。
  • services/extensions/ExtensionInstaller.ts 管理外部 ZIP 插件安装到用户数据目录。
  • services/extensions/ExtensionStorageService.ts 为插件提供 global / workspace JSON 存储。

Preload 与 IPC 边界

src/main/preload.ts 通过 contextBridge.exposeInMainWorld('electronAPI', ...) 暴露能力。BrowserWindow 配置中 nodeIntegration: falsecontextIsolation: truewebSecurity: true

当前暴露的能力按命名空间组织:

  • appwindowdialogtrayhardwareAcceleration
  • librarysettingsuserdata
  • medialyricscoversequalizerPresets
  • audionativeAudioonNativeAudioEvent
  • networkDriveglobalShortcutsdesktopLyrics
  • extensionshttpServerbenchmarkmemory

通用 Node API 已默认关闭。只有设置 MUSICBOX_ENABLE_LEGACY_NODE_APIS=1 时,preload 才会暴露有限的兼容 fsospath 方法。新代码应使用领域 API 或 src/renderer/src/infrastructure/electron/*Gateway.ts,不要重新引入通用文件系统访问。

渲染进程结构

渲染进程位于 src/renderer/,由 Vite 构建。Vite root 是 src/renderer/src,构建产物输出到 src/renderer/public,入口包括主窗口 index.html 和桌面歌词窗口 DesktopLyrics.html

text
src/renderer/src/
  app/                     应用启动、组合根、生命周期、运行时协调
  features/                按业务域拆分的功能模块
  ui/                      页面、弹窗、组件和基础 Component
  infrastructure/electron/ Electron API gateway
  api/                     MusicBoxAPI、播放运行时 API 和类型
  extensions/              插件 host、API、内置插件、示例和文档
  shared/                  跨功能共享的缓存、歌词、网络、类型
  styles/                  SCSS 分层样式
  assets/                  图标和图片
  core/                    deprecated 兼容转发层
  services/                deprecated 兼容转发层

app 层

app/bootstrap/main.ts 是 renderer 的真实入口。它先加载基础设施和 UI component,再导入 ./app 创建应用实例。

app/composition/AppCompositionRoot.ts 是重构后的组合根,负责把运行时 controller、feature service、UI facade 和 legacy app bridge 接到一起。新增跨功能协作时,应优先在组合根显式注入依赖,而不是让模块互相访问全局对象。

app/runtime/MusicBoxApp.ts 保留应用级 facade,兼容现有插件和 UI 调用,同时把具体行为转发到 feature controller/service。

features 层

features/ 按业务域组织 renderer 逻辑,例如:

  • playback:播放状态、队列、播放服务、Web Audio / WASAPI engine adapter。
  • library:音乐库数据、扫描入口、元数据编辑、UI 绑定。
  • mediaAssets:歌词、封面、本地/内嵌/在线资源解析。
  • equalizer:图形均衡器、参量均衡器、预设文件。
  • desktopLyrics:桌面歌词窗口同步和渲染控制。
  • settings:设置页面 controller、renderer、service。
  • extensions:插件管理 UI 和插件 host service。
  • networkDrive:网络磁盘管理和详情页数据。

infrastructure/electron 层

infrastructure/electron/ElectronBridge.tswindow.electronAPI 的类型化访问基础。各 *Gateway.ts 将 preload API 包装成领域方法,例如 libraryGatewaynativeAudioGatewaydesktopLyricsGatewaysettingsSystemGateway

Renderer feature 不应直接散落调用 window.electronAPI。新增 IPC 后,推荐链路是:

text
main controller -> preload namespace -> infrastructure/electron gateway -> feature service/controller -> UI

兼容层

src/renderer/src/core/**src/renderer/src/services/** 已标记 @deprecated。这些文件只能包含注释和 import/export forwarding,由 src/renderer/scripts/check-architecture-boundaries.mjs 保护。新增代码不要从 @/core@/services 或旧 @js 路径导入。

音频架构

MusicBox 当前有两类播放实现:

  • Web Audio engine:位于 features/playback/service/audioEngine/webAudio/,处理浏览器侧解码、播放、预加载、进度、可见性和对象 URL 生命周期。
  • WASAPI/native engine:renderer 通过 WasapiEngine.tsnativeAudioGateway 调用主进程 NativeAudioController,再桥接 dist/main/NativeAudio.node

PlaybackServiceAudioEngineAdapter 负责切换引擎、统一播放控制、播放列表、进度、音量、播放模式、均衡器和桌面歌词同步。native/ 中的 Rust crate 使用 N-API 暴露原生音频能力,并在 npm run build:rs 时复制到 dist/main/NativeAudio.node

音乐库与元数据

音乐库数据由主进程缓存,renderer 通过 libraryGatewayLibraryBridge 获取。缓存文件存放在 Electron userData 目录:

  • music-library-cache.json:歌曲、歌单、扫描目录、忽略列表、统计信息。
  • music-folders-settings.json:音乐文件夹和自动扫描设置。
  • window-config.json:主窗口尺寸和桌面歌词位置。
  • extensions.jsonextensions/extension-storage/:外部插件和插件存储。

元数据读取主要依赖 music-metadata 等 Node 侧库;写入和复杂处理由 metadata_editor.py helper 支持,完整打包时通过 npm run build:python 生成平台可执行文件。

插件系统

插件系统位于 src/renderer/src/extensions/,参考 VS Code 扩展模型:

  • extensions/core/:生命周期、事件、注册表、激活器、插件服务和 sandbox runtime。
  • extensions/api/:播放器、音乐库、UI、存储、设置、命令、快捷键、网络、窗口等标准 API。
  • extensions/builtin/:内置插件和 extensions.json 索引。
  • extensions/examples/:插件示例。
  • extensions/docs/:插件开发文档。

外部插件通过 ZIP 安装。主进程 ExtensionInstaller 负责 manifest 校验、路径安全和文件落盘,renderer 插件 host 负责扫描、加载、激活和停用。插件应通过 context.api 访问能力,不能依赖 renderer 内部模块或 preload 的通用 Node API。

安全边界

  • Renderer 禁用 Node integration,并启用 context isolation。
  • preload 只暴露显式白名单能力。
  • 文件系统、插件安装和扩展文件读取必须在主进程校验路径,复用 src/main/utils/pathSecurity.ts
  • 外部链接通过主进程 app:openExternal 打开。
  • 插件安装会阻止 ZIP path traversal,并拒绝覆盖内置插件 ID。
  • 旧通用 fs/path/os preload 能力默认关闭,仅用于迁移期兼容。

构建与发布链路

text
npm run build
  -> npm run build:python
  -> npm run build:renderer
  -> npm run build:rs
  -> npm run build:ts
  -> electron-builder

打包配置在 electron-builder.yml。应用文件包含:

  • dist/main/**/*:主进程编译产物、Python helper、NativeAudio.node。
  • src/renderer/public/**/*:Vite 构建后的 renderer 静态资源。
  • node_modules/**/*:运行时依赖,按配置排除测试、文档和无关文件。

asarUnpackextraResources 会处理 NativeAudio.nodemetadata_editor,因为它们需要作为独立二进制资源加载。

新增功能建议

新增主进程能力:

  1. src/main/controllers/ 增加或扩展 controller。
  2. src/main/preload.ts 中只暴露必要方法。
  3. src/renderer/src/infrastructure/electron/ 增加 gateway。
  4. 在对应 features/*/service 中封装业务行为。
  5. 由 UI component 或 app composition 调用 feature service。

新增 renderer 功能:

  1. 优先放在对应 features/<domain>/
  2. UI 放在 ui/pagesui/widgetsui/dialogsui/modals
  3. 跨功能共享的纯逻辑放到 shared/
  4. 不要从 deprecated core/services/ 引入新依赖。
  5. 运行 npm run typecheck:renderercd src/renderer && npm run lint

Released under the MIT License.