// Architecture

架构概览

Mio Music 是一个 Cargo 工作区:界面、核心规则、列表契约与插件宿主分别放在不同的 crate 里,桌面端与移动端共享同一套核心。

工作区

位置职责
crates/mio-app桌面应用本体。基于 GPUI Kit 的界面、窗口与托盘、快捷键与媒体键、桌面歌词、DLNA、更新器、旧版数据导入等平台相关部分。
crates/mio-core共享的应用规则。播放引擎与音效、音乐库(SQLite)、下载、备份与恢复、歌词与封面、已安装列表插件的管理。桌面与移动端只负责展示和平台集成,业务规则在这里。
crates/mio-music-sdk音乐列表契约与路由:MusicListProvider trait、能力声明、歌曲 / 歌单 / 歌手 / 发现等数据类型,以及歌词、评论、封面的解码与校验。
crates/mio-plugin插件宿主。基于 QuickJS(rquickjs)的受限运行时、列表插件加载与适配、音源插件与洛雪脚本的转换器。
crates/mio-tokens界面 token(明暗模式配色等),由提取器从源项目生成。
crates/mio-mobile-bridge面向移动端的 flutter_rust_bridge 接口,复用 mio-core。
apps/mobileFlutter 移动端工程(Android / iOS 共用)。GPUI 只用于桌面端。
plugins/子模块 mio-music-plugins,内置列表插件的脚本。
tools/打包脚本、源项目静态快照提取器、黄金图对照工具与 Subsonic 测试夹具。
docs/parity/与源项目的对照清单与实施进度。
website/本官网与文档,纯静态,不参与软件打包。

在线内容的数据流

应用本身不带任何在线来源。每一个来源都是某个已启用的列表插件注册进来的 provider:

界面 (mio-app)
  └─ mio_music_sdk::search_source(source, keyword, page, limit)
       ├─ 校验参数(关键词 ≤1024 字节,page ≥ 1,limit 1..=30)
       ├─ 按来源 ID 找到已注册的 provider,并检查其 search 能力
       └─ ListProvider::search            (mio-plugin)
            └─ 新建 QuickJS 运行时 → 执行脚本 → 调用 listPlugin.search(source, {...})
                 └─ 脚本通过 cerumusic.request 发起受限的 HTTP 请求
            ← JSON 返回值反序列化为 SearchResult,宿主覆盖 source、截断到 500 条

几个有意为之的设计:

播放

播放地址有两条来路:来源所属的列表插件自己提供(musicUrl),或交给当前启用的音源插件按来源与音质解析。选择哪条由插件卡片上「由本插件提供播放」开关决定。解析出的地址只允许不含用户信息的 HTTP / HTTPS。随后由 mio-core 里基于 Rodio、cpal 与 Symphonia 的引擎解码和输出,并提供 Gapless、Crossfade、EQ 与 FFT 频谱。

检查

cargo fmt --all -- --check
cargo test --workspace --locked
cargo check --workspace --locked

CI 在 macOS、Windows 与 Linux 上执行同样的三条命令,见 .github/workflows/check.yml。官网与文档位于 website/,不在工作区内,也不属于 Rust 构建。

延伸阅读