完成 Ruff 全量清理
This commit is contained in:
@@ -44,7 +44,7 @@ class CookieEnricher:
|
||||
self.generate_acf_ccn_cookie()
|
||||
logger.info("补CK完成")
|
||||
return
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
last_error = e
|
||||
logger.warning(f"补CK失败 {attempt}/{max_attempts}: {e}")
|
||||
if attempt < max_attempts:
|
||||
|
||||
@@ -5,7 +5,7 @@ import os
|
||||
import re
|
||||
import threading
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import UTC, datetime, timedelta
|
||||
|
||||
import requests
|
||||
from loguru import logger
|
||||
@@ -68,8 +68,8 @@ class EmailVerifier:
|
||||
f"{self.roundcube_url}?_task=logout",
|
||||
timeout=5,
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.debug(f"Roundcube logout failed: {exc}")
|
||||
self._rc_session = None
|
||||
self._rc_logged_in = False
|
||||
|
||||
@@ -176,7 +176,7 @@ class EmailVerifier:
|
||||
logger.debug(f"Roundcube: {password_name}登录成功 ({self.username})")
|
||||
return True, False
|
||||
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
logger.warning(f"Roundcube: 登录异常: {e}")
|
||||
return False, False
|
||||
|
||||
@@ -230,7 +230,7 @@ class EmailVerifier:
|
||||
|
||||
return messages
|
||||
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
logger.warning(f"Roundcube: 获取邮件列表失败: {e}")
|
||||
return []
|
||||
|
||||
@@ -252,7 +252,7 @@ class EmailVerifier:
|
||||
)
|
||||
return resp.text
|
||||
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
logger.warning(f"Roundcube: 读取邮件 {uid} 失败: {e}")
|
||||
return None
|
||||
|
||||
@@ -270,7 +270,7 @@ class EmailVerifier:
|
||||
- "2026-06-20" → 直接解析
|
||||
- "06-20" → 今年的该日期
|
||||
"""
|
||||
now = datetime.now()
|
||||
now = datetime.now(UTC)
|
||||
|
||||
# 今天
|
||||
if date_str.startswith("今天"):
|
||||
@@ -322,32 +322,36 @@ class EmailVerifier:
|
||||
|
||||
# 日期格式 2026-06-20
|
||||
try:
|
||||
return datetime.strptime(date_str.strip(), "%Y-%m-%d")
|
||||
return datetime.strptime(date_str.strip(), "%Y-%m-%d").replace(tzinfo=UTC)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# 日期格式 2026-06-20 14:30
|
||||
try:
|
||||
return datetime.strptime(date_str.strip(), "%Y-%m-%d %H:%M")
|
||||
return datetime.strptime(date_str.strip(), "%Y-%m-%d %H:%M").replace(
|
||||
tzinfo=UTC
|
||||
)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# 日期格式 2026-06-20 14:30:00
|
||||
try:
|
||||
return datetime.strptime(date_str.strip(), "%Y-%m-%d %H:%M:%S")
|
||||
return datetime.strptime(date_str.strip(), "%Y-%m-%d %H:%M:%S").replace(
|
||||
tzinfo=UTC
|
||||
)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# 日期格式 06-20
|
||||
try:
|
||||
dt = datetime.strptime(date_str.strip(), "%m-%d")
|
||||
dt = datetime.strptime(date_str.strip(), "%m-%d").replace(tzinfo=UTC)
|
||||
return dt.replace(year=now.year)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# 日期格式 06-20 14:30
|
||||
try:
|
||||
dt = datetime.strptime(date_str.strip(), "%m-%d %H:%M")
|
||||
dt = datetime.strptime(date_str.strip(), "%m-%d %H:%M").replace(tzinfo=UTC)
|
||||
return dt.replace(year=now.year)
|
||||
except ValueError:
|
||||
pass
|
||||
@@ -395,7 +399,7 @@ class EmailVerifier:
|
||||
return code
|
||||
except EmailLoginError:
|
||||
raise
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
last_error = str(e)
|
||||
logger.warning(f"Roundcube 读邮件异常: {e}")
|
||||
|
||||
|
||||
+4
-4
@@ -398,7 +398,7 @@ class DouyuLogin:
|
||||
return LoginResult(
|
||||
success=False, message=str(e), code="email_login_failed"
|
||||
)
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
elapsed = time.monotonic() - start_time
|
||||
if self.max_login_retries > 0:
|
||||
logger.error(
|
||||
@@ -475,7 +475,7 @@ class DouyuLogin:
|
||||
return LoginResult(
|
||||
success=False, message=str(e), code="email_login_failed"
|
||||
)
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
elapsed = time.monotonic() - start_time
|
||||
if self.max_login_retries > 0:
|
||||
logger.error(
|
||||
@@ -901,7 +901,7 @@ class DouyuLogin:
|
||||
|
||||
if response2.status_code == 200:
|
||||
logger.info("WebLogin成功")
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
logger.warning(f"WebLogin请求失败(不影响登录): {e}")
|
||||
|
||||
# 登录成功后补齐 Web 侧 Cookie。补 CK 失败只影响完整度,不回滚已成功的登录态。
|
||||
@@ -915,7 +915,7 @@ class DouyuLogin:
|
||||
).enrich_with_retry()
|
||||
except InterruptedError:
|
||||
raise
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
self._cookie_enrich_error = self._truncate_error(str(e), 160)
|
||||
logger.warning(
|
||||
f"补CK最终失败,本次仍按登录成功保存基础CK: {self._cookie_enrich_error}"
|
||||
|
||||
@@ -137,7 +137,7 @@ class BaseWhitelistAdapter(ABC):
|
||||
|
||||
return False, f"白名单添加失败,API响应: {resp}"
|
||||
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
msg = f"白名单同步失败: {e}"
|
||||
logger.error(msg)
|
||||
return False, msg
|
||||
@@ -165,7 +165,8 @@ def _get_local_exit_ip() -> str | None:
|
||||
match = re.search(r"(\d{1,3}(?:\.\d{1,3}){3})", text)
|
||||
if match:
|
||||
return match.group(1)
|
||||
except Exception:
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.debug(f"本机出口 IP 查询失败: {url}: {exc}")
|
||||
continue
|
||||
return None
|
||||
|
||||
@@ -197,6 +198,7 @@ def get_exit_ip_via_proxy(proxy: str) -> str | None:
|
||||
match = re.search(r"(\d{1,3}(?:\.\d{1,3}){3})", text)
|
||||
if match:
|
||||
return match.group(1)
|
||||
except Exception:
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.debug(f"代理出口 IP 查询失败: {url}: {exc}")
|
||||
continue
|
||||
return None
|
||||
|
||||
@@ -75,7 +75,7 @@ class XiequAdapter(BaseWhitelistAdapter):
|
||||
if r.get("IP") or r.get("ip")
|
||||
]
|
||||
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
logger.error(f"获取白名单失败: {e}")
|
||||
return []
|
||||
|
||||
@@ -120,7 +120,7 @@ class XiequAdapter(BaseWhitelistAdapter):
|
||||
logger.warning(f"白名单添加结果: {text}")
|
||||
return False, text
|
||||
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
logger.error(f"添加白名单失败: {e}")
|
||||
return False, str(e)
|
||||
|
||||
@@ -141,7 +141,7 @@ class XiequAdapter(BaseWhitelistAdapter):
|
||||
logger.warning(f"白名单删除结果: {text}")
|
||||
return False, text
|
||||
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
logger.error(f"删除白名单失败: {e}")
|
||||
return False, str(e)
|
||||
|
||||
@@ -160,7 +160,7 @@ class XiequAdapter(BaseWhitelistAdapter):
|
||||
logger.info(msg)
|
||||
return True, msg
|
||||
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
msg = f"连接失败: {e}"
|
||||
logger.error(msg)
|
||||
return False, msg
|
||||
|
||||
@@ -115,7 +115,7 @@ class XkdailiAdapter(BaseWhitelistAdapter):
|
||||
logger.warning(f"星空白名单添加失败: {msg}")
|
||||
return ok, msg
|
||||
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
logger.error(f"星空添加白名单失败: {e}")
|
||||
return False, str(e)
|
||||
|
||||
@@ -136,7 +136,7 @@ class XkdailiAdapter(BaseWhitelistAdapter):
|
||||
logger.warning(f"星空白名单删除失败: {msg}")
|
||||
return ok, msg
|
||||
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
logger.error(f"星空删除白名单失败: {e}")
|
||||
return False, str(e)
|
||||
|
||||
@@ -159,5 +159,5 @@ class XkdailiAdapter(BaseWhitelistAdapter):
|
||||
# 其他错误(如无效IP),说明认证通过了
|
||||
return True, f"连接成功,API可访问: {msg}"
|
||||
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
return False, f"连接失败: {e}"
|
||||
|
||||
@@ -167,7 +167,7 @@ class ProxyResolver:
|
||||
f"代理预检 {attempt}/{max_attempts}: {last_error}: {text[:80]}",
|
||||
)
|
||||
|
||||
except Exception as exc:
|
||||
except Exception as exc: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
last_error = f"代理API请求失败: {exc}"
|
||||
self._log("warning", f"代理预检 {attempt}/{max_attempts}: {last_error}")
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ def verify_proxy_url(proxy_url: str, timeout: tuple = (3, 5)) -> tuple[bool, str
|
||||
)
|
||||
response.raise_for_status()
|
||||
return True, "代理可用 → 斗鱼可达"
|
||||
except Exception as exc:
|
||||
except Exception as exc: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
err_msg = str(exc)
|
||||
if "Tunnel connection failed" in err_msg or "503" in err_msg:
|
||||
detail = "代理拒绝连接(白名单可能未生效)"
|
||||
@@ -75,7 +75,8 @@ def verify_proxies_concurrent(
|
||||
ok, _ = future.result()
|
||||
if ok:
|
||||
available.append(future_map[future])
|
||||
except Exception:
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.debug(f"代理并发验证失败: {future_map[future]}: {exc}")
|
||||
continue
|
||||
if available:
|
||||
logger.success(
|
||||
@@ -99,7 +100,8 @@ def verify_proxies_concurrent(
|
||||
if item != future:
|
||||
item.cancel()
|
||||
return proxy_url, msg
|
||||
except Exception:
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.debug(f"代理并发验证失败: {proxy_url}: {exc}")
|
||||
continue
|
||||
|
||||
return None, f"共 {len(proxy_urls)} 个代理均不可用"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""代理模块使用的白名单适配器。"""
|
||||
|
||||
|
||||
from .proxy_platforms import create_adapter
|
||||
from .proxy_platforms.base import BaseWhitelistAdapter, _get_local_exit_ip
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ def get_challenge_gt_bak() -> tuple[str, str]:
|
||||
}
|
||||
|
||||
params = {
|
||||
"t": str(int(round(time.time() * 1000))),
|
||||
"t": str(round(time.time() * 1000)),
|
||||
}
|
||||
|
||||
response = requests.get(
|
||||
@@ -133,7 +133,7 @@ def get_js_address(gt: str, proxies: Mapping[str, str] | None = None) -> dict:
|
||||
|
||||
params = {
|
||||
"gt": gt,
|
||||
"callback": "geetest_" + str(int(round(time.time() * 1000))),
|
||||
"callback": "geetest_" + str(round(time.time() * 1000)),
|
||||
}
|
||||
|
||||
response = _get(
|
||||
@@ -173,7 +173,7 @@ def get_c_s(
|
||||
+ "&lang=zh-cn&pt=0&client_type=web&w="
|
||||
+ w
|
||||
+ "&callback=geetest_"
|
||||
+ str(int(round(time.time() * 1000))),
|
||||
+ str(round(time.time() * 1000)),
|
||||
headers=headers,
|
||||
proxies=proxies,
|
||||
)
|
||||
@@ -210,7 +210,7 @@ def req_fullpage_validate(
|
||||
+ "&lang=zh-cn&pt=0&client_type=web&w="
|
||||
+ w
|
||||
+ "&callback=geetest_"
|
||||
+ str(int(round(time.time() * 1000))),
|
||||
+ str(round(time.time() * 1000)),
|
||||
headers=headers,
|
||||
proxies=proxies,
|
||||
)
|
||||
@@ -241,7 +241,7 @@ def req_slide(gt: str, challenge: str, w2: str) -> None:
|
||||
+ "&lang=zh-cn&pt=0&client_type=web&w="
|
||||
+ w2
|
||||
+ "&callback=geetest_"
|
||||
+ str(int(round(time.time() * 1000))),
|
||||
+ str(round(time.time() * 1000)),
|
||||
headers=headers,
|
||||
timeout=REQUEST_TIMEOUT,
|
||||
)
|
||||
@@ -277,7 +277,7 @@ def get_picture(gt: str, challenge: str) -> tuple[str, str, list[int], str, str,
|
||||
"isPC": "true",
|
||||
"autoReset": "true",
|
||||
"width": "100%",
|
||||
"callback": "geetest_" + str(int(round(time.time() * 1000))),
|
||||
"callback": "geetest_" + str(round(time.time() * 1000)),
|
||||
}
|
||||
|
||||
response = requests.get(
|
||||
@@ -343,7 +343,7 @@ def req_end(gt: str, challenge: str, w: str) -> dict:
|
||||
+ "&lang=zh-cn&%24_BCm=0&client_type=web&w="
|
||||
+ w
|
||||
+ "&callback=geetest_"
|
||||
+ str(int(round(time.time() * 1000))),
|
||||
+ str(round(time.time() * 1000)),
|
||||
headers=headers,
|
||||
timeout=REQUEST_TIMEOUT,
|
||||
)
|
||||
|
||||
@@ -592,7 +592,7 @@ def H(t: int, e: str) -> str:
|
||||
n = 36 * r[0] + r[1]
|
||||
|
||||
# 计算目标值
|
||||
a = round(t) + n
|
||||
a = (t) + n
|
||||
|
||||
# 构建字符池
|
||||
_ = [[], [], [], [], []]
|
||||
|
||||
@@ -85,7 +85,7 @@ def get_w2(gt: str, challenge: str, c: list[int], s: str, str_16: str) -> str:
|
||||
"u": fake_timing["loadEventEnd"],
|
||||
}
|
||||
|
||||
first_time = int(round(time.time() * 1000)) # 伪造脚本开始运行时间
|
||||
first_time = round(time.time() * 1000) # 伪造脚本开始运行时间
|
||||
|
||||
guiji_yuanshu_shuzu = generate_realistic_trajectory(
|
||||
start_x=random.randint(400, 600), # 起始位置随机
|
||||
@@ -99,7 +99,7 @@ def get_w2(gt: str, challenge: str, c: list[int], s: str, str_16: str) -> str:
|
||||
compressed = compress_trajectory(trajectory)
|
||||
tt = encrypt_string(compressed, c, s)
|
||||
|
||||
passtime = str(int(round(time.time() * 1000)) - first_time)
|
||||
passtime = str(round(time.time() * 1000) - first_time)
|
||||
|
||||
rp = simple_md5(gt + challenge + passtime)
|
||||
|
||||
|
||||
@@ -306,7 +306,7 @@ class UserPrizeRecordItem(TafStruct):
|
||||
self.exchangeDate = ins.read_int64(21, default=self.exchangeDate)
|
||||
while True:
|
||||
pos = ins.buf.tell()
|
||||
tag, dtype = ins.read_head()
|
||||
_tag, dtype = ins.read_head()
|
||||
if dtype == TafType.STRUCT_END:
|
||||
ins.buf.seek(pos)
|
||||
return
|
||||
@@ -406,7 +406,7 @@ class ActTaskPrizeInfo(TafStruct):
|
||||
self.extra = ins.read_map(12)
|
||||
while True:
|
||||
pos = ins.buf.tell()
|
||||
tag, dtype = ins.read_head()
|
||||
_tag, dtype = ins.read_head()
|
||||
if dtype == TafType.STRUCT_END:
|
||||
ins.buf.seek(pos)
|
||||
return
|
||||
@@ -494,7 +494,7 @@ class ActTaskDetailItem(TafStruct):
|
||||
self.endTime = ins.read_string(26, default=self.endTime)
|
||||
while True:
|
||||
pos = ins.buf.tell()
|
||||
tag, dtype = ins.read_head()
|
||||
_tag, dtype = ins.read_head()
|
||||
if dtype == TafType.STRUCT_END:
|
||||
ins.buf.seek(pos)
|
||||
return
|
||||
|
||||
@@ -232,7 +232,7 @@ def solve_safe_auth(
|
||||
result = solver.solve(risk_url)
|
||||
except HuyaQrAuthRequiredError:
|
||||
raise
|
||||
except Exception as exc:
|
||||
except Exception as exc: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
last_err = exc
|
||||
logger.warning(f"[safe_auth] 第 {attempt + 1} 次过验异常: {exc}")
|
||||
time.sleep(1.0)
|
||||
@@ -425,8 +425,8 @@ class HuyaAppPasswordLogin:
|
||||
from .device_profile import record_login
|
||||
|
||||
record_login(self.username, result.success, result.message)
|
||||
except Exception: # 元数据记录失败不影响登录结果
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001 # 元数据记录失败不影响登录结果
|
||||
logger.debug(f"登录元数据记录失败: {exc}")
|
||||
return result
|
||||
|
||||
def _login_impl(self) -> HuyaLoginResult:
|
||||
@@ -450,7 +450,7 @@ class HuyaAppPasswordLogin:
|
||||
message=str(exc),
|
||||
code="QR_AUTH_REQUIRED",
|
||||
)
|
||||
except Exception as exc:
|
||||
except Exception as exc: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
return HuyaLoginResult(
|
||||
success=False,
|
||||
message=f"App 登录凭证获取失败: {exc}",
|
||||
@@ -478,7 +478,7 @@ class HuyaAppPasswordLogin:
|
||||
if env.uid != uid:
|
||||
struct.pack_into(">Q", raw, env.uid_off, uid)
|
||||
wup = base64.b64encode(bytes(raw)).decode("ascii")
|
||||
except Exception as exc:
|
||||
except Exception as exc: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
return HuyaLoginResult(
|
||||
success=False,
|
||||
message=f"证书铸造/信封补丁失败: {exc}",
|
||||
@@ -603,7 +603,7 @@ class HuyaAppPasswordLogin:
|
||||
sdid=sdid,
|
||||
context=pc.context,
|
||||
)
|
||||
except Exception as exc:
|
||||
except Exception as exc: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
return HuyaLoginResult(
|
||||
success=False,
|
||||
message=f"扫码绑定兑换 Cookie 失败: {exc}",
|
||||
|
||||
@@ -6,7 +6,7 @@ import threading
|
||||
import time
|
||||
from collections.abc import Mapping
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from core.sms_provider import SmsLine, SmsProviderClient
|
||||
|
||||
@@ -76,7 +76,7 @@ def register_huya_with_sms_line(
|
||||
sms_url=item.url,
|
||||
)
|
||||
|
||||
sent_at = datetime.now()
|
||||
sent_at = datetime.now(UTC)
|
||||
try:
|
||||
code_result = send_huya_sms_code(phone=phone, proxies=proxies)
|
||||
except HuyaLoginError as exc:
|
||||
@@ -89,7 +89,7 @@ def register_huya_with_sms_line(
|
||||
normalized_phone=normalized_phone,
|
||||
sms_url=item.url,
|
||||
)
|
||||
except Exception as exc:
|
||||
except Exception as exc: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
return HuyaAutoRegisterResult(
|
||||
phone=phone,
|
||||
provider=item.provider,
|
||||
@@ -155,7 +155,7 @@ def register_huya_with_sms_line(
|
||||
sms_url=item.url,
|
||||
attempts=attempts,
|
||||
)
|
||||
except Exception as exc:
|
||||
except Exception as exc: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
return HuyaAutoRegisterResult(
|
||||
phone=phone,
|
||||
provider=item.provider,
|
||||
|
||||
@@ -10,7 +10,7 @@ import time
|
||||
import uuid
|
||||
from collections.abc import Mapping
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from datetime import UTC, datetime
|
||||
from urllib.parse import quote, urlsplit, urlunsplit
|
||||
|
||||
import requests
|
||||
@@ -496,7 +496,7 @@ def change_huya_password_with_sms_line(
|
||||
) -> HuyaChangePasswordResult:
|
||||
"""使用同一手机号接码链接完成改密短信验证。"""
|
||||
changer = HuyaPasswordChanger(uid=uid, cookie=cookie, proxies=proxies)
|
||||
sent_at = datetime.now()
|
||||
sent_at = datetime.now(UTC)
|
||||
code_result = changer.send_code()
|
||||
if not code_result.success or not code_result.session_data:
|
||||
return HuyaChangePasswordResult(
|
||||
|
||||
@@ -22,6 +22,8 @@ import random
|
||||
from collections.abc import Mapping
|
||||
from pathlib import Path
|
||||
|
||||
from loguru import logger
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
DATA_DIR = ROOT / "data"
|
||||
PRIMARY_PROFILE_DB = DATA_DIR / "huya_device_profiles.json"
|
||||
@@ -119,13 +121,13 @@ def _load_db() -> dict:
|
||||
if PRIMARY_PROFILE_DB.exists():
|
||||
try:
|
||||
return json.loads(PRIMARY_PROFILE_DB.read_text("utf-8"))
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.debug(f"读取主设备画像库失败: {exc}")
|
||||
if FALLBACK_PROFILE_DB.exists():
|
||||
try:
|
||||
return json.loads(FALLBACK_PROFILE_DB.read_text("utf-8"))
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.debug(f"读取备用设备画像库失败: {exc}")
|
||||
return {}
|
||||
|
||||
|
||||
@@ -135,8 +137,8 @@ def _save_db(db: dict) -> None:
|
||||
PRIMARY_PROFILE_DB.write_text(
|
||||
json.dumps(db, indent=2, ensure_ascii=False), encoding="utf-8"
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.debug(f"保存设备画像库失败: {exc}")
|
||||
|
||||
|
||||
def _enrich_profile(profile: dict) -> tuple[dict, bool]:
|
||||
|
||||
@@ -10,6 +10,8 @@ import json
|
||||
import struct
|
||||
from pathlib import Path
|
||||
|
||||
from loguru import logger
|
||||
|
||||
INT8, INT16, INT32, INT64 = 0x00, 0x01, 0x02, 0x03
|
||||
STRING1, STRING4 = 0x06, 0x07
|
||||
MAP, LIST = 0x08, 0x09
|
||||
@@ -131,8 +133,8 @@ class Envelope:
|
||||
if candidate.exists():
|
||||
try:
|
||||
return cls._load_from_path(candidate)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.debug(f"加载证书信封候选文件失败: {candidate}: {exc}")
|
||||
return cls(base64.b64decode(DEFAULT_QURL_B64))
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -4,6 +4,8 @@ TAF/WUP 帧解码器 — 将二进制帧转为可读摘要,用于日志输出
|
||||
|
||||
from typing import Any, cast
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from .taf_protocol import TafInputStream, TafType
|
||||
from .wup_protocol import normalize_wup_payload
|
||||
|
||||
@@ -101,13 +103,13 @@ def _decode_taf_struct(ins: TafInputStream, depth: int = 0) -> dict:
|
||||
if depth < 5:
|
||||
try:
|
||||
val = _decode_taf_value(ins, dtype, depth)
|
||||
except Exception:
|
||||
except Exception: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
val = f"<decode_err:0x{dtype:02x}>"
|
||||
else:
|
||||
val = "<...>"
|
||||
try:
|
||||
ins.skip_field(dtype)
|
||||
except Exception:
|
||||
except Exception: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
break
|
||||
key = f"tag{tag}"
|
||||
if key in fields:
|
||||
@@ -195,19 +197,20 @@ def _decode_wup_body(body: bytes) -> dict:
|
||||
if v:
|
||||
try:
|
||||
tins = TafInputStream(v)
|
||||
ttag, tdt = tins.peek_head()
|
||||
_ttag, tdt = tins.peek_head()
|
||||
if tdt == TafType.STRUCT_BEGIN:
|
||||
tins.read_head()
|
||||
result[k] = _decode_taf_struct(tins)
|
||||
else:
|
||||
result[k] = f"<{len(v)}B>"
|
||||
except Exception:
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.debug(f"TAF 嵌套结构解码失败: {exc}")
|
||||
result[k] = f"<{len(v)}B>"
|
||||
else:
|
||||
result[k] = _decode_taf_value(sins, vt)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.debug(f"TAF 字段解码失败: {exc}")
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
result["err"] = str(e)
|
||||
return result
|
||||
|
||||
@@ -286,7 +289,7 @@ def format_wss_log(body: bytes, cmd: int, seq: int, direction: str) -> str:
|
||||
try:
|
||||
ins = TafInputStream(clean)
|
||||
# 看第一个 head
|
||||
tag, dtype = ins.peek_head()
|
||||
_tag, dtype = ins.peek_head()
|
||||
if dtype == TafType.STRUCT_BEGIN:
|
||||
ins.read_head()
|
||||
fields = _decode_taf_struct(ins)
|
||||
@@ -314,6 +317,6 @@ def format_wss_log(body: bytes, cmd: int, seq: int, direction: str) -> str:
|
||||
if fields:
|
||||
return f"{prefix} {cmd_name} {_fmt_fields(cast(dict[str, Any], _truncate(fields)))}"
|
||||
return f"{prefix} {cmd_name}"
|
||||
except Exception:
|
||||
except Exception: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
cmd_name = CMD_NAMES.get(cmd, f"0x{cmd:02x}")
|
||||
return f"{prefix} {cmd_name} ({len(body)}B)"
|
||||
|
||||
@@ -92,7 +92,7 @@ class WSConnectParaInfo(TafStruct):
|
||||
|
||||
def _gen_trace_id() -> str:
|
||||
"""生成 sTraceId (格式 hex8:hex8:0:0,HAR 实证)"""
|
||||
h = "%016x" % random.getrandbits(64)
|
||||
h = f"{random.getrandbits(64):016x}"
|
||||
return f"{h}:{h}:0:0"
|
||||
|
||||
|
||||
@@ -294,7 +294,7 @@ class HuyaHttpClient:
|
||||
import gzip
|
||||
|
||||
resp_data = gzip.decompress(resp_data)
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
self.logger(f"[HTTP] ❌ 请求失败: {type(e).__name__}: {e}")
|
||||
return None
|
||||
|
||||
@@ -611,13 +611,13 @@ class HuyaHttpClient:
|
||||
or resp.headers.get("Content-Encoding") == "gzip"
|
||||
):
|
||||
resp_data = gzip.decompress(resp_data)
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
self.logger(f"[LIVELINK] ❌ 小程序码请求失败: {type(e).__name__}: {e}")
|
||||
return None
|
||||
|
||||
try:
|
||||
data = json.loads(resp_data.decode("utf-8", "replace"))
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
self.logger(f"[LIVELINK] ❌ 小程序码响应解析失败: {type(e).__name__}: {e}")
|
||||
return None
|
||||
|
||||
@@ -679,13 +679,13 @@ class HuyaHttpClient:
|
||||
or resp.headers.get("Content-Encoding") == "gzip"
|
||||
):
|
||||
resp_data = gzip.decompress(resp_data)
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
self.logger(f"[LIVELINK] ❌ 二维码状态请求失败: {type(e).__name__}: {e}")
|
||||
return None
|
||||
|
||||
try:
|
||||
data = json.loads(resp_data.decode("utf-8", "replace"))
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
self.logger(
|
||||
f"[LIVELINK] ❌ 二维码状态响应解析失败: {type(e).__name__}: {e}"
|
||||
)
|
||||
@@ -972,7 +972,7 @@ class HuyaHttpClient:
|
||||
import gzip
|
||||
|
||||
resp_data = gzip.decompress(resp_data)
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
self.logger(f"[HTTP] ❌ payOrderSubmitV5 失败: {e}")
|
||||
return None
|
||||
|
||||
|
||||
+3
-4
@@ -380,10 +380,9 @@ class HuyaPasswordLogin:
|
||||
|
||||
last_exc: Exception | None = None
|
||||
for attempt in range(max_ip_retries + 1):
|
||||
if attempt > 0:
|
||||
if not self._swap_proxy():
|
||||
logger.warning("无可用代理可切换,停止换 IP 重试")
|
||||
break
|
||||
if attempt > 0 and not self._swap_proxy():
|
||||
logger.warning("无可用代理可切换,停止换 IP 重试")
|
||||
break
|
||||
try:
|
||||
return self._login_once()
|
||||
except (HuyaQrAuthRequiredError, HuyaSmsAuthRequiredError) as exc:
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
来源:m-shop.yaoguo.com 的 jce/ShopFacade.js、api/orderui.ts、api/mall/PlayMallNewHome.ts
|
||||
"""
|
||||
|
||||
|
||||
from .taf_protocol import TafInputStream, TafOutputStream, TafStruct, TafType
|
||||
|
||||
|
||||
@@ -68,7 +67,7 @@ def _skip_to_struct_end(ins: TafInputStream):
|
||||
"""跳过当前结构里未解析的尾部字段,停在 STRUCT_END 前。"""
|
||||
while True:
|
||||
pos = ins.buf.tell()
|
||||
tag, dtype = ins.read_head()
|
||||
_tag, dtype = ins.read_head()
|
||||
if dtype == TafType.STRUCT_END:
|
||||
ins.buf.seek(pos)
|
||||
return
|
||||
@@ -427,7 +426,7 @@ class GoodsPriceInfo(TafStruct):
|
||||
def first_sku_id(self) -> int:
|
||||
if not self.skuMap:
|
||||
return 0
|
||||
return sorted(self.skuMap.keys())[0]
|
||||
return min(self.skuMap.keys())
|
||||
|
||||
@property
|
||||
def sku_list(self) -> list[dict]:
|
||||
|
||||
@@ -255,7 +255,7 @@ class TafInputStream:
|
||||
|
||||
def _read_int_len(self) -> int:
|
||||
"""读 map/list 长度(int32 带优化)"""
|
||||
tag, dtype = self.read_head()
|
||||
_tag, dtype = self.read_head()
|
||||
return self._read_int_value(dtype)
|
||||
|
||||
def _read_int_value(self, dtype: int) -> int:
|
||||
@@ -273,7 +273,7 @@ class TafInputStream:
|
||||
|
||||
def _skip_struct(self):
|
||||
while True:
|
||||
tag, dtype = self.read_head()
|
||||
_tag, dtype = self.read_head()
|
||||
if dtype == TafType.STRUCT_END:
|
||||
break
|
||||
self.skip_field(dtype)
|
||||
@@ -441,7 +441,7 @@ class TafInputStream:
|
||||
obj = struct_class()
|
||||
obj.read_from(self)
|
||||
# 消费 STRUCT_END
|
||||
t, dt = self.read_head()
|
||||
_t, dt = self.read_head()
|
||||
if dt != TafType.STRUCT_END:
|
||||
raise ValueError(f"期望 STRUCT_END, 实际 0x{dt:02x}")
|
||||
return obj
|
||||
|
||||
@@ -261,7 +261,7 @@ class HuyaCaptchaOcr:
|
||||
target["cropped_image"],
|
||||
char["cropped_image"],
|
||||
)
|
||||
except Exception:
|
||||
except Exception: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
score_matrix[target_index][char_index] = 1e6
|
||||
|
||||
row_ind, col_ind = linear_sum_assignment(score_matrix)
|
||||
|
||||
@@ -137,7 +137,7 @@ class HuyaVerificationSolver:
|
||||
max_width = max(bg.shape[1], tip.shape[1])
|
||||
|
||||
def pad_right(img, target_width):
|
||||
height, width = img.shape[:2]
|
||||
_height, width = img.shape[:2]
|
||||
if width >= target_width:
|
||||
return img
|
||||
return cv2.copyMakeBorder(
|
||||
@@ -299,8 +299,8 @@ class HuyaVerificationSolver:
|
||||
"虎牙登录风控strategys完整结构: {}",
|
||||
json.dumps(strategies, ensure_ascii=False)[:1200],
|
||||
)
|
||||
except Exception: # noqa: BLE001
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.debug(f"风控策略日志序列化失败: {exc}")
|
||||
strategy_url_lower = strategy_url.lower()
|
||||
# 判定依据是 URL 路径,不是 strategy 数值。
|
||||
# 实测(2026-08-25): strategy=64 时 pt_auth.html 是滑块、qr_auth.html 才是扫码,
|
||||
|
||||
+14
-12
@@ -76,7 +76,7 @@ class WssMessage:
|
||||
def decode(cls, data: bytes) -> "WssMessage":
|
||||
if len(data) < 6:
|
||||
raise ValueError(f"消息太短: {len(data)} bytes")
|
||||
version, command = struct.unpack(">BB", data[0:2])
|
||||
_version, command = struct.unpack(">BB", data[0:2])
|
||||
sequence = struct.unpack(">I", data[2:6])[0]
|
||||
body = data[6:]
|
||||
return cls(command=command, sequence=sequence, body=body)
|
||||
@@ -256,7 +256,7 @@ class HuyaWssClient:
|
||||
format_wss_log(msg.body, msg.command, msg.sequence, "收")
|
||||
)
|
||||
await self._handle_message(msg)
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
self.logger(
|
||||
f"[WSS] 解析消息失败: {e} raw_hex={raw_bytes[:50].hex()}"
|
||||
)
|
||||
@@ -264,7 +264,7 @@ class HuyaWssClient:
|
||||
pass
|
||||
except websockets.exceptions.ConnectionClosed as e:
|
||||
self.logger(f"[WSS] 连接关闭: code={e.code} reason={e.reason}")
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
self.logger(f"[WSS] 接收循环异常: {type(e).__name__}: {e}")
|
||||
|
||||
async def _handle_message(self, msg: WssMessage):
|
||||
@@ -289,7 +289,7 @@ class HuyaWssClient:
|
||||
await self.send_heartbeat()
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
self.logger(f"[WSS] 心跳循环异常: {e}")
|
||||
|
||||
async def send_heartbeat(self):
|
||||
@@ -399,7 +399,7 @@ class HuyaWssClient:
|
||||
)
|
||||
return
|
||||
ins = TafInputStream(treq)
|
||||
tag, dtype = ins.peek_head()
|
||||
_tag, dtype = ins.peek_head()
|
||||
if dtype != 0x0A: # STRUCT_BEGIN
|
||||
self.logger(f"[RPC] wsLaunch tRsp 非结构体 dtype=0x{dtype:02x}")
|
||||
return
|
||||
@@ -432,7 +432,7 @@ class HuyaWssClient:
|
||||
self.logger(
|
||||
f"[RPC] wsLaunch 解析: guid={self._launch_guid} ip={self._launch_ip}"
|
||||
)
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
self.logger(f"[RPC] wsLaunch 响应解析失败: {e}")
|
||||
|
||||
@staticmethod
|
||||
@@ -610,15 +610,17 @@ class HuyaWssClient:
|
||||
if data and isinstance(data, bytes) and len(data) > 0:
|
||||
try:
|
||||
ins = TafInputStream(data)
|
||||
tag, dtype = ins.peek_head()
|
||||
_tag, dtype = ins.peek_head()
|
||||
if dtype == TafType.STRUCT_BEGIN:
|
||||
ins.read_head()
|
||||
decoded = _decode_taf_struct(ins)
|
||||
self.logger(
|
||||
f"[←] {service}.{method} {key}: {_truncate(decoded)}"
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001
|
||||
self.logger(
|
||||
f"[debug] WUP 响应字段解码失败: {service}.{method}.{key}: {exc}"
|
||||
)
|
||||
|
||||
if rsp_class is None:
|
||||
return body
|
||||
@@ -794,13 +796,13 @@ class HuyaWssClient:
|
||||
if data and isinstance(data, bytes) and len(data) > 0:
|
||||
try:
|
||||
ins = TafInputStream(data)
|
||||
tag, dtype = ins.peek_head()
|
||||
_tag, dtype = ins.peek_head()
|
||||
if dtype == TafType.STRUCT_BEGIN:
|
||||
ins.read_head()
|
||||
decoded = _decode_taf_struct(ins)
|
||||
self.logger(f"[←] payOrderSubmitV5 {key}: {_truncate(decoded)}")
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as exc: # noqa: BLE001
|
||||
self.logger(f"[debug] WUP 支付响应字段解码失败: {key}: {exc}")
|
||||
result = wup_resp.readStruct("tRsp", PayOrderRes)
|
||||
if result is None:
|
||||
result = wup_resp.readStruct("tResp", PayOrderRes)
|
||||
|
||||
@@ -211,7 +211,7 @@ class WupResponse:
|
||||
_, vt = ins.read_head()
|
||||
val = _read_bytes_value(ins, vt)
|
||||
self.newdata[key] = val
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
print(f"[WupResponse] 解析 newdata 失败: {e}")
|
||||
|
||||
def readStruct(self, key: str, struct_class=None):
|
||||
@@ -236,13 +236,13 @@ class WupResponse:
|
||||
ins = TafInputStream(data)
|
||||
# newdata 里的结构体以 STRUCT_BEGIN 开头
|
||||
try:
|
||||
tag, dtype = ins.peek_head()
|
||||
_tag, dtype = ins.peek_head()
|
||||
if dtype == TafType.STRUCT_BEGIN:
|
||||
ins.read_head() # 消费 STRUCT_BEGIN
|
||||
obj = struct_class()
|
||||
obj.read_from(ins)
|
||||
return obj
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa: BLE001 外部接口与任务边界需要保留宽泛异常兜底
|
||||
print(f"[WupResponse] 解析 {struct_class.__name__} 失败: {e}")
|
||||
return None
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import annotations
|
||||
import json
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from datetime import UTC, datetime
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import requests
|
||||
@@ -98,7 +98,7 @@ def _parse_sms8_time(value: str) -> datetime | None:
|
||||
return None
|
||||
for fmt in ("%Y-%m-%d %H:%M:%S", "%Y/%m/%d %H:%M:%S"):
|
||||
try:
|
||||
return datetime.strptime(text, fmt)
|
||||
return datetime.strptime(text, fmt).replace(tzinfo=UTC)
|
||||
except ValueError:
|
||||
continue
|
||||
return None
|
||||
|
||||
Reference in New Issue
Block a user