378 lines
8.4 KiB
Markdown
378 lines
8.4 KiB
Markdown
# 📖 网易云音乐工具箱 (v9.x - Web 应用重构版)
|
||
|
||
|
||
|
||
本项目是基于原版 `Netease_url` 项目的深度重构,旨在将其从一个依赖本地 `cookie.txt` 的工具,升级为一个**支持多用户、无状态后端、客户端认证**的现代化 Web 应用。
|
||
|
||
|
||
|
||
## ✨ V9 核心功能升级
|
||
|
||
|
||
|
||
相较于原版,V9 架构带来了质的飞跃:
|
||
|
||
- **用户认证系统**:
|
||
- **扫码登录**:移除本地脚本,实现了完整的 API 驱动的扫码登录流程。
|
||
- **客户端凭证**:用户 Cookie **不再**存储于服务器。登录成功后,Cookie 凭证安全地存储在**用户自己的浏览器 `localStorage`** 中。
|
||
- **无状态 (Stateless) 后端**:
|
||
- 服务器**不保存任何用户状态**。所有 API 请求均通过 `localStorage` 自动携带 Cookie 凭证进行鉴权。
|
||
- **高并发支持**:天然支持多用户同时登录和使用,Cookie 互相隔离,绝不串号。
|
||
- **全局播放器**:
|
||
- 实现了一个固定在底部的**全局 APlayer 播放器**。
|
||
- 音乐播放在页面内导航、搜索、解析时**不会中断**,提供了现代音乐站的体验。
|
||
- **高级 UI/UX**:
|
||
- **智能错误提示**:当解析高音质失败时,系统会智能判断用户是否未登录,并提示“请登录黑胶会员”。
|
||
- **用户设置**:增加了“自动播放”开关,并将其偏好存储在 `localStorage`。
|
||
- **安全加固**:在 F12 控制台增加了醒目的安全警告,防止用户被“社会工程学”攻击。
|
||
|
||
|
||
|
||
## 🚀 部署模式 (重要)
|
||
|
||
|
||
|
||
V9 架构支持两种部署模式,灵活性极高:
|
||
|
||
|
||
|
||
### 1. 🌍 服务器部署模式 (多用户)
|
||
|
||
|
||
|
||
这是标准的线上部署模式。
|
||
|
||
1. **清空 `cookie.txt`**:将 `cookie.txt` 文件内容设置为空。
|
||
2. **启动服务**:`python main.py`。
|
||
3. **用户流程**:
|
||
- 访问者**必须**点击右上角的“登录”按钮。
|
||
- 通过 App 扫码登录。
|
||
- Cookie 自动保存在他们各自的浏览器中,全程不接触你的服务器。
|
||
|
||
|
||
|
||
### 2. 💻 本地开发模式 (单用户)
|
||
|
||
|
||
|
||
这是你自己本地调试时使用的便捷模式。
|
||
|
||
1. **填写 `cookie.txt`**:在 `cookie.txt` 中填入你自己的黑胶会员 Cookie。
|
||
2. **启动服务**:`python main.py`。
|
||
3. **开发者流程**:
|
||
- 你**无需**点击“登录”按钮。
|
||
- 当你进行解析、下载等操作时,前端 `index.html` 会发送一个“空”的 Cookie。
|
||
- 后端 `main.py` 的 `_get_cookies_from_request` 函数会检测到 Cookie 为空,并**自动降级 (Fallback)** 去读取 `cookie.txt` 中的内容来完成请求。
|
||
|
||
|
||
|
||
## 🔌 API 接口文档 (V9)
|
||
|
||
|
||
|
||
原版的 API 文档 已失效。以下是当前 `main.py` 提供的有效接口。
|
||
|
||
**请求说明**:
|
||
|
||
- 所有需要鉴权的接口(如下载、解析高音质),都**必须**在 JSON 请求体中包含 `cookie` 字段。
|
||
- 前端 `index.html` 的 `getApiPayload` 函数会自动完成这一操作。
|
||
|
||
------
|
||
|
||
|
||
|
||
### /login/qr/generate
|
||
|
||
|
||
|
||
- **功能**:生成一个用于扫码登录的二维码 Key 和 Base64 图像。
|
||
|
||
- **方法**:`POST`
|
||
|
||
- **请求 (JSON)**:`{}` (无参数)
|
||
|
||
- **响应 (JSON)**:
|
||
|
||
JSON
|
||
|
||
```
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"qr_key": "xxx-xxx-xxx",
|
||
"qr_img_b64": "data:image/png;base64,..."
|
||
}
|
||
}
|
||
```
|
||
|
||
------
|
||
|
||
|
||
|
||
### /login/qr/check
|
||
|
||
|
||
|
||
- **功能**:轮询检查二维码的扫码状态。
|
||
|
||
- **方法**:`POST`
|
||
|
||
- **请求 (JSON)**:
|
||
|
||
JSON
|
||
|
||
```
|
||
{
|
||
"qr_key": "xxx-xxx-xxx"
|
||
}
|
||
```
|
||
|
||
- **响应 (JSON)** (code: `801`=等待, `802`=已扫码, `803`=成功, `800`=过期):
|
||
|
||
JSON
|
||
|
||
```
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"code": 803,
|
||
"cookie": "MUSIC_U=...; __csrf=...;",
|
||
"message": "登录成功"
|
||
}
|
||
}
|
||
```
|
||
|
||
------
|
||
|
||
|
||
|
||
### /search
|
||
|
||
|
||
|
||
- **功能**:搜索歌曲。
|
||
|
||
- **方法**:`POST`
|
||
|
||
- **请求 (JSON)**:
|
||
|
||
JSON
|
||
|
||
```
|
||
{
|
||
"keyword": "蓝莲花",
|
||
"cookie": "...(来自 localStorage)"
|
||
}
|
||
```
|
||
|
||
------
|
||
|
||
|
||
|
||
### /song
|
||
|
||
|
||
|
||
- **功能**:解析单曲详情和播放链接。
|
||
|
||
- **方法**:`POST`
|
||
|
||
- **请求 (JSON)**:
|
||
|
||
JSON
|
||
|
||
```
|
||
{
|
||
"url": "歌曲ID或链接",
|
||
"level": "lossless",
|
||
"cookie": "...(来自 localStorage)"
|
||
}
|
||
```
|
||
|
||
------
|
||
|
||
|
||
|
||
### /playlist
|
||
|
||
|
||
|
||
- **功能**:解析歌单详情。
|
||
|
||
- **方法**:`POST`
|
||
|
||
- **请求 (JSON)**:
|
||
|
||
JSON
|
||
|
||
```
|
||
{
|
||
"id": "歌单ID或链接",
|
||
"cookie": "...(来自 localStorage)"
|
||
}
|
||
```
|
||
|
||
------
|
||
|
||
|
||
|
||
### /album
|
||
|
||
|
||
|
||
- **功能**:解析专辑详情。
|
||
|
||
- **方法**:`POST`
|
||
|
||
- **请求 (JSON)**:
|
||
|
||
JSON
|
||
|
||
```
|
||
{
|
||
"id": "专辑ID或链接",
|
||
"cookie": "...(来自 localStorage)"
|
||
}
|
||
```
|
||
|
||
------
|
||
|
||
|
||
|
||
### /download_song_zip
|
||
|
||
|
||
|
||
- **功能**:打包下载单曲(含封面、歌词)。
|
||
|
||
- **方法**:`POST`
|
||
|
||
- **请求 (JSON)**:
|
||
|
||
JSON
|
||
|
||
```
|
||
{
|
||
"id": "歌曲ID",
|
||
"quality": "lossless",
|
||
"cookie": "...(来自 localStorage)"
|
||
}
|
||
```
|
||
|
||
- **响应**:`application/zip` 文件流。
|
||
|
||
------
|
||
|
||
|
||
|
||
### /download_playlist_zip
|
||
|
||
|
||
|
||
- **功能**:打包下载整个歌单。
|
||
|
||
- **方法**:`POST`
|
||
|
||
- **请求 (JSON)**:
|
||
|
||
JSON
|
||
|
||
```
|
||
{
|
||
"id": "歌单ID",
|
||
"quality": "lossless",
|
||
"cookie": "...(来自 localStorage)"
|
||
}
|
||
```
|
||
|
||
- **响应**:`application/zip` 文件流。
|
||
|
||
------
|
||
|
||
|
||
|
||
### /download_album_zip
|
||
|
||
|
||
|
||
- **功能**:打包下载整个专辑。
|
||
|
||
- **方法**:`POST`
|
||
|
||
- **请求 (JSON)**:
|
||
|
||
JSON
|
||
|
||
```
|
||
{
|
||
"id": "专辑ID",
|
||
"quality": "lossless",
|
||
"cookie": "...(来自 localStorage)"
|
||
}
|
||
```
|
||
|
||
- **响应**:`application/zip` 文件流。
|
||
|
||
|
||
|
||
## 📝 架构与开发说明
|
||
|
||
|
||
|
||
|
||
|
||
### V9 核心架构
|
||
|
||
|
||
|
||
本项目成功的关键在于**“责任分离”**:
|
||
|
||
1. **`main.py` (服务层)**:作为“总指挥”。它**只负责**编排请求 (接收 HTTP、解析参数) 和响应 (返回 JSON 或 Zip)。它**不**包含任何Cookie管理或API请求的硬编码逻辑。
|
||
2. **`qr_login.py` (认证模块)**:**只负责**生成和检查二维码。
|
||
3. **`music_api.py` (API 模块)**:**只负责**调用网易云的 *JSON* API (如搜索、歌单详情)。它必须是“无状态的”,并接收 `cookies` 作为参数。
|
||
4. **`music_downloader.py` (下载模块)**:**只负责**获取 *文件* API (如歌曲 URL、歌词),并处理打包逻辑。它也必须接收 `cookies` 参数。
|
||
5. **`cookie_manager.py` (工具模块)**:**只负责**解析 Cookie 字符串 (`parse_cookie_string`) 和读取 `cookie.txt` (作为备用)。
|
||
6. **`index.html` (客户端)**:作为“用户界面”和“**凭证保险箱**”。它**全权负责**存储 `userCookie`,并在**每一次** API 调用时主动提供它。
|
||
|
||
|
||
|
||
### 项目结构 (V9)
|
||
|
||
|
||
|
||
```
|
||
Netease_url/
|
||
├── main.py # [!! 重构 !!] Flask 主程序, 路由层
|
||
├── music_api.py # API 核心模块 (基本不变, 仅被调用)
|
||
├── music_downloader.py # [!! 重构 !!] 下载模块 (已解耦, 需传入 cookie)
|
||
├── cookie_manager.py # Cookie 管理工具 (现主要用于解析)
|
||
├── qr_login.py # [!! 重构 !!] 从脚本变为 QR 登录 API 模块
|
||
├── templates/
|
||
│ └── index.html # [!! 重构 !!] V9 前端应用
|
||
├── static/ # [!! 新增 !!] 静态文件目录
|
||
│ └── favicon.ico # [!! 新增 !!] 网站图标
|
||
├── requirements.txt
|
||
├── cookie.txt # (可选) 仅用于本地开发模式
|
||
└── README_v9.md # (本文档)
|
||
```
|
||
|
||
|
||
|
||
### 未来升级的基石 (v10 展望)
|
||
|
||
|
||
|
||
基于 V9 的“无状态后端 + 客户端凭证”架构,我们为下一阶段的升级打下了完美的基础:
|
||
|
||
- **实现“我的音乐”**:
|
||
- 后端:在 `music_api.py` 中新增 `get_user_playlists(uid, cookies)` 函数。
|
||
- 后端:在 `main.py` 中新增 `/my/playlists` 路由,它调用上述函数。
|
||
- 前端:在登录成功后,`fetch('/my/playlists')` 并在 `index.html` 中渲染一个新区域。
|
||
- **实现“真实进度条”**:
|
||
- 后端:`main.py` 引入 `Flask-SocketIO`。
|
||
- 后端:`_package_tracks_as_zip` 在 `for` 循环中 `socketio.emit` 真实进度。
|
||
- 前端:`handleDownloadClick` 不再使用假进度 `setInterval`,而是 `socket.on('progress', ...)` 来更新进度条。
|
||
- **实现“歌单即时播放”**:
|
||
- 前端:在 `renderCollection` 中增加“播放全部”按钮。
|
||
- 前端:点击后,循环 `tracks` 列表,为每首歌调用 `/song` 接口。
|
||
- 前端:将所有返回的 `data.url` 组装成一个列表,一次性 `globalAPlayer.list.add([...])`。 |