""" 百度网盘凭证管理器 — bdstoken 获取与校验 参考 cloud-auto-save 的 BaiduNetDisk.cookie 机制 """ import logging import requests from ...errors import TransferError, TransferErrorCode logger = logging.getLogger(__name__) # 百度网盘 API 基础 URL BAIDU_PAN_API = "https://pan.baidu.com" class BaiduCredentialManager: """百度网盘 Cookie 凭证 + bdstoken 管理 百度网盘的大多数受保护 API 都需要 bdstoken 参数, 该 token 通过 API 获取并缓存在实例中。 """ def __init__(self, cookie: str, session: requests.Session): """ Args: cookie: 完整的百度 Cookie 字符串 session: 共享的 requests.Session(继承 User-Agent 等 headers) """ self.cookie = cookie self.session = session self._bdstoken: str = "" # ─── 公开方法 ────────────────────────────────────────── def validate(self) -> bool: """校验 Cookie 是否有效:长度 >= 50 视为合格""" return bool(self.cookie and len(self.cookie.strip()) >= 50) def get_bdstoken(self, force_refresh: bool = False) -> str: """ 获取 bdstoken,首次调用会请求 API 获取并缓存。 API: GET /api/gettemplatevariable?fields=["bdstoken"] Raises: TransferError: 获取失败 (BAIDU_BDSTOKEN_FAIL) """ if self._bdstoken and not force_refresh: return self._bdstoken url = f"{BAIDU_PAN_API}/api/gettemplatevariable" params = {"fields": '["bdstoken"]'} headers = self.get_headers() try: resp = self.session.get(url, params=params, headers=headers, timeout=15) resp.raise_for_status() data = resp.json() except Exception as e: logger.error(f"获取 bdstoken 网络异常: {e}") raise TransferError( TransferErrorCode.BAIDU_BDSTOKEN_FAIL, message=f"百度 bdstoken 请求失败: {e}", platform="baidu", ) errno = data.get("errno", -1) if errno != 0: logger.error(f"获取 bdstoken API 返回 errno={errno}: {data}") raise TransferError( TransferErrorCode.BAIDU_BDSTOKEN_FAIL, message=f"百度 bdstoken 获取失败 (errno={errno})", platform="baidu", details={"response": data}, ) self._bdstoken = data.get("result", {}).get("bdstoken", "") if not self._bdstoken: raise TransferError( TransferErrorCode.BAIDU_BDSTOKEN_FAIL, message="百度 bdstoken 为空", platform="baidu", ) logger.info("bdstoken 获取成功") return self._bdstoken def get_headers(self) -> dict: """构建携带 Cookie 的请求头(继承 session 默认 headers 外的额外字段)""" headers = { "Cookie": self.cookie, "Referer": "https://pan.baidu.com/", "Origin": "https://pan.baidu.com", } return headers def invalidate_bdstoken(self): """使缓存失效,下次调用 get_bdstoken 会重新获取""" self._bdstoken = "" logger.info("bdstoken 缓存已失效")