Skip to content

合并 upstream/dev 并增强备份快照回滚与缓存一致性 - #506

Closed
pyss56 wants to merge 37 commits into
XCQ0607:devfrom
pyss56:dev
Closed

pyss56 wants to merge 37 commits into
XCQ0607:devfrom
pyss56:dev

Conversation

@pyss56

@pyss56 pyss56 commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

概述

本 PR 将上游 XCQ0607/dev 的最新提交合并进 pyss56/dev,并在此基础上补入备份管理、回滚与缓存一致性增强。合并过程仅 public/js/config.js 一处版本号冲突,已按上游版本号对齐(v2.1.4)。

主要变更

1. 备份管理页 — 歌单快照类型展示与筛选

  • 快照列表每条新增类型角标:蓝色「我的歌单」/ 红色「我不喜欢」,便于一眼区分。
  • 查询条件由快捷标签改为「全部类型 / 我的歌单 / 我不喜欢」下拉筛选(元素 #snapshot-kind-filter),按 kind 字段过滤快照。
  • 修复类型标签此前被 .col-id 的 text-overflow: ellipsis 截断不可见的问题:.col-id 改为 flex 布局,ID 文本单独省略号截断,kind-tag 固定显示(桌面与移动端均已调整)。

2. 「我不喜欢」快照支持回滚

  • 此前回滚接口仅支持歌单(list)数据。现已补齐 dislike 回滚完整链路:
    • dislikeDataManage.restore(data):从指定快照内容恢复当前 dislike 规则。
    • DislikeManage.restoreSnapshot(name):取快照 → restore → clearClients() + setLatest()(在 DislikeSnapshotDataManage 中补齐 clearClients / setLatest 方法)。
    • 后端 /api/data/restore-snapshot 接收 kind 参数,按 list / dislike 分流调用对应恢复逻辑。
  • 前端「我不喜欢」快照记录区复用歌单回滚按钮与确认流程(同一提示文案),无需重复实现。

3. 回滚后主动失效派生缓存(缓存一致性)

  • 回滚成功后按类型失效对应派生缓存,避免旧数据在缓存 TTL 内继续被返回:
    • list 回滚 → 新增 invalidateSubsonicPlaylistCache()(subsonic 模块导出):清空 playlistDetailCache(原 10 分钟 TTL)、playlistRadioCache、sharedPlaylistCoverCache、leaderboardCoverCache,消除 Subsonic API 最长 10 分钟的陈旧歌单窗口。
    • dislike 回滚 → 调用已有的 invalidateDislikeCache(username),消除「过滤不喜欢」最长 30 秒陈旧。
  • 说明:缓存失效为服务端内存级,当前单实例部署完全生效;若多实例横向扩展则需改为跨实例广播失效。

4. 其它 UI / 可观测性优化

  • 启动日志打印当前版本号:LX Music Server version: vX.Y.Z(读取 package.json),便于通过 docker logs 确认实际运行版本。
  • 记录详情弹窗:补齐缺失的 .olb-detail-table / .olb-detail-key / .olb-detail-val 样式,修复「更多」弹窗布局挤压;弹窗标题与名称列只显示文件名,hover 提示显示完整路径。
  • 修复「我不喜欢」快照导出为空 playList_v2 的 bug。

版本号

config.js 与 package.json 版本号已对齐上游 v2.1.4,避免强加 fork 版本号。

验证

  • 前端 node --check 语法校验通过;后端代码经 TypeScript 编译验证。
  • 部署镜像后确认:快照列表类型标签正常显示、下拉筛选可用;回滚「我的歌单」后 Subsonic 歌单立即刷新,回滚「我不喜欢」后过滤规则立即生效。

🎯 核心变更

本次 PR 合并上游改动,并增强快照管理、恢复和备份能力。用户可按类型筛选歌单与「我不喜欢」快照,并恢复对应数据;恢复后会清理相关缓存。

📝 主要改动点

  • 增加「我不喜欢」快照的列表、读取、下载、删除和恢复支持。恢复接口 /api/data/restore-snapshot 根据 kind 选择快照类型。
  • 快照写入时支持本地备份和云端同步;删除时清理对应本地副本。配置备份支持按小时设置周期和锚点时间,并清理过期配置备份及快照副本。
  • OpenList 备份增加系统配置、用户数据和歌单快照处理,支持批量重试、记录筛选和快照类型展示,并调整 upload-delete 的保护规则。
  • 更新备份管理页面、快照筛选和记录详情展示;启动日志增加应用版本号。
  • Docker 工作流增加 dev 和 main 分支推送触发,并调整 GHCR 登录和镜像标签配置。

⚠️ 影响与注意事项

  • 移除 openlist.keepLocalAfterUpload 配置项。未指定 OpenList 条目模式时,默认使用 upload。
  • upload-delete 不会删除受保护的系统配置、用户数据和歌单快照。
  • 缓存失效作用于服务端内存;多实例部署需要跨实例同步缓存失效。
  • 当前 PR head 的 CI、构建和测试结果:not available。

pyss56 added 30 commits October 27, 2026 13:54
…delete backups

When a per-user OpenList backup uses the upload-delete mode, the local cache index is purged after a verified upload, so the next playback has no local cache. To keep OpenList as the permanent cache (instead of re-downloading from source), the Subsonic 'cache-first use OpenList' switch is now auto-enabled on save.

UI (app.js): warn when a backup mode is switched to upload-delete, and persist subsonic.playCacheFirstUseOpenlist=true together with the OpenList config.

fileCache: the restore-from-OpenList path stays globally reachable because OpenList upload backup is itself globally triggered, keeping upload/restore symmetric.

The openlist server module blobs are committed as clean UTF-8.
- 歌单/不喜欢快照落盘后防抖触发云端备份(scheduleOpenlistSync),按 snapshots 类型上传 - 快照落盘后按 configBackup.enable 门控写本地副本到 data/backups/snapshots/<user>/ - 删除快照时清理对应本地副本 - 前端配置备份周期 UI(每N小时+锚点时间,显示下次/上次备份时间) - 版本号 2.1.4.2 -> 2.1.4.3
- effectiveModeFromRow 对 system/data/list 三类禁止 upload-delete,回退为 upload(即便关闭 keepLocalAfterUpload 或条目显式设为 upload-delete) - 删除分支(fs.unlinkSync)显式排除受保护类型,双保险 - 仅 cache/music 仍可按 upload-delete 不保留本地(歌曲缓存删除不影响业务) - 版本号 2.1.4.3 -> 2.1.4.4
- 移除冗余 openlist.keepLocalAfterUpload:同步模式唯一来源为 userBackups[].mode,未配置默认 upload(保留本地),仅显式 upload-delete 删本地 - upload-delete 不对 system/data/list(系统配置与歌单/不喜欢快照)生效,legacy list 入库强制 upload - 本地快照备份加时间戳(snapshot_<name>-<YYYY-MM-DD_HHmmss>[-n]),不覆盖历史;纳入 configBackup.retentionDays 保留期清理;删除快照时清理全部历史副本 - OpenList 额外保留带时间戳的系统配置时间点副本(_system/config-history/),按内容指纹去重、按保留期清理;主镜像文件名不变、不参与恢复 - 版本号 2.1.4.4 -> 2.1.4.5
- 同步模式下拉选项改为「上传后删除本地(仅歌曲/歌词)」 - 帮助文案与选择弹窗明确:仅删除下载/缓存目录中已上传的歌曲及其歌词、封面等附件并清缓存索引;系统配置、歌单与不喜欢快照、用户数据一律保留本地 - index.html 横幅与「播放缓存同时上传封面与歌词」开关描述同步补充该边界 - 版本号 2.1.4.5 -> 2.1.4.6
- dislike/snapshotDataManage 新增 updateSnapshotDir,写入 <备份路径>/<用户>/dislike/snapshot(与歌单快照区分),含历史迁移

- user/index updateAllUserSnapshotDirs 同步热迁移 dislike 快照目录

- backupPolicy scanBackupFiles 外部快照扫描覆盖 dislike 子目录

- openlistBackup 传统模式歌单+dislike 快照对所有真实用户备份,脱离 userBackups 勾选
统计卡此前基于全量记录,与下方按 folder scope 过滤的列表口径不一致,导致混合总数;现将 scope 过滤提前至统计之前并复用同一份列表。
margeConfig 合并时,若原始 config 缺失 subsonic.standalone 键且 subsonic.port>0,默认视为开启独立端口,还原旧版「端口有值即监听」语义;用户显式设为 false 时尊重其意图不被覆盖。热重载逻辑本就缺键不覆盖,不会回归。
- OpenList 同步页「歌单快照」tab 纳入 selectedData 模式下 folder_type='data' 且路径含 snapshot 的 list/dislike 记录

- 备份管理页 /api/data/snapshots 合并 list 与 dislike 快照(标记 kind),下载/删除接口支持 dislike 回退

- 前端对 dislike 快照隐藏「恢复」按钮(恢复逻辑仅适用于歌单快照)
统一数据备份(selectedData)模式下,歌单/不喜欢快照等记录的 user 被记为 _system,但路径含 users/<dirName>。

listBackups 出口按路径把 _system 记录映射回真实逻辑用户名(如 m_6f8f57->m),使 OpenList 同步页按用户筛选能正确归位,修复#1091 类问题。

仅覆盖展示层 user 字段,不改写 DB,避免破坏 openlist_local_files 的 user 一致性与唯一约束。
- package.json version 同步至 v2.1.4.10,使 docker.yml 打 tag 与前端 config.js 版本一致(此前 build 用 package.json 版本覆盖 config.js,导致 :dev 镜像内版本恒为 2.1.4.8、:v2.1.4.10 tag 从未生成)。

- 移除 docker.yml 的 cache-from/to: type=gha:仅改源码不改 Dockerfile 时 gha 缓存命中旧 builder 层,使 f208f5a 的 openlistBackup.ts(user 路径映射) 改动未进 :dev 镜像。
此前仅去 gha cache 仍命中 buildx 本地层缓存,RUN npm run build 复用了 9e7d2f7 的旧编译产物,导致 f208f5a 的 openlistBackup.ts(user 路径映射) 改动未进镜像。

加 no-cache: true 让每次构建从零 npm ci + build,彻底避免源码变更不重新编译的问题。
备份管理页「歌单快照」tab 内新增子页签「全部 / 歌单快照 / 不喜欢」,可一键只看 dislike 快照;

dislike 条目加红色「不喜欢」角标,混排时也能一眼识别(此前仅隐藏回滚按钮导致无法辨认)。

纯前端改动,复用 /api/data/snapshots 已有的 kind 字段过滤,无后端变更。version -> v2.1.4.11。
下载按钮此前对所有快照无条件套用 playList_v2 转换:dislike 数据({dislikeList:[...]})的 defaultList/loveList/userList 均为 undefined,导致导出成空壳 default/love 列表,用户误以为 dislike 无歌曲信息。

现 downloadSnapshot(id,kind) 按 kind 分流:dislike 直接导出原始规则(lx_dislike_<user>_<id>.json),list 仍导出 playList_v2;按钮调用处传入 item.kind。version -> v2.1.4.12。
1) 主快照管理页每条记录显示双向类型标签(我的歌单=蓝/我不喜欢=红),在「全部」子页签下也能一眼区分;

