"""虎牙 Cookie 规范化工具。""" from __future__ import annotations import json from collections.abc import Iterable, Mapping from requests.cookies import RequestsCookieJar def cookie_pairs(cookie: str) -> list[tuple[str, str]]: """把浏览器 Cookie 字符串拆成 key/value 对。""" pairs: list[tuple[str, str]] = [] for part in (cookie or "").split(";"): item = part.strip() if not item or "=" not in item: continue key, value = item.split("=", 1) key = key.strip() if not key: continue pairs.append((key, value.strip())) return pairs def normalize_cookie_pairs(pairs: Iterable[tuple[str, str]]) -> str: """按 Cookie key 去重,保留最后一次出现的值。""" ordered_keys: list[str] = [] values: dict[str, str] = {} for raw_key, raw_value in pairs: key = str(raw_key).strip() if not key: continue if key not in values: ordered_keys.append(key) values[key] = "" if raw_value is None else str(raw_value).strip() return "; ".join(f"{key}={values[key]}" for key in ordered_keys) def normalize_huya_cookie( cookie: str | Mapping[str, str] | RequestsCookieJar | None, ) -> str: """把 Cookie 字符串、dict 或 CookieJar 转成去重后的浏览器 Cookie 字符串。""" if not cookie: return "" if isinstance(cookie, str): return normalize_cookie_pairs(cookie_pairs(cookie)) return normalize_cookie_pairs( [ (str(key), "" if value is None else str(value)) for key, value in cookie.items() ] ) def cookie_value( cookie: str | Mapping[str, str] | RequestsCookieJar | None, key: str ) -> str: """从 Cookie 中读取 key;有重复时以最后一次出现为准。""" if not cookie or not key: return "" if isinstance(cookie, str): pairs = cookie_pairs(cookie) else: pairs = list(cookie.items()) value = "" for item_key, item_value in pairs: if item_key == key: value = "" if item_value is None else str(item_value).strip() return value def browser_login_script( pairs: Mapping[str, str], target_url: str, *, domain: str = ".huya.com", ttl_days: int = 180, secure: bool = True, ) -> str: """生成在用户自己浏览器控制台执行的登录脚本。 脚本把 Cookie 写入指定域后跳转目标页;Cookie 值以 JSON 数组内联, 保证引号、反斜杠等字符安全转义。属性与扩展注入保持一致(默认 Secure), 并先校验当前页面确实在 huya.com 域下——否则 document.cookie 会静默失效, 操作者会以为已登录。 """ payload = json.dumps( [[key, value] for key, value in pairs.items()], ensure_ascii=False ) target = json.dumps(target_url, ensure_ascii=False) ttl_ms = max(1, ttl_days) * 86_400_000 suffix = ";secure" if secure else "" return ( f"(function(){{" f"if(!/(^|\\.)huya\\.com$/i.test(location.hostname)){{" f"alert('请在 huya.com 域下的页面执行本脚本,当前页面:'+location.hostname);" f"return;}}" f"var c={payload};" f"var e=new Date(Date.now()+{ttl_ms}).toUTCString();" f"for(var i=0;i