Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
f598aab
fix: 侧栏滚动条与 userApi 类型小修复
pyss56 Oct 23, 2026
ca7407d
Merge branch 'feat/ui-typing-fixes-20261023' into dev
pyss56 Oct 27, 2026
c72b778
feat(openlist): 缓存未命中优先从 OpenList 取回/直链交付,新增外网地址与交付方式配置 (v2.1.4.1)
pyss56 Oct 28, 2026
b20d33b
feat(openlist): auto-enable Subsonic OpenList cache-first for upload-…
pyss56 Oct 29, 2026
313f705
chore(openlist): 移除源码文件 UTF-8 BOM 头
pyss56 Oct 29, 2026
519c18d
ci(docker): 恢复 dev/main 分支 push 触发镜像构建
pyss56 Oct 29, 2026
ee601cb
Merge feat/openlist-upstream into dev: 带入 CodeRabbit 评审修复(安全/XSS/超时/大…
pyss56 Oct 30, 2026
7626604
ci: trigger dev build (CodeRabbit 修复已合入 dev)
pyss56 Oct 30, 2026
b812d78
ci: 仅推送 ghcr.io,移除缺失密钥的 Docker Hub 登录步骤(修复 build_and_push 失败)
pyss56 Oct 30, 2026
d932dc3
ci: ghcr.io 登录改用 GHCR_TOKEN(与成功运行 39806164426 一致,修复 build/push 推送被拒)
pyss56 Oct 30, 2026
b385bd4
Merge remote-tracking branch 'upstream/dev' into dev
pyss56 Nov 4, 2026
e4490e6
feat(backup): 本地配置备份支持每N小时+锚点时间(默认每天0点),并显示下次/上次备份时间
pyss56 Nov 4, 2026
2d7eef0
chore(release): v2.1.4.3 - 快照创建触发云端与本地备份
pyss56 Nov 4, 2026
1e80f71
fix(backup): 硬保护——upload-delete 不得删除本地配置与快照
pyss56 Nov 4, 2026
dcc823f
feat(backup): 备份可回溯 + 同步模式单一来源
pyss56 Nov 4, 2026
7f73466
docs(ui): 说明 upload-delete 仅删除下载/缓存歌曲及歌词附件
pyss56 Nov 4, 2026
301ab62
feat(openlist): batch retry + media/system/snapshot tabs, dev-tag CI …
pyss56 Nov 5, 2026
16adde3
fix: repair broken version field in package.json (v2.1.4.7)
pyss56 Nov 5, 2026
929b7af
feat(backup): 将 dislike 快照接入 snapshot.backupPath 与传统 OpenList 备份,对所有用户生效
pyss56 Nov 5, 2026
75afde9
fix(ui): OpenList 同步记录状态卡片按当前页签(媒体/系统/快照)过滤统计口径
pyss56 Nov 5, 2026
6a6058a
chore(release): bump version to 2.1.4.8 (dislike 快照备份接入 + 同步记录页签过滤)
pyss56 Nov 5, 2026
c210a07
fix(config): Subsonic 独立端口向后兼容,旧配置升级后不再静默关闭
pyss56 Nov 5, 2026
9e7d2f7
fix(ui+server): 歌单快照页显示 dislike 快照(含 selectedData 模式 data 类型)
pyss56 Nov 5, 2026
ec947c2
chore: 版本号 bump 至 v2.1.4.9(含 Subsonic 独立端口兼容 + 歌单快照 dislike 显示修复)
pyss56 Nov 5, 2026
f208f5a
fix(openlist): 备份记录按路径映射真实用户,纠正 _system 误归属
pyss56 Nov 5, 2026
a500e59
build(ci): 修复 dev 镜像未嵌入最新代码(统一版本号源 + 移除 gha 缓存)
pyss56 Nov 5, 2026
f05a3b9
build(ci): 强制无缓存构建,确保最新 server 源码编译进 :dev 镜像
pyss56 Nov 5, 2026
c8286fd
feat(ui): 歌单快照增加「不喜欢」类型角标与独立子页签
pyss56 Nov 5, 2026
dce64fb
fix(ui): 修复「不喜欢」快照下载导出为空 playList_v2 的 bug
pyss56 Nov 5, 2026
f6c9419
feat(ui): 歌单快照列表增加「我的歌单/我不喜欢」类型标签
pyss56 Nov 5, 2026
ad0f69e
feat(log)+fix(ui): 启动日志打印版本;修复记录详情弹窗布局与名称列
pyss56 Nov 5, 2026
79f655f
feat: 歌单快照查询改下拉;不喜欢快照支持回滚(抽通用方法)
pyss56 Nov 5, 2026
a615b90
fix(ui): 快照列表类型标签被 col-id 截断不可见
pyss56 Nov 5, 2026
3dd357b
feat: 回滚成功后主动失效派生缓存
pyss56 Nov 5, 2026
ebe1e7d
Merge remote-tracking branch 'upstream/dev' into dev
pyss56 Nov 5, 2026
50faf97
chore: PR 中 config.js 版本号对齐上游 v2.1.4
pyss56 Nov 5, 2026
4bcd078
chore: PR 中 package.json 版本号对齐上游 2.1.4
pyss56 Nov 5, 2026
0003d1a
chore: 从上游 PR 中排除 GHCR/docker.yml 改动(恢复与上游一致)
pyss56 Nov 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
243 changes: 199 additions & 44 deletions public/app.js

Large diffs are not rendered by default.

61 changes: 55 additions & 6 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,20 @@ <h3 class="config-card-title">备份与恢复</h3>
</div>
</div>
<div class="config-divider"></div>
<div class="config-field-row">
<div class="config-field">
<label class="config-label">备份周期(小时)</label>
<input type="number" name="configBackup.intervalHours"
class="form-input config-input" min="1" max="8760" placeholder="24" />
<small class="config-hint">每 N 小时自动备份一次</small>
</div>
<div class="config-field">
<label class="config-label">锚点时间</label>
<input type="time" name="configBackup.scheduleTime" class="form-input config-input" />
<small class="config-hint">留空=进程启动后每 N 小时;填 HH:MM 则在该时刻首次触发,之后每 N 小时循环</small>
</div>
</div>
<div class="config-divider"></div>
<div class="config-field">
<label class="config-label">歌单快照备份路径</label>
<input type="text" name="snapshot.backupPath" class="form-input config-input"
Expand Down Expand Up @@ -2301,6 +2315,14 @@ <h3>备份与恢复管理</h3>
<div class="meta-value text-truncate" id="config-backup-dir-text" title="backups">
backups</div>
</div>
<div class="config-backup-meta-item">
<div class="meta-label">下一次自动备份</div>
<div class="meta-value" id="config-backup-next-text">—</div>
</div>
<div class="config-backup-meta-item">
<div class="meta-label">上次自动备份</div>
<div class="meta-value" id="config-backup-last-text">—</div>
</div>
</div>
<div class="config-backup-actions-wrap">
<button type="button" class="btn-primary" id="btn-backup-config-now"
Expand Down Expand Up @@ -2412,15 +2434,30 @@ <h3>备份与恢复管理</h3>
</svg>
<span>备份配置</span>
</button>
<button type="button" class="backup-tab-btn" id="tab-btn-openlist-records" onclick="app.switchOpenlistTab('records')">
<button type="button" class="backup-tab-btn" id="tab-btn-openlist-media" onclick="app.switchOpenlistTab('media')">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:16px;height:16px;">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
<span>文件记录</span>
<span>媒体文件记录</span>
</button>
<button type="button" class="backup-tab-btn" id="tab-btn-openlist-system" onclick="app.switchOpenlistTab('system')">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:16px;height:16px;">
<circle cx="12" cy="12" r="3"></circle>
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
</svg>
<span>系统配置记录</span>
</button>
<button type="button" class="backup-tab-btn" id="tab-btn-openlist-snapshot" onclick="app.switchOpenlistTab('snapshot')">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:16px;height:16px;">
<path d="M9 18V5l12-2v13"></path>
<circle cx="6" cy="18" r="3"></circle>
<circle cx="18" cy="16" r="3"></circle>
</svg>
<span>歌单快照记录</span>
</button>
</div>
<div id="openlist-pane-config" class="backup-tab-pane active">
Expand Down Expand Up @@ -2503,9 +2540,9 @@ <h3 class="config-card-title">OpenList 连接</h3>
<div class="config-toggle-info">
<span class="config-toggle-label">
<span>播放缓存同时上传封面与歌词</span>
<span class="help-icon" role="button" tabindex="0" onclick="app.toggleHelp(this)" data-help="开启后,下载 / 缓存目录里的图片和歌词也会一并上传">?</span>
<span class="help-icon" role="button" tabindex="0" onclick="app.toggleHelp(this)" data-help="开启后,下载 / 缓存目录里的图片和歌词会随歌曲一并上传;在「上传后删除本地」模式下,这些附件也会随歌曲一起从本地删除">?</span>
</span>
<span class="config-toggle-desc">随同音频文件自动备份其本地封面图片与歌词文本</span>
<span class="config-toggle-desc">随同音频文件自动备份其本地封面图片与歌词文本;「上传后删除本地」模式下会一并删除</span>
</div>
<label class="toggle-switch">
<input type="checkbox" name="openlist.includeNonAudio" />
Expand All @@ -2518,7 +2555,7 @@ <h3 class="config-card-title">OpenList 连接</h3>
<line x1="12" y1="16" x2="12" y2="12"></line>
<line x1="12" y1="8" x2="12.01" y2="8"></line>
</svg>
<span>数据备份类型请在「系统设置 → 云端备份范围」中选择。常规备份只上传并保留本地;如需恢复请使用下方恢复按钮。</span>
<span>数据备份类型请在「系统设置 → 云端备份范围」中选择。常规备份只上传并保留本地。「上传后删除本地」仅对下载 / 缓存目录中的歌曲及其歌词、封面等附件生效;系统配置、歌单与不喜欢快照、用户数据一律保留本地,不受该模式影响。如需恢复请使用下方恢复按钮。</span>
</div>
<div class="config-divider"></div>
<div class="config-field">
Expand Down Expand Up @@ -2602,7 +2639,7 @@ <h3 class="config-card-title">OpenList 连接</h3>
</div>
<div>
<h3 class="config-card-title">
<span>同步状态与文件记录</span>
<span>同步记录(媒体文件 / 系统配置 / 歌单快照)</span>
<span class="help-icon" role="button" tabindex="0" onclick="app.toggleHelp(this)" data-help="查看已备份文件与同步结果(含图片等附件计数)">?</span>
</h3>
<p class="config-card-desc">实时查看文件备份进度、验证状态及失败重试</p>
Expand All @@ -2620,6 +2657,13 @@ <h3 class="config-card-title">
</svg>
立即全量同步
</button>
<button type="button" id="olb-bulkretry" class="btn-secondary" onclick="app.retrySelectedOpenlist()" disabled>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:15px;height:15px;">
<polyline points="23 4 23 10 17 10"></polyline>
<path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
</svg>
批量重试
</button>
<button type="button" id="olb-bulkdel" class="btn-secondary btn-danger-soft" onclick="app.deleteSelectedOpenlist()" disabled>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:15px;height:15px;">
<polyline points="3 6 5 6 21 6"></polyline>
Expand All @@ -2646,6 +2690,11 @@ <h3 class="config-card-title">
<option value="failed">失败</option>
<option value="deleted">已删除</option>
</select>
<select id="olb-filter-type" class="form-input config-input olb-select" onchange="app.applyOpenlistFilter()" title="按歌单快照类型筛选(仅歌单快照页生效)">
<option value="">全部类型</option>
<option value="list">我的歌单</option>
<option value="dislike">我不喜欢</option>
</select>
<input type="text" id="olb-filter-name" class="form-input config-input olb-input" placeholder="文件名搜索" oninput="app.scheduleOpenlistReload()" />
<input type="text" id="olb-filter-path" class="form-input config-input olb-input" placeholder="路径包含搜索" oninput="app.scheduleOpenlistReload()" />
<div class="olb-filter-btns">
Expand Down
93 changes: 81 additions & 12 deletions public/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,8 @@ body {
margin: 1rem;
display: flex;
flex-direction: column;
gap: 2rem;
gap: 1rem;
/* [修复] 原 2rem 间距在菜单项较多时白白占用约 32px 纵向空间,导致列表更容易溢出 */
position: sticky;
top: 1rem;
height: calc(100vh - 2rem);
Expand Down Expand Up @@ -524,15 +525,28 @@ body {
gap: 0.5rem;
overflow-y: auto;
min-height: 0;
/* Hide scrollbar for Chrome, Safari and Opera */
-ms-overflow-style: none;
/* IE and Edge */
scrollbar-width: none;
/* Firefox */
padding-right: 4px;
/* [修复] 菜单项多达 10 条时常溢出,此前滚动条被隐藏导致用户以为「菜单变少」。
改为细滚动条:既保留视觉简洁,又让溢出可被发现、可滚动。 */
scrollbar-width: thin;
scrollbar-color: rgba(255, 255, 255, 0.25) transparent;
}

.sidebar-nav::-webkit-scrollbar {
display: none;
width: 6px;
}

.sidebar-nav::-webkit-scrollbar-track {
background: transparent;
}

.sidebar-nav::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.2);
border-radius: 3px;
}

