Skip to content

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

Closed
pyss56 wants to merge 38 commits into
XCQ0607:devfrom
pyss56:pr-upstream-clean
Closed

pyss56 wants to merge 38 commits into
XCQ0607:devfrom
pyss56:pr-upstream-clean

Conversation

@pyss56

@pyss56 pyss56 commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

概述

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

注:本 PR 已排除 .github/workflows/docker.yml(fork 私有的 GHCR/CI 配置,未纳入上游),以避免强加上游不兼容的构建/推送配置与密钥引用。

主要变更

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 歌单立即刷新,回滚「我不喜欢」后过滤规则立即生效。

🎯 核心变更

扩展快照管理与 OpenList 备份流程,新增不喜欢快照的列表、下载、恢复和删除支持,并在恢复后清理相关缓存。配置备份支持自定义周期和计划时间,同时补充本地快照备份及 OpenList 历史配置备份。

📝 主要改动点

  • 快照管理: API 和管理页区分歌单与不喜欢快照,增加类型筛选和类型标识。不喜欢快照导出原始规则数据;恢复时按类型分流,并触发对应缓存失效。
  • 配置备份: 新增备份间隔和计划时间配置,管理页显示下次及上次备份时间。快照保存时可创建带时间戳的本地副本,删除快照时清理对应副本。
  • OpenList: 增加系统配置历史副本、歌单及不喜欢快照同步、批量重试和存量文件回填。upload-delete 保护系统配置、数据及快照记录;管理页新增记录分页签、类型筛选和详情入口。
  • 界面与日志: 调整备份记录布局和时间显示,启动日志增加版本号。

⚠️ 影响与注意事项

  • 移除 openlist.keepLocalAfterUpload 配置项。OpenList 未指定模式的记录默认使用 upload;配置为 upload-delete 时,删除范围限于符合条件的歌曲及附件。
  • 配置备份默认间隔为 24 小时,默认计划时间为 00:00。
  • 当前提供的差异结果未包含 CI、构建或测试的执行结果,验证状态不可用。

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 备份规则、记录筛选及批量重试界面。

Changes: 备份与快照管理

Layer / File(s) Summary
配置备份调度与本地副本
src/types/config.d.ts, src/types/app.d.ts, src/index.ts, src/server/server.ts, public/index.html, public/app.js
配置备份新增周期小时数和时间锚点。服务端新增定时重设,并返回下次与上次备份时间。配置备份清理同时清理过期快照副本。
歌单与不喜欢快照生命周期
src/modules/dislike/*, src/modules/list/snapshotDataManage.ts, src/server/server.ts, src/server/integrations/subsonic.ts, src/user/index.ts, src/utils/backupPolicy.ts, public/app.js
不喜欢快照新增恢复、目录更新、文件迁移和元数据管理。歌单与不喜欢快照接入本地备份及快照 API;界面支持按类型筛选、下载和恢复。
OpenList 备份规则与同步
src/server/openlistBackup.ts, src/server/server.ts, src/defaultConfig.ts, src/types/config.d.ts
移除 openlist.keepLocalAfterUpload。系统配置、数据和快照类型受上传后删除保护。同步增加快照备份、系统配置历史副本和存量文件回填。
备份记录与管理界面
public/app.js, public/index.html, public/style.css, src/server/server.ts
OpenList 记录页按媒体、系统配置和快照分类,并增加筛选、详情与批量重试。快照记录可区分歌单和不喜欢类型。相关时间显示改为中文 24 小时制。

运行时调整

Layer / File(s) Summary
配置与运行时兼容调整
src/index.ts, src/server/server.ts, src/server/sources/userApi.ts
配置未显式设置 subsonic.standalone 且端口大于零时,合并后的配置将其设为开启。启动日志增加版本号;调试目录输出改用类型转换后的 console 调用。

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

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant SnapshotUI
  participant SnapshotAPI
  participant DislikeManage
  participant DislikeDataManage
  participant SnapshotDataManage
  participant SubsonicCache
  SnapshotUI->>SnapshotAPI: 提交快照 id 和 kind
  SnapshotAPI->>DislikeManage: 恢复指定不喜欢快照
  DislikeManage->>DislikeDataManage: 恢复 dislike 数据
  DislikeManage->>SnapshotDataManage: 清除客户端记录并设置最新快照
  SnapshotAPI->>SubsonicCache: 使不喜欢缓存失效
Loading

Possibly related PRs

Suggested reviewers: xcq0607

Merge Risk: Moderate · up to 0003d

The new backup and snapshot features have several functional bugs. Deleting a "我不喜欢" snapshot reports success but keeps the file, and a restored snapshot can later be cleaned up, losing the rules after a restart. Long backup intervals can make the scheduler spin, and some OpenList records are hidden or stay pending. These should be fixed before merge.

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

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 closed this Nov 5, 2026
@pyss56
pyss56 deleted the pr-upstream-clean branch November 5, 2026 10:33
@pyss56

pyss56 commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

已重新整理提交:本 PR 现基于 upstream/dev 干净基底,提交历史不再含「改了又改回」的噪音,且排除了 fork 私有的 GHCR/CI 配置(.github/workflows/docker.yml)。请重新 review。

@pyss56

pyss56 commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

本 PR 已关闭,由 #508 替代。

原因:本 PR 的 head 分支 pr-upstream-clean 在整理提交时被删除,且其中混杂了 fork 私有的 CI / GHCR 构建提交、版本号 bump 与临时合并提交,commit 历史不适合上游 review。

新 PR 改为基于 upstream/dev 的干净单 commit 分支 pyss56:upstream-pr:仅含通用功能改动,不含 .github/workflows/docker.yml 变更、不含任何版本号改动。

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