- 新增 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 路由验证通过
78 lines
2.5 KiB
Python
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
|