- 新增 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 路由验证通过
60 lines
2.3 KiB
Python
60 lines
2.3 KiB
Python
"""懒人听书登录(对应 sdk/lr/auth.ts,web 通道 m.lrts.me/ajax/logon)。
|
||
|
||
参考社区下载器(yoval/lrts 等):POST form {account, pwd: base64(password)},
|
||
成功响应 json.phone 非空,Set-Cookie 种下会话;取流接口必须携带该会话
|
||
(免费章节匿名也返回"收费章节未购买",2026-10-02 实测)。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import base64
|
||
from typing import Any
|
||
from urllib.parse import quote
|
||
|
||
from app.http.api_error import ApiError
|
||
from app.sdk.auth_store import get_credentials, set_credentials
|
||
from app.sdk.common.request import http_fetch
|
||
|
||
UA_MI = (
|
||
"Mozilla/5.0 (Linux; U; Android 4.1.1; zh-cn; MI2 Build/JRO03L) AppleWebKit/534.30 "
|
||
"(KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0"
|
||
)
|
||
LOGON_URL = "https://m.lrts.me/ajax/logon"
|
||
|
||
|
||
async def login(account: str, password: str) -> dict[str, Any]:
|
||
"""账号密码登录(成功保存会话 Cookie)。"""
|
||
form = f"account={quote(str(account), safe='')}&pwd={base64.b64encode(str(password).encode()).decode()}"
|
||
resp = await http_fetch(
|
||
LOGON_URL,
|
||
method="POST",
|
||
headers={
|
||
"User-Agent": UA_MI,
|
||
"Referer": "https://m.lrts.me/",
|
||
"Content-Type": "application/x-www-form-urlencoded",
|
||
},
|
||
body=form,
|
||
timeout=15_000,
|
||
)
|
||
body = resp.body if isinstance(resp.body, dict) else {}
|
||
if resp.status_code != 200 or not body.get("phone"):
|
||
raise ApiError(401, str(body.get("msg") or "登录失败(账号或密码错误)"))
|
||
cookie = "; ".join(part for part in (item.split(";")[0].strip() for item in resp.set_cookies) if part)
|
||
if not cookie:
|
||
raise RuntimeError("登录成功但未返回会话 Cookie")
|
||
set_credentials("lr", {"cookie": cookie, "phone": str(body["phone"])})
|
||
return {"logged": True, "phone": str(body["phone"])}
|
||
|
||
|
||
def get_lr_cookie() -> str:
|
||
"""登录会话 Cookie(未登录返回空串)。"""
|
||
return str((get_credentials("lr") or {}).get("cookie") or "")
|
||
|
||
|
||
def status() -> dict[str, Any]:
|
||
"""登录状态。"""
|
||
cred = get_credentials("lr") or {}
|
||
if cred.get("cookie"):
|
||
return {"logged": True, "phone": cred.get("phone"), "updatedAt": cred.get("updatedAt")}
|
||
return {"logged": False}
|