2) OpenList 同步页歌单快照记录同样显示类型标签;查询区新增「全部类型/我的歌单/我不喜欢」下拉,按类型过滤(仅歌单快照页生效)。version -> v2.1.4.13。
1) server.ts 启动时读取 package.json 并打印「LX Music Server version: vX.Y.Z」,docker logs 可直接确认运行版本;

2) 补齐 olb-detail-table/key/val 缺失样式(此前无样式 table 挤成一字一行),修复「更多」弹窗布局;弹窗标题只显示文件名;

3) OpenList 歌单记录名称列只显示文件名(basename),hover 提示显示完整路径。version -> v2.1.4.14。
1) 备份管理页歌单快照:类型快捷标签改为「全部类型/我的歌单/我不喜欢」下拉查询;列表每条保留类型标签;

2) 不喜欢快照支持回滚:dislikeDataManage.restore + DislikeManage.restoreSnapshot + 后端 /api/data/restore-snapshot 按 kind 分流,复用 list 回滚逻辑框架;

3) 前端 restoreSnapshot(id,kind) 抽成通用回滚入口(list/dislike 共用),后续 openlist 页也可复用。version -> v2.1.4.15。
col-id 原为 inline-block + nowrap + ellipsis + max-width:fit-content,长 ID 后的类型标签(我的歌单/我不喜欢)被整体截断。改为 flex 布局:ID 文本用 col-id-text 单独省略号截断,kind-tag flex-shrink:0 固定显示;移动端同步调整。version -> v2.1.4.16。
1) subsonic 新增 invalidateSubsonicPlaylistCache():回滚后清空 playlistDetailCache / playlistRadioCache / sharedPlaylistCoverCache / leaderboardCoverCache,避免 Subsonic API 在 TTL(10min) 内返回陈旧歌单;

