状态栏歌词插件:面板上的一行歌词与媒体控制

写代码时听歌,想瞄一眼歌词。音乐软件窗口占半屏,桌面歌词工具又太重。面板上单行歌词刚好,有位置就看,没位置就收。

插件跑在 Cinnamon 面板上,拆成三块:libmpris.js 管播放器发现与状态,libaudio.js 管 PipeWire 音频流,liblyrics.js 管歌词匹配。播放时歌词按进度逐行滚动,没播放时自动收起,不占面板空间。

歌词插件面板效果

面板空间紧张时会自动降级:完整 → 紧凑 → 仅图标,带滞回,不会在边界上反复跳。

紧凑模式 仅图标
紧凑模式 仅图标

多播放器仲裁:谁在真正出声

网页播放器和本地播放器同时开着,面板该显示哪个?

播放器列表好拿,MPRIS 的 NameOwnerChanged 信号一响,就知道谁启动、谁退出。但”哪个在真正出声”是另一回事。MPRIS 的 PlaybackStatus 只代表播放器自己的认知,浏览器标签页放久了,状态位和真实出声对不上是常有的事。

所以又接了 PipeWire:pactl subscribe 触发事件,pw-dump 读节点 state,只有 running 的才算真在出声。多个都在响,取最近开始播放的那个。只靠 MPRIS 状态位做仲裁,在”浏览器 + 本地播放器”的混合场景下会翻车。

歌词匹配:四级兜底

顺序是本地 .lrc(音频同目录同名,或 ~/Music 下的几种命名)→ 磁盘缓存(~/.cache/lyricbar/)→ LRCLIB → 网易云。

匹配不到就显示”歌名 - 歌手”。宁可不显示,也不显示错的歌词,显示错歌词比不显示更烦。

歌词定位用 500ms 本地插值推进,每 5 秒跟播放器对时一次。不对时就会累积漂移,唱到第三句,歌词还停在第一行。

其他实现细节

  • 事件驱动:MPRIS 信号、窗口标题变化、PipeWire 音频流事件,没有周期轮询,待机时不耗 CPU。
  • 所有外部命令以 LC_ALL=C 启动。pw-dump 的输出被本地化过,字段名都能变样,解析必然失败,这个坑踩过一次。
  • 暴露 MPRIS 的浏览器页面(Chrome / Firefox 等)也能显示标题并控制。
  • 字体不写死,跟面板时钟保持一致。

实测环境与已知限制

项目 情况
桌面环境 Cinnamon 6.6.9(支持 5.x / 6.x)
操作系统 Linux Mint 22.3(基于 Ubuntu 24.04 LTS)
音频服务 PipeWire 1.0.5(pipewire-pulse),要求 1.0+
内核 7.0.0-38-generic(HWE)
会话 X11;Wayland 未适配

已知限制:不暴露 MPRIS 的播放器无法控制;无时间戳的 .lrc 按 5 秒轮播;Chromium 只提供粗粒度媒体信息,个别网站没有曲目元数据。

安装

1
2
3
git clone https://github.com/LuminDream/lyricbar.git
cd lyricbar
./install.sh

然后打开 系统设置 → 面板 → 添加小程序,选「状态栏歌词插件」,建议放面板右侧。

仓库地址:LuminDream/lyricbar,MIT License。播放器适配细节见仓库 docs/PLAYER_SUPPORT.md。