# -*- coding: utf-8 -*- """ UploadUserPlaylog —— 上传单局成绩原始记录(UploadUserPlaylogApi) ★ 为什么需要它: 真机结算序列是**先 UploadUserPlaylog、后 UpsertUserAll**(2026-10-21 抓包 055/056 号): 055_UploadUserPlaylogApi request 2083 字节 -> returnCode=1 056_UpsertUserAllApi request 21833 字节 -> returnCode=1 Astral 原来只发 UpsertUserAll,服务端就只回 returnCode=1 而不落库。 这条前置是「本次会话确实打过这一局」的凭证。 请求体(源码 Net.VO.Mai2/UserPlaylogRequestVO.cs): { "userId": , "userPlaylog": { ...110 字段... } } """ from __future__ import annotations from typing import Any, Dict, Optional from config import CLIENT_ID, TIMEOUT_MS from .MaimaiNet import MaimaiNetClient, get_default_client, request_dict from .LogSetup import log_info def UploadUserPlaylog( user_id: int, user_playlog: Dict[str, Any], *, client_id: str = CLIENT_ID, timeout_ms: Optional[int] = None, client: Optional[MaimaiNetClient] = None, ) -> Dict[str, Any]: """上传一局成绩明细(无落库副作用,但服务端会记账,供 UpsertUserAll 消费)。 参数: user_id: 用户 ID user_playlog: 110 字段成绩明细,用 api.UpsertUserAll.build_user_playlog(playlog_id, login_date, play) 构造 返回:原始响应 dict({"returnCode": 1, "apiName": "UploadUserPlaylogApi"}) """ body = {"userId": int(user_id), "userPlaylog": user_playlog} log_info("上传成绩明细:user_id=" + str(user_id) + " musicId=" + str(user_playlog.get("musicId")) + " level=" + str(user_playlog.get("level")) + " achievement=" + str(user_playlog.get("achievement"))) return request_dict( "UploadUserPlaylogApi", body, user_id=user_id, client_id=client_id, timeout_ms=timeout_ms or TIMEOUT_MS, client=client, )