基于行业最佳用户体验(UX)实践,面向程序员用户群体 更新日期:2026-04-03
| Phase | 功能 | 状态 | 备注 |
|---|---|---|---|
| 1.1 | 常驻 Daemon 模式 | ✅ 已完成 | Unix socket + PID 管理 |
| 1.2 | 零配置首次使用 | ✅ 已完成 | load() 自动 init |
| 1.3 | 音频元数据自动提取 | ✅ 已完成 | symphonia 0.5 ID3/Vorbis |
| 2.1 | Now Playing 实时反馈 | ✅ 已完成 | 进度条/时长/状态 |
| 2.2 | 交互式搜索选择 | ✅ 已完成 | crossterm TUI |
| 2.3 | 播放列表快捷管理 | ✅ 已完成 | 名称模糊匹配 |
| 2.4 | seek 快捷命令 | ✅ 已完成 | rodio try_seek |
| 3.1 | 推荐引擎升级 | ✅ 已完成 | 时间/评分/新鲜度 |
| 3.2 | 标签浏览与发现 | ✅ 已完成 | browse --genre |
| 3.3 | 歌曲评分系统 | ✅ 已完成 | rate 命令 |
| 4.1 | 自动备份 | ✅ 已完成 | 递归复制 DB |
| 4.2 | 导入/导出 | ✅ 已完成 | JSON/M3U8 |
| 4.3 | 索引重建/诊断 | ✅ 已完成 | reindex + doctor |
| 5.1 | Shell 补全 | ✅ 已完成 | clap_complete |
| 5.2 | JSON 结构化输出 | ✅ 已完成 | --json 全局 flag |
| 5.3 | doctor 诊断命令 | ✅ 已完成 | 健康检查 |
| 6.1 | 音效处理 | 🔲 待开发 | P3 |
| 6.2 | Gapless 播放 | 🔲 待开发 | P3 |
| 6.3 | 终端可视化 | 🔲 待开发 | P3 |
| 6.4 | 插件系统 | 🔲 待开发 | P3 |
P0-P2 全部完成,仅剩 P3 高级功能待开发。
| 维度 | 现状 | 行业基准 |
|---|---|---|
| 首次使用 | ✅ 零配置,自动初始化 | 零配置,开箱即用 |
| 交互模式 | ✅ Daemon 常驻 + 交互式搜索 | 常驻进程 + TUI/键盘控制 |
| 发现能力 | ✅ 搜索 + 标签浏览 + 场景推荐 + 评分 | 智能推荐、标签浏览、相似发现 |
| 反馈信息 | ✅ 进度条 + Now Playing + --json | 进度条、now-playing 通知、格式化表格 |
| 播放体验 | ✅ seek + 进度跟踪 | 完整播放控制、音效、无缝切换 |
| 数据安全 | ✅ 导出 + reindex + doctor + backup | 自动备份、导出/导入、版本迁移 |
| 可扩展性 | 无插件机制 | 插件/脚本/钩子系统 |
| 可观测性 | ✅ doctor 诊断 | 结构化日志、指标采集、健康检查 |
monkey-flow daemon start # 启动后台守护进程
monkey-flow play --scene algo # 通过 socket 发指令
monkey-flow next # 同上
monkey-flow daemon stop # 停止
monkey-flow status # 查询状态(不启动 daemon)实现:
src/core/daemon.rs— DaemonServer 监听~/.monkey-flow/monkey-flow.socksrc/protocol/mod.rs— 长度前缀 JSON 协议 + PID 管理(使用kill -0检测存活)src/cli/mod.rs—Daemon { Start | Stop | Status }子命令main.rs— 所有播放命令通过send_to_daemon()转发- PID 记录到
~/.monkey-flow/daemon.pid
实现:
AppConfig::load()自动创建 config 文件和所有目录(music/index/cache/playlists/logs)- 首次运行任意命令即自动初始化,无需手动
init - 移除了
tokio/reqwest(daemon 为同步架构,无需异步)
实现:
src/core/metadata.rs— 使用 symphonia 0.5 提取 ID3v2/Vorbis Comment 标签- 提取字段:title、artist、album、genre、duration
services/mod.rs— import 时先尝试 symphonia 提取,失败回退路径推断- 新增依赖:
symphonia = { version = "0.5", features = ["mp3", "flac", "vorbis", "wav", "isomp4"] }
实现:
player.rs新增play_start: Instant、paused_elapsed: AtomicU64、track_duration: u32跟踪播放进度pause()累计已播放时间,resume()重置计时器now命令返回:进度条[==== ] 25%、elapsed/total 时间、状态、模式、音量、播放列表位置- JSON 数据包含:elapsed_seconds、volume_percent、playlist_position、playlist_length
$ monkey-flow search "lofi" --interactive
搜索结果 (5 首) ↑↓/jk 导航 | Enter 播放 | 数字键 快速选择 | q 退出
1. Lofi Beats - Artist A [lofi] 03:00
> 2. Lofi Dreams - ChilledCow [lofi] ← 高亮选中
3. Lofi Coding - Beatsmith [lofi] 04:12
4. Night Lofi - Sleepy Fish [lofi] 02:45
5. Chill Vibes - Lofi Girl [lofi] 05:00实现:
src/cli/interactive.rs— crossterm 0.28 交互式 TUI- 支持键盘导航:↑↓/j/k、Shift+g 跳首尾、PageUp/PageDown/Ctrl+u/Ctrl+d
- 数字键 1-9 快速选择、回车/空格播放、q/Esc 退出
- 搜索后本地渲染 picker,选中后通过 daemon 播放
实现:
indexer::resolve_playlist_name(name)— 三级匹配:精确 → 前缀 → 包含daemon.rs的play_playlist先尝试名称匹配,回退 UUID 查找- 使用示例:
play --playlist "code"匹配 "Coding Music"
monkey-flow seek +30s # 快进 30 秒
monkey-flow seek -10s # 快退 10 秒
monkey-flow seek 50% # 跳到 50%
monkey-flow seek 1:30 # 跳到 1分30秒实现:
player.rs新增seek_to(position_secs)方法- 使用
rodio::Source::try_seek()实现跳转 daemon.rs支持+30s/-10s/50%/1:30四种格式pause()累计已播放时间,resume()重置计时器
实现:
- 时间上下文:6 个时段权重(早晨 1.2、上午 1.0、午后 0.8、下午 1.0、傍晚 1.1、夜间 0.6)
- 评分权重:
track.rating * cfg.rating_weight - 收藏加成:
cfg.favorite_boost - 新鲜度惩罚:按创建时间递减
- 过度播放惩罚:
play_count > 50减 1.0 分 - 移除了
play_count * history_weight(过度播放不应加分)
实现:
indexer.rs新增list_all_genres() -> Result<Vec<(String, usize)>>方法cli/mod.rs新增Browse { --genre }子命令browse --genre列出所有风格及歌曲数browse --genre lofi列出指定风格所有歌曲- daemon 新增
browse_genres、browse_genrehandler
实现:
indexer.rs新增rate_track(track_id, rating)方法,rating 限制在 0.0-5.0cli/mod.rs新增Rate { track_id, value }命令- 支持绝对评分
rate <id> 5和相对调整rate <id> +1/rate <id> -0.5 - daemon 新增
ratehandler
实现:
indexer.rs新增backup(backup_dir)方法- 递归复制 DB 目录到
~/.monkey-flow/backups/backup_20260403_143000.db - 使用
crate::utils::ensure_dir_exists确保目录存在
monkey-flow export --format json --output my-music.json
monkey-flow export --format m3u --output playlist.m3u实现:
src/services/exporter.rs—export_json()和export_m3u8()函数- JSON 导出完整 Track 数据(含所有字段)
- M3U8 导出带
#EXTINF时长信息和文件路径 cli/mod.rs新增Export { --format, --output }子命令
monkey-flow reindex # 检查无效索引引用
monkey-flow reindex --fix # 自动清理无效索引
monkey-flow doctor # 诊断报告实现:
reindex:遍历所有 track,检查file_path是否存在,--fix时自动删除doctor:检查配置文件、数据库状态、音乐目录文件数、Daemon 运行状态- 输出
[OK]/[!!]/[--]状态标记
monkey-flow completion zsh > ~/.monkey-flow/completion.zsh
source ~/.monkey-flow/completion.zsh实现:
- 新增依赖:
clap_complete = "4.5" cli/mod.rs新增Completion { shell }命令- 支持 bash、zsh、fish、elvish、powershell
monkey-flow status --json
monkey-flow search "lofi" --json
monkey-flow now --json
monkey-flow browse --genre --json实现:
cli/mod.rs顶层Cli新增#[arg(long, global = true)] pub json: boolmain.rs检测--json时仅输出resp.data(紧凑 JSON)
$ monkey-flow doctor
Monkey Flow 诊断报告
[OK] 配置文件: ~/.monkey-flow/config.toml
[OK] 数据库: 51 首
[OK] 音乐目录: ~/.monkey-flow/music (23 个文件)
[--] Daemon: 未运行- GitHub Actions 自动编译(macOS + Linux + Windows)
cargo install --locked确保可复现构建Makefile简化常用操作
monkey-flow eq rock # 预设均衡器
monkey-flow eq custom --boost 2k:3 # 自定义均衡器基于 rodio 的自定义 Source wrapper 实现滤波。
无缝切换(前一首结束前加载下一首)。需要预解码 + 双 buffer。
monkey-flow visualize # 终端音频频谱可视化基于 rodio::Sink::try_set_end_of_stream + 周期采样。
# ~/.monkey-flow/plugins.toml
[[plugin]]
name = "git-activity"
# 当 git commit 时自动切换到 debugging 场景| Phase | 功能 | 优先级 | 状态 | 用户体验影响 |
|---|---|---|---|---|
| 1.1 | 常驻 Daemon 模式 | P0 | ✅ | 极大 |
| 1.2 | 零配置首次使用 | P0 | ✅ | 极大 |
| 1.3 | 音频元数据自动提取 | P0 | ✅ | 大 |
| 2.1 | Now Playing 实时反馈 | P1 | ✅ | 大 |
| 2.2 | 交互式搜索选择 | P1 | ✅ | 大 |
| 2.3 | 播放列表快捷管理 | P1 | ✅ | 中 |
| 2.4 | seek 快捷命令 | P1 | ✅ | 中 |
| 3.1 | 推荐引擎升级 | P1 | ✅ | 大 |
| 3.2 | 标签浏览 | P1 | ✅ | 中 |
| 3.3 | 评分系统 | P1 | ✅ | 中 |
| 4.1 | 自动备份 | P2 | ✅ | 中 |
| 4.2 | 导入/导出 | P2 | ✅ | 中 |
| 4.3 | 索引重建/诊断 | P2 | ✅ | 中 |
| 5.1 | Shell 补全 | P2 | ✅ | 小 |
| 5.2 | JSON 结构化输出 | P2 | ✅ | 小 |
| 5.3 | doctor 诊断命令 | P2 | ✅ | 中 |
| 6.1 | 均衡器 | P3 | 🔲 | 小 |
| 6.2 | Gapless 播放 | P3 | 🔲 | 小 |
| 6.3 | 终端可视化 | P3 | 🔲 | 小 |
| Crate | 用途 | 版本 |
|---|---|---|
symphonia |
ID3/Vorbis 标签提取 | 0.5 |
clap-complete |
Shell 补全生成 | 4.5 |
crossterm |
终端交互式 UI | 0.28 |
| Crate | 原因 |
|---|---|
tokio |
daemon 为同步架构,无需异步运行时 |
reqwest |
无 HTTP 下载/URL 播放需求 |
libc |
改用 std::process::Command("kill", "-0") 检测进程存活 |
- trait 抽象播放后端:
MusicPlayer抽象为trait Player,方便测试和替换实现 - 事件总线:播放状态变更通过 channel 广播(now-playing 通知、历史记录、推荐更新)
- 分层日志:
tracing添加 JSON 输出支持,方便日志分析
src/
├── cli/
│ ├── mod.rs # CLI 命令定义(含 Daemon/Now/Browse/Rate/Seek/Export/Reindex/Doctor/Completion)
│ └── interactive.rs # 交互式 TUI(crossterm)
├── core/
│ ├── mod.rs
│ ├── config.rs # 配置管理(自动初始化)
│ ├── daemon.rs # Daemon 进程 + Unix socket + seek/rate/browse handler
│ ├── indexer.rs # RocksDB 索引引擎(backup/get_all_tracks/delete_track/resolve_playlist_name)
│ ├── metadata.rs # 音频元数据提取(symphonia)
│ ├── player.rs # 播放器(进度跟踪/暂停累计/seek_to)
│ └── recommender.rs # 推荐引擎(时间上下文/评分权重/新鲜度)
├── models/
│ └── mod.rs # 数据模型(Track/Playlist/Favorite/History/Scene/PlayMode)
├── services/
│ ├── mod.rs # ServiceManager + import_music
│ └── exporter.rs # JSON/M3U8 导出
├── protocol/
│ └── mod.rs # Daemon 通信协议(长度前缀 JSON + PID 管理)
├── error/
│ └── mod.rs # MonkeyFlowError 枚举
└── utils/
└── mod.rs # 字符串工具(normalize/is_combining_mark)
| 产品 | 亮点 | 可借鉴 |
|---|---|---|
| mpd | Daemon 架构、丰富的客户端生态 | 客户端/服务端分离 |
| cmus | Vim 风格 TUI、快捷键绑定 | 交互模式设计 |
| ncmpcpp | 曲目导航、可视化、播放列表 | 搜索与浏览 UX |
| spotify-tui | Rust TUI 音乐播放器 | Rust 终端 UI 实践 |
| youtube-dl | URL 直接下载/播放 | URL 播放体验 |
| lazygit | 交互式终端 UI | crossterm 使用模式 |