mirror of
https://github.com/mikumifa/biliTickerBuy.git
synced 2026-07-15 06:12:45 -04:00
163 lines
5.2 KiB
Python
163 lines
5.2 KiB
Python
from __future__ import annotations
|
|
|
|
import tempfile
|
|
import time
|
|
from pathlib import Path
|
|
|
|
import requests
|
|
|
|
from .common import (
|
|
_cookie_store_path,
|
|
_fetch_username_silently,
|
|
_make_request,
|
|
_resolve_cookie_list,
|
|
)
|
|
|
|
|
|
def get_login_state(
|
|
*,
|
|
cookies: list[dict[str, object]] | dict[str, object] | None = None,
|
|
cookies_path: str | Path | None = None,
|
|
) -> dict[str, object]:
|
|
cookie_list = _resolve_cookie_list(cookies, cookies_path=cookies_path)
|
|
has_cookies = bool(cookie_list)
|
|
username = _fetch_username_silently(cookie_list)
|
|
logged_in = has_cookies and username != "Not login"
|
|
return {
|
|
"ok": True,
|
|
"logged_in": logged_in,
|
|
"username": username,
|
|
"has_cookies": has_cookies,
|
|
"cookies_path": _cookie_store_path(cookies_path),
|
|
"next_action": "continue" if logged_in else "prompt_qr_login",
|
|
}
|
|
|
|
|
|
def start_qr_login(
|
|
*,
|
|
headers: dict[str, str] | None = None,
|
|
max_retry: int = 10,
|
|
retry_interval: float = 1.0,
|
|
qr_image_path: str | Path | None = None,
|
|
) -> dict[str, object]:
|
|
import qrcode
|
|
|
|
request_headers = headers or {
|
|
"user-agent": (
|
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
|
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
|
"Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0"
|
|
),
|
|
}
|
|
last_error = "二维码生成失败"
|
|
for _ in range(max_retry):
|
|
response = requests.get(
|
|
"https://passport.bilibili.com/x/passport-login/web/qrcode/generate",
|
|
headers=request_headers,
|
|
timeout=10,
|
|
)
|
|
payload = response.json()
|
|
if payload.get("code") == 0:
|
|
data = payload["data"]
|
|
image_path_value: str | None = None
|
|
if qr_image_path is not False:
|
|
target = (
|
|
Path(qr_image_path)
|
|
if qr_image_path is not None
|
|
else Path(tempfile.gettempdir()) / "biliTickerBuy-login-qrcode.png"
|
|
)
|
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
qr = qrcode.QRCode(box_size=10, border=4)
|
|
qr.add_data(data["url"])
|
|
qr.make(fit=True)
|
|
qr.make_image(fill_color="black", back_color="white").save(target)
|
|
image_path_value = str(target)
|
|
return {
|
|
"ok": True,
|
|
"login_url": data["url"],
|
|
"qrcode_key": data["qrcode_key"],
|
|
"qr_image_path": image_path_value,
|
|
"next_action": "show_qr_and_confirm_scan",
|
|
}
|
|
last_error = payload.get("message", last_error)
|
|
time.sleep(retry_interval)
|
|
return {"ok": False, "error": last_error}
|
|
|
|
|
|
def poll_qr_login(
|
|
qrcode_key: str,
|
|
*,
|
|
cookies_path: str | Path | None = None,
|
|
timeout_seconds: float = 60.0,
|
|
poll_interval: float = 0.5,
|
|
headers: dict[str, str] | None = None,
|
|
) -> dict[str, object]:
|
|
from util.request.CookieManager import parse_cookie_list
|
|
|
|
if not qrcode_key:
|
|
raise ValueError("qrcode_key is required")
|
|
|
|
request_headers = headers or {"User-Agent": "Mozilla/5.0"}
|
|
deadline = time.time() + timeout_seconds
|
|
last_message = "等待扫码"
|
|
|
|
while time.time() < deadline:
|
|
response = requests.get(
|
|
"https://passport.bilibili.com/x/passport-login/web/qrcode/poll",
|
|
params={"qrcode_key": qrcode_key},
|
|
headers=request_headers,
|
|
timeout=10,
|
|
)
|
|
payload = response.json()
|
|
if payload.get("code") != 0:
|
|
last_message = payload.get("message", "轮询登录失败")
|
|
time.sleep(poll_interval)
|
|
continue
|
|
|
|
data = payload.get("data", {})
|
|
state_code = data.get("code")
|
|
last_message = data.get("message", last_message)
|
|
|
|
if state_code == 0:
|
|
cookies = parse_cookie_list(response.headers.get("set-cookie", ""))
|
|
cookie_path_value = _cookie_store_path(cookies_path)
|
|
request = _make_request(cookies=cookies, cookies_path=cookie_path_value)
|
|
username = request.get_request_name()
|
|
return {
|
|
"ok": True,
|
|
"status": "confirmed",
|
|
"message": "登录成功",
|
|
"cookies": cookies,
|
|
"cookies_path": cookie_path_value,
|
|
"username": username,
|
|
}
|
|
|
|
if state_code in (86101, 86090):
|
|
time.sleep(poll_interval)
|
|
continue
|
|
|
|
return {
|
|
"ok": False,
|
|
"status": "failed",
|
|
"message": last_message,
|
|
"code": state_code,
|
|
}
|
|
|
|
return {"ok": False, "status": "timeout", "message": last_message or "登录超时"}
|
|
|
|
|
|
def login_with_cookies(
|
|
cookies: list[dict[str, object]] | dict[str, object],
|
|
*,
|
|
cookies_path: str | Path | None = None,
|
|
) -> dict[str, object]:
|
|
cookie_list = _resolve_cookie_list(cookies, cookies_path=cookies_path)
|
|
username = _fetch_username_silently(cookie_list)
|
|
return {
|
|
"ok": True,
|
|
"logged_in": username != "Not login",
|
|
"username": username,
|
|
"cookies": cookie_list,
|
|
"cookies_path": _cookie_store_path(cookies_path),
|
|
}
|