ksjsb/core/reward_request.py
2026-07-30 20:25:56 +08:00

173 lines
5.1 KiB
Python

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",
]