2) 回滚路由(/api/data/restore-snapshot)按 kind 分流后调用对应失效:list -> invalidateSubsonicPlaylistCache(),dislike -> 已有的 invalidateDislikeCache(username)。version -> v2.1.4.17。
# Conflicts:
#	public/js/config.js
@coderabbitai

coderabbitai Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Explain Change →

Caution

Review failed

The pull request is closed.

Walkthrough

本次变更增加配置备份周期和状态管理,扩展歌单与不喜欢快照的保存、恢复和筛选,并调整 OpenList 备份策略及记录操作。Docker 工作流改为面向 GHCR 的分支构建。另有 Subsonic 配置默认值、沙箱控制台调用和启动版本日志调整。

Changes: 配置自动备份

Layer / File(s) Summary
配置项与接口字段
src/types/config.d.ts, src/types/app.d.ts
新增备份周期、时间锚点和备份状态字段。
备份执行与清理调度
src/index.ts
配置备份按小时周期槽位执行;过期清理使用独立的每日定时器。
配置接口与管理页面
src/server/server.ts, public/app.js, public/index.html
服务器校验备份设置并返回备份状态;页面提供周期、时间锚点及上次和下次备份时间。

快照存储与恢复

Layer / File(s) Summary
本地快照副本与目录
src/index.ts, src/modules/dislike/snapshotDataManage.ts, src/user/index.ts, src/utils/backupPolicy.ts
配置备份目录保存和清理快照副本。不喜欢快照目录支持路径更新、文件迁移及外部目录映射。
快照保存与元数据
src/modules/list/snapshotDataManage.ts, src/modules/dislike/snapshotDataManage.ts
保存歌单或不喜欢快照时触发可选的云端同步和本地备份;不喜欢快照增加元数据操作。
不喜欢快照恢复与缓存失效
src/modules/dislike/dislikeDataManage.ts, src/modules/dislike/manage.ts, src/server/integrations/subsonic.ts, src/server/server.ts
恢复接口按类型读取或恢复快照,并使对应缓存失效;删除接口可处理两类快照。
快照列表与类型操作
public/app.js
页面支持按类型筛选、下载和恢复快照。不喜欢快照下载为原始规则数据。

