"""虎牙多账号设备画像生成与管理。 为每个账号生成并持久化独立的设备身份画像(机型、屏幕、指纹、设备ID等)。 """ from __future__ import annotations import hashlib import json import os import random from pathlib import Path ROOT = Path(__file__).resolve().parent.parent.parent DATA_DIR = ROOT / "data" PRIMARY_PROFILE_DB = DATA_DIR / "huya_device_profiles.json" FALLBACK_PROFILE_DB = ROOT / "evidence" / "device_profiles.json" REAL_MODELS = [ ("xiaomi", "M2102J2SC", "M2102J2SC,30,11", (1080, 2120)), ("vivo", "V2370A", "V2370A,34,13", (1080, 2412)), ("oppo", "PFFM20", "PFFM20,34,13", (1080, 2412)), ("honor", "SDY-AN00", "SDY-AN00,31,12", (1080, 2400)), ("samsung", "SM-G9910", "SM-G9910,31,12", (1440, 3200)), ("oneplus", "PGZ110", "PGZ110,34,13", (1080, 2412)), ("redmi", "23049PCD8G", "23049PCD8G,34,13", (1080, 2400)), ("realme", "RMX3366", "RMX3366,34,13", (1080, 2412)), ("iqoo", "V2183A", "V2183A,34,13", (1080, 2400)), ("nubia", "NX729J", "NX729J,33,13", (1080, 2400)), ("motorola", "XT2301-5", "XT2301-5,33,13", (1080, 2400)), ("gionee", "GN9013", "GN9013,29,10", (720, 1560)), ] HDID = "ed0db8334cadd236c00cadf7e11ab5a5" APP_VERSION = "13.4.22" SDK_VERSION = "1.0.80138" SAFEDEVICEID_DEFAULT = ( "PQwemAN9NHkZKoMqVTFUZBIypqMTaQEOrmXr37xQVhQZqrL/gUKEQ11xvE0ju48V8O/" "t9UBGSp27m4+6bP4IiAEnpaR5Rj1kHEfN2SPLPqYZW9vroxUSoAvjJn6ezTP9jWGxxlRDCbt" "Py4Rd6MencYT/pNImVIWK+YbNKZt1O05bHUFhqHf3" ) def _rand_sha1_hex() -> str: return hashlib.sha1(os.urandom(20)).hexdigest() def generate_profile(model_pick=None) -> dict: """生成一套随机设备画像。""" vendor, model, screen, (w, h) = ( random.choice(REAL_MODELS) if model_pick is None else model_pick ) return { "app_version": APP_VERSION, "sdk_version": SDK_VERSION, "vendor": vendor, "model": model, "os": "android", "ip": "127.0.0.1", "fingerprint": _rand_sha1_hex(), "screen": screen, "width": str(w), "height": str(h), "device_id": _rand_sha1_hex(), "hdid": HDID, "safedeviceid": SAFEDEVICEID_DEFAULT, } def _load_db() -> dict: if PRIMARY_PROFILE_DB.exists(): try: return json.loads(PRIMARY_PROFILE_DB.read_text("utf-8")) except Exception: pass if FALLBACK_PROFILE_DB.exists(): try: return json.loads(FALLBACK_PROFILE_DB.read_text("utf-8")) except Exception: pass return {} def _save_db(db: dict) -> None: try: PRIMARY_PROFILE_DB.parent.mkdir(parents=True, exist_ok=True) PRIMARY_PROFILE_DB.write_text(json.dumps(db, indent=2, ensure_ascii=False), encoding="utf-8") except Exception: pass def get_profile(account: str, force_new: bool = False) -> dict: """按账号获取或创建画像(幂等:同账号复用同一套)。""" db = _load_db() if not force_new and account in db: return db[account] p = generate_profile() db[account] = p _save_db(db) return p