环境:Win11,主要用 Apple Music(商店版),NSD 2.4.6(issue #77 里那个测试包,2.4.5 也一样复现)
遇到两个歌词相关的问题:
1. 有时候启动后歌词不显示,重启 NSD 或切到下一首就恢复了
媒体控制一切正常,就是没歌词。个人猜测是启动时机的问题:NSD 是开机自启的,第一次轮询到歌曲的时候网络可能还没就绪。看了下代码,WidgetIsland.vue 的 syncMusicStatus 里,fetch_netease_lyrics 只在 isNewTrack 分支里发一次,而 currentBaseInfo 在发请求的同时就被赋值了,之后每 2 秒的轮询看到"还是这首歌"就永远不会重试。Rust 那边三个歌词引擎(QQ → 网易云 → LRCLIB)是串行的、各 4 秒超时,网络冷启动时全超时的话 .catch 直接吞掉,这首歌就没词了。重启 NSD 后 currentBaseInfo 清空,当前歌重新按新歌走一遍流程就又能拉到了,和实际表现一致。
对比了一下,封面那边有 scheduleCoverRetry(5 秒一次最多重试 4 次),歌词没有对应的重试机制,感觉是漏了。
2. 歌词能显示、也是当前这首的词,但显示的段落和实际唱的对不上,整首都是偏的,切下一首可能又正常了
不是串到别的歌,就是同一首歌内部时间轴错位,段落整体超前或滞后。看代码怀疑两个点:
一是歌词版本选错了。music_controller.rs 的 search_song_meta 里,QQ 引擎(第一优先)的匹配条件是 name_match && (artist_match || |时长差|≤3s),也就是说只要歌手对得上就完全不看时长,而且遍历候选时第一个命中就直接返回。同名同歌手的不同版本(Live、专辑版、单曲版、精粹版之类)段落起点经常差十几秒,我在 Apple Music 里放的版本和 QQ/网易云曲库里的版本对不上时,拉回来的 LRC 时间轴整首都是偏的。网易云那边虽然是按时长差最小挑的,但 QQ 先命中就轮不到它。
二是进度推算可能重复计算。fetch_netease_music_info 里 position = SMTC Timeline 的 Position + (now - LastUpdatedTime) 的外推补偿,这个假设是"Position 冻结在 LastUpdatedTime 那一刻";如果播放器实际是"持续刷新 Position、但 LastUpdatedTime 很少更新"的写法,补偿就会重复叠加,position 系统性偏大。前端同歌校准(误差超过 800ms 才校一次,一次拉回 positionMs-250)会不断跟着这个错误值走,于是整首都错位。这个和播放器的 SMTC 实现习惯有关,也解释了为什么时好时坏。
修复建议
- 歌词拉取失败时重试,可以直接参考封面 scheduleCoverRetry 的模式;
- QQ 引擎把时长校验改成硬条件(歌手命中时也校时长),或者像网易云那样在所有通过初筛的候选里按时长差最小的挑;
- 进度外推加保护:比如连续两次轮询发现原始 Position 在前进,就直接用最新 Position、跳过 LastUpdatedTime 外推;或者给外推量设个上限。
感谢!2.4.6 的双屏修复和悬停唤出都很好用👍
环境:Win11,主要用 Apple Music(商店版),NSD 2.4.6(issue #77 里那个测试包,2.4.5 也一样复现)
遇到两个歌词相关的问题:
1. 有时候启动后歌词不显示,重启 NSD 或切到下一首就恢复了
媒体控制一切正常,就是没歌词。个人猜测是启动时机的问题:NSD 是开机自启的,第一次轮询到歌曲的时候网络可能还没就绪。看了下代码,WidgetIsland.vue 的 syncMusicStatus 里,fetch_netease_lyrics 只在 isNewTrack 分支里发一次,而 currentBaseInfo 在发请求的同时就被赋值了,之后每 2 秒的轮询看到"还是这首歌"就永远不会重试。Rust 那边三个歌词引擎(QQ → 网易云 → LRCLIB)是串行的、各 4 秒超时,网络冷启动时全超时的话 .catch 直接吞掉,这首歌就没词了。重启 NSD 后 currentBaseInfo 清空,当前歌重新按新歌走一遍流程就又能拉到了,和实际表现一致。
对比了一下,封面那边有 scheduleCoverRetry(5 秒一次最多重试 4 次),歌词没有对应的重试机制,感觉是漏了。
2. 歌词能显示、也是当前这首的词,但显示的段落和实际唱的对不上,整首都是偏的,切下一首可能又正常了
不是串到别的歌,就是同一首歌内部时间轴错位,段落整体超前或滞后。看代码怀疑两个点:
一是歌词版本选错了。music_controller.rs 的 search_song_meta 里,QQ 引擎(第一优先)的匹配条件是 name_match && (artist_match || |时长差|≤3s),也就是说只要歌手对得上就完全不看时长,而且遍历候选时第一个命中就直接返回。同名同歌手的不同版本(Live、专辑版、单曲版、精粹版之类)段落起点经常差十几秒,我在 Apple Music 里放的版本和 QQ/网易云曲库里的版本对不上时,拉回来的 LRC 时间轴整首都是偏的。网易云那边虽然是按时长差最小挑的,但 QQ 先命中就轮不到它。
二是进度推算可能重复计算。fetch_netease_music_info 里 position = SMTC Timeline 的 Position + (now - LastUpdatedTime) 的外推补偿,这个假设是"Position 冻结在 LastUpdatedTime 那一刻";如果播放器实际是"持续刷新 Position、但 LastUpdatedTime 很少更新"的写法,补偿就会重复叠加,position 系统性偏大。前端同歌校准(误差超过 800ms 才校一次,一次拉回 positionMs-250)会不断跟着这个错误值走,于是整首都错位。这个和播放器的 SMTC 实现习惯有关,也解释了为什么时好时坏。
修复建议
感谢!2.4.6 的双屏修复和悬停唤出都很好用👍