.sidebar-nav::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.35);
}

.nav-item {
Expand Down Expand Up @@ -565,6 +579,18 @@ body {
box-shadow: var(--shadow-md);
}

/* [修复] 视口较矮时(笔记本常见 700~800px)侧栏进一步收紧,避免底部菜单被挤出可视区 */
@media (max-height: 900px) {
.sidebar {
padding: 1.25rem 1rem;
gap: 0.75rem;
}

.nav-item {
padding: 0.625rem 1rem;
}
}

.sidebar-divider {
height: 1px;
background: var(--glass-border);
Expand Down Expand Up @@ -4812,11 +4838,23 @@ input:-webkit-autofill:active {
padding: 0.25rem 0.5rem;
border-radius: 6px;
border: 1px solid rgba(255, 255, 255, 0.06);
display: flex;
align-items: center;
gap: 0.4rem;
min-width: 0;
overflow: hidden;
}

/* ID 文本单独截断,避免挤掉后面的类型标签 */
.col-id .col-id-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
max-width: fit-content;
min-width: 0;
}

.col-id .kind-tag {
flex-shrink: 0;
}

.col-size {
Expand Down Expand Up @@ -4928,15 +4966,21 @@ input:-webkit-autofill:active {

/* 快照ID显示优化 */
.col-id {
display: block !important;
display: flex !important;
flex-wrap: wrap;
font-family: monospace;
font-size: 0.85rem;
color: var(--text-secondary);
word-break: break-all;
white-space: normal;
margin-top: -0.25rem;
}

.col-id .col-id-text {
overflow: visible;
text-overflow: unset;
white-space: normal;
word-break: break-all;
}

/* 操作按钮区域:使用网格布局,一行三个按钮 */
.snapshot-actions {
display: grid !important;
Expand Down Expand Up @@ -6876,6 +6920,31 @@ input:-webkit-autofill:active {
background: var(--badge-color, currentColor);
}

.olb-detail-table {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
font-size: 0.85rem;
}

.olb-detail-table td {
padding: 0.45rem 0.6rem;
vertical-align: top;
border-bottom: 1px solid rgba(148, 163, 184, 0.15);
word-break: break-all;
}

.olb-detail-key {
width: 96px;
white-space: nowrap;
color: var(--text-secondary);
font-weight: 500;
}

.olb-detail-val {
color: var(--text-primary);
}

.olb-user-tag {
display: inline-block;
padding: 1px 7px;
Expand Down
1 change: 0 additions & 1 deletion src/defaultConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ const config: LX.Config = {
'openlist.password': '', // OpenList 密码
'openlist.token': '', // OpenList 用户令牌(与账号密码二选一)
'openlist.root': '/lx_music', // OpenList 中 lx-music 备份根目录
'openlist.keepLocalAfterUpload': true, // 上传 OpenList 后是否保留本地文件
'openlist.verifyInterval': 5, // 远端可用性校验周期(分钟)
'openlist.syncInterval': 60, // 双向同步周期(分钟)
'openlist.userBackups': '[]', // 各用户备份目录配置(JSON 数组)
Expand Down
Loading