{"id":50665322,"url":"https://github.com/laoshuikaixue/VoiceHub","last_synced_at":"2026-06-25T03:00:28.605Z","repository":{"id":304343048,"uuid":"1018509102","full_name":"laoshuikaixue/VoiceHub","owner":"laoshuikaixue","description":"这是一个使用Nuxt 4全栈框架开发的低成本校园广播站点歌系统。系统提供完整的点歌投票、排期管理、权限控制和打印导出功能，具备现代化的UI设计。管理员可通过直观的拖拽界面进行排期管理，支持多播出时段配置。系统内置完善的权限管理体系、学期管理、黑名单控制等功能，同时针对移动端进行了优化，确保在各种设备上都能提供出色的用户体验","archived":false,"fork":false,"pushed_at":"2026-06-20T12:35:07.000Z","size":27919,"stargazers_count":150,"open_issues_count":36,"forks_count":85,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-06-20T13:12:39.674Z","etag":null,"topics":["drizzle-orm","neon-database","neondb","netlify","nuxt","nuxt4","postgres","postgresql","redis","songrequest","tailwindcss","typescript","vercel","vue"],"latest_commit_sha":null,"homepage":"https://voicehub.smart-teach.cn","language":"Vue","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/laoshuikaixue.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"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":"2025-07-12T12:15:32.000Z","updated_at":"2026-06-20T12:35:11.000Z","dependencies_parsed_at":"2026-03-07T14:00:49.482Z","dependency_job_id":null,"html_url":"https://github.com/laoshuikaixue/VoiceHub","commit_stats":null,"previous_names":["laoshuikaixue/voicehub"],"tags_count":74,"template":false,"template_full_name":null,"purl":"pkg:github/laoshuikaixue/VoiceHub","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laoshuikaixue%2FVoiceHub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laoshuikaixue%2FVoiceHub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laoshuikaixue%2FVoiceHub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laoshuikaixue%2FVoiceHub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/laoshuikaixue","download_url":"https://codeload.github.com/laoshuikaixue/VoiceHub/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laoshuikaixue%2FVoiceHub/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34757355,"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-06-25T02:00:05.521Z","response_time":101,"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":["drizzle-orm","neon-database","neondb","netlify","nuxt","nuxt4","postgres","postgresql","redis","songrequest","tailwindcss","typescript","vercel","vue"],"created_at":"2026-06-08T06:00:18.132Z","updated_at":"2026-06-25T03:00:28.574Z","avatar_url":"https://github.com/laoshuikaixue.png","language":"Vue","funding_links":[],"categories":["Uncategorized"],"sub_categories":["Uncategorized"],"readme":"# VoiceHub - 校园广播站点歌系统\n\n这是一个使用Nuxt 4全栈框架开发的现代化校园广播站点歌管理系统。系统提供完整的点歌、投票、排期管理、通知推送、数据分析、权限控制和数据库管理功能，支持多角色权限管理和灵活的系统配置。\n\n\u003cdiv align=\"center\"\u003e\n\n[交流群](https://qm.qq.com/cgi-bin/qm/qr?k=5DV4vGlqn82YaNi7a3xW4zjmS8ZUr6cz\u0026jump_from=webapi\u0026authKey=axAl02PMsIVVAwrXij0YUUrOrUTeLpqLipu5XcTvyBUOzeWaOnicBB+fmBwNJs5S) | [使用学校收集表](https://laoshuikaixue.feishu.cn/share/base/form/shrcniUKakpNYP6KH7qrU20qq5e) | [项目宣传片](https://www.bilibili.com/video/BV1B9ArzMEkA) | [赞助支持](#sponsor)\n\n\u003c/div\u003e\n\n## 项目截图\n\n\u003cimg width=\"1920\" height=\"1080\" alt=\"image\" src=\"https://github.com/user-attachments/assets/fef6970e-95eb-4cab-a11f-db4e71fc87b5\" /\u003e\n\u003cimg width=\"1920\" height=\"1080\" alt=\"image\" src=\"https://github.com/user-attachments/assets/f76e912c-1263-424b-b379-72321de205f7\" /\u003e\n\u003cimg width=\"1920\" height=\"1080\" alt=\"image\" src=\"https://github.com/user-attachments/assets/b5de5880-6635-4698-9fd9-dbea9642f06a\" /\u003e\n\u003cimg width=\"1920\" height=\"1080\" alt=\"image\" src=\"https://github.com/user-attachments/assets/05472008-57d5-4586-b7ca-572bff8a30ae\" /\u003e\n\u003cimg width=\"1920\" height=\"1080\" alt=\"image\" src=\"https://github.com/user-attachments/assets/c30f2e5a-4cc8-48cb-aca2-4d41daeaaaf8\" /\u003e\n\n## 主要功能\n\n### 🎵 核心功能\n\n- **智能点歌系统**：用户可以点歌或给已有歌曲投票，支持网易云音乐、QQ音乐和哔哩哔哩搜索，可选择期望播出时段\n- **多平台登录支持**：\n  - **OAuth 账户系统**：支持通过 GitHub、Casdoor 等 OAuth 提供商快速创建和登录账户\n    - **直接创建账户**：用户通过 OAuth 认证后可创建新账户，但仍需设置本地用户名和密码\n    - **账户绑定**：已有账户的用户可将 OAuth 身份绑定到现有账户，实现多平台统一登录\n    - **WebAuthn 支持**：支持 Windows Hello、生物识别和硬件安全密钥（如 YubiKey）登录\n    - **双因素认证（2FA）**：支持 TOTP 和邮箱验证，增强账户安全性\n  - **网易云音乐登录**：支持扫码登录，登录后可搜索个人歌单、收藏及播客电台内容\n    - **一键添加到歌单**：登录后支持将排期中的网易云音乐歌曲一键添加到个人歌单\n    - **从歌单投稿**：支持从个人歌单中直接投稿歌曲到系统\n    - **从最近播放投稿**：支持从最近播放记录中投稿歌曲\n    - **播客电台投稿**：支持搜索和投稿播客电台内容\n- **投稿限额管理**：灵活配置用户投稿限制，支持按时间段、用户角色设置不同的投稿额度，有效控制系统负载\n- **歌曲去重功能**：智能识别重复歌曲，优化歌曲库管理，避免重复播放\n- **歌曲管理**：按热度排序，避免重复播放，动态URL防止链接过期，支持黑名单管理\n- **音乐播放器**：内置音乐播放器，支持进度控制和音质实时切换\n- **音质切换**：支持多种音质选择（标准、HQ、无损、Hi-Res等），动态获取最新播放链接\n- **音乐下载功能**：支持管理员下载歌曲到本地，提供多种音质选择和批量下载\n- **歌曲重播功能**：支持用户对已播放过的歌曲发起重播申请，支持查看申请记录和撤回申请\n\n### 👥 用户管理\n\n- **用户管理**：管理员添加用户，支持按年级班级分类\n- **账户创建方式**：\n  - 管理员直接添加账户\n  - 用户通过 OAuth 快速创建账户\n  - 用户通过传统用户名/密码注册\n- **权限控制**：多级权限管理，支持普通用户、管理员、超级管理员\n- **账户安全**：\n  - bcrypt 密码加密\n  - 双因素认证（TOTP、邮箱验证）\n  - WebAuthn 支持（生物识别、硬件密钥）\n  - 账户锁定和风险控制\n- **身份关联**：支持将多个 OAuth 身份绑定到同一账户，实现统一登录\n- **黑名单管理**：支持歌曲和艺术家黑名单，自动过滤不当内容\n\n### 📅 排期管理\n\n- **排期管理**：管理员可以通过拖拽界面进行歌曲排期和顺序管理\n- **排期草稿**：支持保存排期草稿功能，允许管理员分步完成排期安排\n  - 草稿状态不影响公开展示，可随时修改和完善\n  - 支持草稿发布为正式排期，确保排期质量\n- **播出时段**：灵活配置播出时段，**支持多时段管理**\n- **打印排期**：支持自定义纸张大小、内容选择、编写备注和PDF导出的打印功能\n- **学期管理**：管理员可设置当前学期，自动关联点歌记录\n- **公开展示**：公开展示歌曲播放排期，按日期分组展示\n\n### 🔔 通知系统\n\n- **实时通知**：歌曲被选中、投票和系统通知\n- **通知设置**：用户可自定义通知偏好，支持独立页面设置\n- **批量通知**：管理员可向特定用户群体发送通知\n- **社交账号绑定**：支持绑定MeoW等账号，同步推送通知到外部平台\n- **验证码验证**：安全的验证码验证机制，支持动态样式反馈\n\n### 💾 数据管理\n\n- **数据库备份**：完整的数据库备份和恢复功能\n- **数据库重置**：支持安全的数据库重置操作，可选择性保留用户数据或完全重置\n- **文件导入导出**：支持备份文件的上传、下载和管理\n- **数据库自检**：自动数据库验证和修复机制，确保系统稳定性\n\n### 🎨 用户体验\n\n- **现代UI**：响应式设计，深色主题，流畅的动画效果\n- **玻璃态设计**：现代化的视觉效果和交互体验\n- **交互反馈**：hover效果，点击反馈，状态变化动画\n- **移动端优化**：适配支持移动设备访问，触摸友好的交互设计\n\n## 技术栈\n\n### 前端技术\n\n- **Nuxt 4**：Vue.js全栈框架，提供SSR和SPA支持\n- **Vue 3**：响应式前端框架，使用Composition API\n- **TypeScript**：类型安全的JavaScript，提供完整的类型定义\n- **Tailwind CSS**：实用优先的CSS框架，响应式设计\n- **Vue Router**：前端路由管理\n\n### 后端技术\n\n- **Nuxt Server API**：服务端API路由，支持中间件和认证\n- **Drizzle ORM**：现代化数据库ORM，提供类型安全的数据库操作和高性能查询\n- **Neon Database**：Serverless PostgreSQL数据库，支持自动启停和无缝扩展\n- **PostgreSQL**：关系型数据库，支持复杂查询和事务处理\n- **Redis**：高性能缓存数据库，提升系统响应速度（可选，暂不推荐，可能存在潜在的问题）\n- **JWT**：标准JWT认证机制，支持24小时token有效期\n- **bcrypt**：密码加密，安全的哈希算法\n- **Multer**：文件上传处理，支持多种存储方式\n\n## 系统架构\n\n系统采用了现代化的 Serverless 全栈架构：\n\n- **前端**：使用 Nuxt 4 + Vue 3 组合式API构建响应式用户界面\n- **后端**：使用 Nuxt Server API 构建 RESTful API 服务\n- **数据库**：使用 Drizzle ORM + Neon Database，提供类型安全和高性能的数据库操作\n- **认证**：标准 JWT 认证系统\n- **缓存**：可选的 Redis 缓存层，提升系统响应速度\n- **部署**：支持 Vercel、Netlify、EdgeOne 等 Serverless 平台一键部署，并提供 Docker、Linux 一键脚本及飞牛 FnOS (fpk安装包) 等多种部署方式\n\n## 部署指南\n\n### 一键部署\n\n本项目可以一键部署到Vercel/Netlify/EdgeOne平台：\n\n[![Deploy to Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Flaoshuikaixue%2FVoiceHub\u0026env=DATABASE_URL,JWT_SECRET,NODE_ENV\u0026envDefaults=%7B%22NODE_ENV%22%3A%22production%22%7D\u0026envDescription=%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E8%AF%B4%E6%98%8E\u0026envLink=https%3A%2F%2Fgithub.com%2Flaoshuikaixue%2FVoiceHub%23%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E8%AF%B4%E6%98%8E)\n[![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/laoshuikaixue/VoiceHub)\n[![Deploy to EdgeOne Pages](https://cdnstatic.tencentcs.com/edgeone/pages/deploy.svg)](https://edgeone.ai/pages/new?repository-url=https://github.com/laoshuikaixue/VoiceHub\u0026env=DATABASE_URL,JWT_SECRET\u0026env-description=%E9%9C%80%E8%A6%81%E9%85%8D%E7%BD%AE%E6%95%B0%E6%8D%AE%E5%BA%93%E5%9C%B0%E5%9D%80%E3%80%81JWT%E5%AF%86%E9%92%A5)\n\n在部署过程中，需要输入必要的环境变量：\n\n1. `DATABASE_URL`：PostgreSQL数据库连接地址\n2. `JWT_SECRET`：JWT令牌签名密钥\n\n### Claw 部署\n\n[![Claw](https://ap-southeast-1.run.claw.cloud/logo.svg)](https://ap-southeast-1.run.claw.cloud/)\n\n1. **点击部署按钮**：选择上方的 Claw 部署按钮\n2. **打开应用程序启动板**：打开 App Launchpad （应用程序启动板）\n3. **创建应用**：选 Create App （创建应用）\n4. **相关配置**：\n   ```\n   Application Name：VoiceHub 或 其它\n   Image Name: ghcr.io/laoshuikaixue/voicehub:latest\n   Usage：按需调整\n   Network：3000 ，开 Public Access\n   Environment Variables：\n      DATABASE_URL=postgresql://user:password@postgres:5432/voicehub \n      # 可能需要 ?sslmode=disable\n      JWT_SECRET=your-jwt-secret-here\n      # 按实际情况填写\n   ```\n5. **等待部署**：平台会自动构建和部署应用\n6. **访问应用**：部署完成后，您将获得一个可访问的 URL\n\n### Linux 服务器部署\n\n本项目提供了针对 Ubuntu/Debian 服务器的一键部署脚本，支持自动安装 Node.js 22、配置环境变量、安装依赖和构建项目。\n\n**一键命令：**\n\n```bash\nbash \u003c(curl -sL https://raw.githubusercontent.com/laoshuikaixue/VoiceHub/main/sh/main.sh)\n```\n\n如果你需要 gh-proxy 加速，使用以下命令：\n\n```bash\nbash \u003c(curl -sL https://gh-proxy.com/https://raw.githubusercontent.com/laoshuikaixue/VoiceHub/main/sh/main.sh)\n```\n\n### Docker 部署\n\nVoiceHub 支持通过 Docker 进行容器化部署，提供了多种部署方式。\n\n#### 方式一：使用 Docker Compose（推荐）\n\n这是最简单的部署方式，会自动创建应用和数据库容器。\n\n\n##### 使用预构建镜像\n\n查看 [docker-compose](/docker-compose) 并选择适合的配置文件\n\n##### 本地构建镜像\n\n1. 克隆项目\n\n```bash\ngit clone https://github.com/laoshuikaixue/VoiceHub.git\ncd VoiceHub\n```\n\n2. 修改 docker-compose.yml 中的环境变量\n\n```yaml\nenvironment:\n  - DATABASE_URL=postgresql://user:password@postgres:5432/voicehub # 可能需要 ?sslmode=disable\n  - JWT_SECRET=your-jwt-secret-here # 请修改为强随机字符串\n  - NODE_ENV=production\n```\n\n3. 启动服务\n\n```bash\ndocker-compose up -d\n```\n\n4. 访问应用\n   打开浏览器访问 http://localhost:3000\n\n默认管理员账号：\n\n- 用户名：admin\n- 密码：admin123\n\n#### 方式二：使用预构建镜像\n\n如果你已有 PostgreSQL 数据库，可以直接使用预构建的镜像。\n\n使用 GitHub 镜像源：\n\n```bash\ndocker run -d \\\n  -p 3000:3000 \\\n  -e DATABASE_URL=\"postgresql://username:password@host:port/database?sslmode=require\" \\  \n  # 可能需要替换成 ?sslmode=disable\n  -e JWT_SECRET=\"your-very-secure-jwt-secret-key\" \\\n  -e NODE_ENV=production \\\n  --name voicehub \\\n  ghcr.io/laoshuikaixue/voicehub:latest\n```\n\n使用南京大学镜像源：\n\n```bash\ndocker run -d \\\n  -p 3000:3000 \\\n  -e DATABASE_URL=\"postgresql://username:password@host:port/database?sslmode=require\" \\  \n  # 可能需要替换成 ?sslmode=disable\n  -e JWT_SECRET=\"your-very-secure-jwt-secret-key\" \\\n  -e NODE_ENV=production \\\n  --name voicehub \\\n  ghcr.nju.edu.cn/laoshuikaixue/voicehub:latest\n```\n\n#### 方式三：本地构建镜像\n\n如果需要自定义构建，可以本地构建镜像。\n\n```bash\ngit clone https://github.com/laoshuikaixue/VoiceHub.git\ncd VoiceHub\n\n# 构建镜像（不使用缓存，确保完全重新构建）\ndocker build --no-cache -t voicehub .\n\n# 运行容器\ndocker run -d \\\n  -p 3000:3000 \\\n  -e DATABASE_URL=\"postgresql://username:password@host:port/database?sslmode=require\" \\  \n  # 可能需要替换成 ?sslmode=disable\n  -e JWT_SECRET=\"your-very-secure-jwt-secret-key\" \\\n  -e NODE_ENV=production \\\n  --name voicehub \\\n  voicehub\n```\n\n### 飞牛 (FnOS) 部署\n\nVoiceHub 现已支持飞牛 OS (FnOS) 的 `.fpk` 安装包。\n- 从 [GitHub Actions](https://github.com/laoshuikaixue/VoiceHub/actions/workflows/build-fpk.yml) 获取最新版本\n\n### Nix / NixOS\n\nVoiceHub 提供了一个 Nix flake，用于构建、开发和在 NixOS 上部署。\n\n#### 前提条件\n\n- [Nix](https://nixos.org/download)（带 flake 支持）\n- PostgreSQL 数据库\n\n#### NixOS 部署\n\n将 VoiceHub 添加为 flake input：\n\n```nix\n{\n  inputs = {\n    nixpkgs.url = \"github:NixOS/nixpkgs/nixos-unstable\";\n    voicehub.url = \"github:laoshuikaixue/VoiceHub\";\n  };\n\n  outputs = { self, nixpkgs, voicehub, ... }: {\n    nixosConfigurations.my-server = nixpkgs.lib.nixosSystem {\n      specialArgs = { inherit voicehub; };\n      modules = [\n        voicehub.nixosModules.default\n        ./configuration.nix\n      ];\n    };\n  };\n}\n```\n\n\u003e [!TIP]\n\u003e 启用 Binary Cache 可大幅加快构建速度，详见下方[使用 Binary Cache 加速构建](#使用-binary-cache-加速构建)。\n\n然后在 NixOS 配置中使用模块，根据数据库管理方式选择对应场景。\n\n```nix\n# 场景 A：自动配置本地 PostgreSQL\n# environmentFile 只需提供 JWT_SECRET，DATABASE_URL 由模块自动构造\n{ pkgs, inputs, config, ... }: {\n  imports = [ inputs.voicehub.nixosModules.default ];\n\n  services.voicehub = {\n    enable = true;\n    database.createLocally = true;\n    environmentFile = config.sops.templates.\"voicehub-env\".path;\n    runDeployScript = true;\n  };\n\n  sops.templates.\"voicehub-env\" = {\n    content = ''\n      JWT_SECRET=${config.sops.placeholder.\"voicehub/jwt-secret\"}\n    '';\n  };\n}\n```\n\n```nix\n# 场景 B：手动管理数据库（Neon / Docker / 远程 PG）\n# environmentFile 需同时提供 DATABASE_URL 和 JWT_SECRET\n{ pkgs, inputs, config, ... }: {\n  imports = [ inputs.voicehub.nixosModules.default ];\n\n  services.voicehub = {\n    enable = true;\n    environmentFile = config.sops.templates.\"voicehub-env\".path;\n    runDeployScript = true;\n  };\n\n  sops.templates.\"voicehub-env\" = {\n    content = ''\n      DATABASE_URL=${config.sops.placeholder.\"voicehub/database-url\"}\n      JWT_SECRET=${config.sops.placeholder.\"voicehub/jwt-secret\"}\n    '';\n  };\n}\n```\n\n环境文件 (`sops.templates.\"voicehub-env\".content`) 格式参考：\n\n```env\nDATABASE_URL=postgresql://voicehub:secret@localhost:5432/voicehub\nJWT_SECRET=your-very-secure-jwt-secret-key\nNUXT_PUBLIC_HOST=https://voicehub.example.com\n```\n\n推荐使用 [sops-nix](https://github.com/Mic92/sops-nix) 管理 secrets，避免明文存储在 Nix store 中。\n\n模块会自动设置 `DynamicUser`、`ProtectSystem=strict`、`NoNewPrivileges` 等安全加固。\n\n应用配置并部署：\n\n```bash\nsudo nixos-rebuild switch --flake .#my-server\n```\n\n查看服务状态和日志：\n\n```bash\nsystemctl status voicehub\njournalctl -u voicehub -f\n```\n\n默认监听 `0.0.0.0:3000`，可通过 `services.voicehub.host` 和 `services.voicehub.port` 修改。\n\n#### 使用 Binary Cache 加速构建\n\nVoiceHub CI 会将构建产物推送到 [Cachix](https://cachix.org) binary cache，\n下游用户可直接下载预构建的 `pnpmDeps` 和 `voicehub` 包，跳过本地构建。\n\n在你的 flake 中添加 `nixConfig` 以启用：\n\n```nix\n{\n  nixConfig = {\n    extra-substituters = [ \"https://voicehub.cachix.org\" ];\n    extra-trusted-public-keys = [ \"voicehub.cachix.org-1:CKw4/RvZy5c0WVpyo5ZyLbJgdpHZ/+epofIwGOeIOhU=\" ];\n  };\n  inputs = {\n    voicehub.url = \"github:laoshuikaixue/VoiceHub\";\n  };\n}\n```\n\n\u003e [!IMPORTANT]\n\u003e 请勿通过 `follows` 覆盖 VoiceHub 的 `nixpkgs` input。缓存中的产物使用\n\u003e VoiceHub 自带的 nixpkgs 构建，替换后 hash 不同，无法命中缓存。\n\n#### 其他功能\n\n##### 开发环境\n\n进入开发 shell（自动提供 Node.js、pnpm、PostgreSQL 客户端）：\n\n```bash\nnix develop\n```\n\n然后在 shell 内：\n\n```bash\ncp .env.example .env   # 配置 DATABASE_URL + JWT_SECRET\npnpm install\npnpm run dev           # 启动开发服务器 (port 3000)\n```\n\n##### 构建\n\n```bash\nnix build              # 产出 result/bin/voicehub\n```\n\n构建产物可以直接运行（需要 `DATABASE_URL` 等环境变量）：\n\n```bash\nDATABASE_URL=\"postgresql://...\" JWT_SECRET=\"...\" ./result/bin/voicehub\n```\n\n或使用附带的环境文件：\n\n```bash\nnix run .#default --impure\n```\n\n\u003e `nix run` 需要设置 `DATABASE_URL` 环境变量，否则会启动失败。\n\n##### 更新 pnpm 依赖哈希\n\n当 `pnpm-lock.yaml` 更新后，需要同步 `flake.nix` 中的 `pnpmDeps` 哈希。仓库已配置 GitHub Actions，会在 `pnpm-lock.yaml` 或 `flake.nix` 变更时自动计算新哈希并提交回触发分支。\n\n如果需要在本地手动更新，可以先将 `flake.nix` 中 `pnpmDeps.hash` 临时改为空字符串，然后运行：\n\n```bash\nnix build .#voicehub\n```\n\nNix 会因固定输出哈希不匹配而失败，并输出 `got: sha256-...`，将该值写回 `pnpmDeps.hash` 即可。也可以使用 impure 构建辅助命令（需要网络和已安装的 pnpm）：\n\n```bash\nnix run .#build                # 在项目目录中执行，生成 .output 目录\n```\n\n---\n\n### 本地开发部署\n\n#### 前提条件\n\n- Node.js 20+\n- PostgreSQL 数据库（推荐使用 Neon）\n- Redis 数据库（可选，暂不推荐）\n\n#### 快速开始\n\n1. 克隆项目\n\n```bash\ngit clone https://github.com/laoshuikaixue/VoiceHub.git\ncd VoiceHub\n```\n\n2. 安装依赖\n\n```bash\npnpm install --frozen-lockfile\n```\n\n3. 配置环境变量\n\n复制 `.env.example` 文件并重命名为 `.env`：\n\n```bash\ncp .env.example .env\n```\n\n编辑 `.env` 文件，配置必需的环境变量：\n\n```env\n# 数据库连接地址（必填）\nDATABASE_URL=\"postgresql://username:password@host:port/database?sslmode=require\"\n# 可能需要替换成 ?sslmode=disable\n\n# JWT 认证密钥（必填）\nJWT_SECRET=\"your-very-secure-jwt-secret-key\"\n\n# 应用运行环境（可选）\nNODE_ENV=development\n```\n\n4. 初始化数据库\n\n首次运行需要初始化数据库结构：\n\n```bash\n# 生成数据库迁移文件\npnpm run db:generate\n\n# 执行数据库迁移\npnpm run db:migrate\n```\n\n或使用一键部署命令（推荐）：\n\n```bash\npnpm run deploy\n```\n\n5. 创建管理员账户\n\n系统会在首次部署时自动创建管理员账户。如需手动创建：\n\n```bash\npnpm run create-admin\n```\n\n默认管理员账户：\n\n- 用户名：admin\n- 密码：admin123\n\n6. 启动开发服务器\n\n```bash\npnpm run dev\n```\n\n应用将在 http://localhost:3000 启动。\n\n### 生产环境部署\n\n1. 构建生产版本\n\n```bash\npnpm run build\n```\n\n2. 启动生产服务器\n\n```bash\npnpm run start\n```\n\n### 数据库管理命令\n\n```bash\n# 新的数据库初始化\npnpm run init-help\n\n# 生成迁移文件\npnpm run db:generate\n\n# 执行数据库迁移\npnpm run db:migrate\n\n# 推送模式变更到数据库（开发环境）\npnpm run db:push\n\n# 启动 Drizzle Studio（数据库管理界面）\npnpm run db:studio\n\n# 清空数据库并重新创建管理员\npnpm run clear-db\n\n# 安全迁移（带备份）\npnpm run safe-migrate\n```\n\n### 升级与迁移\n\n有关如何升级现有部署和迁移数据，请参阅 [升级指南](UPGRADE.md)。\n\n## 系统配置\n\n### 站点配置管理\n\nVoiceHub 提供了完整的站点配置管理功能，支持通过管理后台动态配置系统参数：\n\n#### 基本信息配置\n\n- **站点标题**：自定义系统显示名称\n- **站点描述**：系统功能描述和介绍\n- **站点Logo**：支持上传自定义Logo图片\n\n#### 播放时段管理\n\n- **多时段支持**：支持配置多个播放时段（如午间、晚间）\n- **时段名称**：自定义时段显示名称\n- **开始/结束时间**：精确到分钟的时间控制\n- **时段排序**：支持拖拽调整时段显示顺序\n\n#### 通知系统配置\n\n- **通知开关**：控制系统通知功能的启用状态\n- **通知类型**：配置不同类型通知的发送规则\n- **通知模板**：自定义通知消息的格式和内容\n\n### 数据库备份与恢复\n\n系统提供了完整的数据备份和恢复解决方案：\n\n#### 备份功能\n\n- **完整备份**：包含所有数据表的完整系统备份\n- **用户数据备份**：仅备份用户相关数据（用户、歌曲、投票等）\n- **增量备份**：支持基于时间的增量备份策略\n\n#### 恢复功能\n\n- **合并模式**：将备份数据与现有数据合并，保留现有数据\n- **替换模式**：完全替换现有数据（谨慎使用）\n- **数据验证**：恢复前自动验证备份文件完整性\n\n### 权限与角色管理\n\nVoiceHub 实现了细粒度的权限控制系统：\n\n#### 角色类型\n\n- **超级管理员 (SUPER_ADMIN)**：拥有所有系统权限，包括用户管理、系统配置、数据库管理等\n- **管理员 (ADMIN)**：拥有日常管理权限，如用户管理、排期管理、歌曲管理、系统配置等\n- **歌曲管理员 (SONG_ADMIN)**：专门负责歌曲相关管理，包括排期管理、歌曲管理、打印排期等\n- **普通用户 (USER)**：基本的点歌、投票和查看权限\n\n#### 权限分类\n\n- **内容管理权限**：排期管理、歌曲管理、打印排期等\n- **用户管理权限**：创建、编辑、删除用户账户\n- **系统管理权限**：通知管理、播放时间管理、学期管理、黑名单管理、站点配置、数据库管理等\n\n#### 权限继承与分配\n\n- **SUPER_ADMIN**：拥有所有权限\n- **ADMIN**：拥有除数据库管理外的所有权限\n- **SONG_ADMIN**：拥有内容管理相关权限（排期、歌曲、打印）\n- **USER**：仅拥有基本的点歌和查看权限\n\n#### 权限验证\n\n- 前端基于角色动态显示界面元素和菜单\n- 后端API进行严格的权限验证\n- 支持页面级和功能级的权限控制\n\n## 环境变量说明\n\n| 变量名          | 必填 | 说明                              | 示例值                                                                 |\n|--------------|----|---------------------------------|---------------------------------------------------------------------|\n| DATABASE_URL | 是  | PostgreSQL数据库连接字符串              | `postgresql://username:password@host:port/database?sslmode=require` |\n| JWT_SECRET   | 是  | JWT令牌签名密钥，建议使用强随机字符串            | `your-very-secure-jwt-secret-key`                                   |\n| NODE_ENV     | 否  | 运行环境，development或production     | `production`                                                        |\n| REDIS_URL    | 否  | Redis缓存服务连接字符串，填写后自动启用Redis缓存功能 | `redis://default:password@host:port`                                |\n| NITRO_PRESET | 否  | Nitro预设                         | `vercel`                                                            |\n| NUXT_PUBLIC_HOST | 否  | 用于 CORS 和反向代理的主机名验证 | `your-app.com`                                                            |\n| NUXT_PUBLIC_SEO_CONFIG | 否  | 用于自定义 PWA/SEO 配置的 JSON 字符串 | `{\"title\":\"VoiceHub校园广播站点歌系统\",\"shortName\":\"校园广播\",\"description\":\"校园广播站点歌系统 - 让你的声音被听见\",\"logo\":\"/images/logo.png\"}` |\n\n## OAuth 配置\n\n系统支持通过 OAuth 提供商（如 GitHub、Casdoor、Google 等）快速创建账户和登录：\n\n1. **在管理员后台配置**：\n  - 导航到系统设置 \u003e OAuth 配置\n  - 配置基础设置：\n    - **OAuth 重定向 URI**：`https://yourdomain.com/api/auth/[provider]/callback`\n    - **OAuth State 密钥**：强随机字符串，用于 state 参数加密\n  - 启用需要的 OAuth 提供商并填写相应凭证：\n    - GitHub：Client ID / Secret\n    - Casdoor：Server URL / Client ID / Secret / Organization Name\n    - Google：Client ID / Secret\n    - 第三方 OAuth2：完整的 OAuth 端点和字段映射\n\n2. **OAuth 提供商配置**：\n  在 OAuth 提供商的开发者控制台配置重定向 URI，确保与后台配置一致\n\n3. **账户创建流程**：\n  - 用户点击 OAuth 登录按钮\n  - 完成 OAuth 认证后，若身份未关联，用户可选择：\n    - 创建新账户：设置用户名和密码，直接创建新账户\n    - 绑定现有账户：输入现有用户名和密码进行绑定\n  - 成功后自动登录\n\n4. **安全特性**：\n  - 所有密码使用 bcrypt 加密\n  - OAuth 状态参数使用 AES 加密校验\n  - 绑定令牌有 10 分钟有效期\n  - 支持账户锁定和风险控制\n\n## 项目结构\n\n```\nVoiceHub/\n├── .github/                   # GitHub 配置目录\n│   └── workflows/             # GitHub Actions 工作流\n│       ├── build-fpk.yml      # FnOS FPK 安装包构建\n│       ├── docker-build.yml   # Docker 镜像构建\n│       ├── docker-postgres.yml # PostgreSQL Docker 镜像构建\n│       ├── nix.yml            # Nix 构建校验\n│       └── update-nix-pnpm-hash.yml # 自动同步 pnpmDeps 哈希\n├── app/                       # Nuxt 4 应用主目录\n│   ├── app.vue                # 应用入口文件\n│   ├── assets/                # 静态资源目录\n│   │   └── css/               # CSS样式文件\n│   │       ├── components.css      # 组件样式\n│   │       ├── lyric-player.module.css  # 歌词播放器样式\n│   │       ├── main.css           # 主样式文件\n│   │       ├── mobile-admin.css   # 移动端管理样式\n│   │       ├── print-fix.css      # 打印样式修复\n│   │       ├── sf-pro-icons.css   # SF Pro图标字体\n│   │       ├── theme-protection.css # 主题保护样式\n│   │       ├── transitions.css    # 过渡动画样式\n│   │       ├── variables.css      # CSS变量定义\n│   │       └── year-review.css    # 年度回顾样式\n│   ├── components/            # Vue组件目录\n│   │   ├── Admin/             # 管理员功能组件\n│   │   │   ├── ApiKeyManager.vue      # API密钥管理\n│   │   │   ├── BackupManager.vue      # 数据库备份管理\n│   │   │   ├── BatchUpdateModal.vue   # 批量更新模态框\n│   │   │   ├── BlacklistManager.vue   # 黑名单管理\n│   │   │   ├── CardCodesManager.vue   # 点歌券管理\n│   │   │   ├── DataAnalysisPanel.vue  # 数据分析面板\n│   │   │   ├── DatabaseManager.vue    # 数据库管理\n│   │   │   ├── EmailTemplateManager.vue # 邮件模板管理\n│   │   │   ├── NotificationSender.vue # 通知发送管理\n│   │   │   ├── OAuthConfigManager.vue # OAuth 配置管理\n│   │   │   ├── OverviewDashboard.vue  # 管理概览仪表板\n│   │   │   ├── PlayTimeManager.vue    # 播放时间管理\n│   │   │   ├── ProviderConfigSection.vue # OAuth 提供商配置组件\n│   │   │   ├── RequestTimeManager.vue # 点歌时间管理\n│   │   │   ├── ScheduleForm.vue       # 排期表单\n│   │   │   ├── ScheduleItemPrint.vue  # 排期项目打印\n│   │   │   ├── ScheduleManager.vue    # 排期管理\n│   │   │   ├── SchedulePlaylistFilterModal.vue # 排期歌单过滤器\n│   │   │   ├── SchedulePrinter.vue    # 排期打印功能\n│   │   │   ├── ScheduleTablePrint.vue # 排期表格打印功能\n│   │   │   ├── SemesterManager.vue    # 学期管理\n│   │   │   ├── Sidebar.vue            # 管理后台侧边栏\n│   │   │   ├── SiteConfigManager.vue  # 站点配置管理\n│   │   │   ├── SmtpManager.vue        # SMTP邮件服务管理\n│   │   │   ├── SongDownloadDialog.vue # 歌曲下载弹窗\n│   │   │   ├── SongManagement.vue     # 歌曲管理\n│   │   │   ├── SubmissionRemarkDialog.vue # 投稿备注弹窗\n│   │   │   ├── UserManager.vue        # 用户管理\n│   │   │   ├── UserSongsModal.vue     # 用户歌曲查看弹窗\n│   │   │   └── VotersModal.vue        # 投票人员查看弹窗\n│   │   ├── AMLL/              # Apple Music-Like Lyrics组件\n│   │   │   └── LyricPlayer.vue # AMLL歌词播放器\n│   │   ├── Auth/              # 认证相关组件\n│   │   │   ├── Providers/     # 第三方登录提供商组件\n│   │   │   │   ├── Casdoor/   # Casdoor登录组件\n│   │   │   │   │   └── Icon.vue # Casdoor图标\n│   │   │   │   ├── GitHub/    # GitHub登录组件\n│   │   │   │   │   └── Icon.vue # GitHub图标\n│   │   │   │   └── Google/    # Google登录组件\n│   │   │   │       └── Icon.vue # Google图标\n│   │   │   ├── ChangePasswordForm.vue # 修改密码表单\n│   │   │   ├── LoginForm.vue         # 登录表单\n│   │   │   ├── OAuthBindingCard.vue  # OAuth绑定卡片\n│   │   │   ├── CaptchaInput.vue      # 图形验证码输入组件\n│   │   │   ├── TurnstileWidget.vue   # Cloudflare Turnstile验证组件\n│   │   │   ├── OAuthButtons.vue      # OAuth登录按钮组\n│   │   │   ├── TwoFactorSetup.vue    # 双重认证设置组件\n│   │   │   └── TwoFactorVerify.vue   # 双重认证验证组件\n│   │   ├── Common/            # 通用组件\n│   │   │   └── UserSearchModal.vue   # 用户搜索弹窗\n│   │   ├── Notifications/     # 通知系统组件\n│   │   │   └── NotificationSettings.vue # 通知设置\n│   │   ├── Player/            # 播放器相关组件\n│   │   │   └── PlayerLyric/   # 播放器歌词子组件\n│   │   │       ├── AMLyric.vue        # Apple Music风格歌词\n│   │   │       └── DefaultLyric.vue   # 默认风格歌词\n│   │   ├── Songs/             # 歌曲相关组件\n│   │   │   ├── AlbumDetailsModal.vue   # 网易云音乐专辑详情弹窗\n│   │   │   ├── BilibiliEpisodesModal.vue # Bilibili剧集选择弹窗\n│   │   │   ├── DuplicateSongModal.vue # 重复歌曲处理对话框\n│   │   │   ├── ImportSongsModal.vue   # 导入歌曲弹窗\n│   │   │   ├── NeteaseLoginModal.vue  # 网易云音乐登录弹窗\n│   │   │   ├── NeteaseUploadDialog.vue # 网易云云盘上传弹窗\n│   │   │   ├── PlaylistSelectionModal.vue # 歌单选择弹窗\n│   │   │   ├── PodcastEpisodesModal.vue # 播客节目弹窗\n│   │   │   ├── QQMusicLoginModal.vue # QQ音乐登录弹窗\n│   │   │   ├── RecentSongsModal.vue   # 最近播放弹窗\n│   │   │   ├── RequestForm.vue        # 点歌表单\n│   │   │   ├── ScheduleList.vue       # 排期列表展示\n│   │   │   └── SongList.vue           # 歌曲列表\n│   │   ├── UI/                # 通用UI组件\n│   │   │   ├── AudioPlayer/   # 音频播放器组件模块\n│   │   │   │   ├── AudioElement.vue   # 音频元素组件\n│   │   │   │   ├── PlayerControls.vue # 播放器控制组件\n│   │   │   │   ├── PlayerInfo.vue     # 播放器信息组件\n│   │   │   │   └── VolumeControl.vue  # 播放器音量控制组件\n│   │   │   ├── Common/        # 通用UI组件\n│   │   │   │   ├── CustomSelect.vue   # 自定义选择器\n│   │   │   │   ├── DataTable.vue      # 通用数据表格组件\n│   │   │   │   ├── ErrorBoundary.vue  # 错误边界组件\n│   │   │   │   ├── LoadingState.vue   # 加载状态组件\n│   │   │   │   ├── Pagination.vue     # 翻页组件\n│   │   │   │   ├── Popover.vue        # 弹出框组件\n│   │   │   │   ├── SearchFilter.vue   # 搜索过滤组件\n│   │   │   │   └── StatCard.vue       # 统计卡片组件\n│   │   │   ├── AppleMusicLyrics.vue   # 类Apple Music风格歌词显示组件\n│   │   │   ├── AudioPlayer.vue        # 主音频播放器组件\n│   │   │   ├── BilibiliIframeModal.vue # Bilibili视频预览弹窗\n│   │   │   ├── ConfirmDialog.vue      # 确认对话框\n│   │   │   ├── Icon.vue               # 图标组件\n│   │   │   ├── LyricsModal.vue        # 全屏歌词模态框组件\n│   │   │   ├── MarqueeText.vue        # 滚动文本显示组件\n│   │   │   ├── Notification.vue       # 单个通知组件\n│   │   │   ├── NotificationContainer.vue # 通知容器组件\n│   │   │   ├── PageTransition.vue     # 页面过渡动画\n│   │   │   ├── ProgressBar.vue        # 进度条组件\n│   │   │   ├── AppLoadingScreen.vue   # 启动加载屏幕组件\n│   │   │   ├── SongComments.vue       # 网易云音乐评论组件\n│   │   │   └── WarpCanvas.vue         # 动态画布背景组件\n│   │   ├── year-review/       # 年度回顾组件\n│   │   └── SiteFooter.vue         # 站点页脚\n│   ├── composables/           # Vue 3 组合式API\n│   │   ├── useAdmin.ts         # 管理员功能hooks\n│   │   ├── useAudioPlayer.ts   # 音频播放器hooks\n│   │   ├── useAudioPlayerControl.ts # 音频播放器控制hooks\n│   │   ├── useAudioPlayerEnhanced.ts # 增强音频播放器hooks\n│   │   ├── useAudioPlayerSync.ts # 音频播放器同步hooks\n│   │   ├── useAudioQuality.ts  # 音质管理hooks\n│   │   ├── useAudioVisualizer.ts # 音频可视化hooks\n│   │   ├── useAuth.ts          # 认证功能hooks\n│   │   ├── useBackgroundRenderer.ts # 背景渲染hooks\n│   │   ├── useBilibiliPreview.ts # Bilibili视频预览hooks\n│   │   ├── useErrorHandler.ts  # 错误处理hooks\n│   │   ├── useLyricManager.ts  # 歌词管理hooks\n│   │   ├── useLyricPlayer.ts   # 类Apple Music风格歌词播放器hooks\n│   │   ├── useLyrics.ts        # 歌词功能hooks\n│   │   ├── useLyricSettings.ts # 歌词设置hooks\n│   │   ├── useMediaSession.ts  # 媒体会话API hooks\n│   │   ├── useMusicSources.ts    # 音乐源管理hooks\n│   │   ├── useMusicWebSocket.ts  # 音乐WebSocket hooks\n│   │   ├── useNotifications.ts # 通知功能hooks\n│   │   ├── usePermissions.ts   # 权限管理hooks\n│   │   ├── useProgress.ts      # 进度管理hooks\n│   │   ├── useProgressEvents.ts # 进度事件hooks\n│   │   ├── useRequestDedup.ts  # 请求去重hooks\n│   │   ├── useSemesters.ts     # 学期管理hooks\n│   │   ├── useSiteConfig.js    # 站点配置hooks\n│   │   ├── useSongPlayer.ts    # 歌曲播放器hooks\n│   │   ├── useSongs.ts         # 歌曲管理hooks\n│   │   ├── useSyncedTime.ts    # 时间同步hooks\n│   │   ├── useToast.ts         # Toast提示hooks\n│   │   └── useUserFilters.ts  # 用户过滤器hooks\n│   ├── drizzle/               # 数据库相关\n│   │   ├── db.ts               # 数据库连接\n│   │   ├── schema.ts           # 数据库模型\n│   │   └── migrations/         # 数据库迁移文件\n│   ├── layouts/               # 布局组件\n│   │   └── default.vue         # 默认布局模板\n│   ├── middleware/            # 中间件\n│   │   └── auth.global.ts      # 全局认证中间件\n│   ├── pages/                 # 页面组件（Nuxt 4路由）\n│   │   ├── account/           # 账户管理页面\n│   │   │   └── index.vue      # 账户中心（绑定管理）\n│   │   ├── auth/              # 认证相关页面\n│   │   │   └── error.vue      # 认证错误页面\n│   │   ├── change-password.vue # 修改密码页面\n│   │   ├── dashboard.vue       # 用户仪表盘\n│   │   ├── forgot-password.vue # 找回密码页面\n│   │   ├── index.vue           # 首页\n│   │   ├── login.vue           # 登录页面\n│   │   ├── notification-settings.vue # 通知设置页面\n│   │   ├── reset-password.vue  # 重置密码页面\n│   │   └── year-review.vue     # 年度回顾页面\n│   ├── plugins/               # Nuxt插件\n│   │   ├── auth.client.ts      # 客户端认证插件\n│   │   ├── auth.server.ts      # 服务端认证插件\n│   │   └── time-sync.client.ts # 客户端时间同步插件\n│   ├── public/                # 静态文件目录\n│   │   ├── images/            # 图片资源\n│   │   │   ├── logo.png       # PNG格式Logo\n│   │   │   ├── logo.svg       # SVG格式Logo\n│   │   │   ├── search.svg     # 搜索图标\n│   │   │   └── thumbs-up.svg  # 点赞图标\n│   │   ├── favicon.ico        # 网站图标\n│   │   └── robots.txt         # 搜索引擎爬虫配置\n│   └── utils/                 # 工具函数\n│       ├── core/              # 核心工具\n│       │   └── security.ts    # 安全相关工具\n│       ├── lyric/             # 歌词处理工具\n│       │   ├── exclude.ts     # 歌词排除规则\n│       │   ├── lyricFormat.ts # 歌词格式化\n│       │   ├── lyricParser.ts # 歌词解析器\n│       │   ├── lyricStripper.ts # 歌词清理\n│       │   ├── parseLrc.ts    # LRC格式解析\n│       │   └── qrc-parser.ts  # QRC格式解析\n│       ├── bilibiliSource.ts  # 哔哩哔哩音源\n│       ├── debounce.ts       # 防抖工具\n│       ├── lyricAdapter.ts    # 歌词适配器\n│       ├── musicSources.ts    # 音乐源配置\n│       ├── musicUrl.ts        # 音乐URL处理\n│       ├── sentryUpstreamMusicErrors.ts # Sentry 上游音源错误过滤\n│       ├── neteaseApi.ts      # 网易云音乐API\n│       ├── oauth-register.ts  # OAuth注册工具\n│       ├── oauth.ts           # OAuth工具\n│       ├── timeUtils.ts       # 时间工具\n│       └── url.ts             # URL处理工具\n├── server/                # 服务端代码\n│   ├── api/                # API路由\n│   │   ├── admin/          # 管理员API\n│   │   │   ├── api-keys/            # API密钥管理API\n│   │   │   │   ├── [id].delete.ts   # 删除API密钥\n│   │   │   │   ├── [id].get.ts      # 获取API密钥详情\n│   │   │   │   ├── [id].put.ts      # 更新API密钥\n│   │   │   │   ├── index.get.ts     # 获取API密钥列表\n│   │   │   │   ├── index.post.ts    # 创建API密钥\n│   │   │   │   └── logs.get.ts      # API使用日志\n│   │   │   ├── backup/              # 备份管理API\n│   │   │   │   ├── delete/          # 删除备份子目录\n│   │   │   │   │   └── [filename].delete.ts\n│   │   │   │   ├── download/        # 下载备份子目录\n│   │   │   │   │   └── [filename].get.ts\n│   │   │   │   ├── clear.post.ts    # 清空备份历史\n│   │   │   │   ├── download.get.ts  # 下载备份\n│   │   │   │   ├── export.post.ts   # 创建备份\n│   │   │   │   ├── list.get.ts      # 获取备份列表\n│   │   │   │   ├── restore-chunk.post.ts # 恢复备份分片\n│   │   │   │   ├── restore.post.ts  # 恢复备份\n│   │   │   │   └── upload.post.ts   # 上传备份文件\n│   │   │   ├── blacklist/           # 黑名单管理API\n│   │   │   │   ├── [id].delete.ts   # 删除黑名单项\n│   │   │   │   ├── [id].patch.ts    # 更新黑名单项\n│   │   │   │   ├── index.get.ts     # 获取黑名单列表\n│   │   │   │   └── index.post.ts    # 添加黑名单项\n│   │   │   ├── card-codes/          # 点歌券管理API\n│   │   │   │   ├── [id].put.ts      # 更新单张点歌券\n│   │   │   │   ├── create.post.ts   # 创建点歌券\n│   │   │   │   ├── export.get.ts    # 导出点歌券\n│   │   │   │   ├── index.get.ts     # 获取点歌券列表\n│   │   │   │   ├── redeem-logs.get.ts # 获取点歌券日志\n│   │   │   │   └── update.post.ts   # 批量更新点歌券\n│   │   │   ├── database/            # 数据库管理API\n│   │   │   │   ├── cleanup.post.ts  # 数据库清理\n│   │   │   │   ├── performance.get.ts # 数据库性能监控\n│   │   │   │   ├── pool-status.get.ts # 连接池状态\n│   │   │   │   ├── reset.post.ts    # 重置数据库\n│   │   │   │   └── status.get.ts    # 数据库状态\n│   │   │   ├── db-status.get.ts     # 数据库状态检查\n│   │   │   ├── email-templates/     # 邮件模板管理API\n│   │   │   │   ├── index.delete.ts  # 删除邮件模板\n│   │   │   │   ├── index.get.ts     # 获取邮件模板列表\n│   │   │   │   ├── index.post.ts    # 创建/更新邮件模板\n│   │   │   │   └── preview.post.ts  # 预览邮件模板\n│   │   │   ├── fix-sequence.post.ts # 修复数据库序列\n│   │   │   ├── notifications/       # 管理员通知API\n│   │   │   │   └── send.post.ts     # 发送通知\n│   │   │   ├── play-times/          # 播放时间管理API\n│   │   │   │   ├── [id].ts          # 播放时间操作\n│   │   │   │   ├── index.post.ts    # 创建播放时间\n│   │   │   │   └── index.ts         # 播放时间列表\n│   │   │   ├── replay-requests/     # 重播申请管理API\n│   │   │   │   ├── index.get.ts     # 获取重播申请列表\n│   │   │   │   └── reject.post.ts   # 拒绝重播申请\n│   │   │   ├── request-times/       # 点歌时间管理API\n│   │   │   │   ├── [id].ts          # 点歌时间操作\n│   │   │   │   ├── index.post.ts    # 创建点歌时间\n│   │   │   │   └── index.ts         # 点歌时间列表\n│   │   │   ├── schedule/            # 排期管理API\n│   │   │   │   ├── bulk-publish.post.ts # 批量发布排期\n│   │   │   │   ├── draft.post.ts    # 保存排期草稿\n│   │   │   │   ├── full.get.ts      # 获取完整排期数据（包含草稿）\n│   │   │   │   ├── move-date.post.ts # 排期日期迁移\n│   │   │   │   ├── publish.post.ts  # 发布排期草稿\n│   │   │   │   ├── remove.post.ts   # 移除排期\n│   │   │   │   └── sequence.post.ts # 更新排期顺序\n│   │   │   ├── schedule.post.ts     # 创建排期\n│   │   │   ├── semesters/           # 学期管理API\n│   │   │   │   ├── [id].delete.ts   # 删除学期\n│   │   │   │   ├── [id].put.ts      # 更新学期\n│   │   │   │   ├── index.get.ts     # 获取学期列表\n│   │   │   │   ├── index.post.ts    # 创建学期\n│   │   │   │   └── set-active.post.ts # 设置活跃学期\n│   │   │   ├── smtp/                # SMTP邮件服务API\n│   │   │   │   ├── reload.post.ts   # 重新加载SMTP配置\n│   │   │   │   ├── test-connection.post.ts # 测试SMTP连接\n│   │   │   │   └── test-email.post.ts # 发送测试邮件\n│   │   │   ├── songs/               # 管理员歌曲管理API\n│   │   │   │   ├── delete.post.ts   # 删除歌曲\n│   │   │   │   ├── mark-played.post.ts  # 标记歌曲已播放\n│   │   │   │   └── reject.post.ts  # 驳回歌曲\n│   │   │   ├── stats.get.ts         # 统计数据\n│   │   │   ├── activities.get.ts    # 活动管理API\n│   │   │   ├── stats/               # 详细统计API\n│   │   │   │   ├── active-users.get.ts # 活跃用户统计\n│   │   │   │   ├── realtime.get.ts  # 实时统计\n│   │   │   │   ├── semester-comparison.get.ts # 学期对比统计\n│   │   │   │   ├── top-songs.get.ts # 热门歌曲统计\n│   │   │   │   ├── trends.get.ts    # 趋势分析\n│   │   │   │   └── user-engagement.get.ts # 用户参与度统计\n│   │   │   ├── system-settings/     # 系统设置API\n│   │   │   │   ├── env-oauth-import.post.ts # 导入环境变量OAuth配置\n│   │   │   │   ├── env-oauth.get.ts # 获取环境变量OAuth配置\n│   │   │   │   ├── index.post.ts    # 更新系统设置\n│   │   │   │   ├── index.ts         # 获取系统设置\n│   │   │   │   └── secretMask.ts    # 密钥脱敏工具\n│   │   │   └── users/               # 用户管理API\n│   │   │       ├── [id]/            # 用户详情操作子目录\n│   │   │       │   ├── reset-password.post.ts # 重置用户密码\n│   │   │       │   ├── songs.get.ts     # 获取用户点歌记录\n│   │   │       │   ├── status-logs.get.ts # 获取用户状态变更日志\n│   │   │       │   └── status.put.ts    # 更新用户状态\n│   │   │       ├── [id].delete.ts   # 删除用户\n│   │   │       ├── [id].put.ts      # 更新用户\n│   │   │       ├── [id].get.ts      # 用户详情\n│   │   │       ├── batch-grade-update.post.ts # 批量年级更新\n│   │   │       ├── batch-status.put.ts # 批量状态更新\n│   │   │       ├── batch-update.post.ts # 批量更新用户\n│   │   │       ├── batch.post.ts    # 批量操作用户\n│   │   │       ├── index.get.ts     # 获取用户列表\n│   │   │       ├── index.post.ts    # 创建用户\n│   │   │       ├── index.ts         # 用户管理\n│   │   │       ├── options.ts       # 用户管理选项\n│   │   │       └── status-logs.get.ts # 用户状态日志\n│   │   ├── api-enhanced/          # 网易云音乐API\n│   │   │   └── netease/           # 网易云增强接口代理\n│   │   │       └── [...path].ts   # 转发网易云API请求\n│   │   ├── auth/           # 认证API\n│   │   │   ├── captcha.get.ts         # 图形验证码\n│   │   │   ├── oauth-register-options.get.ts # OAuth注册选项\n│   │   │   ├── 2fa/             # 2FA验证API\n│   │   │   │   ├── send-email.post.ts # 发送2FA验证邮件\n│   │   │   │   └── verify.post.ts     # 验证2FA代码\n│   │   │   ├── webauthn/      # WebAuthn 相关 API\n│   │   │   │   ├── login/     # 登录验证\n│   │   │   │   │   ├── options.post.ts   # 获取登录 Challenge\n│   │   │   │   │   └── verify.post.ts    # 验证登录签名\n│   │   │   │   ├── register/  # 设备注册\n│   │   │   │   │   ├── options.get.ts    # 获取注册 Challenge\n│   │   │   │   │   └── verify.post.ts    # 验证注册签名\n│   │   │   │   └── rename.post.ts    # 重命名设备\n│   │   │   ├── [provider]/           # OAuth提供商路由\n│   │   │   │   ├── callback.get.ts   # OAuth回调处理\n│   │   │   │   └── index.get.ts      # OAuth授权跳转\n│   │   │   ├── bind.post.ts          # 绑定社交账号\n│   │   │   ├── change-password.post.ts # 修改密码\n│   │   │   ├── forgot-password.post.ts # 找回密码\n│   │   │   ├── identities.get.ts     # 获取已绑定身份列表\n│   │   │   ├── login.post.ts        # 用户登录\n│   │   │   ├── logout.post.ts       # 用户登出\n│   │   │   ├── oauth-register.post.ts # OAuth用户注册\n│   │   │   ├── reset-password.post.ts # 重置密码\n│   │   │   ├── set-initial-password.post.ts # 设置初始密码\n│   │   │   ├── unbind.post.ts        # 解绑社交账号\n│   │   │   └── verify.get.ts        # 验证Token并获取用户信息\n│   │   ├── bilibili/       # Bilibili相关API\n│   │   │   ├── playurl.get.ts       # 获取播放链接\n│   │   │   └── search.get.ts        # Bilibili视频搜索\n│   │   ├── blacklist/      # 黑名单API\n│   │   │   └── check.post.ts        # 检查黑名单\n│   │   ├── card-codes/     # 点歌券API\n│   │   │   └── validate.post.ts     # 验证点歌券可用性\n│   │   ├── meow/           # MeoW账号绑定API\n│   │   │   ├── bind.post.ts         # 绑定MeoW账号\n│   │   │   └── unbind.post.ts       # 解绑MeoW账号\n│   │   ├── music/          # 音乐相关API\n│   │   │   ├── resolve-url.post.ts # 音乐播放链接统一解析\n│   │   │   ├── state.post.ts        # 音乐状态管理\n│   │   │   └── websocket.ts         # 音乐WebSocket连接\n│   │   ├── native-api/     # 原生音乐API\n│   │   │   ├── lyric/               # 歌词API\n│   │   │   │   └── tx.get.ts        # 腾讯音乐歌词\n│   │   │   ├── qq/                  # QQ音乐账号API\n│   │   │   │   ├── avatar.get.ts    # 获取QQ音乐头像\n│   │   │   │   ├── check-login.post.ts # 检查扫码登录情况\n│   │   │   │   └── login-qr.get.ts  # 获取登录二维码\n│   │   │   └── search/              # 搜索API\n│   │   │       ├── tx.get.ts        # 腾讯音乐搜索\n│   │   │       └── wy.get.ts        # 网易云音乐搜索\n│   │   ├── notifications/  # 通知系统API\n│   │   │   ├── [id]/                # 通知操作子目录\n│   │   │   │   └── read.post.ts     # 标记通知已读\n│   │   │   ├── [id].delete.ts       # 删除通知\n│   │   │   ├── clear-all.delete.ts  # 清空所有通知\n│   │   │   ├── index.ts             # 通知列表\n│   │   │   ├── meow/                # MeoW通知API\n│   │   │   │   ├── send-verification.post.ts # 发送验证码\n│   │   │   │   └── test.post.ts     # 测试通知\n│   │   │   ├── read-all.post.ts     # 标记所有已读\n│   │   │   ├── settings.post.ts     # 更新通知设置\n│   │   │   └── settings.ts          # 获取通知设置\n│   │   ├── open/           # 开放API（无需认证）\n│   │   │   ├── songs/               # 歌曲相关开放API\n│   │   │   │   └── mark-played.post.ts # 标记歌曲已播放（供外部调用）\n│   │   │   ├── schedules.get.ts     # 获取公开排期\n│   │   │   └── songs.get.ts         # 获取公开歌曲列表\n│   │   ├── play-times/     # 播放时间API\n│   │   │   └── index.ts             # 播放时间管理\n│   │   ├── request-times/  # 点歌时间API\n│   │   │   └── index.ts             # 点歌时间管理\n│   │   ├── progress/       # 进度条API\n│   │   │   ├── events.ts            # 进度事件\n│   │   │   └── id.ts                # 进度ID管理\n│   │   ├── proxy/          # 代理服务API\n│   │   │   └── image.get.ts         # 图片代理（解决HTTP/HTTPS混合内容及跨域问题）\n│   │   ├── semesters/      # 学期API\n│   │   │   ├── current.get.ts       # 获取当前学期\n│   │   │   └── options.get.ts       # 获取学期选项\n│   │   ├── site-config.get.ts       # 站点配置API\n│   │   ├── songs/          # 歌曲相关API\n│   │   │   ├── [id]/                # 歌曲详情操作\n│   │   │   │   ├── update.put.ts    # 更新歌曲信息\n│   │   │   │   └── voters.get.ts    # 获取投票人员\n│   │   │   ├── collaborators/       # 联合投稿管理\n│   │   │   │   └── reply.post.ts    # 处理联合投稿邀请\n│   │   │   ├── add.post.ts          # 添加歌曲\n│   │   │   ├── count.get.ts         # 歌曲统计\n│   │   │   ├── import.post.ts       # 导入歌曲\n│   │   │   ├── index.get.ts         # 歌曲列表\n│   │   │   ├── public.get.ts        # 公开歌曲列表\n│   │   │   ├── request.post.ts      # 点歌请求\n│   │   │   ├── replay.post.ts       # 提交重播申请\n│   │   │   ├── replay.delete.ts     # 撤回重播申请\n│   │   │   ├── submission-status.get.ts # 投稿状态\n│   │   │   ├── vote.post.ts         # 投票\n│   │   │   └── withdraw.post.ts     # 撤回歌曲\n│   │   ├── sys/            # 系统辅助API\n│   │   │   └── time.get.ts          # 获取校准后的服务器时间\n│   │   ├── system/         # 系统API\n│   │   │   ├── instance.get.ts      # 实例信息\n│   │   │   ├── location.get.ts      # 获取系统位置信息\n│   │   │   ├── reconnect.post.ts    # 重连数据库\n│   │   │   └── status.get.ts        # 系统状态\n│   │   ├── user/           # 用户相关API\n│   │   │   ├── 2fa/             # 2FA管理API\n│   │   │   │   ├── disable.post.ts  # 关闭双重认证\n│   │   │   │   ├── enable.post.ts   # 开启双重认证\n│   │   │   │   └── generate.post.ts # 生成双重认证密钥\n│   │   │   ├── email/               # 用户邮箱管理\n│   │   │   │   ├── bind.post.ts     # 绑定邮箱\n│   │   │   │   ├── resend-verification.post.ts # 重发验证邮件\n│   │   │   │   ├── send-code.post.ts # 发送验证码\n│   │   │   │   ├── unbind.post.ts   # 解绑邮箱\n│   │   │   │   └── verify-code.post.ts # 验证邮箱验证码\n│   │   │   └── year-review.get.ts   # 获取年度回顾数据\n│   │   └── users/          # 用户API\n│   │       ├── meow/                # 用户MeoW相关子目录\n│   │       ├── social-accounts/     # 社交账号管理\n│   │       │   ├── meow.delete.ts   # 删除MeoW绑定\n│   │       │   └── meow.post.ts     # MeoW账号操作\n│   │       ├── search.get.ts        # 搜索用户\n│   │       └── social-accounts.get.ts # 获取社交账号\n│   ├── config/             # 服务端配置\n│   │   └── constants.ts    # 风控阈值与时间窗口常量\n│   ├── error.ts            # 全局错误处理\n│   ├── middleware/         # 服务端中间件\n│   │   ├── api-auth.ts     # API认证中间件\n│   │   ├── api-cors.ts     # API跨域中间件\n│   │   └── auth.ts         # 认证中间件\n│   ├── plugins/            # 服务端插件\n│   │   └── error-handler.ts # 错误处理插件\n│   ├── services/           # 业务服务层\n│   │   ├── apiLogService.ts # API日志服务\n│   │   ├── cardCodeLifecycleService.ts # 点歌券生命周期服务\n│   │   ├── cacheService.ts # 缓存服务（Redis缓存管理）\n│   │   ├── meowNotificationService.ts # MeoW通知服务\n│   │   ├── notificationService.ts # 通知服务\n│   │   ├── securityService.ts # 安全服务\n│   │   ├── smtpService.ts  # SMTP邮件服务\n│   │   └── userService.ts # 用户服务\n│   ├── utils/              # 服务端工具函数\n│   │   ├── auth.ts         # 认证工具函数\n│   │   ├── bilibiliWbi.ts  # Bilibili WBI签名工具\n│   │   ├── cache-helpers.ts # 缓存辅助工具\n│   │   ├── database-health.ts # 数据库健康检查\n│   │   ├── database-manager.ts # 数据库管理工具\n│   │   ├── geo.ts          # 地理位置工具\n│   │   ├── ip-utils.ts     # IP地址工具\n│   │   ├── jwt-enhanced.ts # JWT工具\n│   │   ├── log-manager.ts  # 日志管理工具\n│   │   ├── native_common.ts # 原生API通用工具\n│   │   ├── native_tx.ts    # 腾讯音乐原生API\n│   │   ├── native_wy.ts    # 网易云音乐原生API\n│   │   ├── qq_music_sdk.ts # QQ音乐SDK调用封装\n│   │   ├── oauth-strategies.ts # OAuth策略配置\n│   │   ├── oauth-token.ts  # OAuth令牌工具\n│   │   ├── oauth.ts        # OAuth通用工具\n│   │   ├── open-api-cache.ts # 开放API缓存\n│   │   ├── permissions.js  # 权限系统配置\n│   │   ├── redis.ts        # Redis连接和操作工具\n│   │   ├── request-utils.ts # 请求处理通用工具\n│   │   ├── siteUtils.ts    # 站点工具函数\n│   │   ├── studentMask.ts  # 学生隐私工具\n│   │   ├── submissionLimit.ts # 投稿限额工具\n│   │   ├── system-settings-defaults.ts # 系统设置默认值\n│   │   ├── twoFactorStore.ts # 双重认证存储工具\n│   │   ├── user.ts         # 用户相关工具函数\n│   │   ├── webauthn-config.ts # WebAuthn配置工具\n│   │   └── webauthn-token.ts # WebAuthn令牌工具\n│   ├── workers/            # 服务端工作进程\n│   │   └── audioEncoderWorker.js # 音频编码工作进程\n│   └── tsconfig.json       # 服务端TypeScript配置\n├── types/                 # TypeScript类型定义\n│   ├── global.d.ts         # 全局类型定义\n│   └── index.ts            # 通用类型定义\n├── .env.example           # 环境变量示例文件\n├── .gitignore             # Git忽略文件配置\n├── .vercelignore          # Vercel部署忽略文件\n├── docker-compose/        # Docker Compose配置目录\n├── docker-compose.yml     # Docker编排文件\n├── Dockerfile             # Docker构建文件\n├── drizzle.config.ts      # Drizzle配置文件\n├── flake.lock             # Nix flake锁定文件\n├── flake.nix              # Nix构建与NixOS模块配置\n├── LICENSE                # 开源许可证文件\n├── netlify.toml           # Netlify部署配置\n├── nuxt.config.ts         # Nuxt 4主配置文件\n├── package.json           # Node.js项目配置和依赖\n├── README.md              # 项目说明文档\n├── tsconfig.json          # TypeScript配置文件\n└── vercel.json            # Vercel部署配置\n```\n\n### 目录说明\n\n#### 核心目录 (app/)\n\n- **`app/components/`**: Vue组件库，按功能模块组织\n  - **`Admin/`**: 管理后台组件（排期、用户、数据分析等）\n  - **`Admin_Backup/`**: 管理组件备份目录\n  - **`AMLL/`**: Apple Music-Like Lyrics歌词播放器组件\n  - **`Auth/`**: 认证相关组件（登录、OAuth绑定等）\n  - **`Common/`**: 通用业务组件\n  - **`Notifications/`**: 通知系统组件\n  - **`Player/`**: 播放器相关组件\n  - **`Songs/`**: 歌曲相关组件（点歌、导入、歌单等）\n  - **`UI/`**: 通用UI组件（播放器、对话框、进度条等）\n  - **`year-review/`**: 年度回顾功能组件\n- **`app/pages/`**: 页面组件，Nuxt 4 自动路由\n- **`app/composables/`**: Vue 3组合式API，业务逻辑复用\n- **`app/drizzle/`**: Drizzle ORM配置、数据库连接和迁移文件\n\n#### 配置目录 (app/)\n\n- **`app/assets/css/`**: 样式文件，支持CSS变量和主题\n- **`app/plugins/`**: Nuxt插件，扩展框架功能\n- **`app/middleware/`**: 中间件，处理路由和认证\n- **`app/utils/`**: 客户端工具函数\n  - **`core/`**: 核心工具（安全等）\n  - **`lyric/`**: 歌词处理工具集\n\n#### 服务端目录 (server/)\n\n- **`server/api/`**: 服务端API，RESTful接口设计\n  - **`admin/`**: 管理员专用API（用户、排期、统计等）\n  - **`auth/`**: 认证相关API\n  - **`songs/`**: 歌曲管理API\n  - **`notifications/`**: 通知系统API\n  - **`open/`**: 公共API（无需认证）\n- **`server/config/`**: 服务端配置（常量、环境配置等）\n- **`server/middleware/`**: 服务端中间件（认证、日志等）\n- **`server/plugins/`**: 服务端插件（错误处理等）\n- **`server/services/`**: 业务逻辑服务层\n- **`server/utils/`**: 服务端工具函数\n\n#### 静态资源\n\n- **`app/public/`**: 静态文件\n- **`app/public/images/`**: 图片资源，包含Logo和图标文件\n\n## 使用说明\n\n### 普通用户\n\n1. 访问主页，查看当前排期\n2. 注册/登录账号\n3. 在仪表盘中点歌或给喜欢的歌曲投票\n   - 支持搜索网易云音乐、QQ音乐和哔哩哔哩平台\n   - 可以试听歌曲并选择音质\n   - 支持给已有歌曲投票\n   - **网易云音乐登录功能**：\n     - 扫码登录网易云音乐账号\n     - 登录后可一键添加当前排期歌曲到个人歌单\n     - 支持从个人歌单中直接投稿歌曲\n     - 支持从最近播放记录中投稿歌曲\n     - 可搜索并投稿播客和电台内容\n4. 使用内置播放器播放歌曲\n   - 支持多种音质切换（标准、HQ、无损、Hi-Res等）\n   - 实时切换音质并保持播放进度\n5. 查看通知中心获取歌曲状态更新\n\n### 管理员\n\n1. 使用管理员账号登录（默认账号：admin，密码：admin123）\n2. 进入管理后台，选择相应功能标签\n3. **排期管理**：可以看到左侧\"待排歌曲\"和右侧\"播放顺序\"\n   - 通过拖拽将歌曲从左侧添加到右侧的排期列表\n   - 可以在右侧拖拽调整歌曲播放顺序\n   - 支持播出时段管理，可设置不同时段的播放安排\n   - **草稿功能**：支持保存排期草稿，允许管理员先保存未完成的排期安排\n     - 点击\"保存草稿\"按钮保存当前排期为草稿状态\n     - 草稿不会影响公开展示的排期，可以随时修改\n     - 点击\"保存并发布\"按钮将草稿发布为正式排期\n   - 点击\"保存顺序\"按钮保存排期\n4. **打印排期**：专业的排期打印和导出功能\n   - 选择纸张大小（A4、A3、Letter、Legal）和页面方向\n   - 自定义显示内容：歌曲封面、歌名、歌手、投稿人、热度等\n   - 快捷日期选择：今天、明天、本周、下周\n   - 智能分组显示：按日期分组，有多个播出时段时自动按时间排序\n   - 实时预览：所见即所得的打印预览\n   - PDF导出：支持导出高质量PDF文件，自动处理跨域图片\n5. **歌曲管理**：查看和管理所有歌曲\n   - 支持播放歌曲并实时切换音质\n   - 动态获取最新的音乐播放链接\n   - 提供歌曲下载功能，支持批量下载管理\n   - 批量更新歌曲信息和状态\n6. **数据分析**：查看系统使用统计和数据分析\n   - 实时统计数据：用户活跃度、歌曲热度、投票趋势\n   - 学期对比分析：不同学期的数据对比\n   - 用户参与度分析：用户行为和参与度统计\n   - 趋势分析：系统使用趋势和预测\n7. **数据库管理**：数据库备份恢复和维护\n   - 创建和下载数据库备份\n   - 上传和恢复备份文件\n   - 序列重置：修复数据库序列问题\n   - 数据库状态检查和完整性验证\n8. **学期管理**：设置和管理学期信息\n   - 创建新学期（如\"2024-2025学年上学期\"）\n   - 设置当前活跃学期\n   - 点歌记录自动关联到当前学期\n9. **用户管理**：添加、编辑和删除用户\n   - 单个添加：填写用户信息（包括姓名、账号、年级、班级）\n   - 批量导入：通过EXCEL文件批量添加用户\n   - 可以重置用户密码\n10. **黑名单管理**：管理歌曲和关键词黑名单\n    - 添加具体歌曲或关键词到黑名单\n    - 自动过滤包含黑名单内容的点歌请求\n    - 支持启用/禁用黑名单项\n11. **系统设置**：配置系统参数和功能开关\n    - 站点信息配置：标题、Logo、描述等\n    - 投稿限额设置：每日/每周投稿限制\n    - 播出时段管理：配置不同的播出时间段\n    - 功能开关：启用/禁用特定功能\n12. **通知管理**：向用户发送系统通知\n    - 支持按全体用户、年级、班级或多班级发送\n    - 实时显示发送进度和结果\n    - 通知历史记录和管理\n\n## 数据库管理\n\n### Drizzle ORM + Neon Database\n\n项目使用 Drizzle ORM 作为数据库 ORM，配合 Neon Database 提供现代化的数据库解决方案。\n\n#### 核心文件结构\n\n- **`drizzle.config.ts`** - Drizzle ORM 主配置文件\n- **`app/drizzle/db.ts`** - 数据库连接和客户端配置\n- **`app/drizzle/schema.ts`** - 数据库表结构定义（TypeScript 类型安全）\n- **`app/drizzle/migrations/`** - 数据库迁移脚本目录\n\n### 数据库初始化\n\n首次部署时，系统会自动初始化数据库结构。\n\n#### 自动初始化（推荐）\n\n使用部署脚本自动完成数据库初始化：\n\n```bash\npnpm run deploy\n```\n\n该命令会：\n\n1. 检查环境变量配置\n2. 安装依赖\n3. 执行数据库迁移\n4. 创建默认管理员账户\n5. 构建应用\n\n#### 手动初始化\n\n如需手动管理数据库：\n\n1. 生成迁移文件\n\n```bash\npnpm run db:generate\n```\n\n2. 执行数据库迁移\n\n```bash\npnpm run db:migrate\n```\n\n3. 推送模式变更到数据库（开发环境）\n\n```bash\npnpm run db:push\n```\n\n4. 启动 Drizzle Studio（数据库管理界面）\n\n```bash\npnpm run db:studio\n```\n\n访问 https://local.drizzle.studio 查看和管理数据库\n\n5. 清空数据库并创建管理员\n\n```bash\npnpm run clear-db\n```\n\n### 数据库备份与恢复\n\n#### 通过管理后台\n\n1. 创建备份\n   - 登录管理后台\n   - 进入\"数据库管理\"页面\n   - 点击\"创建备份\"按钮\n   - 选择备份类型（完整备份/用户数据备份）\n\n2. 下载备份\n   - 备份完成后在列表中找到备份文件\n   - 点击\"下载\"按钮保存到本地\n\n3. 恢复备份\n   - 点击\"上传备份\"按钮\n   - 选择备份文件\n   - 选择恢复模式：\n     - 增量恢复：合并备份数据与现有数据\n     - 完全恢复：替换所有现有数据（谨慎使用）\n   - 确认并执行恢复\n\n#### 使用 PostgreSQL 命令行\n\n```bash\n# 备份数据库\npg_dump -h localhost -U username -d database_name \u003e backup.sql\n\n# 恢复数据库\npsql -h localhost -U username -d database_name \u003c backup.sql\n```\n\n### 备份文件格式\n\n- **完整备份**：包含所有数据表的 JSON 格式文件\n- **用户备份**：仅包含用户相关数据\n- **元数据**：包含创建时间、创建者、表信息等\n\n## 开发指南\n\n### 组合式API\n\n项目使用了Vue 3的组合式API，主要包括：\n\n- `useAuth`: 处理用户认证、登录、注册和权限控制\n- `useSongs`: 处理歌曲相关操作，包括获取歌曲列表、点歌和投票\n- `useAdmin`: 处理管理员操作，包括排期管理和标记播放\n- `useNotifications`: 处理通知系统，包括获取、标记已读和设置\n- `useAudioQuality`: 处理音质管理，包括音质设置和持久化\n- `useSemesters`: 处理学期管理，包括创建学期和设置活跃学期\n\n### 添加新功能\n\n1. 在 `server/api` 中添加新的API端点\n2. 在 `app/composables` 中添加相应的组合式函数\n3. 在 `app/components` 中创建UI组件\n4. 在 `app/pages` 中整合组件和功能\n\n### 数据库模型修改\n\n如需修改数据库模型：\n\n1. 编辑`app/drizzle/schema.ts`文件中的表结构定义\n2. 生成新的迁移文件：`pnpm run db:generate`\n3. 应用迁移到数据库：`pnpm run db:migrate`\n4. 确保同时更新 `types/index.ts` 中的TypeScript类型定义\n5. 使用Drizzle Studio查看数据库：`pnpm run db:studio`\n\n### OAuth 平台扩展指南\n\nVoiceHub 采用配置化与策略模式（Strategy Pattern）相结合的灵活 OAuth 扩展机制，所有 OAuth 提供商及认证设置现均已迁移至管理员后台界面。你可以直接在后台动态配置，无需修改环境变量和重启服务。\n\n对于想要通过代码深度定制 OAuth 行为（如自定义用户信息解析逻辑等）的开发者，可参考以下机制：\n\n#### 扩展步骤\n\n##### 1. 定义 OAuth 策略\n\n在 `server/utils/oauth-strategies.ts` 文件中，实现 `OAuthStrategy` 接口。该接口定义了 OAuth 流程中的三个核心方法：\n\n```typescript\nexport interface OAuthStrategy {\n  /**\n   * 获取授权跳转 URL\n   * @param redirectUri 回调地址（通常是 /api/auth/[provider]/callback）\n   * @param state 包含安全校验信息的加密字符串\n   */\n  getAuthorizeUrl(redirectUri: string, state: string): string\n\n  /**\n   * 使用 code 换取 access_token\n   * @param code 授权码\n   * @param redirectUri 回调地址\n   */\n  exchangeToken(code: string, redirectUri: string): Promise\u003cstring\u003e\n\n  /**\n   * 获取用户信息\n   * @param accessToken 访问令牌\n   */\n  getUserInfo(accessToken: string): Promise\u003cOAuthUserInfo\u003e\n}\n```\n\n**示例：接入 Google 登录**\n\n```typescript\n// server/utils/oauth-strategies.ts\nconst googleStrategy: OAuthStrategy = {\n  getAuthorizeUrl(redirectUri, state) {\n    const clientId = process.env.GOOGLE_CLIENT_ID\n    // Google 授权端点\n    return `https://accounts.google.com/o/oauth2/v2/auth?client_id=${clientId}\u0026redirect_uri=${encodeURIComponent(redirectUri)}\u0026response_type=code\u0026scope=email%20profile\u0026state=${encodeURIComponent(state)}`\n  },\n\n  async exchangeToken(code, redirectUri) {\n    // ... 实现 Google 的 Token 交换逻辑\n    // 通常是发送 POST 请求到 https://oauth2.googleapis.com/token\n  },\n\n  async getUserInfo(accessToken) {\n    // ... 实现获取 Google 用户信息的逻辑\n    // 通常是发送 GET 请求到 https://www.googleapis.com/oauth2/v3/userinfo\n    // 需返回统一的 OAuthUserInfo 格式：\n    // { id, username, email, name, avatar }\n  }\n}\n```\n\n##### 2. 注册策略\n\n在同一个文件 (`server/utils/oauth-strategies.ts`) 的 `strategies` 对象中注册你的新策略：\n\n```typescript\nconst strategies: Record\u003cstring, OAuthStrategy\u003e = {\n  github: githubStrategy,\n  casdoor: casdoorStrategy,\n  google: googleStrategy // \u003c--- 注册新平台\n  // ... 其他平台\n}\n```\n\n##### 3. 完成！\n\n现在，你可以在管理员后台的 **站点配置 -\u003e OAuth 第三方登录配置** 中直接填写该平台的信息并启用它。系统会自动处理路由分发、State 校验、CSRF 保护和用户绑定逻辑。\n\n#### Casdoor 配置说明\n\n项目已内置对 [Casdoor](https://casdoor.org/) 的支持。Casdoor 是一个开源的 UI 优先的身份认证管理系统 (IAM)，支持 OAuth 2.0、OIDC 等多种协议。\n\n要启用 Casdoor 登录，只需进入管理员后台的 **站点配置 -\u003e OAuth 第三方登录配置**，开启 Casdoor 选项，并填入以下信息：\n- **Casdoor 服务器 URL** (如 `https://your-casdoor-domain.com`)\n- **Casdoor Client ID**\n- **Casdoor Client Secret**\n- **Casdoor 组织名称**\n\n配置保存后，系统会立即启用 Casdoor 登录策略。\n\n#### 前端图标配置\n\n当添加了新的服务端 OAuth 策略后，如果需要在前端登录页面显示对应的图标按钮，请按照以下步骤操作：\n\n1.  在 `app/components/Auth/Providers` 目录下创建一个以 Provider 名称（首字母大写）命名的文件夹，例如 `Google`。\n2.  在该文件夹内创建一个 `Icon.vue` 组件，放入对应的 SVG 图标代码。\n    - 建议 SVG 大小设置为 `w-5 h-5` 以保持样式统一。\n3.  系统会自动检测并加载该图标，无需额外配置。\n\n例如：`app/components/Auth/Providers/Google/Icon.vue`\n\n**注意：** 对于 Casdoor，请创建 `app/components/Auth/Providers/Casdoor/Icon.vue`，并填入 Casdoor 的图标代码。\n\n#### OAuth 工具函数\n\n为了统一前端 OAuth 提供商的名称显示，系统提供了 `getProviderDisplayName` 工具函数。\n\n**位置**: `app/utils/oauth.ts`\n\n**使用方法**:\n\n```typescript\nimport { getProviderDisplayName } from '~/utils/oauth'\n\n// 获取显示名称\nconst displayName = getProviderDisplayName('github') // 返回 \"GitHub\"\nconst displayName2 = getProviderDisplayName('casdoor') // 返回 \"Casdoor\"\nconst displayName3 = getProviderDisplayName('google') // 返回 \"Google\" (默认首字母大写)\n```\n\n**扩展**:\n当添加新的 OAuth 提供商时，可以在 `app/utils/oauth.ts` 的 `map` 对象中添加对应的映射关系，以实现自定义显示名称。\n\n#### 添加绑定卡片\n\n为了在账号管理页面显示新添加的 OAuth 提供商绑定选项，你需要修改 `app/components/Auth/OAuthBindingCard.vue` 文件。\n\n**1. 添加计算属性**\n\n在 `\u003cscript setup\u003e` 中，添加用于获取特定提供商身份信息的计算属性：\n\n```javascript\nconst googleIdentity = computed(() =\u003e identities.value.find((i) =\u003e i.provider === 'google'))\n```\n\n**2. 添加卡片模板**\n\n在 `\u003ctemplate\u003e` 中添加对应的卡片代码。你可以复制现有的卡片代码并进行修改：\n\n```vue\n\u003c!-- Google (如果启用) --\u003e\n\u003cdiv v-if=\"config.public.oauth.google\" :class=\"itemClass\"\u003e\n  \u003cdiv class=\"flex items-center gap-4\"\u003e\n    \u003cdiv class=\"w-10 h-10 rounded-xl bg-zinc-950 flex items-center justify-center border border-zinc-800 text-zinc-100\"\u003e\n      \u003c!-- 引入你之前创建的图标组件 --\u003e\n      \u003cAuthProvidersGoogleIcon class=\"w-5 h-5\" /\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"flex flex-col\"\u003e\n      \u003cspan class=\"text-sm font-bold text-zinc-200\"\u003eGoogle\u003c/span\u003e\n      \u003cspan v-if=\"googleIdentity\" class=\"text-[11px] text-blue-500 font-medium mt-0.5\"\u003e{{ googleIdentity.providerUsername }}\u003c/span\u003e\n      \u003cspan v-else class=\"text-[11px] text-zinc-500 mt-0.5\"\u003e未绑定\u003c/span\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\n  \u003cbutton\n      v-if=\"googleIdentity\"\n      class=\"...\"\n      @click=\"confirmUnbind('google')\"\n      :disabled=\"actionLoading\"\n  \u003e\n    {{ actionLoading ? '处理中...' : '解绑' }}\n  \u003c/button\u003e\n  \u003cbutton\n      v-else\n      class=\"...\"\n      @click=\"handleBind('google')\"\n      :disabled=\"actionLoading\"\n  \u003e\n    {{ actionLoading ? '跳转中...' : '立即绑定' }}\n  \u003c/button\u003e\n\u003c/div\u003e\n```\n\n**3. 更新解绑确认逻辑**\n\n修改 `confirmUnbind` 方法，添加新提供商的显示名称映射：\n\n```javascript\nconst confirmUnbind = (provider) =\u003e {\n  let providerName = ''\n  switch (provider) {\n    case 'github':\n      providerName = 'GitHub'\n      break\n    case 'casdoor':\n      providerName = 'Casdoor'\n      break\n    case 'google':\n      providerName = 'Google'\n      break // \u003c--- 添加这一行\n    default:\n      providerName = provider\n  }\n  // ...\n}\n```\n\n---\n\n### 音源扩展开发指南\n\nVoiceHub 采用了模块化的音源架构，支持多音源故障转移和动态扩展。开发者可以轻松添加新的音乐API源，提高系统的可用性和音乐资源覆盖率。\n\n#### 音源架构概述\n\n音源系统由以下核心组件构成：\n\n- **音源配置文件** (`app/utils/musicSources.ts`)：定义音源接口、配置和默认设置\n- **音源管理器** (`app/composables/useMusicSources.ts`)：提供多音源搜索、故障转移和状态监控\n- **数据转换层**：统一不同API的响应格式\n- **故障转移机制**：自动切换到可用的备用音源\n\n#### 音源接口定义\n\n每个音源都必须实现以下接口：\n\n```typescript\nexport interface MusicSource {\n  /** 音源唯一标识 */\n  id: string\n  /** 音源显示名称 */\n  name: string\n  /** API基础URL */\n  baseUrl: string\n  /** 优先级，数字越小优先级越高 */\n  priority: number\n  /** 是否启用 */\n  enabled: boolean\n  /** 请求超时时间（毫秒），可选 */\n  timeout?: number\n  /** 自定义请求头，可选 */\n  headers?: Record\u003cstring, string\u003e\n}\n```\n\n#### 如何添加新音源\n\n##### 1. 在配置文件中添加音源\n\n编辑 `app/utils/musicSources.ts` 文件，在 `MUSIC_SOURCE_CONFIG.sources` 数组中添加新音源：\n\n```\n{\n  id: 'my-new-source',\n  name: '我的新音源',\n  baseUrl: 'https://api.example.com',\n  priority: 6, // 设置优先级\n  enabled: true,\n  timeout: 8000,\n  headers: {\n    // ...\n  }\n}\n```\n\n##### 2. 实现数据转换函数\n\n在 `app/composables/useMusicSources.ts` 中的 `searchWithSource` 函数里添加新音源的处理逻辑：\n\n```typescript\nif (source.id === 'my-new-source') {\n  // 构建API请求URL\n  url = `${source.baseUrl}/search?q=${encodeURIComponent(params.keywords)}\u0026limit=${params.limit || 30}`\n\n  // 定义响应数据转换函数\n  transformResponse = (data: any) =\u003e transformMyNewSourceResponse(data)\n}\n```\n\n##### 3. 编写数据转换函数\n\n创建对应的数据转换函数，将API响应转换为统一格式：\n\n```typescript\nconst transformMyNewSourceResponse = (response: any): any[] =\u003e {\n  if (!response || !response.data) {\n    throw new Error('API响应数据为空')\n  }\n\n  return response.data.map((song: any) =\u003e ({\n    id: song.songId,\n    title: song.songName,\n    artist: song.artistName || '未知艺术家',\n    cover: song.albumCover,\n    album: song.albumName,\n    duration: song.duration,\n    musicPlatform: 'my-platform',\n    musicId: song.songId?.toString(),\n    sourceInfo: {\n      source: 'my-new-source',\n      originalId: song.songId?.toString(),\n      fetchedAt: new Date()\n    }\n  }))\n}\n```\n\n#### 音源配置说明\n\n##### 优先级设置\n\n- **priority**: 数字越小优先级越高\n- 系统会按优先级顺序尝试音源\n\n##### 超时配置\n\n- **timeout**: 单个请求的超时时间（毫秒）\n- 建议设置为5000-10000ms\n\n##### 请求头配置\n\n- **headers**: 自定义HTTP请求头\n- 常用于设置User-Agent、Authorization等\n\n#### 数据转换函数编写\n\n##### 统一数据格式\n\n所有音源的搜索结果都应转换为以下统一格式：\n\n```\n{\n  id: string | number,           // 歌曲ID\n  title: string,                 // 歌曲标题\n  artist: string,                // 艺术家（多个艺术家使用 / 分隔）\n  cover?: string,                // 封面图片URL\n  album?: string,                // 专辑名称\n  duration?: number,             // 时长（秒）\n  musicPlatform: string,         // 音乐平台标识\n  musicId: string,               // 音乐平台的歌曲ID\n  sourceInfo: {                  // 音源信息\n    source: string,              // 音源ID\n    originalId: string,          // 原始ID\n    fetchedAt: Date             // 获取时间\n  }\n}\n```\n\n**注意**：为了确保歌曲重复匹配判断的准确性，所有音源返回的歌手信息都应使用 `/` 作为分隔符。例如：\n\n- 单个歌手：`\"周深\"`\n- 多个歌手：`\"颜人中/VaVa娃娃\"`\n\n这是为了保证各个音源的歌手格式保持一致，避免因分隔符不同导致的重复歌曲匹配失效。\n\n##### 错误处理\n\n数据转换函数应包含完善的错误处理：\n\n```typescript\nconst transformResponse = (response: any): any[] =\u003e {\n  // 检查响应状态\n  if (response.code !== 200) {\n    throw new Error(`API错误: ${response.message} (code: ${response.code})`)\n  }\n\n  // 检查数据存在性\n  if (!response.data || !Array.isArray(response.data)) {\n    throw new Error('API响应数据格式错误')\n  }\n\n  // 转换数据\n  return response.data\n    .map((item: any) =\u003e {\n      // 验证必要字段\n      if (!item.id || !item.title) {\n        console.warn('跳过无效歌曲数据:', item)\n        return null\n      }\n\n      return {\n        // ... 转换逻辑\n      }\n    })\n    .filter(Boolean) // 过滤掉null值\n}\n```\n\n#### 故障转移机制\n\n系统内置了自动故障转移机制：\n\n##### 工作原理\n\n1. **按优先级尝试**：系统按priority从小到大的顺序尝试音源\n2. **错误检测**：当音源请求失败时，自动记录错误并尝试下一个音源\n3. **状态监控**：实时监控各音源的可用性和响应时间\n4. **智能重试**：支持配置重试次数和重试间隔\n\n##### 故障转移配置\n\n```typescript\nexport const MUSIC_SOURCE_CONFIG: MusicSourceConfig = {\n  primarySource: 'vkeys', // 主音源ID\n  enableFailover: true, // 启用故障转移\n  timeout: 10000, // 默认超时时间\n  retryAttempts: 2, // 重试次数\n  sources: [\n    /* 音源列表 */\n  ]\n}\n```\n\n#### 开发示例\n\n以下是一个完整的音源扩展示例，展示如何添加一个虚构的\"MusicAPI\"音源：\n\n##### 1. 添加音源配置\n\n```\n// app/utils/musicSources.ts\n{\n  id: 'music-api',\n  name: 'MusicAPI音源',\n  baseUrl: 'https://api.musicapi.com/v1',\n  priority: 4,\n  enabled: true,\n  timeout: 8000,\n  headers: {\n    'User-Agent': 'VoiceHub/1.0',\n    'X-API-Key': 'your-api-key'\n  }\n}\n```\n\n##### 2. 实现搜索逻辑\n\n```typescript\n// app/composables/useMusicSources.ts\nif (source.id === 'music-api') {\n  url = `${source.baseUrl}/search?query=${encodeURIComponent(params.keywords)}\u0026limit=${params.limit || 30}\u0026type=song`\n  transformResponse = (data: any) =\u003e transformMusicApiResponse(data)\n}\n```\n\n##### 3. 数据转换函数\n\n```typescript\nconst transformMusicApiResponse = (response: any): any[] =\u003e {\n  console.log('[transformMusicApiResponse] 开始转换数据:', response)\n\n  if (!response || response.status !== 'success') {\n    throw new Error(`MusicAPI错误: ${response.message || '未知错误'}`)\n  }\n\n  if (!response.results || !Array.isArray(response.results)) {\n    throw new Error('MusicAPI响应数据格式错误')\n  }\n\n  return response.results\n    .map((song: any) =\u003e {\n      if (!song.id || !song.name) {\n        console.warn('[transformMusicApiResponse] 跳过无效歌曲:', song)\n        return null\n      }\n\n      return {\n        id: song.id,\n        title: song.name,\n        artist: song.artists?.map((a: any) =\u003e a.name).join('/') || '未知艺术家',\n        cover: song.album?.cover_url,\n        album: song.album?.name,\n        duration: song.duration_ms ? Math.floor(song.duration_ms / 1000) : undefined,\n        musicPlatform: 'musicapi',\n        musicId: song.id.toString(),\n        sourceInfo: {\n          source: 'music-api',\n          originalId: song.id.toString(),\n          fetchedAt: new Date(),\n          // 保存额外信息供后续使用\n          popularity: song.popularity,\n          explicit: song.explicit\n        }\n      }\n    })\n    .filter(Boolean)\n}\n```\n\n## 贡献说明\n\n如果您希望为 VoiceHub 贡献代码，请注意以下几点，特别是涉及数据库变更时：\n\n1. **数据库迁移文件**：\n   - 任何对 `schema.ts` 的更改都**必须**伴随相应的迁移文件。\n   - 迁移文件需要使用有意义的命名。请通过命令 `pnpm exec drizzle-kit generate --name=your_meaningful_name` 生成。\n2. **备份与恢复支持**：\n   - 当向系统设置（`systemSettings`）或其它关键表添加新字段时，**必须**同步更新数据备份和恢复的相关端点。\n   - 需要检查并更新的文件：\n     - `server/api/admin/backup/restore.post.ts`（`systemSettingsFields` 数组等）\n     - `server/api/admin/backup/restore-chunk.post.ts`（`fields` 数组等）\n3. **提交规范**：\n   - 请确保在提交 PR 前至少在本地测试过相关功能。\n   - 请使用标准的 Git 提交规范。\n\n## 音乐服务免责声明\n\nVoiceHub 是一款开源的校园广播站点歌管理系统。本软件遵循 GPLv3 协议开源，但请注意在使用过程中涉及的第三方服务和内容可能受相关法律法规限制。\n\n### 关于音乐内容与版权\n- 本系统**不存储任何音乐文件**，不拥有任何音乐的版权；\n- 所有音乐资源、播放及下载链接均来自**第三方音乐平台 API**；\n- 音乐内容的版权、著作权归相应版权方及音乐平台所有。\n\n### 关于功能说明\n- 本系统提供**音乐搜索、播放链接获取、音乐下载辅助**功能；\n- 系统仅做接口调用与工具呈现，不生产、不篡改音乐内容。\n\n### 法律与责任声明\n- 用户使用本系统进行播放、下载等行为，**须自行遵守所在地区版权法律法规及第三方平台服务协议**；\n- 用户需自行确保对本系统的使用不侵犯第三方权益（如音乐版权方、API提供方等），特别是涉及商业用途时，请务必确认是否获得相应授权；\n- 因用户使用不当、侵权用途所产生的一切法律责任，由**用户自行承担**，项目开发者不承担连带责任；\n- 若版权方认为相关功能或接口使用侵犯其合法权益，请联系我们，我们将立即配合整改。\n\n用户使用本系统即表示已阅读、理解并同意以上条款。\n\n## 隐私说明与遥测\n\nVoiceHub 内置可选的错误遥测功能，用于帮助开发者快速定位和修复系统问题。\n\n### 遥测默认状态\n- 遥测功能**默认开启**，但**可在管理员后台随时关闭**（站点配置 → 启用错误追踪与遥测）\n\n### 收集的数据范围\n系统通过 Sentry 仅收集以下**技术性信息**（不涉及任何个人隐私）：\n- **错误堆栈与消息**：前端 Vue 错误、服务端未捕获异常和未处理 Promise 拒绝的技术信息\n- **实例标识符**：系统安装时生成的随机 UUID（仅用于区分不同部署实例，不可用于识别个人）\n- **实例心跳**：系统启动时发送一条 `instance_online` 消息（仅含实例 ID），用于统计活跃部署实例数量，不包含任何业务数据\n- **请求上下文**：请求方法、URL 路径（**不含查询参数，避免泄露令牌**）、HTTP User-Agent\n- **运行时环境**：运行平台（Vercel/Netlify/自托管）、Node.js 版本、Nitro 预设\n- **前端组件名称**：出错的 Vue 组件名称（仅用于定位前端问题）\n\n### 安全保障\n- 所有 HTTP 4xx 业务错误（如认证失败、权限不足）**自动忽略**，不会上报 Sentry\n- 前端网络离线状态和浏览器扩展产生的错误**自动过滤**\n- 数据通过加密通道传输至 Sentry\n- 遥测开关变更即时生效，无需重启服务\n\n### 数据接收方\n错误数据由 [Sentry](https://sentry.io/) 处理，仅用于错误排查与系统稳定性改进。\n\n## 致谢\n\n### UI设计\n\n特别感谢 [过客是个铁憨憨](https://github.com/1811304592) 为本项目提供首页UI样式设计\n\n感谢 [Awesome Iwb](https://github.com/awesome-iwb) 项目提供的统一遮罩风格的图标\n\n### 贡献者\n\nThanks goes to these wonderful people:\n\n[![Contributors](https://contrib.rocks/image?repo=laoshuikaixue/VoiceHub\u0026repo=laoshuikaixue/VoiceHub-docs\u0026repo=laoshuikaixue/VoiceHub-hmos)](https://github.com/laoshuikaixue/VoiceHub/graphs/contributors)\n\n### 参考项目\n\n本项目在开发过程中参考和使用了以下优秀的开源项目和API服务：\n\n- [落月API](https://doc.vkeys.cn/api-doc/)\n- [NeteaseCloudMusicApiEnhanced](https://github.com/NeteaseCloudMusicApiEnhanced/api-enhanced)\n- [meting-api](https://github.com/injahow/meting-api)\n- [lx-music-desktop](https://github.com/lyswhut/lx-music-desktop) (搜索功能参考)\n- [the1068fm - 深中风华子衿广播站点歌系统](https://github.com/SMS-COSMO/the1068fm)\n- [Sound-of-experiment - 实验之声广播站点歌系统](https://github.com/ljk743121/Sound-of-experiment) (哔哩哔哩音源搜索功能参考)\n- [Bilibili-audio-extraction](https://github.com/rio4raki/Bilibili-audio-extraction) (哔哩哔哩音频流获取参考)\n- [SPlayer](https://github.com/imsyy/SPlayer)\n- [SPlayer-Next](https://github.com/SPlayer-Dev/SPlayer-Next)\n- [Apple Music-like Lyrics](https://github.com/amll-dev/applemusic-like-lyrics)\n- [official-website - Sparkinit](https://github.com/Sparkinit/official-website)\n- [MusicAPI-rrvenn](https://music.rrvenn.cn)\n- [qq-music-api](https://github.com/sansenjian/qq-music-api) (QQ音乐歌词获取参考)\n\n## 许可证\n\n[GPL-3.0](LICENSE)\n\n## 星标历史\n\n\u003cpicture\u003e\n   \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://api.star-history.com/svg?repos=laoshuikaixue/VoiceHub\u0026type=Date\u0026theme=dark\" /\u003e\n   \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://api.star-history.com/svg?repos=laoshuikaixue/VoiceHub\u0026type=Date\" /\u003e\n   \u003cimg alt=\"Star History Chart\" src=\"https://api.star-history.com/svg?repos=laoshuikaixue/VoiceHub\u0026type=Date\" /\u003e\n \u003c/picture\u003e\n\n## 其他\n\n本项目有对应的原生鸿蒙版本：https://github.com/laoshuikaixue/VoiceHub-hmos\n\n该项目通过创新的混合架构设计，实现了Web端Vue音频播放器与鸿蒙原生端的跨平台音频控制同步\n\n\u003ch2 id=\"sponsor\"\u003e赞助支持\u003c/h2\u003e\n\n如果这个项目对你有帮助，欢迎赞助支持，让我有更多动力持续维护和更新。\n\n\u003cdiv align=\"center\"\u003e\n\n\u003cimg width=\"200\" alt=\"wechat\" src=\"https://github.com/user-attachments/assets/0cd13f75-bd9c-4486-8bba-a8895e2e55fd\" /\u003e\n\n\u003c/div\u003e\n\n---\n\nPowered By LaoShui @ 2025-2026\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaoshuikaixue%2FVoiceHub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flaoshuikaixue%2FVoiceHub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaoshuikaixue%2FVoiceHub/lists"}