{"id":51407557,"url":"https://github.com/abloom25/meliora","last_synced_at":"2026-07-04T12:00:33.396Z","repository":{"id":365452474,"uuid":"1270142392","full_name":"abloom25/Meliora","owner":"abloom25","description":"[⚠️目前这个项目还在破坏性的更新状态，请使用发布版本，不要使用RC版本！]基于 Vue 3、TypeScript、Pinia 和 SCSS 的沉浸式单页音乐播放器。所有远程歌单和本地音乐会合并为一个匿名曲库，页面不会显示歌单名称、平台或来源。","archived":false,"fork":false,"pushed_at":"2026-07-01T13:28:23.000Z","size":43535,"stargazers_count":7,"open_issues_count":2,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-01T15:15:12.942Z","etag":null,"topics":["aplayer","meting","meting-api","metingjs","music","music-player","online","scss","vue"],"latest_commit_sha":null,"homepage":"https://music.abloom.site","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/abloom25.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":"SECURITY.md","support":"SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-15T12:31:47.000Z","updated_at":"2026-07-01T13:27:11.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/abloom25/Meliora","commit_stats":null,"previous_names":["abloom25/meliora"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/abloom25/Meliora","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abloom25%2FMeliora","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abloom25%2FMeliora/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abloom25%2FMeliora/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abloom25%2FMeliora/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/abloom25","download_url":"https://codeload.github.com/abloom25/Meliora/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abloom25%2FMeliora/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35120682,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-04T02:00:05.987Z","response_time":113,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aplayer","meting","meting-api","metingjs","music","music-player","online","scss","vue"],"created_at":"2026-07-04T12:00:27.777Z","updated_at":"2026-07-04T12:00:33.389Z","avatar_url":"https://github.com/abloom25.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n\u003cimg src=\"public/pwa-icon.svg\" alt=\"Meliora\" width=\"100\" height=\"100\" /\u003e\n\n# Meliora\n\n**沉浸式 · 视听一体的网页音乐播放器**\n\n[![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg?style=flat-square)](LICENSE)\n[![Vue 3](https://img.shields.io/badge/Vue-3.5-42b883?style=flat-square\u0026logo=vue.js\u0026logoColor=white)](https://vuejs.org/)\n[![Vite](https://img.shields.io/badge/Vite-8-646cff?style=flat-square\u0026logo=vite\u0026logoColor=white)](https://vite.dev/)\n[![TypeScript](https://img.shields.io/badge/TypeScript-6-3178c6?style=flat-square\u0026logo=typescript\u0026logoColor=white)](https://www.typescriptlang.org/)\n[![PWA](https://img.shields.io/badge/PWA-Ready-5a0fc8?style=flat-square\u0026logo=pwa\u0026logoColor=white)](https://web.dev/progressive-web-apps/)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](CONTRIBUTING.md)\n\n[特性](#-特性) · [快速开始](#-快速开始) · [管理后台](#-管理后台) · [快捷键](#-快捷键) · [部署](#-部署) · [开发](#-开发) · [路线图](ROADMAP.md)\n\n[在线预览](https://music.abloom.site) · [反馈问题](https://github.com/abloom25/Meliora/issues) · [贡献指南](CONTRIBUTING.md)\n\n\u003c/div\u003e\n\n---\n\n## ✨ 特性\n\n### 视听一体\n\n- 🎨 **实时节拍分析**:Web Audio API 频谱采样驱动背景呼吸效果,封面取色驱动全局主题色过渡\n- 🌈 **动态背景**:封面模糊渲染 + 可调节模糊/饱和度/节奏亮度,支持关闭\n- 🎵 **零延迟切歌**:三 Audio 池 + 预加载槽 + 平滑切歌淡入淡出\n\n### 歌词体验\n\n- 📜 **LRC 歌词跟随**:FLIP 牵引滚动 + 逐行高亮 + 可调字号\n- 🪟 **歌词小窗**:Document Picture-in-Picture 独立浮窗,支持在外部应用时查看歌词\n\n### 播放控制\n\n- 🎚️ **内置均衡器**:10 频段增益调节 + 预设方案\n- ⏰ **定时关闭**:倒计时自动停止播放\n- 🔀 **播放模式**:顺序 / 随机 / 单曲循环\n- ⏭️ **自动跳过**:加载失败自动跳到下一首\n\n### 沉浸模式\n\n- 📱 **全屏模式**:一键占满整个屏幕\n- 👻 **自动隐藏**:鼠标闲置 30 秒后只保留歌曲内容\n- 📳 **触感反馈**:移动端切歌/操作轻震动\n\n### 平台集成\n\n- 📲 **PWA 安装**:可添加到桌面,支持离线启动\n- 🔒 **MediaSession**:锁屏 / 控制中心播放控制\n- 🔗 **歌曲分享**:Web Share API 分享当前曲目\n\n### 曲库管理\n\n- 🌐 **远程歌单**:网易云 / QQ 音乐歌单,通过 Meting API 解析\n- 💾 **本地音乐**:上传音频/封面/歌词,自动合并去重\n- ⚙️ **可视化管理**:完整的 Web 管理后台,无需编辑代码\n\n### 无障碍\n\n- ♿ `prefers-reduced-motion` 支持\n- ⌨️ 完整键盘快捷键 + focus trap\n- 🎨 颜色 + 图标双重状态提示\n\n---\n\n## 🚀 快速开始\n\n```powershell\npnpm install\npnpm dev          # 仅前端(5175)\npnpm dev:full     # 前端 + 后端模拟(5175 + 8788)\n```\n\n需要 Node 22+ 与 pnpm 11.5.3+。\n\n- `pnpm dev`:仅启动 Vite 前端开发服务器,默认端口 5175,适合纯 UI 开发\n- `pnpm dev:full`:同时启动 Vite + Wrangler Pages Functions 本地模拟,`/api/*` 请求代理到 8788 端口,可完整测试管理后台(含 `/setup` 初始化流程)。Wrangler 使用 `.wrangler/pages-dev-static` 临时静态目录启动本地 Functions,静态页面仍由 Vite 提供,不依赖 `dist` 是否存在或是否最新。\n\n本地后端可使用开发模式(`.dev.vars` 中 `DEVELOPMENT=true`),配置和密码不持久化,重启即重置。复制 [.dev.vars.example](.dev.vars.example) 为 `.dev.vars` 并填入真实 GitHub Token、关闭 `DEVELOPMENT` 后可测试完整流程。\n\n---\n\n## ⚙️ 管理后台\n\n访问 `https://你的域名/admin` 进入管理后台。\n\n### 首次使用\n\n部署后首次访问 `/admin` 会进入 `/setup` 页面,设置管理员密码即可。密码经 PBKDF2 哈希后存储,后续可在后台「安全」页面修改。\n\n### 后台功能\n\n| 页面         | 功能                                       |\n| ------------ | ------------------------------------------ |\n| **站点**     | 站点名称、图标、Meting API 端点、API Token |\n| **歌单**     | 添加/删除/启用网易云与 QQ 音乐歌单         |\n| **本地音乐** | 上传音频/封面/歌词,编辑曲目信息            |\n| **统计**     | Umami / Google Analytics 配置              |\n| **高级**     | GitHub 代理、预发布更新、自定义 CSS / JS   |\n| **安全**     | 修改管理员密码                             |\n| **关于**     | 版本信息、检查更新、同步上游代码           |\n\n保存配置时,后台通过 GitHub API 将变更写入仓库 `public/config.json`,触发部署平台自动重新构建后生效。播放器公开配置在构建期写入前端 bundle,首屏不再请求管理 API;远程歌单仍按 `apiEndpoint` 与歌单 ID 实时请求 Meting API,不会把歌曲列表结果预构建进前端。\n\n### 更新说明\n\n管理后台「关于」页的一键更新用于同步官方上游版本,适合未修改源码、仅通过后台维护配置和曲库的部署。\n\n用户只需要点击一次“更新”。后台会触发 GitHub Actions,Actions 在 `meliora-update/*` 临时分支里同步上游代码,运行依赖安装、测试、类型检查、Lint、格式检查与构建;验证通过后再合并目标分支最新提交并执行关键验证,无冲突才自动合并并推送回目标分支。\n\n失败、冲突或推送被拒绝时目标分支保持不变,后台会显示运行状态、失败原因和 GitHub Actions 日志入口,不需要用户手动 merge。流程会保留 `public/config.json`、`public/admin.json`、`public/music/`、`.env`、`.env.local`、`.dev.vars` 和构建产物等用户数据;`.env.example`、`.dev.vars.example` 等模板文件会随上游更新。\n\n如果仓库启用了 branch protection 且禁止 `github-actions[bot]` push,自动合并会失败,需要允许 GitHub Actions 写入目标分支,或后续改用 PR auto-merge 模式。如果你已经修改过源码、样式、工作流或部署配置,请不要使用后台一键更新,应自行通过 Git 合并上游代码并处理冲突。\n\n---\n\n## ⌨️ 快捷键\n\n| 快捷键        | 操作             |\n| ------------- | ---------------- |\n| `Space`       | 播放 / 暂停      |\n| `←` / `→`     | 后退 / 快进 5 秒 |\n| `Shift + ←/→` | 上一曲 / 下一曲  |\n| `L`           | 切换歌词面板     |\n| `S`           | 打开设置抽屉     |\n| `F`           | 切换全屏         |\n| `M`           | 静音切换         |\n| `Esc`         | 关闭抽屉 / 弹层  |\n\n输入框中自动让出快捷键。\n\n---\n\n## 🌍 部署\n\n一键部署到以下平台(点击图标,Fork 后自动构建):\n\n| 平台                 | 一键部署                                                                                                                                                                                                                         |\n| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| **Vercel**           | [![Deploy](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fabloom25%2FMeliora)                                                                                                |\n| **Netlify**          | [![Deploy](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/abloom25/Meliora)                                                                                  |\n| **Cloudflare Pages** | [![Deploy to Cloudflare Pages](https://img.shields.io/badge/Deploy-Cloudflare%20Pages-F38020?style=flat-square\u0026logo=cloudflare\u0026logoColor=white)](https://deploy.workers.cloudflare.com/?url=https://github.com/abloom25/Meliora) |\n\n### 环境变量\n\n部署后在平台 Dashboard 的 Settings → Environment Variables 中配置环境变量:\n\n| 变量                    | 必填 | 说明                                                                                                                                                                                            |\n| ----------------------- | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `GH_TOKEN`              | ✅   | GitHub Personal Access Token。Fine-grained token 需要 `Contents: Read and write` + `Actions: Write`; classic token 可使用 `repo` 权限。用于配置读写、文件上传、触发更新 workflow 与查询更新状态 |\n| `GH_REPO`               | ✅   | 仓库标识,`owner/repo` 格式                                                                                                                                                                      |\n| `CONFIG_ENCRYPTION_KEY` | ✅   | 配置加密密钥,32 位以上随机字符串。配置加密、Cookie 签名与构建期公开配置生成都依赖它,GH_TOKEN 可独立轮换而不影响已加密配置                                                                       |\n| `GH_BRANCH`             | ❌   | 目标分支,默认 `main`                                                                                                                                                                            |\n| `GITHUB_PROXY`          | ❌   | GitHub 代理,用于检查更新和 workflow 内拉取上游代码;触发 workflow 与查询 Actions 状态仍需部署环境可访问 `api.github.com`                                                                         |\n| `ADMIN_DISABLED`        | ❌   | 设为 `true`/`1`/`yes`/`on`(大小写不敏感)时禁用管理后台,`/admin` 显示“已禁用”,除状态探针外所有 `/api/*` 返回 403                                                                                 |\n| `DEVELOPMENT`           | ❌   | 设为 `true`/`1`/`yes`/`on`(大小写不敏感)时进入开发模式:配置与密码不持久化、加密走明文降级                                                                                                       |\n\n\u003e 生成 `CONFIG_ENCRYPTION_KEY`:`node -e \"console.log(require('crypto').randomBytes(32).toString('hex'))\"`\n\n\u003e `CONFIG_ENCRYPTION_KEY` 需要同时提供给平台的构建环境和 Functions/运行时环境。构建期会用它解密 `public/config.json`,生成前端公开配置;如果仓库中已有密文配置但构建阶段缺少该变量,构建会失败以避免站点静默变成空配置。\n\n\u003e ### 🎉 零配置密码\n\u003e\n\u003e 首次部署后访问 `/admin`,会自动进入 `/setup` 页面设置管理员密码——**无需在环境变量中预设任何密码**。\n\u003e\n\u003e - **密码**:通过 `/setup` 页面设置,经 PBKDF2(100k 迭代)哈希后存储在仓库 `public/admin.json`,后续可在后台修改\n\u003e - **Cookie 签名密钥**:从 `CONFIG_ENCRYPTION_KEY` 运行时派生(`HMAC-SHA256(密钥, \"meliora-cookie-signing\")`),**不落盘、不出现在任何文件/响应/日志中**\n\u003e - **密钥强度校验**:初始化时若 `CONFIG_ENCRYPTION_KEY` 未设置或过弱(\u003c 32 位 / 常见弱密钥),`/setup` 页面会显示警告并拒绝初始化,提示用户在部署平台配置后再试\n\u003e - **先到先得**:部署后谁先访问 `/setup` 谁设置密码,设置后 `/setup` 自动关闭\n\n\u003e ### 🔒 配置文件加密\n\u003e\n\u003e 管理后台保存的所有配置(站点信息、API Token、歌单、Umami / GA ID 等)在写入 GitHub 仓库时**全文 AES-GCM 256 加密**,仓库中只存储 base64 密文。构建期会从中生成公开播放器配置,但 `apiToken` 不会进入前端 bundle;需要 token 的 Meting API 后续应通过专门后端代理支持。\n\u003e\n\u003e - **加密密钥**:从 `CONFIG_ENCRYPTION_KEY` 用 PBKDF2(100k 迭代)派生,密钥本身**不落盘、不出现在任何文件中**\n\u003e - **密钥解耦**:`CONFIG_ENCRYPTION_KEY` 专用于加密与签名,`GH_TOKEN` 仅用于 GitHub API 读写,两者独立——`GH_TOKEN` 可随时轮换而不影响已加密的配置\n\u003e - **加密范围**:`public/config.json`(站点配置)和 `public/admin.json`(密码哈希)均为密文存储\n\u003e - **构建期公开配置**:构建脚本解密并清洗站点公开配置后写入前端 bundle;直接访问仓库文件或 `/admin.json` 只能看到密文\n\u003e - **本地开发**:`DEVELOPMENT=true` 时不加密,明文存内存,方便调试\n\n### 各平台说明\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eVercel\u003c/strong\u003e\u003c/summary\u003e\n\n已包含 `vercel.json`,导入仓库后自动部署。\n\n- 框架:Vite(自动识别)\n- 构建命令:`pnpm build`\n- 输出目录:`dist`\n- 安装命令:`pnpm install --frozen-lockfile`(配置文件已指定)\n- 安全头(CSP / X-Content-Type-Options / X-Frame-Options / Referrer-Policy / Permissions-Policy)、Service Worker 缓存策略、静态资源 immutable 缓存、SPA fallback 均已在 [vercel.json](vercel.json) 配置\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eNetlify\u003c/strong\u003e\u003c/summary\u003e\n\n已包含 [netlify.toml](netlify.toml),接入仓库后自动识别。\n\n- 构建命令:`pnpm build`(配置文件已指定)\n- 发布目录:`dist`(配置文件已指定)\n- 运行环境:Node 22 + pnpm 11.5.3(配置文件已指定)\n- 安全头、Service Worker 缓存策略、静态资源 immutable 缓存、SPA fallback 均已配置\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eCloudflare Pages\u003c/strong\u003e\u003c/summary\u003e\n\n已包含 [wrangler.toml](wrangler.toml),可通过控制台导入或 `wrangler pages deploy dist` 部署。\n\n- 构建命令:`pnpm build`\n- 输出目录:`dist`\n- `wrangler.toml` 已设置 `pages_build_output_dir = \"dist\"`\n- 安全头、Service Worker 缓存策略、静态资源 immutable 缓存、SPA fallback 通过 [public/\\_headers](public/_headers) 与 [public/\\_redirects](public/_redirects) 配置,构建时会复制到 `dist`\n\n\u003c/details\u003e\n\n所有平台配置统一:构建命令 `pnpm build`、输出目录 `dist`,并保持安全头与缓存策略一致。Node 版本遵循 `package.json` 的 `engines` 要求,Netlify 额外在 `netlify.toml` 中固定构建环境版本。\n\n---\n\n## 🛠️ 开发\n\n```powershell\npnpm dev          # 开发服务器(前端)\npnpm dev:full     # 开发服务器(前端 + 后端模拟)\npnpm test         # 单元测试\npnpm type-check   # 类型检查\npnpm lint         # ESLint\npnpm format       # Prettier\npnpm build        # 生产构建\n```\n\n### 本地配置同步\n\n`DEVELOPMENT=true` 时,管理后台的配置与密码仍由本地后端以内存模式处理,重启后会重置。为了让主页保持与生产一致的“构建期公开配置”读取方式,Vite 开发服务器会在后台保存配置成功后,把配置同步写入 `.meliora/config.local.json`,并重新生成 `src/generated/public-config.ts`。\n\n- `.meliora/` 已加入 `.gitignore`,仅用于本地调试。\n- 主页不会请求运行时配置接口,仍然只读取生成后的公开配置。\n- 重新执行 `pnpm generate:public-config:dev` 时,如果 `.meliora/config.local.json` 存在,会优先用它生成本地公开配置。\n- 要测试真实生产链路,请关闭 `DEVELOPMENT`,配置真实 `GH_TOKEN` / `GH_REPO` / `CONFIG_ENCRYPTION_KEY`,让后台写入仓库后再构建。\n\n### 项目结构\n\n```\nsrc/\n├── components/      共享 UI 组件(ConfirmModal / ToggleSwitch / Toast 等)\n├── composables/     业务 hook(useAudioPlayer / useBeatAnalyser 等)\n├── stores/          Pinia 状态管理\n├── services/        远程 IO 抽象(Meting API / 歌词)\n├── utils/           纯函数工具(无副作用、无 DOM 依赖)\n├── workers/         Web Worker(主题色提取)\n├── admin/           管理后台(独立子应用)\n│   ├── components/  后台 UI 组件\n│   ├── views/       后台页面(Setup / Login / Dashboard / About)\n│   └── services/    后台 API 服务\n└── styles/          全局样式\n\nserver/              Edge Functions 后端\n├── core/            核心逻辑(路由 / 鉴权 / 配置 / 上传)\n└── tests/           后端测试\n\napi/                 Vercel Edge Function 入口\nfunctions/           Cloudflare Pages Function 入口\nnetlify/             Netlify Function 入口\n```\n\n提交时 Husky 会自动运行 `lint-staged` 与 `commitlint`。提交信息遵循 [Conventional Commits](https://www.conventionalcommits.org/)。\n\n---\n\n## 🤝 贡献\n\n欢迎一切形式的贡献。详情请看 [CONTRIBUTING.md](CONTRIBUTING.md);代码风格与设计规范请看 [agent.md](agent.md)。\n\n---\n\n## 📄 开源许可\n\n[GNU Affero General Public License v3.0 or later](LICENSE) © abloom25\n\n\u003e AGPL-3.0 要求任何**修改后部署到公网**的衍生版本必须向用户提供完整源代码。如需闭源商业使用,请联系作者协商授权。\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n如果这个项目对你有帮助,欢迎点亮 ⭐ Star\n\nMade with ❤️ by [abloom25](https://github.com/abloom25) and OpenAI Codex\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabloom25%2Fmeliora","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fabloom25%2Fmeliora","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabloom25%2Fmeliora/lists"}