Repository navigation
Releases: superxyline/fnos_music_ext
Release list
v3.7.1
fnmusic-ext 3.7.1
修复
- 勾选「接管小爱音箱音乐播放」后找不到「保存并生效」按钮:分发安装的使用者反馈——勾上开关后页面提示要保存,但页面上根本没有按钮。根因:保存条
#save-bar默认translateY(110%)隐藏,只有markDirty()给它加.show才从底部滑出;而#xm-enabled既不在批量change绑定数组里、也没有单独绑定,勾选永不触发脏标记,按钮永不出现(其他页面的开关都绑了,唯独漏了它)。修复:app.js补#xm-enabled的change绑定,保存条左侧提示「小爱音箱接管需保存后生效」;- 文案改为「勾选/取消后,页面底部会弹出『保存并生效』按钮」,明确按钮是弹出而非常驻;
- 回归测试:断言该开关绑定
markDirty,并新增通用防护——index.html里所有switch-row开关都必须在markDirty上下文出现,防止以后再漏。
安装
- fnOS「应用中心 → 手动安装」选择
fnmusic-ext-3.7.1.fpk;覆盖安装,数据保留 - 校验:
sha256sum -c fnmusic-ext-3.7.1.fpk.sha256
v3.7.0
fnmusic-ext 3.7.0
新增
- 小爱音箱页显示「正在播放」:接管期间打开管理台「小爱音箱」页,完成页新增一张卡片,显示音箱正在播放的歌名、来源徽标(本地曲库 / 在线 · 酷我/咪咕/哔哩哔哩/QQ音乐/网易云…)与设备名,随 5 秒轮询自动刷新;未在播放时显示「当前未在播放」,暂停时显示「已暂停」并保留最后一首。实现:桥接
/health新增now_playing(歌名取设备当前曲device.cur_music,来源由该曲的/play?guid=解析,online:<源>:<id>/online:lx:<平台>:<id>落到具体源,其余为本地曲库;在线源点歌是"下载成 mp3 再播",此时用/play记录与点歌时记下的last_played_guid/title兜底,不会误标成本地)。 - 按歌手播本地收藏(歌手合辑):对小爱说「播放周杰伦的本地收藏歌曲」「来点五月天的收藏」「放几首林俊杰本地歌」等,把收藏里该歌手的所有歌随机打乱成一张临时歌单连播(
PLAY_TYPE_ALL整张循环),收藏里没有该歌手时明确播报。实现:- 口令在分发器里先于上游「播放」模糊匹配判定,否则整句会被点歌抢走(去搜「周杰伦的本地收藏歌曲」这个不存在的歌名);只认带「本地/收藏」限定的说法——不带限定的「播放周杰伦的歌」保持原点歌语义(收藏命中播收藏、没有搜在线源),泛指词(全部/所有/我的…)不当歌手;
- 打乱顺序靠
_order_guard_names保住:临时歌单名登记进同一套 guard(上游is_online_music()视为网络歌单),入库与每取一首下一曲都不会再按歌名重排——否则打乱结果会被字典序抹平; - 歌名筛选按「艺术家 - 歌名」整体匹配(收藏条目名就是这形态),临时歌单名前缀
__singer__,不会被口令/歌单模糊匹配误命中; - 实测(282 首收藏):说「播放周杰伦的本地收藏歌曲」→ 筛出 53 首、零混入、随机顺序与收藏原序不同、上游排序被跳过。
- 口令介绍补齐顺序播放:完成页口令表新增「顺序播放本地收藏 / 顺序播放本地歌曲 / 按顺序播放本地收藏」一行(标注排序口径"最近收藏的在前"与"整张放完再从头循环")、以及「播放X的本地收藏歌曲」歌手合辑一行,并补上「收藏这首歌」与睡眠定时两条既有能力;顶部开关说明也同步提到顺序播放、歌手合辑与正在播放展示。
修复
- 「顺序播放本地收藏」没按收藏顺序播(从《心痛2009》开始):用户反馈口令能播但首曲不是最新收藏的那首。根因不在口令,而在上游两处按歌名重排——
MusicLibrary.gen_all_music_list(music_library.py:181,入库时)与XiaoMusicDevice.update_playlist(device_player.py:245,几乎每取一首下一曲都会调)都会对「非网络歌单」执行sort(custom_sort_key)(Unicode 码位序):桥接推送的保序歌单在入库那一刻就被重排,收藏顺序丢失。实测 282 首按该规则排序后第 0 位正是「欢子 - 心痛2009」,与现象完全吻合。修复:新增NativeCore._install_seq_playlist_order_guard——借上游is_online_music()这个开关,把保序歌单视为网络歌单以跳过两处排序;只影响该歌单,其它歌单排序、取流(is_web_music按 URL 判定)均不受影响。guard 必须在首次gen_all_music_list之前安装。 - 顺序播放改为整张收藏循环:原先用
PLAY_TYPE_SEQ(触底get_music返回空串即停),用户要的是放完最后一首再从头来。改用PLAY_TYPE_ALL:顺序/循环分支同样不打乱,且触底时new_index回卷到 0,整张收藏循环播放。 - 回归测试:guard 安装顺序、复刻上游排序条件下保序歌单顺序不变、其它歌单仍排序、
playlist_seq_name为空时不特殊对待;当前播放快照的来源解析(本地/在线/lx 平台段/未知源/空引擎);歌手合辑的口令识别(8 种说法 + 不误伤歌单口令/泛指词/点歌/顺序播放)与动作(只收该歌手、打乱、临时歌单登记 guard、整张循环);完成页正在播放卡片、顺序播放与歌手合辑口令介绍的前端断言。
安装
- fnOS「应用中心 → 手动安装」选择
fnmusic-ext-3.7.0.fpk;覆盖安装,数据保留 - 校验:
sha256sum -c fnmusic-ext-3.7.0.fpk.sha256 - 升级后到管理台「小爱音箱」页确认状态(正在播放卡片会显示当前曲与来源)
v3.6.1
fnmusic-ext v3.6.1
修复
- 【热修】重启 NAS 后小爱音箱桥接不可达:开机时应用中心重建容器,旧镜像缺桥接依赖文件(audio_id_resolver / native)导致 xiaomusic 启动即崩——Dockerfile 已补齐并重建镜像,重启/容器重建不再依赖热部署补丁
- 管理台左侧菜单无法滚动:菜单项超出视口时导航区现在自身可滚动(3.6.0 新增两页后暴露)
升级
应用中心内升级,或下载附件 fpk 手动安装。升级不影响曲库与收藏数据。
已完成隐私审查,无敏感信息。
v3.6.0
fnmusic-ext v3.6.0
新增
- 搜索结果音质优先排序:在线搜索按音质分档排序(无损 > 有损高码率 > 低码率),快源抢跑不再截断能出无损的源,根治"B 站霸屏"
- 收藏下载音质门槛:
FNMUSIC_DOWNLOAD_MIN_QUALITY(any/320/lossless),红心下载不达标先换源、仍不达标拒绝入库,管理台可选 - 直链输出(302):管理台「直链输出」页配置令牌后,外部播放器(车机/电视 App 等)经
/direct?id=…&token=…直接播放在线曲库 - 最近常听歌单:播放历史(播放次数+新鲜度)驱动的只读虚拟歌单,数据全在本地
- 歌单导入(网易云 / QQ 音乐):粘贴歌单链接/ID,逐首在线匹配整轨下载(试听探针+音质门槛)、写标签内嵌封面,官方收录后自动加入目标歌单(支持自动新建与先导前 N 首)
- 小爱睡眠定时口令:「半小时后停止播放」「定时30分钟」等到点自动停止,「取消定时」撤销
升级
应用中心内升级,或下载附件 fpk 手动安装。升级不影响曲库与收藏数据。
已完成隐私审查,无敏感信息。
v3.5.2——3.5.1 歌单同步 KeyError 热修(配置加载默认值打底)
[3.5.2] - 2026-10-22
修复
- 【热修】3.5.1 歌单同步 500(KeyError: 'playlist_seq_name'):3.5.1 新增的保序歌单配置键只加在了默认值里,而桥接配置加载是「文件存在就整份返回」——老安装的 config.json 没有这个键,
do_sync直接 KeyError,收藏同步/歌单推送全断(顺序播放也不可用)。修复:- 配置加载改为默认值打底 + 配置文件覆盖(
{**DEFAULT_CONFIG, **load_json(...)}):以后新增默认键对老安装自动生效,不再需要手动迁移; build_playlist的歌单名读取改防御性CFG.get(..., 默认值),双保险;- 回归测试:老配置文件缺新键时默认值必须打底、配置文件值优先、build_playlist 不再抛 KeyError。
- 配置加载改为默认值打底 + 配置文件覆盖(
升级说明
- 3.5.1 用户必升:3.5.1 在已有配置的安装上收藏同步会 500(KeyError),歌单停更;本热修仅改桥接配置加载与歌单名读取,升级即恢复。
- 登录态、设备勾选、歌单、待关联条目全部保留;无需重新配置。
- sha256(fnmusic-ext-3.5.2.fpk):
a6a463246c7aaa138913eec9e5bb60afc3ee71a3778b63055ff9a6128fcdd3ef
v3.5.1——顺序播放本地歌曲 / NEW 诈尸修复 / 升级弹窗自选 GitHub+Gitee / 关于页加 Gitee
[3.5.1] - 2026-10-22
新增
- 顺序播放本地歌曲(用户需求):对小爱说「顺序播放本地歌曲」「顺序播放本地收藏」「按顺序播放本地收藏」等,即按歌曲进入收藏歌单的先后从第一首开始顺序播放(区别于「播放收藏」的乱序)。实现:
- 桥接歌单改为两份同曲:「本地收藏」(乱序,口令播放收藏用)+「本地收藏(顺序)」(严格按收藏进入顺序);
- 口令在引擎分发里**优先于上游默认词「顺序播放」**判定——后者映射 set_play_type_seq 且排在关键词匹配表前排,会把「顺序播放本地歌曲」整句抢成模式切换(arg=本地歌曲),音箱什么都不播;
- 播放时设备临时切顺序模式(PLAY_TYPE_SEQ,不播报切换):上游
update_playlist在随机模式下会强制洗牌,保序歌单也会被洗乱;顺序模式下直接取歌单原序,播完触底即停(不循环); - 第一首显式点名开播:上游
_play_next→get_music恒取"当前曲的下一首"(index+1),空位置会落到第二首——随机模式无感,顺序模式就是跳过第一首收藏; - 之后的「播放收藏」由桥接把设备切回随机模式,"每次重新打乱"的行为不变;
- 保序歌单未就绪(首次同步未完成)时明确播报,不静默失败。
修复
- 已是最新版仍提示 NEW(用户实测):热部署升级后 webui 进程没重启,检查更新的 6 小时内存缓存停在升级前的版本对比,NEW 一直亮到缓存过期。修复:缓存命中时按当前版本重算
has_update(真源数据仍按 TTL 缓存不出网)——本地升级后下一次进页面即熄灭 NEW,不再依赖重启进程或等缓存过期。
变更
- 升级弹窗支持自选下载源(用户需求):发现新版本的弹窗原来只有单个「升级」链接(指向主检查源);现在同时提供 GitHub 下载 / Gitee 下载两个按钮(两平台 tag 路径一致,版本号拼接,无需为第二源额外出网),mirrors 缺失时退回主源单链接。
- 关于页加入 Gitee 链接(用户需求):项目仓库/问题反馈现在同时列出 GitHub 与 Gitee 两个入口。
升级说明
- 从 v3.5.0 及以前升级:登录态、设备勾选、歌单、待关联条目全部保留;无需重新配置。
- 前端改动(升级弹窗双源/关于页):升级后强刷浏览器(Ctrl+F5)(静态资源缓存参数已随版本升到 v3.5.1,正常刷新亦可)。
- 「顺序播放本地歌曲」为口令新能力:首次同步完成后保序歌单即就绪;同步前发口令会播报"顺序歌单还没准备好"。
- sha256(fnmusic-ext-3.5.1.fpk):
cc854397bcbd10862ef24b0e503993e4d06c330dcc9c7223bc6412852f92f240
v3.5.0——深色主题+设置页 / 口语化停止指令 / 收藏绑定缺口补齐
[3.5.0] - 2026-10-22
新增
-
深色主题 + 设置页(移植上游 PR #72 及后续修复):管理台支持「跟随系统 / 浅色 / 深色」三档外观(设置 → 外观,存当前浏览器 localStorage,不进 .env)。嵌入飞牛时以宿主主题为准(getPlatformConfig 取初值 + $on("os/theme") 监听切换,宿主主题缓存 localStorage 供刷新首屏引导);直连 8774 或宿主不可用时回退 prefers-color-scheme。theme-boot.js 在样式表之前同步执行,深色用户不闪白底。CSS 重构为完整变量体系(浅色 :root + 深色 :root[data-theme="dark"] 只覆盖配色,布局共用),原有硬编码颜色全部变量化;内容列居中统一页宽(--content-max),保存条与卡片右缘对齐;hover 反馈不再用 opacity/filter(避免降低文字对比度,移植上游 98a5a37/749b61c 修复);二维码保持白底不随主题反色
-
测试:新增 test_frontend_theme.py(8 项结构契约:boot 时序/设置页三选项/变量覆盖/对比度 4.5:1/列宽对齐/键名一致);test_app_js.js +7 项主题行为用例(首屏引导/偏好持久化/宿主 os/theme/缓存刷新沿用/失效回退)
-
口语化停止指令扩充(用户反馈):停止口令从上游 7 个规范词扩充到 30+ 变体(
停下来吧/别放了/别播了/别唱了/别响了/不要再放了/安静/消停/闭嘴/停一下/停了/停掉/音乐停/暂停播放等,上游原有 7 词全保留)。口语停止此前会被小爱自带技能接走——音箱停了,但桥接侧is_playing仍为True、下一曲定时器仍 armed,到点自动续播一首(用户感知"停一会又播下一首")。
修复
- 停止口令优先于点歌模糊匹配:
停止播放音乐这类 Query 以前会被播放关键词抢先匹配成点歌(arg=音乐);现在停止词出现在点歌词之前即判停止(位置感知),播放安静(歌名)等点歌不受影响,N分钟后关机(定时关机)也不被抢走。 - 未匹配指令的停止兜底:口令没匹配上但明显是"别放了"的口语时,自动取消组内下一曲定时器并置
is_playing=False,杜绝自动续播;点歌意图词(播放/放首等)不触发兜底。 - 收藏自动绑定三处缺口补齐(对照上游 #82 /
4502fde):- 滚动缓存转存带歌词:红心触达的试听缓存定名挪进曲库时,除随迁已有
.lrc外,FNMUSIC_LYRIC_AUTO_DL开启时向源站补拉歌词,且补拉排在通知官方扫描之前——官方扫描入库时.lrc已落在音频旁,入库即带歌词。 - 在途去重:滚动缓存转存按 guid 去重(重复收藏/列表自愈并发触发只搬一次文件;搬运走线程池,不再阻塞事件循环);官方绑定轮询按 (user, guid) 去重;同用户对账加 per-user 锁串行——并发触发不再重复打官方搜索、重复建官方红心。
- 待关联集合去污染:
_seed_pending_from_favorites只认曲库内的文件——滚动缓存形态(官方扫描不索引 cache 目录)的条目进了待关联集合也永远匹配不上,只会每轮收藏列表请求反复打官方搜索;收藏列表自愈循环相应改为:滚动缓存命中先转存进曲库再绑定。 - 转存成功即登记待关联并起轮询(对齐上游绑定调度),不必等下一次收藏列表请求;元数据缺失转存不了时回退后台整轨下载——不以 unknown 定名入库,也不卡在滚动缓存里被淘汰。
- 测试:新增
proxy/tests/test_fav_rolling_promote.py(10 项:音频+歌词随迁 / ID3 兜底 / 元数据双空保持缓存形态 / 转存在途去重 / 失败回退后台下载 / 转存后即时登记 / 轮询去重与清理 / 对账串行不重叠 / seed 过滤滚动缓存 / 列表自愈端到端)。
- 滚动缓存转存带歌词:红心触达的试听缓存定名挪进曲库时,除随迁已有
升级说明
- 从 v3.4.x 升级:登录态、设备勾选、歌单、audio_id 缓存、待关联条目全部保留(conf 目录不变);无需重新配置。
- 前端改动(深色主题/设置页/向导步骤条):升级后**强刷浏览器(Ctrl+F5)**即可看到新界面。
- 收藏绑定改动位于代理侧,升级即时生效;建议升级后打开一次收藏页触发对账自愈。
- sha256(fnmusic-ext-3.5.0.fpk):
5959a18e37c040c1679000ceb210a00359d76cf18f7a4dc48028b0cffdf35912
v3.4.2 向导完成态修复 + 菜单红点移除
v3.4.2
修复
- 小爱音箱配置向导"完成"步骤不显示绿色对勾(用户反馈):完成后端返回
step=4,而步骤条规则是n < step ? done : active——第 4 步"完成"永远落在蓝色active上显示数字 4。修复:完成页(step >= 步骤总数)时全部步骤(含"完成")点亮为绿色 ✓。管理台与旁路页(8775)同步修复。
变更
- 管理台「关于」「小爱音箱」菜单移除红点(用户要求):删除桌面侧栏与移动端底栏共 4 个红点元素及
xmUpdateNavDot逻辑。登录失效 / 轮询降频等异常状态的展示不受影响——小爱音箱页"完成页健康检查"本就有醒目提示。
升级说明
- 从 v3.3.x / v3.4.0 / v3.4.1 升级:登录态、设备勾选、歌单、audio_id 缓存全部保留(conf 目录不变);无需重新配置。
- 纯前端改动,升级后强刷浏览器(Ctrl+F5)即可看到新界面。
详见 CHANGELOG.md。
v3.4.1 带屏小爱播放界面 audio_id 解析
v3.4.1
新增
-
带屏设备播放界面 audio_id 解析:修复"屏幕显示错歌"(用户真机反馈)
X4B 等带屏音箱播放时,屏幕上的歌名/歌手/封面/歌词由 mina ubus
player_play_music指令里的audio_id对应的小米曲库记录决定(播放内容是桥接 URL,两者本无绑定)。上游_get_audio_id按「歌名-歌手」拆名,而歌单条目名是「歌手 - 歌名」(artist 在前),拆分后与曲库歌名永远不相等,只能掉到搜索结果第一首兜底——蒙对显示正确、蒙错显示另一首歌(即"偶尔显示错误"的根因)。- 预解析:歌单重建后后台批量解析全部条目并落盘
bridge/audio_id_cache.json(重启不丢;负缓存防反复打接口;接口异常中止本轮且不写负缓存,登录恢复后自动重试) - 标题规范化:繁→简(opencc,容器必装依赖)+ NFKC 全半角 + 去 feat./Live/Remix/- Remastered 等修饰后缀
- 三级匹配:严格(歌名相等+歌手互含)→ 宽松(歌名相等)→ 近似(歌名互含)
- 播放兜底:仅对走
play_music路径的设备(X4B 等)生效,其余设备照搬上游行为 /health暴露audio_id_cache统计(resolved / negative)- 实测(275 首收藏,真机 NAS):预解析 266 首命中(96.7%),约 100 秒跑完
- 已知边界:audio_id 只影响屏幕显示与歌词时间轴,不决定播放内容;曲库确实没有的歌只能显示默认占位(与上游一致)
- 预解析:歌单重建后后台批量解析全部条目并落盘
-
测试:新增
test_audio_id_resolver.py(25 项)
升级说明
- 从 v3.3.x / v3.4.0 升级:登录态、设备勾选、歌单、audio_id 缓存全部保留(conf 目录不变);无需重新配置。
- 预解析在歌单重建后自动进行,无需手动触发;首次约 1-2 分钟后台完成。
详见 CHANGELOG.md。
fnmusic-ext v3.4.0
v3.4.0
变更
- 移除 xiaomusic 引擎,native 成为唯一口令引擎(双引擎灰度期结束——native 已于 v3.3.4 在 X4B/L05B/LX06 三台真实设备完成全链路验证):
- 删除 XiaoMusic 主类集成、
/xm/*api 子应用挂载、POST /api/engine切换端点、engine配置字段、全部双引擎分支代码与/proxy/music根级转发(app.py-285 行); - 小米登录仍 100% 使用上游代码(
miservice+AuthManager+MiJiaAPI扫码),未做任何改动。
- 删除 XiaoMusic 主类集成、
- 依赖裁剪:
xiaomusic改--no-deps安装 + 精选传递依赖(requirements-core.txt,10 项,经 ast + 运行时双重导入追踪与干净 venv 全链路实测验证)。镜像不再携带 yt-dlp(25M)、sentry-sdk、apscheduler、watchdog、ga4mp、aiofiles、psutil、pyjwt、python-multipart。 - 管理台易用性:小爱音箱完成页移除「xiaomusic 高级设置」入口(其指向的
/xm/页面随引擎一并移除);口令表点歌描述更新为「本地曲库直接播 / 在线源下载,都不进收藏」。 - 测试:单一引擎断言(无切换端点/无
/xm挂载/无引擎分支/无死代码残留)+ 依赖清单与 Dockerfile--no-deps断言 + WebUI 入口移除断言;修复import app组合运行串味(按文件路径加载)与本地重定向测试服务器请求体未消费导致的偶发ReadError。
升级说明
- 从 v3.3.x 升级:登录态、设备勾选、歌单全部保留(conf 目录不变);原
engine配置字段被忽略(不再有意义),无需手动清理。 - 依赖精简在镜像构建时生效——已安装的应用热更新代码不重装镜像,依赖不变;重装/升级 FPK 后镜像即为精简版。
详见 CHANGELOG.md。