OpenList 备份与记录

Layer / File(s) Summary
本地保留与上传模式
src/defaultConfig.ts, src/types/config.d.ts, src/server/openlistBackup.ts
移除全局本地保留配置。系统、数据和歌单类型不使用上传后删除模式。
快照、系统配置与存量文件同步
src/server/openlistBackup.ts
同步流程增加快照备份、系统配置历史副本和存量文件回填。
服务端配置、回填与批量重试
src/server/server.ts
符合条件的 OpenList 规则会触发存量回填;新增管理员批量重试接口。
记录分类、筛选与操作
public/app.js, public/index.html, public/style.css
记录页面增加分类、快照类型筛选、批量重试和详情展示;更新页面说明、表格及导航样式。

Docker 发布工作流

Layer / File(s) Summary
分支构建与镜像发布
.github/workflows/docker.yml
工作流新增 dev 和 main 分支 push 触发器,使用 GHCR 凭据,并按分支设置镜像标签。

Subsonic 启动配置

Layer / File(s) Summary
独立模式默认值
src/index.ts
未显式设置独立模式且 Subsonic 端口大于零时,配置合并逻辑将独立模式设为启用。

调试控制台调用

Layer / File(s) Summary
沙箱控制台调用
src/server/sources/userApi.ts
rawSandboxConsole.dir 改为通过类型断言调用 console.dir。

启动版本日志

Layer / File(s) Summary
启动版本信息
src/server/server.ts
服务器启动时记录应用版本;无法读取版本时记录 unknown。

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant App as 管理页面
  participant Server as 快照 API
  participant DislikeManage as 不喜欢快照管理器
  participant SnapshotStore as 快照存储
  participant Cache as 播放列表缓存

  App->>Server: 提交快照 ID 和 kind
  Server->>DislikeManage: 按 kind 请求恢复
  DislikeManage->>SnapshotStore: 读取指定快照
  SnapshotStore-->>DislikeManage: 返回快照数据
  DislikeManage-->>Server: 恢复规则并更新快照状态
  Server->>Cache: 使对应缓存失效
  Server-->>App: 返回恢复结果
Loading

Possibly related issues

Suggested reviewers: xcq0607

Merge Risk: High · up to 4bcd0

This change can delete local music files without confirming the cloud copy still exists, can wipe or lose "dislike" rules during restore or directory changes, may spin in a backup loop for long intervals, forgets backup schedule settings after restart, and the image workflow can overwrite or delete published images. These should be fixed before merging.

- [ ] Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@pyss56

pyss56 commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

已由 #507 替代:本 PR 移除了 fork 私有的 GHCR/CI 配置(.github/workflows/docker.yml),新 PR 已基于干净分支 pr-upstream-clean 提交,欢迎 review。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant