Files
Netease_url/qr_login.py
2025-11-05 14:22:18 +08:00

152 lines
4.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""网易云音乐二维码登录模块 (已修改为API)
提供网易云音乐二维码登录功能,被 main.py 调用。
- 二维码生成 (key 和 base64)
- 登录状态检查 (返回 code 和 cookie)
"""
import json
import logging
import base64
import io
import re # [!! 已添加 !!]
from random import randrange # [!! 关键修复 !!] 导入 randrange
from typing import Optional, Dict, Any, Tuple
try:
# qrcode 库在 music_api.py 中被导入,这里我们也需要它
import qrcode
except ImportError:
print("错误:缺少 'qrcode' 库。请运行 `pip install qrcode`")
qrcode = None
try:
# 我们需要从 music_api 借用很多底层工具
from music_api import (
QRLoginManager, APIException, HTTPClient,
CryptoUtils, APIConstants
)
from cookie_manager import CookieManager, CookieException
except ImportError as e:
print(f"导入模块失败: {e}")
print("请确保 music_api.py 和 cookie_manager.py 文件存在且可用")
def api_generate_qr_key() -> Dict[str, Any]:
"""
[新API] 生成二维码Key和Base64图像
Returns:
{'success': bool, 'qr_key': str, 'qr_img_b64': str, 'message': str}
"""
if not qrcode:
return {'success': False, 'message': "qrcode 库未安装"}
try:
qr_manager = QRLoginManager()
unikey = qr_manager.generate_qr_key()
if not unikey:
raise APIException("生成二维码key失败")
# 生成二维码数据
qr_data = f'https://music.163.com/login?codekey={unikey}'
# 在内存中生成二维码图片
qr = qrcode.QRCode()
qr.add_data(qr_data)
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")
# 将图片保存到 BytesIO
buffered = io.BytesIO()
img.save(buffered, format="PNG")
# 转换为 Base64 字符串
img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
qr_img_b64 = f"data:image/png;base64,{img_str}"
return {
'success': True,
'qr_key': unikey,
'qr_img_b64': qr_img_b64
}
except Exception as e:
logging.error(f"生成二维码失败: {e}")
return {'success': False, 'message': str(e)}
def api_check_qr_status(unikey: str) -> Dict[str, Any]:
"""
[新API] 检查二维码登录状态
此函数复制并*修复*了 music_api.py 中 check_qr_login 的逻辑,
以便返回完整的 Cookie 字符串,而不只是 MUSIC_U。
Args:
unikey: 二维码key
Returns:
{'code': int, 'cookie': Optional[str], 'message': str}
code: 800=过期, 801=等待, 802=已扫码, 803=成功
"""
try:
http_client = HTTPClient()
crypto_utils = CryptoUtils()
config = APIConstants.DEFAULT_CONFIG.copy()
# [!! 关键修复 !!] 现在 randrange 已经被导入,这行代码可以正常工作
config["requestId"] = str(randrange(20000000, 30000000))
payload = {
'key': unikey,
'type': 1,
'header': json.dumps(config)
}
params = crypto_utils.encrypt_params(APIConstants.QR_LOGIN_API, payload)
# 我们需要完整的 response 对象来获取 headers
response = http_client.post_request_full(
APIConstants.QR_LOGIN_API, params, {}
)
result = json.loads(response.text)
code = result.get('code', -1)
cookie_string = None
if code == 803:
# 登录成功提取cookie
raw_cookies = response.headers.get('Set-Cookie', '')
# 使用 re.sub 来处理 'path=/,' 这种导致错误分割的情况
raw_cookies = re.sub(r"path=/,", "path=/", raw_cookies)
cookie_list = [c.strip() for c in raw_cookies.split(',') if c.strip()]
final_cookie_parts = []
for item in cookie_list:
if not item:
continue
part = item.split(';')[0]
if part.strip():
final_cookie_parts.append(part.strip())
cookie_string = '; '.join(final_cookie_parts)
if "MUSIC_U" not in cookie_string:
return {'code': -1, 'cookie': None, 'message': '登录成功但未获取到 MUSIC_U'}
return {
'code': code,
'cookie': cookie_string,
'message': result.get('message', '')
}
except Exception as e:
# 在 `api_check_qr_status` 捕获异常时,记录详细的 traceback
logging.error(f"检查登录状态响应失败: {e}", exc_info=True)
return {'code': -1, 'cookie': None, 'message': f"检查失败: {e}"}
# --- 删除了所有旧的交互式代码 ---