Files
MusicServer/app/routes/refresh.py
T
snowy-yang dfc06bf4de feat(python): 完成 Python 全量迁移——剩余平台、登录通道与公共层修复
- 新增 5sing/apple/xm/me/qt/lr 平台包与取流实现(含 xm-sign、MissEvan 签名、蜻蜓 HMAC、Apple developer token)
- 新增 wy/kg/tx/lr 登录:扫码、手机号、账密(kg 20028 风控指纹)、cookie 绑定、kg/tx 续期
- request 层:保留多值 Set-Cookie;JSON body 紧凑化(修复 kg 网关验签);直连不经系统代理(对齐 Node)
- 登录路由统一 Body(embed=True),修复扫码轮询 422;lifespan 接入登录续期调度
- ruff/format/pyright 全绿;14 平台真实联网与 HTTP 路由验证通过
2026-10-23 21:55:45 +08:00

78 lines
2.5 KiB
Python

"""登录态自动续期 —— 启动后延时刷一轮 + 每 24h 一次(对应原 src/refresh.ts)。
各平台凭据独立处理:未登录跳过,单个平台失败不影响另一个。
"""
from __future__ import annotations
import asyncio
import contextlib
from datetime import datetime
from typing import Any
from app.sdk.auth import kg as kg_auth
from app.sdk.auth import tx as tx_auth
INTERVAL_SECONDS = 24 * 60 * 60
# 启动后延迟触发,避开启动期与冒烟测试的快速起停
STARTUP_DELAY_SECONDS = 10
_running = False
_tasks: list[asyncio.Task[None]] = []
def _log(msg: str) -> None:
print(f"[{datetime.now().isoformat(timespec='milliseconds')}] [登录续期] {msg}")
async def refresh_all() -> dict[str, Any]:
"""手动/定时共用的续期入口,返回各平台结果(skipped / refreshed / error)。"""
global _running
if _running:
return {"skipped": True}
_running = True
try:
result: dict[str, Any] = {}
for name, fn in (("kg", kg_auth.refresh_login), ("tx", tx_auth.refresh_login)):
try:
res = await fn()
result[name] = res
if isinstance(res, dict) and res.get("skipped"):
_log(f"{name}: 未登录,跳过")
else:
_log(f"{name}: 登录态已刷新")
except NotImplementedError:
result[name] = {"skipped": True, "msg": "尚未移植"}
except Exception as err: # noqa: BLE001 - 单平台失败不影响其它平台
result[name] = {"error": str(err)}
_log(f"{name}: {err}")
return result
finally:
_running = False
async def _loop() -> None:
await asyncio.sleep(STARTUP_DELAY_SECONDS)
while True:
await refresh_all()
await asyncio.sleep(INTERVAL_SECONDS)
def start_refresh_scheduler() -> None:
"""注册定时任务(在应用 startup 时调用)。"""
try:
loop = asyncio.get_running_loop()
except RuntimeError: # 无事件循环(如导入期)时忽略
return
task = loop.create_task(_loop())
_tasks.append(task)
_log(f"已启动自动续期(启动后 {STARTUP_DELAY_SECONDS}s 首刷,此后每 {INTERVAL_SECONDS // 3600}h 一次)")
async def stop_refresh_scheduler() -> None:
while _tasks:
task = _tasks.pop()
task.cancel()
with contextlib.suppress(asyncio.CancelledError):
await task