mirror of
https://github.com/N1ngYu/SaltBot.git
synced 2025-09-28 08:42:40 +08:00
500 lines
19 KiB
Python
500 lines
19 KiB
Python
import hashlib
|
|
import random
|
|
import re
|
|
|
|
import time
|
|
import nonebot
|
|
from datetime import datetime, timedelta
|
|
from nonebot.log import logger
|
|
|
|
import requests
|
|
|
|
from nonebot_plugin_maimai_helper.util.net.HTTPRequest import HTTPRequest
|
|
from nonebot_plugin_maimai_helper.data import ticket_define, region_map
|
|
from nonebot_plugin_maimai_helper.util.utils import find_chara_levels, find_chara_awakening
|
|
from nonebot_plugin_maimai_helper.manager.game_data import GameDataManager
|
|
|
|
chara_manager = GameDataManager("chara")
|
|
title_manager = GameDataManager("title")
|
|
frame_manager = GameDataManager("frame")
|
|
plate_manager = GameDataManager("plate")
|
|
partner_manager = GameDataManager("partner")
|
|
icon_manager = GameDataManager("icon")
|
|
|
|
|
|
config = nonebot.get_driver().config
|
|
dateTime_constant = getattr(config, 'dateTime_constant', 114514)
|
|
region_id = getattr(config, 'region_id', 114514)
|
|
placeId = getattr(config, 'place_id', 114514)
|
|
clientId = getattr(config, 'client_id', 'ABCDEFG')
|
|
chimeSalt = getattr(config, 'chime_salt', 'PArBXE')
|
|
chimeHost = getattr(config, 'chime_host', 'localhost')
|
|
aimeHost = getattr(config, 'aime_host', 'http://localhost')
|
|
|
|
|
|
def get_user_music_details(uid: int):
|
|
req = HTTPRequest(uid)
|
|
data = req.Request("GetUserMusicApiMaimaiChn", {"userId": uid, "nextIndex": 0, "maxCount": 2147483647})
|
|
return [detail for music in data["userMusicList"] for detail in music["userMusicDetailList"]]
|
|
|
|
|
|
def get_preview(uid):
|
|
result = {"is_success": False, "is_error": False, "user_id": uid, "data": {}, "msg_body": "",
|
|
"is_in_whitelist": False}
|
|
login_dict = {
|
|
"userId": uid,
|
|
"accessCode": "",
|
|
"regionId": region_id,
|
|
"placeId": placeId,
|
|
"clientId": clientId,
|
|
"dateTime": dateTime_constant,
|
|
"isContinue": False,
|
|
"genericFlag": 0
|
|
}
|
|
request = HTTPRequest(uid=uid)
|
|
logger.debug("开始获取用户数据")
|
|
preview = request.Request("GetUserPreviewApiMaimaiChn", login_dict)
|
|
preview["iconName"] = icon_manager.get_resource(preview["iconId"])
|
|
result["data"] = preview
|
|
result["is_success"] = True
|
|
result["is_error"] = False
|
|
result["msg_body"] = "成功"
|
|
return result
|
|
|
|
|
|
def get_preview_detailed(uid):
|
|
result = {"is_success": False, "is_error": False, "user_id": uid, "data": {}, "msg_body": "",
|
|
"is_in_whitelist": False, "is_got_qr_code": False}
|
|
login_dict = {
|
|
"userId": uid,
|
|
"accessCode": "",
|
|
"regionId": region_id,
|
|
"placeId": placeId,
|
|
"clientId": clientId,
|
|
"dateTime": dateTime_constant,
|
|
"isContinue": False,
|
|
"genericFlag": 0,
|
|
"nextIndex": 0,
|
|
"maxCount": 20
|
|
}
|
|
request = HTTPRequest(uid=uid)
|
|
logger.debug("开始获取用户数据")
|
|
preview = request.Request("GetUserPreviewApiMaimaiChn", login_dict)
|
|
if not preview["isLogin"]:
|
|
logger.debug("开始登入用户账号")
|
|
login = request.Request("UserLoginApiMaimaiChn", login_dict)
|
|
if login["returnCode"] != 1:
|
|
result["is_got_qr_code"] = False
|
|
result["msg_body"] = "请在微信「舞萌 | 中二」公众号上点击一次「玩家二维码」按钮后再试一遍吧~"
|
|
logger.error("登入失败,请在微信「舞萌 | 中二」公众号上点击一次「玩家二维码」按钮后再试一遍吧~")
|
|
return result
|
|
logger.success("登入成功")
|
|
result["is_got_qr_code"] = True
|
|
else:
|
|
result["is_got_qr_code"] = True
|
|
result["is_already_login"] = True
|
|
logger.debug("开始获取用户详细信息")
|
|
user_data = request.Request("GetUserDataApiMaimaiChn", login_dict)
|
|
logger.debug("开始获取用户旅行伙伴信息")
|
|
character_list = request.Request("GetUserCharacterApiMaimaiChn", login_dict)["userCharacterList"]
|
|
|
|
player_info = user_data["userData"]
|
|
player_info["charaLevel"] = find_chara_levels(character_list, user_data["userData"]["charaSlot"])
|
|
player_info["charaAwakening"] = find_chara_awakening(character_list, user_data["userData"]["charaSlot"])
|
|
player_info["charaName"] = [chara_manager.get_resource(title_id) for title_id in user_data["userData"]["charaSlot"]]
|
|
player_info["frameName"] = frame_manager.get_resource(user_data["userData"]["frameId"])
|
|
player_info["plateName"] = plate_manager.get_resource(user_data["userData"]["plateId"])
|
|
player_info["iconName"] = icon_manager.get_resource(user_data["userData"]["iconId"])
|
|
player_info["partnerName"] = partner_manager.get_resource(user_data["userData"]["partnerId"])
|
|
player_info["titleName"] = title_manager.get_resource(user_data["userData"]["titleId"])["title"]
|
|
player_info["titleRare"] = title_manager.get_resource(user_data["userData"]["titleId"])["rareType"]
|
|
player_info["classRank"] = user_data["userData"]["classRank"]
|
|
player_info["courseRank"] = user_data["userData"]["courseRank"]
|
|
player_info["banState"] = user_data["banState"]
|
|
player_info["loginState"] = preview["isLogin"]
|
|
player_info["frameId"] = user_data["userData"]["frameId"]
|
|
player_info["plateId"] = user_data["userData"]["plateId"]
|
|
player_info["iconId"] = user_data["userData"]["iconId"]
|
|
player_info["charaId"] = [(title_id)for title_id in user_data["userData"]["charaSlot"]]
|
|
# result["userData"]
|
|
result["data"] = player_info
|
|
|
|
if not preview["isLogin"]:
|
|
logger.debug("开始登出用户账号")
|
|
returnCode = request.Request("UserLogoutApiMaimaiChn", login_dict)['returnCode']
|
|
retry = 1
|
|
while returnCode != 1 and retry <= 5:
|
|
returnCode = request.Request("UserLogoutApiMaimaiChn", login_dict)['returnCode']
|
|
retry += 1
|
|
|
|
return result
|
|
|
|
|
|
def send_ticket(uid, ticket_id):
|
|
result = {"is_success": False, "is_got_qr_code": True, "is_already_login": False, "is_already_had_ticket": False,
|
|
"is_error": False, "user_id": uid, "data": {}, "msg_body": ""}
|
|
login_dict = {
|
|
"userId": uid,
|
|
"accessCode": "",
|
|
"regionId": region_id,
|
|
"placeId": placeId,
|
|
"clientId": clientId,
|
|
"dateTime": dateTime_constant,
|
|
"isContinue": False,
|
|
"genericFlag": 0
|
|
}
|
|
|
|
request = HTTPRequest(uid=uid)
|
|
logger.debug("开始获取用户信息")
|
|
preview = request.Request("GetUserPreviewApiMaimaiChn", login_dict)
|
|
if preview["isLogin"]:
|
|
result["is_already_login"] = True
|
|
result["msg_body"] = "当前用户已上机,请先下机然后再试一遍"
|
|
return result
|
|
else:
|
|
logger.debug("开始登入用户账户")
|
|
login = request.Request("UserLoginApiMaimaiChn", login_dict)
|
|
if login["returnCode"] != 1:
|
|
result["is_got_qr_code"] = False
|
|
result["msg_body"] = "请在微信「舞萌 | 中二」公众号上点击一次「玩家二维码」按钮后再试一遍吧~"
|
|
return result
|
|
user_data = request.Request("GetUserDataApiMaimaiChn", login_dict)
|
|
charges = request.Request("GetUserChargeApiMaimaiChn", login_dict)
|
|
|
|
had_ticket = False
|
|
if charges["userChargeList"]:
|
|
for charge in charges["userChargeList"]:
|
|
if charge["stock"] > 0 and charge["chargeId"] == int(ticket_id):
|
|
had_ticket = True
|
|
result["is_already_had_ticket"] = True
|
|
result["msg_body"] = "无法重复发放跑图票"
|
|
break
|
|
|
|
if not had_ticket:
|
|
date_time = datetime.now()
|
|
timestamp_str = date_time.strftime('%Y-%m-%d %H:%M:%S.0')
|
|
expire_timestamp = (date_time + timedelta(days=90)).strftime('%Y-%m-%d 04:00:00')
|
|
ticket_dict = {
|
|
"userId": uid,
|
|
"userChargelog": {
|
|
"chargeId": ticket_id,
|
|
"price": ticket_define[ticket_id]["cost"],
|
|
"purchaseDate": timestamp_str,
|
|
"playCount": int(user_data["userData"]["playCount"]),
|
|
"playerRating": int(user_data["userData"]["playerRating"]),
|
|
"placeId": placeId,
|
|
"regionId": region_id,
|
|
"clientId": clientId,
|
|
},
|
|
"userCharge": {
|
|
"chargeId": ticket_id,
|
|
"stock": 1,
|
|
"purchaseDate": timestamp_str,
|
|
"validDate": expire_timestamp
|
|
}
|
|
}
|
|
|
|
try:
|
|
logger.debug("开始充值功能票")
|
|
result["data"] = request.Request("UpsertUserChargelogApiMaimaiChn", ticket_dict)
|
|
result["is_success"] = True
|
|
result["msg_body"] = "成功"
|
|
except Exception as e:
|
|
print(e.with_traceback(None))
|
|
result["is_error"] = True
|
|
result["msg_body"] = f"未知错误:{e.with_traceback(None)}"
|
|
|
|
if not preview["isLogin"]:
|
|
logger.debug("开始登出用户账户")
|
|
returnCode = request.Request("UserLogoutApiMaimaiChn", login_dict)['returnCode']
|
|
retry = 1
|
|
while returnCode != 1 and retry <= 5:
|
|
returnCode = request.Request("UserLogoutApiMaimaiChn", login_dict)['returnCode']
|
|
retry += 1
|
|
|
|
return result
|
|
|
|
|
|
def logout(uid, timestamp=dateTime_constant):
|
|
result = {"is_success": False, "is_error": False, "user_id": uid, "data":{}, "msg_body": ""}
|
|
login_dict = {
|
|
"userId": uid,
|
|
"accessCode": "",
|
|
"placeId": placeId,
|
|
"regionId": region_id,
|
|
"clientId": clientId,
|
|
"dateTime": timestamp,
|
|
"isContinue": False,
|
|
"type": 5
|
|
}
|
|
try:
|
|
request = HTTPRequest(uid=uid)
|
|
logger.debug("开始登出用户账户")
|
|
result["data"] = request.Request("UserLogoutApiMaimaiChn", login_dict)
|
|
result["is_success"] = True
|
|
result["msg_body"] = "成功"
|
|
except Exception as e:
|
|
e.with_traceback(None)
|
|
result["data"] = None
|
|
result["is_error"] = True
|
|
result["msg_body"] = f"未知错误:{e.with_traceback(None)}"
|
|
|
|
return result
|
|
|
|
|
|
def login(uid, timestamp=dateTime_constant):
|
|
result = {"is_success": False, "is_error": False, "user_id": uid, "data": {}, "msg_body": ""}
|
|
login_dict = {
|
|
"userId": uid,
|
|
"accessCode": "",
|
|
"regionId": region_id,
|
|
"placeId": placeId,
|
|
"clientId": clientId,
|
|
"dateTime": timestamp,
|
|
"isContinue": False,
|
|
"genericFlag": 0
|
|
}
|
|
|
|
request = HTTPRequest(uid=uid)
|
|
logger.debug("开始获取用户信息")
|
|
preview = request.Request("GetUserPreviewApiMaimaiChn", login_dict)
|
|
if preview["isLogin"]:
|
|
result["data"] = None
|
|
result["is_already_login"] = True
|
|
result["msg_body"] = "当前用户已上机,请先下机然后再试一遍"
|
|
return result
|
|
else:
|
|
logger.debug("开始登入用户账户")
|
|
login = request.Request("UserLoginApiMaimaiChn", login_dict)
|
|
if login["returnCode"] != 1:
|
|
result["data"] = login
|
|
result["is_got_qr_code"] = False
|
|
result["msg_body"] = "请在微信「舞萌 | 中二」公众号上点击一次「玩家二维码」按钮后再试一遍吧~"
|
|
return result
|
|
else:
|
|
result["data"] = login
|
|
result["is_success"] = True
|
|
result["msg_body"] = "成功"
|
|
return result
|
|
|
|
|
|
def dump_user_all(uid):
|
|
result = {"is_success": False, "is_got_qr_code": True, "is_error": False, "user_id": uid, "data": {},
|
|
"msg_body": ""}
|
|
|
|
available_attrs = ["UserData", "UserExtend", "UserOption", "UserCharacter", "UserMap", "UserLoginBonus",
|
|
"UserRating", "UserItem", "UserMusic", "UserCourse", "UserCharge"]
|
|
data = {}
|
|
|
|
login_dict = {
|
|
"userId": uid,
|
|
"accessCode": "",
|
|
"regionId": region_id,
|
|
"placeId": placeId,
|
|
"clientId": clientId,
|
|
"dateTime": dateTime_constant,
|
|
"isContinue": False,
|
|
"genericFlag": 0
|
|
}
|
|
|
|
request = HTTPRequest(uid=uid)
|
|
logger.debug("开始获取用户信息")
|
|
preview = request.Request("GetUserPreviewApiMaimaiChn", login_dict)
|
|
if not preview["isLogin"]:
|
|
logger.debug("开始登入用户")
|
|
login = request.Request("UserLoginApiMaimaiChn", login_dict)
|
|
if login["returnCode"] != 1:
|
|
result["is_got_qr_code"] = False
|
|
result["msg_body"] = "请在微信「舞萌 | 中二」公众号上点击一次「玩家二维码」按钮后再试一遍吧~"
|
|
return result
|
|
else:
|
|
result["is_already_login"] = True
|
|
|
|
for ava_attr in available_attrs:
|
|
for i in range(0, 1):
|
|
try:
|
|
api = f"Get{ava_attr}Api"
|
|
final_attr = ava_attr[0].lower() + ava_attr[1:]
|
|
|
|
query = {"userId": uid, "nextIndex": 10000000000 if final_attr == "userItem" else 0,
|
|
"maxCount": 2147483647}
|
|
resp = request.Request(api, datas=query)
|
|
if final_attr in resp:
|
|
match final_attr:
|
|
case "userActivity":
|
|
data["userActList"] = resp["userActivity"]["playList"] + resp["userActivity"]["musicList"]
|
|
case _:
|
|
data[final_attr] = resp[final_attr]
|
|
else:
|
|
match final_attr:
|
|
case "userMusic":
|
|
data["userMusicDetailList"] = []
|
|
for music in resp["userMusicList"]:
|
|
data["userMusicDetailList"] += music["userMusicDetailList"]
|
|
case _:
|
|
data[final_attr + "List"] = resp[final_attr + "List"]
|
|
break
|
|
except Exception as e:
|
|
continue
|
|
|
|
if not preview["isLogin"]:
|
|
logger.debug("开始登出账户")
|
|
returnCode = request.Request("UserLogoutApiMaimaiChn", login_dict)['returnCode']
|
|
retry = 1
|
|
while returnCode != 1 and retry <= 5:
|
|
returnCode = request.Request("UserLogoutApiMaimaiChn", login_dict)['returnCode']
|
|
retry += 1
|
|
result["is_success"] = True
|
|
result["msg_body"] = "成功"
|
|
result["data"] = data
|
|
return result
|
|
|
|
|
|
def query_ticket(uid):
|
|
result = {"is_success": False, "is_error": False, "user_id": uid, "data": {}, "msg_body": ""}
|
|
request = HTTPRequest(uid=uid)
|
|
logger.debug("开始获取用户功能票信息")
|
|
ticket = request.Request("GetUserChargeApiMaimaiChn", {"userId": uid})
|
|
if not ticket["userChargeList"]:
|
|
ticket["userChargeList"] = []
|
|
result["data"] = ticket
|
|
result["is_success"] = True
|
|
result["is_error"] = False
|
|
result["msg_body"] = "成功"
|
|
return result
|
|
|
|
|
|
def get_user_region(uid):
|
|
result = {"is_success": False, "is_error": False, "user_id": uid, "data": {}, "msg_body": ""}
|
|
request = HTTPRequest(uid=uid)
|
|
logger.debug("开始获取用户登入信息")
|
|
resp = request.Request("GetUserRegionApiMaimaiChn", {"userId": uid})
|
|
|
|
for i in range(len(resp["userRegionList"])):
|
|
region_name = region_map[int(resp["userRegionList"][i]["regionId"]) - 1]
|
|
resp["userRegionList"][i]["regionName"] = region_name
|
|
|
|
result["data"] = resp
|
|
result["is_success"] = True
|
|
result["is_error"] = False
|
|
result["msg_body"] = "成功"
|
|
return result
|
|
|
|
|
|
def get_user_id_by_qr(qr_code):
|
|
if not (qr_code.startswith("SGWCMAID") and len(qr_code) == 84 and bool(re.match(r'^[0-9A-F]+$', qr_code[20:]))):
|
|
return {
|
|
"userID": 0,
|
|
"errorID": 99,
|
|
"timestamp": datetime.now().strftime("%Y%m%d%H%M%S")[2:],
|
|
"key": ""
|
|
}
|
|
return get_user_id(qr_code[20:])
|
|
|
|
|
|
def get_user_id(qr_code):
|
|
GAME_ID = "MAID"
|
|
AIME_SALT = chimeSalt
|
|
AIME_HOST = aimeHost
|
|
|
|
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")[2:]
|
|
chip_id = "A63E-01E{0:08}".format(random.randint(0, 99999999))
|
|
key = hashlib.sha256(f"{chip_id}{timestamp}{AIME_SALT}".encode()).hexdigest().upper()
|
|
data_json = f"{{\"chipID\":\"{chip_id}\",\"openGameID\":\"{GAME_ID}\",\"key\":\"{key}\",\"qrCode\":\"{qr_code}\",\"timestamp\":\"{timestamp}\"}}"
|
|
|
|
logger.debug("开始获取用户USER_ID")
|
|
resp = requests.post(f"{AIME_HOST}/wc_aime/api/get_data", data_json, headers={
|
|
"User-Agent": "WC_AIME_LIB",
|
|
})
|
|
return resp.json()
|
|
|
|
|
|
def get_user_music(uid):
|
|
result = {"is_success": False, "is_error": False, "user_id": uid, "data": {}, "msg_body": "",
|
|
"is_in_whitelist": False}
|
|
data = {}
|
|
dump_dict = {"userId": uid, "nextIndex": 0,
|
|
"maxCount": 2147483647}
|
|
request = HTTPRequest(uid=uid)
|
|
logger.debug("开始获取用户音乐数据")
|
|
preview = request.Request("GetUserMusicApiMaimaiChn", dump_dict)
|
|
data["userMusicDetailList"] = []
|
|
for music in preview["userMusicList"]:
|
|
data["userMusicDetailList"] += music["userMusicDetailList"]
|
|
result["data"] = data
|
|
result["is_success"] = True
|
|
result["is_error"] = False
|
|
result["msg_body"] = "成功"
|
|
return result
|
|
|
|
def title_ping():
|
|
result = {"is_success": False, "is_error": False, "data": {}, "msg_body": ""}
|
|
login_dict = {}
|
|
try:
|
|
request = HTTPRequest(uid=-1)
|
|
resp = request.Request("PingMaimaiChn", login_dict)
|
|
result["is_success"] = True
|
|
result["msg_body"] = "成功"
|
|
result['data'] = resp
|
|
print(resp)
|
|
|
|
except Exception as e:
|
|
e.with_traceback(None)
|
|
result["is_error"] = True
|
|
result["msg_body"] = f"未知错误:{e.with_traceback(None)}"
|
|
|
|
return result
|
|
|
|
|
|
def chime_ping():
|
|
result = {"is_success": False, "is_error": False, "data": {}, "msg_body": ""}
|
|
headers = {
|
|
'Connection': 'Close',
|
|
'Host': 'at.sys-allnet.cn',
|
|
'User-Agent': 'SDGB',
|
|
'Content-Length': '0',
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
}
|
|
data = {}
|
|
url = "http://at.sys-allnet.cn/report-api/Report"
|
|
try:
|
|
request = requests.post(url, headers=headers, data=data)
|
|
if request.status_code == 200:
|
|
result['is_success'] = True
|
|
result['data'] = request.text
|
|
result['msg_body'] = '成功'
|
|
else:
|
|
result['is_error'] = True
|
|
result['msg_body'] = request.status_code
|
|
return result
|
|
except Exception as e:
|
|
result['is_error'] = True
|
|
result['msg_body'] = e
|
|
return result
|
|
|
|
|
|
def all_net_ping():
|
|
result = {"is_success": False, "is_error": False, "data": {}, "msg_body": ""}
|
|
url = "http://ai.sys-allnet.cn/wc_aime/api/alive_check"
|
|
headers = {
|
|
'Connection': 'Keep-Alive',
|
|
'Host': 'ai.sys-allnet.cn',
|
|
'User-Agent': 'WC_AIME_LIB',
|
|
'Content-Length': '0'
|
|
}
|
|
data = {}
|
|
try:
|
|
request = requests.post(url, headers=headers, data=data)
|
|
if request.text == 'alive':
|
|
result['is_success'] = True
|
|
result['data'] = request.text
|
|
result['msg_body'] = '成功'
|
|
else:
|
|
result['is_error'] = True
|
|
result['msg_body'] = request.status_code
|
|
return result
|
|
except Exception as e:
|
|
result['is_error'] = True
|
|
result['msg_body'] = e
|
|
return result
|