fix(server): 修复路由遮蔽、流式背压与鉴权限流顺序

- 专辑搜索静态路由优先注册,避免被 /album/{source}/{id}/{page} 捕获
- mg 流改为异步背压队列,慢客户端不再 QueueFull 悬挂,错误中断响应
- 限流移到鉴权外层,401 爆破计入限流
- 酷我 token 重试移出锁,修复 asyncio.Lock 递归死锁
- 补 CORS、5sing 音质、parse _kind、wy 首次登录 cookie、stream 签名溢出
- mg 流直连、lifespan 关闭 aiohttp 会话、cookie 登录路由与 auth_store 健壮性
- 测试改用 aiohttp + 进程内 uvicorn,移除 httpx/TestClient
- 更新 start.bat 与文档
This commit is contained in:
snowy-yang committed 2026-10-23 23:40:55 +08:00
1 parent 39565a3913
commit 0df18f048b
19 files changed
+534 -241

No files matched your search

+39 -2
View File
@@ -9,12 +9,12 @@ from __future__ import annotations
from typing import Any
from app.http.api_error import ApiError, upstream
from app.http.api_error import ApiError, not_found, upstream
from app.http.envelope import ok
from app.routes.refresh import refresh_all
from app.sdk import auth as auth_mod
from app.sdk.auth_store import clear_credentials, get_credentials, get_tx_auth, set_credentials
from fastapi import APIRouter, Body
from fastapi import APIRouter, Body, Path
router = APIRouter()
@@ -331,6 +331,43 @@ async def login_refresh() -> Any:
return ok(await refresh_all())
# 这些平台没有独立登录协议,只能从浏览器/App 复制 cookie(README 平台表已声明 cookie 登录)。
# 白名单限定,避免动态路由把任意平台写进凭据文件。
_COOKIE_LOGIN_SOURCES = {"mg", "bd", "joox", "apple", "5sing"}
@router.post(
"/login/{source}",
tags=[LOGIN_TAG],
summary="绑定平台 cookie",
description="mg/bd/joox/apple/5sing 用:从浏览器或 App 复制完整 cookie 字符串并持久化。"
"apple 需包含 media-user-token;joox 通常需 wmid/session_key。服务端不做在线校验。",
)
async def cookie_bind(
source: str = Path(..., description="平台 id(mg/bd/joox/apple/5sing)", examples=["bd"]),
cookie: str = Body(..., embed=True, description="完整 cookie 字符串"),
) -> Any:
if source not in _COOKIE_LOGIN_SOURCES:
raise not_found(f"不支持的 cookie 登录平台: {source}")
value = str(cookie or "").strip()
if not value:
raise ApiError(422, "cookie 不能为空")
set_credentials(source, {"cookie": value})
return ok({"logged": True})
@router.delete(
"/login/{source}",
tags=[LOGIN_TAG],
summary="退出平台登录(cookie 平台)",
)
async def cookie_logout(source: str = Path(..., description="平台 id(mg/bd/joox/apple/5sing)")) -> Any:
if source not in _COOKIE_LOGIN_SOURCES:
raise not_found(f"不支持的 cookie 登录平台: {source}")
clear_credentials(source)
return ok({"logged": False})
def _stored_status(package: str) -> dict[str, Any]:
"""按已存凭据判断登录态(xm/me/bd/joox/apple/5sing 用)。"""
cred = get_credentials(package)