前台播放器
- 悬浮按钮:右下角圆形音符按钮,平时缩进窗口外露出一点圆弧,悬停 / 点击即滑出
- 弹出面板:点击按钮弹出卡片面板 —— 曲目信息 · 可拖动进度条 · 上一首 / 播放暂停 / 下一首 · 音量 · 播放列表(点击切换、当前曲目高亮 + 均衡动画);点面板外部或 ✕ 收起
- 记忆:自动连播;记忆上次曲目与进度、音量持久化(
localStorage),刷新后恢复但不自动出声 - 自适应:无音乐或接口失败时完全隐藏;后台路由(
/admin、/write、编辑页)自动收起 - 按需加载:播放器的 CSS 与 JS 不在首屏关键路径上,滚动 / 空闲时才加载,不影响首屏
后台音乐管理
- 上传:选择 / 拖拽音频文件,浏览器直传 R2(预签名 URL),显示上传进度;选择文件后按文件名自动识别**「歌曲名-歌手」**预填输入框
- 列表:行内试听 / 重命名 / 删除(删除与 R2 对象同步);曲目多时列表卡片内滚动、表头吸顶,上传区不随列表滚走
- 管理端列表请求带
?_=<时间戳>穿透s-maxage边缘缓存,增删即时可见
上传架构(R2 直传)
- 音频文件不经过 Worker,规避请求体上限与带宽计费(R2 egress 免费)
- 环境变量:
R2_ACCESS_KEY_ID/R2_SECRET_ACCESS_KEY/R2_ENDPOINT+ 下面两组桶变量 - 降级:未配置 R2 凭据时,读取播放列表仍可用(D1),上传返回
503
目标桶选择(musicStorage())
音乐优先写回音乐桶,仅在音乐桶配置不完整时回退媒体桶(兼容只授予媒体桶权限的旧凭据):
这个优先级是 v2.7.1 的修复点:此前的实现会误把音乐写进媒体桶。现在只要音乐桶两个变量都在,就一定写音乐桶。删除时用
resolveR2Object() 同时识别媒体桶与音乐桶的公开域名,因此切换上传目标前后的历史曲目都能正确同步删除;外链(非 /music/ 前缀或域名不匹配)不会被当成桶内对象。文件白名单与大小
oga(Ogg Audio 的另一种扩展名)在 v2.7.1 加入白名单;但接口的错误提示文案里尚未列出 oga——收到不支持格式时返回的仍是 不支持的音频格式(mp3 / m4a / ogg / wav / aac / opus / flac),而 oga 实际上可以正常上传。预签名 PUT 签名细节
上传失败时接口会暴露真实失败阶段(预检失败 / 签名不匹配 / 网络中断等),便于定位是 CORS 还是签名问题;同时前端会调用删除接口清理可能产生的孤儿对象(幂等)。
API
获取播放列表(公开)
sort ASC, created_at ASC 排序。响应头 Cache-Control: s-maxage=60, max-age=30。
只读接口带
s-maxage=60 边缘缓存;管理后台以 ?_=<时间戳> 穿透缓存取最新列表。签发预签名上传 URL(需登录)
浏览器拿到后直接
PUT 上传(Content-Type 与响应一致);上传失败时调用删除接口清理孤儿对象(幂等)。
注册曲目(需登录)
title 与 url 必填):
201):
id 由服务端生成(song- + 随机串);缺 title 或 url 返回 400「缺少 title / url」。注意响应字段名是 track(不是 music)。
编辑曲目(需登录)
{ "title", "artist", "cover", "sort", "duration" },title 必填(否则 400「缺少 title」)。成功返回 { "ok": true },D1 写入失败返回 500「数据库更新失败,请稍后重试」。
删除曲目(需登录)
- 用
resolveR2Object()解析url所属桶与对象 key(同时识别音乐桶与媒体桶公开域名;外链返回null,跳过 R2 删除) - 命中则向对应桶发起服务端签名 DELETE(
x-amz-content-sha256: UNSIGNED-PAYLOAD+x-amz-date,SignedHeadershost;x-amz-content-sha256;x-amz-date) - R2 删除失败 → 返回
502「R2 对象删除失败,请稍后重试」,D1 行保留(数据一致优先,避免幽灵曲目) - R2 成功(或对象本就不存在,S3 DELETE 幂等,
404视为成功)后再删 D1 行;D1 删除失败返回500「数据库删除失败,请稍后重试」
环境变量(GitHub Secrets)
逐项获取方式(控制台路径、格式要求)见 部署密钥指南。
表结构
迁移
0015_hot_path_indexes.sql 为 music 表补了 idx_music_sort,让播放列表的 sort ASC, created_at ASC 排序走索引。