from __future__ import annotations import base64 import json from dataclasses import dataclass from typing import Any from .enc_data import kwsg_10400_raw, load_kwsg_10400_tables from .sig3 import Kwsg10418State REWARD_SDK = "95147564-9763-4413-a937-6f0e3c12caf1" APP_NAME = "\u5feb\u624b\u6781\u901f\u7248" @dataclass(frozen=True) class RewardBody: enc_data: str sign: str sdk_id: str sign_counter: int def _safe_int(value: Any, default: int = 0) -> int: try: if value in (None, ""): return default return int(str(value)) except Exception: return default def _android_release(api_params: dict[str, str]) -> str: sys_value = str(api_params.get("sys") or "") if sys_value.startswith("ANDROID_"): return sys_value.split("_", 1)[1] return str(api_params.get("androidApiLevel") or "16") def _screen_size(api_params: dict[str, str]) -> dict[str, int]: width = _safe_int(api_params.get("sw"), 1080) height = _safe_int(api_params.get("sh"), 2376) status_bar = _safe_int(api_params.get("sbh"), 120) content_height = max(1, height - status_bar - 48) return {"width": width, "height": content_height} def _connection_type(api_params: dict[str, str]) -> int: net = str(api_params.get("net") or "").upper() if net in {"5G", "NR"}: return 5 if net in {"WIFI", "WI-FI"}: return 100 return 100 def _json_bytes(value: dict[str, Any]) -> bytes: return json.dumps(value, ensure_ascii=False, separators=(",", ":")).encode("utf-8") def build_reward_str_e( *, kind: str, cookie_dict: dict[str, str], api_params: dict[str, str], oaid: str, scene: tuple[int, int, int], business_id: int, neo_params: str = "", now_ms: int, network_ip: str = "172.31.230.147", ipdx_ip: str = "106.178.190.155", ) -> bytes: user_id = cookie_dict.get("userId") or cookie_dict.get("ud") or api_params.get("ud") or "" page_id, sub_page_id, _pos_id = scene imp_ext: dict[str, Any] = { "openH5AdCount": 0, "sessionLookedCompletedCount": "0", "sessionType": "1", } if neo_params: imp_ext["neoParams"] = neo_params session_id = f"adNeo-{user_id}-{sub_page_id}-{now_ms}" request_scene_type = 1 if business_id != 606 else 7 data = { "appInfo": { "appId": "kuaishou_nebula", "name": APP_NAME, "packageName": "com.kuaishou.nebula", "version": api_params.get("appver") or cookie_dict.get("appver") or "14.5.50.11631", "versionCode": -1, }, "deviceInfo": { "oaid": oaid, "osType": 1, "osVersion": _android_release(api_params), "language": "zh", "deviceId": cookie_dict.get("did") or api_params.get("did") or "", "screenSize": _screen_size(api_params), "ftt": api_params.get("ftt", ""), "supportGyroscope": True, }, "networkInfo": { "ip": network_ip, "connectionType": _connection_type(api_params), }, "geoInfo": {"latitude": 0, "longitude": 0}, "userInfo": {"userId": user_id, "age": 0, "gender": ""}, "impInfo": [ { "pageId": page_id, "subPageId": sub_page_id, "action": 0, "width": 0, "height": 0, "browseType": _safe_int(api_params.get("browseType"), 3), "requestSceneType": request_scene_type, "lastReceiveAmount": 0, "impExtData": json.dumps(imp_ext, ensure_ascii=False, separators=(",", ":")), "mediaExtData": "{}", "session": json.dumps({"id": session_id}, ensure_ascii=False, separators=(",", ":")), } ], "adClientInfo": json.dumps( {"ipdxIP": ipdx_ip}, ensure_ascii=False, separators=(",", ":"), ), "recoReportContext": json.dumps( {"adClientInfo": {"shouldShowAdProfileSectionBanner": None, "profileAuthorId": 0}}, ensure_ascii=False, separators=(",", ":"), ), } return _json_bytes(data) def build_reward_body( str_e: bytes, state: Kwsg10418State, *, t1: bytes | None = None, t2: bytes | None = None, sdk_id: str = REWARD_SDK, unix_time: int | None = None, enc_epoch_seconds: int | None = None, ) -> RewardBody: if t1 is None and t2 is None: t1, t2 = load_kwsg_10400_tables() if t1 is None or t2 is None: raise ValueError("t1 and t2 must be provided together") enc_raw = kwsg_10400_raw(str_e, sdk_id, t1, t2, epoch_seconds=enc_epoch_seconds) enc_data = base64.b64encode(enc_raw).decode("ascii") sign = state.reward_sign(str_e, sdk_id, unix_time=unix_time, t1=t1, t2=t2) return RewardBody( enc_data=enc_data, sign=sign, sdk_id=sdk_id, sign_counter=state.counter, ) __all__ = [ "APP_NAME", "REWARD_SDK", "RewardBody", "build_reward_body", "build_reward_str_e", ]