mirror of
https://github.com/N1ngYu/SaltBot.git
synced 2025-09-28 08:42:40 +08:00
Add: Separate Plugin
This commit is contained in:
557
nonebot_plugin_maimai_helper/__init__.py
Normal file
557
nonebot_plugin_maimai_helper/__init__.py
Normal file
@@ -0,0 +1,557 @@
|
|||||||
|
from nonebot import on_command, on_regex, on_startswith
|
||||||
|
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message , MessageSegment, bot
|
||||||
|
from nonebot.params import EventMessage
|
||||||
|
from nonebot.permission import SUPERUSER
|
||||||
|
from nonebot_plugin_maimai_helper.helper.simai import *
|
||||||
|
from nonebot_plugin_maimai_helper.util.utils import *
|
||||||
|
from nonebot_plugin_maimai_helper.helper.diving_fish import *
|
||||||
|
from nonebot_plugin_maimai_helper.update_music_list import *
|
||||||
|
from nonebot_plugin_maimai_helper.helper.download import download_image
|
||||||
|
from nonebot_plugin_maimai_helper.helper.qrcode import *
|
||||||
|
from nonebot_plugin_maimai_helper.helper.convert import *
|
||||||
|
from os import *
|
||||||
|
import subprocess
|
||||||
|
#from nonebot_plugin_maimai_helper.img import *
|
||||||
|
#from time import *
|
||||||
|
|
||||||
|
config = nonebot.get_driver().config
|
||||||
|
TICKET = getattr(config, 'ticket', True)
|
||||||
|
ALLOWGROUP = getattr(config, 'allowgroup', [6324])
|
||||||
|
WHITELIST = getattr(config, 'whitelist', False)
|
||||||
|
USER_IMGPYFILE = 'generate_img.py'
|
||||||
|
|
||||||
|
def check_time() -> bool:
|
||||||
|
|
||||||
|
current_hour = datetime.now().hour
|
||||||
|
if 3 <= current_hour < 7:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def is_ticket_enable() -> bool:
|
||||||
|
return True if TICKET and check_time() else False
|
||||||
|
|
||||||
|
|
||||||
|
#bind_user_id = on_startswith(('SGWCMAID'), ignorecase=False, rule=check_time)
|
||||||
|
bind_user_id = on_command('maibind', aliases={'绑定舞萌','绑定maimaidx','绑定maimai','绑定舞萌id'}, priority=20, rule=check_time)
|
||||||
|
seeme = on_command('seeme', aliases={'看我','kw', '审视党性'}, priority=20, rule=check_time)
|
||||||
|
maihelp = on_command('maihelp', priority=20)
|
||||||
|
g_login = on_command('login', priority=20, rule=check_time)
|
||||||
|
g_logout = on_command('logout', priority=20, rule=check_time)
|
||||||
|
tickets = on_command('ticket',aliases={'查票'}, priority=20, rule=check_time)
|
||||||
|
trick = on_command('舞萌足迹',aliases={'place'}, priority=20, rule=check_time)
|
||||||
|
token_bind = on_command("sybind",aliases={'绑定水鱼'}, priority=20, rule=check_time)
|
||||||
|
gb = on_command("syup",aliases={'更新b50','水鱼更新'}, priority=20, rule=check_time)
|
||||||
|
status = on_command('status',aliases={'华立状态','状态','活着不','活着吗','活着嘛','mai?', 'mai?'}, priority=20, rule=check_time)
|
||||||
|
up_list = on_command('uplist', priority=20, permission=SUPERUSER)
|
||||||
|
user_img = on_command('myimg',aliases={'盒','看看你的'} ,priority=20, rule=check_time)
|
||||||
|
|
||||||
|
'''
|
||||||
|
@user_login_img.handle()
|
||||||
|
async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
user_qq = event.get_user_id()
|
||||||
|
user_id = None
|
||||||
|
if is_userid_exist(user_qq):
|
||||||
|
user_id = get_userid(user_qq)
|
||||||
|
else:
|
||||||
|
await seeme.send("你还没有绑定舞萌账号~\n请先发送「maibind+你的登录二维码识别后字符串」绑定账号吧~")
|
||||||
|
if user_id != -1:
|
||||||
|
data = get_preview(user_id)
|
||||||
|
if data["is_success"]:
|
||||||
|
await user_login_img.send([MessageSegment.reply(event.message_id), MessageSegment.text("盐巴正在整理你的舞萌资料卡~不要重复请求哦~")])
|
||||||
|
user_name = "\""+data['data']['userName']+"\""
|
||||||
|
with os.popen("python F:/main.py --nickname" +" "+ user_name + " " + " --icon " +" "+ str(data['data']['iconId']) +" "+ "--rating" +" "+ str(data['data']['playerRating']) ) as file:
|
||||||
|
for line in file.readlines():
|
||||||
|
logger.info(line.strip())
|
||||||
|
await user_img.send([MessageSegment.reply(event.message_id), MessageSegment.image("file:///F:/img/passport.png")])
|
||||||
|
else:
|
||||||
|
await user_img.send("用户未获取二维码,请获取后再试。")
|
||||||
|
|
||||||
|
'''
|
||||||
|
@bind_user_id.handle()
|
||||||
|
async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
await bind_user_id.send(MessageSegment.text("请直接发送您的登录二维码或发送识别后字符串~"))
|
||||||
|
|
||||||
|
@bind_user_id.receive()
|
||||||
|
async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
user_qq = event.get_user_id()
|
||||||
|
msg = event.get_message()
|
||||||
|
if msg and msg[0].type == "image":
|
||||||
|
image_url = msg[0].data.get("url")
|
||||||
|
logger.info(image_url)
|
||||||
|
image_bytes = download_image(image_url,"F:/img/test.png")
|
||||||
|
# 将字节数据读取为 numpy 数组
|
||||||
|
logger.info(image_bytes)
|
||||||
|
#image_array = np.frombuffer(image_bytes, np.uint8)
|
||||||
|
#logger.info(image_array)
|
||||||
|
|
||||||
|
gray_image = convert_to_grayscale("F:/img/test.png")
|
||||||
|
logger.info(gray_image)
|
||||||
|
qr_code = decode_qr_code(gray_image)
|
||||||
|
|
||||||
|
if not qr_code:
|
||||||
|
logger.warning("没有找到二维码!")
|
||||||
|
await bind_user_id.finish("我好像没有看到二维码呢")
|
||||||
|
|
||||||
|
user_id = None
|
||||||
|
id_result = get_user_id_by_qr(str(qr_code).strip())
|
||||||
|
logger.debug(f'USERID获取结果:{id_result}')
|
||||||
|
errorResult = {
|
||||||
|
1: "ReaderSetupFail(二维码可能已过期)", 2: "二维码可能已过期", 3: "ReaderIncompatible", 4: "DBResolveFail",
|
||||||
|
5: "DBAccessTimeout", 6: "DBAccessFail", 7: "AimeIdInvalid", 8: "NoBoardInfo",
|
||||||
|
9: "LockBanSystemUser", 10: "LockBanSystem", 11: "LockBanUser", 12: "LockBan",
|
||||||
|
13: "LockSystem", 14: "LockUser"
|
||||||
|
}
|
||||||
|
if id_result['errorID'] == 0:
|
||||||
|
user_id = id_result['userID']
|
||||||
|
else:
|
||||||
|
await bind_user_id.finish([MessageSegment.reply(event.message_id), MessageSegment.text(f"查询ID失败:{errorResult[id_result['errorID']]}")])
|
||||||
|
if save_user_id(user_qq, user_id) == 1:
|
||||||
|
await bind_user_id.finish([MessageSegment.reply(event.message_id), MessageSegment.text("绑定成功了喵~")])
|
||||||
|
elif save_user_id(user_qq, user_id) == -1:
|
||||||
|
await bind_user_id.finish([MessageSegment.reply(event.message_id), MessageSegment.text("请先联系机修解绑账号喵~")])
|
||||||
|
elif save_user_id(user_qq, user_id) == -2:
|
||||||
|
await bind_user_id.finish([MessageSegment.reply(event.message_id), MessageSegment.text("绑定发生错误,请联系机修。")])
|
||||||
|
else:
|
||||||
|
await bind_user_id.finish([MessageSegment.reply(event.message_id), MessageSegment.text("绑定未知错误,请联系机修。")])
|
||||||
|
logger.info(qr_code)
|
||||||
|
logger.info(msg)
|
||||||
|
elif msg and msg[0].type == "text" and str(msg).startswith("SGWCMAID") and len(str(msg)) == 84:
|
||||||
|
user_qq = event.get_user_id()
|
||||||
|
user_id = None
|
||||||
|
id_result = get_user_id_by_qr(str(event.message).strip())
|
||||||
|
logger.debug(f'USERID获取结果:{id_result}')
|
||||||
|
errorResult = {
|
||||||
|
1: "ReaderSetupFail(二维码可能已过期)", 2: "二维码可能已过期", 3: "ReaderIncompatible", 4: "DBResolveFail",
|
||||||
|
5: "DBAccessTimeout", 6: "DBAccessFail", 7: "AimeIdInvalid", 8: "NoBoardInfo",
|
||||||
|
9: "LockBanSystemUser", 10: "LockBanSystem", 11: "LockBanUser", 12: "LockBan",
|
||||||
|
13: "LockSystem", 14: "LockUser"
|
||||||
|
}
|
||||||
|
if id_result['errorID'] == 0:
|
||||||
|
user_id = id_result['userID']
|
||||||
|
else:
|
||||||
|
await bind_user_id.finish([MessageSegment.reply(event.message_id), MessageSegment.text(f"查询ID失败:{errorResult[id_result['errorID']]}")])
|
||||||
|
if save_user_id(user_qq, user_id) == 1:
|
||||||
|
await bind_user_id.finish([MessageSegment.reply(event.message_id), MessageSegment.text("绑定成功了喵~")])
|
||||||
|
elif save_user_id(user_qq, user_id) == -1:
|
||||||
|
await bind_user_id.finish([MessageSegment.reply(event.message_id), MessageSegment.text("您已经绑定过了,若需重新绑定请联系机修喵~")])
|
||||||
|
elif save_user_id(user_qq, user_id) == -2:
|
||||||
|
await bind_user_id.finish([MessageSegment.reply(event.message_id), MessageSegment.text("绑定发生错误,请联系机修。")])
|
||||||
|
else:
|
||||||
|
await bind_user_id.finish([MessageSegment.reply(event.message_id), MessageSegment.text("绑定未知错误,请联系机修。")])
|
||||||
|
elif msg and len(str(msg)) == 128:
|
||||||
|
if is_token_exist(user_qq):
|
||||||
|
await token_bind.send([MessageSegment.reply(event.message_id), MessageSegment.text("出错了...请先联系机修解绑Token再试试吧~")])
|
||||||
|
else:
|
||||||
|
if save_user_token(user_qq, msg) == 1:
|
||||||
|
await token_bind.send([MessageSegment.reply(event.message_id), MessageSegment.text("绑定水鱼成功啦~正在尝试撤回Token~若失败请手动撤回!!")])
|
||||||
|
await bot.delete_msg(event.message_id)
|
||||||
|
elif save_user_token(user_qq, msg) == -1:
|
||||||
|
await token_bind.send(
|
||||||
|
[MessageSegment.reply(event.message_id), MessageSegment.text("出错了...请先联系机修解绑Token。\nErr:-1")])
|
||||||
|
elif save_user_token(user_qq, msg) == -2:
|
||||||
|
await token_bind.send(
|
||||||
|
[MessageSegment.reply(event.message_id), MessageSegment.text("出错了...请联系机修。\nErr:-2")])
|
||||||
|
else:
|
||||||
|
await token_bind.send("请发送正确的水鱼Token~")
|
||||||
|
|
||||||
|
|
||||||
|
@user_img.handle()
|
||||||
|
async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
user_qq = event.get_user_id()
|
||||||
|
user_id = None
|
||||||
|
script_path = 'F:/generate_img.py'
|
||||||
|
if is_userid_exist(user_qq):
|
||||||
|
user_id = get_userid(user_qq)
|
||||||
|
else:
|
||||||
|
await seeme.send("你还没有绑定舞萌账号~\n请先发送「maibind+你的登录二维码识别后字符串」绑定账号吧~")
|
||||||
|
if user_id != -1:
|
||||||
|
data = get_preview_detailed(user_id)
|
||||||
|
if data["is_got_qr_code"]:
|
||||||
|
await user_img.send([MessageSegment.reply(event.message_id), MessageSegment.text("盐巴正在开你的盒,请不要重复请求!!!")])
|
||||||
|
chara_level = str(data['data']['charaLevel'])
|
||||||
|
chara_id = str(data['data']['charaId'])
|
||||||
|
chara_id1 = chara_id.replace("[","")
|
||||||
|
chara_id2 = chara_id1.replace("]","")
|
||||||
|
chara_id3 = chara_id2.replace(","," ")
|
||||||
|
chara_id4 = chara_id3.replace(" "," ")
|
||||||
|
chara_level1 = chara_level.replace("[","")
|
||||||
|
chara_level2 = chara_level1.replace("]","")
|
||||||
|
chara_level3 = chara_level2.replace(","," ")
|
||||||
|
chara_level4 = chara_level3.replace(" "," ")
|
||||||
|
# chara_level = re.sub(r'[\[\]\s,]', '', str(data['data']['charaLevel']))
|
||||||
|
# chara_id = re.sub(r'[\[\]\s,]', '', str(data['data']['charaId']))
|
||||||
|
logger.info(chara_id3)
|
||||||
|
logger.info(chara_level3)
|
||||||
|
logger.info(chara_id4)
|
||||||
|
logger.info(chara_level4)
|
||||||
|
logger.info(chara_id3)
|
||||||
|
logger.info(chara_level3)
|
||||||
|
logger.info(chara_id4)
|
||||||
|
logger.info(chara_level4)
|
||||||
|
user_name = "\""+data['data']['userName']+"\""
|
||||||
|
title_name = "\""+data['data']['titleName']+"\""
|
||||||
|
logger.info(data['data']['courseRank'])
|
||||||
|
logger.info(data['data']['classRank'])
|
||||||
|
with os.popen("python F:/generate_img.py --nickname" +" "+ user_name + " --title " +" "+ title_name + " --icon " +" "+ str(data['data']['iconId']) + " --frame " +" "+ str(data['data']['frameId']) + " --plate " +" "+ str(data['data']['plateId']) + " --rating" +" "+ str(data['data']['playerRating']) + " --titleRare" +" "+ str(data['data']['titleRare']) + " --chara" +" "+ str(chara_id4) +" --charaLevel" +" "+str(chara_level4)+" "+"--classRank"+" "+str(data['data']['classRank'])+" "+"--courseRank"+" "+str(data['data']['courseRank']) ) as file:
|
||||||
|
for line in file.readlines():
|
||||||
|
logger.info(line.strip())
|
||||||
|
await user_img.send([MessageSegment.reply(event.message_id), MessageSegment.image("file:///F:/img/output.png")])
|
||||||
|
os.remove("F:/img/output.png")
|
||||||
|
|
||||||
|
else:
|
||||||
|
await user_img.send("用户未获取二维码,请获取后再试。")
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
@bind_user_id.handle()
|
||||||
|
async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
user_qq = event.get_user_id()
|
||||||
|
user_id = None
|
||||||
|
id_result = get_user_id_by_qr(str(event.message)[7:].strip())
|
||||||
|
logger.debug(f'USERID获取结果:{id_result}')
|
||||||
|
errorResult = {
|
||||||
|
1: "ReaderSetupFail(二维码可能已过期)", 2: "二维码可能已过期", 3: "ReaderIncompatible", 4: "DBResolveFail",
|
||||||
|
5: "DBAccessTimeout", 6: "DBAccessFail", 7: "AimeIdInvalid", 8: "NoBoardInfo",
|
||||||
|
9: "LockBanSystemUser", 10: "LockBanSystem", 11: "LockBanUser", 12: "LockBan",
|
||||||
|
13: "LockSystem", 14: "LockUser"
|
||||||
|
}
|
||||||
|
if id_result['errorID'] == 0:
|
||||||
|
user_id = id_result['userID']
|
||||||
|
else:
|
||||||
|
await bind_user_id.finish([MessageSegment.reply(event.message_id), MessageSegment.text(f"查询ID失败:{errorResult[id_result['errorID']]}")])
|
||||||
|
if save_user_id(user_qq, user_id) == 1:
|
||||||
|
await bind_user_id.finish([MessageSegment.reply(event.message_id), MessageSegment.text("绑定成功了喵~")])
|
||||||
|
elif save_user_id(user_qq, user_id) == -1:
|
||||||
|
await bind_user_id.finish([MessageSegment.reply(event.message_id), MessageSegment.text("请先联系机修解绑账号喵~")])
|
||||||
|
elif save_user_id(user_qq, user_id) == -2:
|
||||||
|
await bind_user_id.finish([MessageSegment.reply(event.message_id), MessageSegment.text("绑定发生错误,请联系机修。")])
|
||||||
|
else:
|
||||||
|
await bind_user_id.finish([MessageSegment.reply(event.message_id), MessageSegment.text("绑定未知错误,请联系机修。")])
|
||||||
|
'''
|
||||||
|
@seeme.handle()
|
||||||
|
async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
user_qq = event.get_user_id()
|
||||||
|
user_id = None
|
||||||
|
if is_userid_exist(user_qq):
|
||||||
|
user_id = get_userid(user_qq)
|
||||||
|
else:
|
||||||
|
await seeme.send("你还没有绑定舞萌账号~\n请先发送「maibind+你的登录二维码识别后字符串」绑定账号吧~")
|
||||||
|
if user_id != -1:
|
||||||
|
data = get_preview_detailed(user_id)
|
||||||
|
if data["is_got_qr_code"]:
|
||||||
|
await seeme.send([MessageSegment.reply(event.message_id), MessageSegment.text(
|
||||||
|
f"玩家昵称:\t{data['data']['userName']}\n"
|
||||||
|
f"玩家Rating:\t{data['data']['playerRating']}\n"
|
||||||
|
f"总觉醒数:\t{data['data']['totalAwake']}\n"
|
||||||
|
f"头像:\t{data['data']['iconName']}\n"
|
||||||
|
f"背景板:\t{data['data']['frameName']}\n"
|
||||||
|
f"姓名框:\t{data['data']['plateName']}\n"
|
||||||
|
f"称号:\t{data['data']['titleName']}\n"
|
||||||
|
f"搭档:\t{data['data']['partnerName']}\n"
|
||||||
|
f"最近登录系统号:\t{data['data']['lastRomVersion']}\n"
|
||||||
|
f"最近登录版本号:\t{data['data']['lastDataVersion']}\n"
|
||||||
|
f"上次登陆时间:\t{data['data']['lastLoginDate']}\n"
|
||||||
|
f"最后游玩时间:\t{data['data']['lastPlayDate']}\n"
|
||||||
|
f"玩家注册时间:\t{data['data']['firstPlayDate']}\n"
|
||||||
|
f"游玩次数:\t{data['data']['playCount']}\n"
|
||||||
|
f"当前游玩区域:\t{data['data']['lastSelectCourse']}\n"
|
||||||
|
f"旅行伙伴名称:\t{data['data']['charaName']}\n"
|
||||||
|
f"旅行伙伴等级:\t{data['data']['charaLevel']}\n"
|
||||||
|
f"旅行伙伴觉醒数:\t{data['data']['charaAwakening']}\n"
|
||||||
|
f"banState:\t{data['data']['banState']}"
|
||||||
|
)
|
||||||
|
])
|
||||||
|
else:
|
||||||
|
data1 = get_preview(user_id)
|
||||||
|
if data1['is_success']:
|
||||||
|
await seeme.send([MessageSegment.reply(event.message_id), MessageSegment.text(
|
||||||
|
f"玩家昵称:\t{data1['data']['userName']}\n"
|
||||||
|
f"玩家Rating:\t{data1['data']['playerRating']}\n"
|
||||||
|
f"总觉醒数:\t{data1['data']['totalAwake']}\n"
|
||||||
|
f"头像:\t{data1['data']['iconName']}\n"
|
||||||
|
f"最近登录系统号:\t{data1['data']['lastRomVersion']}\n"
|
||||||
|
f"最近登录版本号:\t{data1['data']['lastDataVersion']}\n"
|
||||||
|
f"上次登陆时间:\t{data1['data']['lastLoginDate']}\n"
|
||||||
|
f"上次游玩时间:\t{data1['data']['lastPlayDate']}\n"
|
||||||
|
f"是否登入:\t{data1['data']['isLogin']}\n"
|
||||||
|
f"banState:\t{data1['data']['banState']}\n"
|
||||||
|
f"在公众号获取二维码后可以查看更多信息哟~"
|
||||||
|
)])
|
||||||
|
else:
|
||||||
|
await seeme.send([MessageSegment.reply(event.message_id), MessageSegment.text("获取失败,请联系机修。")])
|
||||||
|
|
||||||
|
|
||||||
|
@maihelp.handle()
|
||||||
|
async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
await maihelp.send(
|
||||||
|
"maimai插件帮助 - Ver.1.35-E\n"
|
||||||
|
"绑定舞萌账号 - maibind+你的登录二维码识别后字符串~ 例:「maibind SGWCMAID123456114514」\n"
|
||||||
|
"查询舞萌账号 - 发送「看我」~\n"
|
||||||
|
"发2/3/5/6倍券 - 发送「发券2/3/5/6」~\n"
|
||||||
|
"(发券7 可发送中二·舞萌联合2倍券,是发券,不是发卷,来跟我读 quàn)\n"
|
||||||
|
"查询账户内剩余功能票 - 发送「ticket」~\n"
|
||||||
|
"登入账号 - 发送「login + 时间戳(必选项)」\n"
|
||||||
|
"登出账号 - 发送「logout + 时间戳(必选项)」\n"
|
||||||
|
"游玩足迹 - 发送「舞萌足迹」\n"
|
||||||
|
"绑定水鱼查分器 - 发送「sybind+水鱼查分器Token」\n"
|
||||||
|
"更新b50 - 发送「syup」或「更新b50」;「水鱼更新」\n"
|
||||||
|
"检测服务器状态 - 发送「status」或「活着不」;「mai?」\n"
|
||||||
|
"更新水鱼乐曲列表 - 发送'uplist'(仅限机修)\n"
|
||||||
|
"请勿在凌晨三点至早上七点内使用SaltBot!!\n"
|
||||||
|
"由于华立近期严查发票,请勿频繁使用发票功能!!"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
ticket = on_regex(r"发券(\d+)", priority=20, rule=is_ticket_enable)
|
||||||
|
@ticket.handle()
|
||||||
|
async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
OPEN = False
|
||||||
|
if WHITELIST:
|
||||||
|
if event.group_id in ALLOWGROUP:
|
||||||
|
OPEN = True
|
||||||
|
else:
|
||||||
|
OPEN = True
|
||||||
|
if OPEN:
|
||||||
|
regex = r"发券(\d+)"
|
||||||
|
user_qq = event.get_user_id()
|
||||||
|
user_id = None
|
||||||
|
ticket_id = None
|
||||||
|
match = re.search(regex, str(event.get_message()))
|
||||||
|
if match:
|
||||||
|
try:
|
||||||
|
ticket_id = int(match.group(1))
|
||||||
|
except ValueError:
|
||||||
|
await ticket.send(
|
||||||
|
[MessageSegment.reply(event.message_id), MessageSegment.text("现在还不支持这种券...换一张试试吧~")])
|
||||||
|
raise ValueError("匹配的不是有效的数字...检查后再试吧~")
|
||||||
|
else:
|
||||||
|
await ticket.send([MessageSegment.reply(event.message_id), MessageSegment.text("你想发什么券呢?")])
|
||||||
|
return
|
||||||
|
if is_userid_exist(user_qq):
|
||||||
|
# 判断是否存在userid
|
||||||
|
user_id = get_userid(user_qq)
|
||||||
|
else:
|
||||||
|
await ticket.send([MessageSegment.reply(event.message_id), MessageSegment.text("你还没有绑定舞萌账号~\n请先发送「maibind+你的登录二维码识别后字符串」绑定账号吧~")])
|
||||||
|
return
|
||||||
|
if ticket_id == 2:
|
||||||
|
result = send_ticket(user_id, 2)
|
||||||
|
if result["is_success"]:
|
||||||
|
await ticket.send([MessageSegment.reply(event.message_id), MessageSegment.text("成功发送了一张跑图2倍+旅行伙伴2倍+紫谱解禁一张~\n最近华立严查发券,请勿频繁使用发票功能!!")])
|
||||||
|
else:
|
||||||
|
await ticket.send(
|
||||||
|
[MessageSegment.reply(event.message_id), MessageSegment.text(f"失败了...{result['msg_body']}")])
|
||||||
|
return
|
||||||
|
elif ticket_id == 3:
|
||||||
|
result = send_ticket(user_id, 3)
|
||||||
|
if result["is_success"]:
|
||||||
|
await ticket.send([MessageSegment.reply(event.message_id), MessageSegment.text("成功发送了一张跑图3倍+旅行伙伴3倍+紫谱解禁一张~\n最近华立严查发券,请勿频繁使用发票功能!!")])
|
||||||
|
else:
|
||||||
|
await ticket.send(
|
||||||
|
[MessageSegment.reply(event.message_id), MessageSegment.text(f"失败了...{result['msg_body']}")])
|
||||||
|
return
|
||||||
|
elif ticket_id == 5:
|
||||||
|
result = send_ticket(user_id, 5)
|
||||||
|
if result["is_success"]:
|
||||||
|
await ticket.send([MessageSegment.reply(event.message_id), MessageSegment.text("成功发送了一张跑图5倍+旅行伙伴5倍+紫谱解禁一张~\n最近华立严查发券,请勿频繁使用发票功能!!")])
|
||||||
|
else:
|
||||||
|
await ticket.send(
|
||||||
|
[MessageSegment.reply(event.message_id), MessageSegment.text(f"失败了...{result['msg_body']}")])
|
||||||
|
return
|
||||||
|
elif ticket_id == 6:
|
||||||
|
result = send_ticket(user_id, 6)
|
||||||
|
if result["is_success"]:
|
||||||
|
await ticket.send([MessageSegment.reply(event.message_id), MessageSegment.text("成功发送了一张跑图6倍+旅行伙伴6倍+紫谱解禁一张~\n最近华立严查发券,请勿频繁使用发票功能!!")])
|
||||||
|
else:
|
||||||
|
await ticket.send(
|
||||||
|
[MessageSegment.reply(event.message_id), MessageSegment.text(f"失败了...{result['msg_body']}")])
|
||||||
|
return
|
||||||
|
elif ticket_id == 7:
|
||||||
|
result = send_ticket(user_id, 20020)
|
||||||
|
if result["is_success"]:
|
||||||
|
await ticket.send([MessageSegment.reply(event.message_id), MessageSegment.text("成功发送了一张跑图2倍+中二节奏2倍券~\n最近华立严查发券,请勿频繁使用发票功能!!")])
|
||||||
|
else:
|
||||||
|
await ticket.send(
|
||||||
|
[MessageSegment.reply(event.message_id), MessageSegment.text(f"失败了...{result['msg_body']}")])
|
||||||
|
else:
|
||||||
|
await ticket.send([MessageSegment.reply(event.message_id), MessageSegment.text("你想发什么券呢?")])
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
await ticket.send([MessageSegment.reply(event.message_id), MessageSegment.text("本群暂无权限,请联系机修授权。")])
|
||||||
|
|
||||||
|
|
||||||
|
@g_login.handle()
|
||||||
|
async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
user_qq = event.get_user_id()
|
||||||
|
time = str(event.message)[5:].strip()
|
||||||
|
if is_userid_exist(user_qq):
|
||||||
|
user_id = get_userid(user_qq)
|
||||||
|
result = login(user_id, time)
|
||||||
|
if result["data"]:
|
||||||
|
if result["data"]["returnCode"] == 1:
|
||||||
|
await g_login.send([MessageSegment.reply(event.message_id), MessageSegment.text("登入成功啦!")])
|
||||||
|
else:
|
||||||
|
await g_login.send([MessageSegment.reply(event.message_id), MessageSegment.text(f"登入失败了...\nErr: {result['msg_body']}")])
|
||||||
|
else:
|
||||||
|
await g_login.send([MessageSegment.reply(event.message_id), MessageSegment.text(f"登入失败了...\nErr: {result['msg_body']}")])
|
||||||
|
else:
|
||||||
|
await g_login.send([MessageSegment.reply(event.message_id), MessageSegment.text("你还没有绑定舞萌账号~\n请先发送「maibind+你的登录二维码识别后字符串」绑定账号吧~")])
|
||||||
|
|
||||||
|
|
||||||
|
@g_logout.handle()
|
||||||
|
async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
user_qq = event.get_user_id()
|
||||||
|
time = str(event.message)[6:].strip()
|
||||||
|
if is_userid_exist(user_qq):
|
||||||
|
user_id = get_userid(user_qq)
|
||||||
|
result = logout(user_id, time)
|
||||||
|
if result["data"]:
|
||||||
|
if result["data"]["returnCode"] == 1:
|
||||||
|
await g_logout.send([MessageSegment.reply(event.message_id), MessageSegment.text("登出成功啦~")])
|
||||||
|
else:
|
||||||
|
await g_logout.send([MessageSegment.reply(event.message_id), MessageSegment.text(f"登出失败了...\nErr: {result['msg_body']}")])
|
||||||
|
else:
|
||||||
|
await g_logout.send([MessageSegment.reply(event.message_id), MessageSegment.text(f"登出失败了...\nErr: {result['msg_body']}")])
|
||||||
|
else:
|
||||||
|
await g_logout.send([MessageSegment.reply(event.message_id), MessageSegment.text("你还没有绑定舞萌账号~\n请先发送「maibind+你的登录二维码识别后字符串」绑定账号吧~")])
|
||||||
|
|
||||||
|
|
||||||
|
@tickets.handle()
|
||||||
|
async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
user_qq = event.get_user_id()
|
||||||
|
if is_userid_exist(user_qq):
|
||||||
|
user_id = get_userid(user_qq)
|
||||||
|
result = query_ticket(user_id)
|
||||||
|
ticketlist = [MessageSegment.reply(event.message_id),]
|
||||||
|
for ticket in result['data']['userChargeList']:
|
||||||
|
if ticket['chargeId'] == 2:
|
||||||
|
ticketlist.append(MessageSegment.text(f"倍券ID: 2 | 当前持有 {ticket['stock']} 张\n"))
|
||||||
|
elif ticket['chargeId'] == 3:
|
||||||
|
ticketlist.append(MessageSegment.text(f"倍券ID: 3 | 当前持有 {ticket['stock']} 张\n"))
|
||||||
|
elif ticket['chargeId'] == 5:
|
||||||
|
ticketlist.append(MessageSegment.text(f"倍券ID: 5 | 当前持有 {ticket['stock']} 张\n"))
|
||||||
|
elif ticket['chargeId'] == 6:
|
||||||
|
ticketlist.append(MessageSegment.text(f"倍券ID: 6 | 当前持有 {ticket['stock']} 张\n"))
|
||||||
|
elif ticket['chargeId'] == 20020:
|
||||||
|
ticketlist.append(MessageSegment.text(f"倍券ID: 7 | 当前持有 {ticket['stock']} 张"))
|
||||||
|
await tickets.send(ticketlist)
|
||||||
|
else:
|
||||||
|
await tickets.send([MessageSegment.reply(event.message_id), MessageSegment.text("你还没有绑定舞萌账号~\n请先发送「maibind+你的登录二维码识别后字符串」绑定账号吧~")])
|
||||||
|
|
||||||
|
|
||||||
|
@trick.handle()
|
||||||
|
async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
user_qq = event.get_user_id()
|
||||||
|
if is_userid_exist(user_qq):
|
||||||
|
user_id = get_userid(user_qq)
|
||||||
|
USERID = True
|
||||||
|
else:
|
||||||
|
USERID = False
|
||||||
|
await trick.send('你还没有绑定舞萌账号~\n请先发送「maibind+你的登录二维码识别后字符串」绑定账号吧~')
|
||||||
|
if USERID:
|
||||||
|
tricklist = [MessageSegment.reply(event.message_id),MessageSegment.text('数据以机台注册地为准!\n出现了你没有去过的地方就代表你玩的机台被搬运过~\n你曾经在以下地方游玩过舞萌DX:\n=======\n'),]
|
||||||
|
data = get_user_region(user_id)['data']['userRegionList']
|
||||||
|
for test in data:
|
||||||
|
tricklist.append(
|
||||||
|
MessageSegment.text(
|
||||||
|
|
||||||
|
f"- [ {test['regionName']} ] 共勤 {test['playCount']} 次\n"
|
||||||
|
f"- 首次游玩日期: {test['created']}\n"
|
||||||
|
f"=======\n"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await trick.send(tricklist)
|
||||||
|
|
||||||
|
|
||||||
|
@token_bind.handle()
|
||||||
|
async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
token = str(event.message)[6:].strip()
|
||||||
|
user_qq = event.get_user_id()
|
||||||
|
if token and len(token) == 128:
|
||||||
|
if is_token_exist(user_qq):
|
||||||
|
await token_bind.send([MessageSegment.reply(event.message_id), MessageSegment.text("出错了...请先联系机修解绑Token再试试吧~")])
|
||||||
|
else:
|
||||||
|
if save_user_token(user_qq, token) == 1:
|
||||||
|
await token_bind.send([MessageSegment.reply(event.message_id), MessageSegment.text("绑定水鱼成功啦~正在尝试撤回Token~若失败请手动撤回!!")])
|
||||||
|
await bot.delete_msg(event.message_id)
|
||||||
|
elif save_user_token(user_qq, token) == -1:
|
||||||
|
await token_bind.send(
|
||||||
|
[MessageSegment.reply(event.message_id), MessageSegment.text("出错了...请先联系机修解绑Token。\nErr:-1")])
|
||||||
|
elif save_user_token(user_qq, token) == -2:
|
||||||
|
await token_bind.send(
|
||||||
|
[MessageSegment.reply(event.message_id), MessageSegment.text("出错了...请联系机修。\nErr:-2")])
|
||||||
|
else:
|
||||||
|
await token_bind.send("请发送正确的水鱼Token~")
|
||||||
|
#12
|
||||||
|
|
||||||
|
@gb.handle()
|
||||||
|
async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
user_qq = event.get_user_id()
|
||||||
|
if not is_token_exist(user_qq):
|
||||||
|
await gb.send([MessageSegment.reply(event.message_id), MessageSegment.text("你还没有绑定水鱼查分器成绩导入Token~\n请先发送「sybind+Token」绑定Token吧~")])
|
||||||
|
else:
|
||||||
|
if not is_userid_exist(user_qq):
|
||||||
|
await gb.send([MessageSegment.reply(event.message_id), MessageSegment.text("你还没有绑定舞萌账号~\n请先发送「maibind+你的登录二维码识别后字符串」绑定账号吧~")])
|
||||||
|
else:
|
||||||
|
await gb.send([MessageSegment.reply(event.message_id), MessageSegment.text("正在更新你的b50,请耐心等待,不要重复请求哦~")])
|
||||||
|
token = get_token(user_qq)
|
||||||
|
user_id = get_userid(user_qq)
|
||||||
|
old_data = get_user_music(user_id)
|
||||||
|
if not old_data['is_success']:
|
||||||
|
await gb.finish([MessageSegment.reply(event.message_id), MessageSegment.text(f"更新失败了...{old_data['msg_body']}")])
|
||||||
|
else:
|
||||||
|
old_data = old_data['data']['userMusicDetailList']
|
||||||
|
try:
|
||||||
|
print(-1)
|
||||||
|
new_data, n = change_data(old_data)
|
||||||
|
print(0)
|
||||||
|
result = send_user_data(new_data, token)
|
||||||
|
print(1)
|
||||||
|
if result['status'] == 200:
|
||||||
|
await gb.send([MessageSegment.reply(event.message_id), MessageSegment.text(f"更新成功啦!发送了{n}首歌曲,可以直接发送「b50」查询你的b50哦~")])
|
||||||
|
else:
|
||||||
|
await gb.send([MessageSegment.reply(event.message_id), MessageSegment.text(f"更新失败了...请联系机修查看错误信息。\nErr: {result['msg']}")])
|
||||||
|
except Exception as e:
|
||||||
|
await gb.send([MessageSegment.reply(event.message_id), MessageSegment.text(f"更新失败了...请联系机修查看错误信息。\nErr: {e}")])
|
||||||
|
|
||||||
|
|
||||||
|
@up_list.handle()
|
||||||
|
async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
try:
|
||||||
|
update_music_list()
|
||||||
|
await up_list.send([MessageSegment.reply(event.message_id), MessageSegment.text("更新成功啦!")])
|
||||||
|
except Exception as e:
|
||||||
|
await up_list.send([MessageSegment.reply(event.message_id), MessageSegment.text(f"更新失败了...\nErr: {e}")])
|
||||||
|
|
||||||
|
@status.handle()
|
||||||
|
async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
result = {'title': '坏...', 'chime': '坏...', 'all_net': '坏...',}#'allnet_delay':'???','chime_delay':'???','title_delay':'???'}
|
||||||
|
title = title_ping()
|
||||||
|
chime = chime_ping()
|
||||||
|
all_net = all_net_ping()
|
||||||
|
if title['is_success']:
|
||||||
|
result['title'] = '好!'
|
||||||
|
# result['title_delay'] = title['delay']
|
||||||
|
if chime['is_success']:
|
||||||
|
result['chime'] = '好!'
|
||||||
|
# result['chime_delay'] = chime['delay']
|
||||||
|
if all_net['is_success']:
|
||||||
|
result['all_net'] = '好!'
|
||||||
|
# result['allnet_delay'] = all_net['delay']
|
||||||
|
await status.send([MessageSegment.reply(event.message_id), MessageSegment.text(
|
||||||
|
f"[Title/标题服务器]:\t{result['title']}\n"
|
||||||
|
f"[Chime/会员服务器]:\t{result['chime']}\n"
|
||||||
|
f"[ALL.Net状态]: \t{result['all_net']}\n"
|
||||||
|
f"[机厅的网络状态]: 不知道\n"
|
||||||
|
f"[你家的网络状态]: 不知道\n"
|
||||||
|
f"[机厅网络运营商状态]:不知道\n"
|
||||||
|
f"[你家网络运营商状态]:不知道"
|
||||||
|
)])
|
||||||
|
|
||||||
|
|
||||||
|
#@runhw.handle()
|
||||||
|
#async def _(event: GroupMessageEvent, message: Message = EventMessage()):
|
||||||
|
# user_qq = event.get_user_id()
|
||||||
|
# if is_userid_exist(user_qq):
|
||||||
|
# for i in range(time):
|
||||||
Binary file not shown.
BIN
nonebot_plugin_maimai_helper/__pycache__/data.cpython-312.pyc
Normal file
BIN
nonebot_plugin_maimai_helper/__pycache__/data.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
203
nonebot_plugin_maimai_helper/data.py
Normal file
203
nonebot_plugin_maimai_helper/data.py
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
from nonebot_plugin_maimai_helper.manager.usage_count import NetworkCount
|
||||||
|
|
||||||
|
|
||||||
|
root_path = os.path.dirname(__file__)
|
||||||
|
network_count = NetworkCount()
|
||||||
|
|
||||||
|
|
||||||
|
start_time = datetime.now()
|
||||||
|
|
||||||
|
# constants
|
||||||
|
ticket_define = {
|
||||||
|
2:{
|
||||||
|
"id": 2,
|
||||||
|
"cost": 1
|
||||||
|
},
|
||||||
|
3:{
|
||||||
|
"id": 3,
|
||||||
|
"cost": 2
|
||||||
|
},
|
||||||
|
4:{
|
||||||
|
"id": 4,
|
||||||
|
"cost": 3
|
||||||
|
},
|
||||||
|
5:{
|
||||||
|
"id": 5,
|
||||||
|
"cost": 4
|
||||||
|
},
|
||||||
|
6:{
|
||||||
|
"id": 6,
|
||||||
|
"cost": 5
|
||||||
|
},
|
||||||
|
20020:{
|
||||||
|
"id": 20020,
|
||||||
|
"cost": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
region_map = (
|
||||||
|
"北京市",
|
||||||
|
"重庆市",
|
||||||
|
"上海市",
|
||||||
|
"天津市",
|
||||||
|
"安徽省",
|
||||||
|
"福建省",
|
||||||
|
"甘肃省",
|
||||||
|
"广东省",
|
||||||
|
"贵州省",
|
||||||
|
"海南省",
|
||||||
|
"河北省",
|
||||||
|
"黑龙江省",
|
||||||
|
"河南省",
|
||||||
|
"湖北省",
|
||||||
|
"湖南省",
|
||||||
|
"江苏省",
|
||||||
|
"江西省",
|
||||||
|
"吉林省",
|
||||||
|
"辽宁省",
|
||||||
|
"青海省",
|
||||||
|
"陕西省",
|
||||||
|
"山东省",
|
||||||
|
"山西省",
|
||||||
|
"四川省",
|
||||||
|
"台湾省",
|
||||||
|
"云南省",
|
||||||
|
"浙江省",
|
||||||
|
"广西壮族自治区",
|
||||||
|
"内蒙古自治区",
|
||||||
|
"宁夏回族自治区",
|
||||||
|
"新疆维吾尔自治区",
|
||||||
|
"西藏自治区"
|
||||||
|
)
|
||||||
|
|
||||||
|
mai_genres = [
|
||||||
|
{
|
||||||
|
"id": 101,
|
||||||
|
"title": "流行&动漫",
|
||||||
|
"genre": "POPSアニメ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 102,
|
||||||
|
"title": "niconico&VOCALOID™",
|
||||||
|
"genre": "niconicoボーカロイド"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 103,
|
||||||
|
"title": "东方Project",
|
||||||
|
"genre": "東方Project"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 104,
|
||||||
|
"title": "其他游戏",
|
||||||
|
"genre": "ゲームバラエティ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 105,
|
||||||
|
"title": "舞萌",
|
||||||
|
"genre": "maimai"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 106,
|
||||||
|
"title": "音击/中二节奏",
|
||||||
|
"genre": "オンゲキCHUNITHM"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 107,
|
||||||
|
"title": "宴会場",
|
||||||
|
"genre": "宴会場"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
mai_versions = [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"title": "maimai",
|
||||||
|
"version": 10000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"title": "maimai PLUS",
|
||||||
|
"version": 11000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"title": "GreeN",
|
||||||
|
"version": 12000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"title": "GreeN PLUS",
|
||||||
|
"version": 13000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"title": "ORANGE",
|
||||||
|
"version": 14000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"title": "ORANGE PLUS",
|
||||||
|
"version": 15000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"title": "PiNK",
|
||||||
|
"version": 16000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"title": "PiNK PLUS",
|
||||||
|
"version": 17000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 8,
|
||||||
|
"title": "MURASAKi",
|
||||||
|
"version": 18000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 9,
|
||||||
|
"title": "MURASAKi PLUS",
|
||||||
|
"version": 18500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 10,
|
||||||
|
"title": "MiLK",
|
||||||
|
"version": 19000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 11,
|
||||||
|
"title": "MiLK PLUS",
|
||||||
|
"version": 19500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 12,
|
||||||
|
"title": "FiNALE",
|
||||||
|
"version": 19900
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 13,
|
||||||
|
"title": "舞萌DX",
|
||||||
|
"version": 20000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 15,
|
||||||
|
"title": "舞萌DX 2021",
|
||||||
|
"version": 21000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 17,
|
||||||
|
"title": "舞萌DX 2022",
|
||||||
|
"version": 22000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 19,
|
||||||
|
"title": "舞萌DX 2023",
|
||||||
|
"version": 23000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 21,
|
||||||
|
"title": "舞萌DX 2024",
|
||||||
|
"version": 24000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
716
nonebot_plugin_maimai_helper/game_data/chara_list.json
Normal file
716
nonebot_plugin_maimai_helper/game_data/chara_list.json
Normal file
@@ -0,0 +1,716 @@
|
|||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"101": "でらっくま",
|
||||||
|
"102": "いえてぃっくま",
|
||||||
|
"103": "りすっくま",
|
||||||
|
"104": "ぱんだっくま",
|
||||||
|
"105": "みつよしっくま",
|
||||||
|
"301": "ラズ",
|
||||||
|
"201": "水野舞衣",
|
||||||
|
"202": "青沼優",
|
||||||
|
"203": "葵巴",
|
||||||
|
"204": "花田美空",
|
||||||
|
"205": "浅葱光一",
|
||||||
|
"302": "ソルト",
|
||||||
|
"303": "シフォン",
|
||||||
|
"304": "乙姫",
|
||||||
|
"305": "しゃま",
|
||||||
|
"306": "みるく",
|
||||||
|
"392": "たぬっくま",
|
||||||
|
"393": "ひげっくま",
|
||||||
|
"394": "おねむっくま",
|
||||||
|
"395": "めがねっくま",
|
||||||
|
"401": "SAM_RAI",
|
||||||
|
"402": "BEN_KEI",
|
||||||
|
"403": "SIN_BA",
|
||||||
|
"404": "TO_KI",
|
||||||
|
"405": "黒姫",
|
||||||
|
"501": "バハムート",
|
||||||
|
"502": "ニーズヘッグ",
|
||||||
|
"503": "ファフニール",
|
||||||
|
"504": "ラタトスク",
|
||||||
|
"505": "フレーズベルグ",
|
||||||
|
"601": "百合咲ミカ",
|
||||||
|
"602": "白銅寺アズリ",
|
||||||
|
"603": "兎花宮イオフィ",
|
||||||
|
"604": "白王院ラグ",
|
||||||
|
"605": "兎花宮サラ",
|
||||||
|
"701": "アウル",
|
||||||
|
"702": "リッツ",
|
||||||
|
"703": "ニック",
|
||||||
|
"704": "エリー",
|
||||||
|
"705": "ヒュド・ルー",
|
||||||
|
"706": "クレメンス",
|
||||||
|
"707": "ラルフ",
|
||||||
|
"708": "バイロン",
|
||||||
|
"709": "マスティマ",
|
||||||
|
"3301": "紲星あかり",
|
||||||
|
"3302": "結月ゆかり",
|
||||||
|
"3303": "弦巻マキ",
|
||||||
|
"3304": "琴葉 茜",
|
||||||
|
"3305": "琴葉 葵",
|
||||||
|
"3306": "GYARI",
|
||||||
|
"3501": "初音ミク",
|
||||||
|
"3505": "巡音ルカ",
|
||||||
|
"3506": "鏡音リン",
|
||||||
|
"3507": "鏡音レン",
|
||||||
|
"3509": "KAITO",
|
||||||
|
"3508": "MEIKO",
|
||||||
|
"3502": "初音ミクV3",
|
||||||
|
"3503": "エトワール",
|
||||||
|
"3504": "天袖",
|
||||||
|
"3901": "からめる/ねこ/ラーメン",
|
||||||
|
"3902": "からめる/ねこ/DJ",
|
||||||
|
"3903": "からめる/人/まいった",
|
||||||
|
"3904": "からめる/人/刺身",
|
||||||
|
"3905": "からめる/レース",
|
||||||
|
"3401": "博麗霊夢",
|
||||||
|
"3402": "霧雨魔理沙",
|
||||||
|
"3403": "十六夜咲夜",
|
||||||
|
"3404": "レミリア・スカーレット",
|
||||||
|
"3405": "フランドール・スカーレット",
|
||||||
|
"3406": "魂魄妖夢",
|
||||||
|
"3407": "八雲紫",
|
||||||
|
"3408": "鈴仙・優曇華院・イナバ",
|
||||||
|
"3409": "蓬莱山輝夜",
|
||||||
|
"3410": "藤原妹紅",
|
||||||
|
"4001": "明坂 芹菜",
|
||||||
|
"4002": "御形 アリシアナ",
|
||||||
|
"4003": "天王洲 なずな",
|
||||||
|
"4004": "小仏 凪",
|
||||||
|
"4005": "箱部 なる",
|
||||||
|
"4006": "月鈴 那知",
|
||||||
|
"4007": "月鈴 白奈",
|
||||||
|
"4008": "五十嵐 撫子",
|
||||||
|
"4009": "萩原 七々瀬",
|
||||||
|
"4201": "結月ゆかり/幾望の月",
|
||||||
|
"4202": "結月ゆかり/フリィダム ロリィタ",
|
||||||
|
"4203": "結月ゆかり/チュルリラ・チュルリラ・ダッダッダ!",
|
||||||
|
"4204": "結月ゆかり/幸せになれる隠しコマンドがあるらしい",
|
||||||
|
"4205": "結月ゆかり/サヨナラチェーンソー",
|
||||||
|
"50101": "あおはるっくま",
|
||||||
|
"50102": "にんじゃっくま",
|
||||||
|
"50103": "どらごっくま",
|
||||||
|
"50104": "えんじぇっくま",
|
||||||
|
"50105": "くろばらっくま",
|
||||||
|
"50201": "ピリポ",
|
||||||
|
"50202": "ケファ",
|
||||||
|
"50203": "バルトルメ",
|
||||||
|
"50204": "アンドレアス",
|
||||||
|
"50205": "イーシュ",
|
||||||
|
"50401": "萌木ゆずか",
|
||||||
|
"50402": "萌木ほのか",
|
||||||
|
"50403": "萌木はるか",
|
||||||
|
"50404": "萌木いよか",
|
||||||
|
"50405": "萌木せとか",
|
||||||
|
"50601": "ブリュンヒルデ",
|
||||||
|
"50602": "ジグニュー",
|
||||||
|
"50603": "ジークルーネ",
|
||||||
|
"50604": "グリムゲルデ",
|
||||||
|
"50605": "シュヴェルトライテ",
|
||||||
|
"50606": "ヴァルトラウテ",
|
||||||
|
"50607": "オーディン",
|
||||||
|
"50701": "maimaiちゃん",
|
||||||
|
"50702": "はっぴー",
|
||||||
|
"50703": "カメ",
|
||||||
|
"50704": "タイ",
|
||||||
|
"50705": "エリザビー",
|
||||||
|
"50801": "ルイ",
|
||||||
|
"50802": "ニック(悪魔憑き)",
|
||||||
|
"50803": "ティノ",
|
||||||
|
"50804": "エレノラ",
|
||||||
|
"53301": "星咲 あかり",
|
||||||
|
"53302": "藤沢 柚子",
|
||||||
|
"53303": "三角 葵",
|
||||||
|
"53304": "日向 千夏",
|
||||||
|
"53305": "藍原 椿",
|
||||||
|
"53306": "九條 楓",
|
||||||
|
"53401": "グスタフ ハイドリヒ",
|
||||||
|
"53402": "マリア=S=レオンブルク",
|
||||||
|
"53403": "ヴィーナス ポロロッチョ",
|
||||||
|
"53404": "メグメグ",
|
||||||
|
"53405": "Voidoll",
|
||||||
|
"53406": "リリカ",
|
||||||
|
"53407": "ルチアーノ",
|
||||||
|
"53408": "双挽 乃保",
|
||||||
|
"53409": "桜華 忠臣",
|
||||||
|
"53601": "カク",
|
||||||
|
"53602": "イムラ",
|
||||||
|
"53603": "ミツイ",
|
||||||
|
"53604": "クロヌマ",
|
||||||
|
"53605": "ツチダ",
|
||||||
|
"53701": "DIVA 初音ミク/スクール",
|
||||||
|
"53702": "DIVA 初音ミク/マジシャン",
|
||||||
|
"53703": "DIVA 初音ミク/リボンガール",
|
||||||
|
"53704": "DIVA 初音ミク/クリスマス",
|
||||||
|
"53705": "DIVA 初音ミク/∞",
|
||||||
|
"53901": "霧雨魔理沙",
|
||||||
|
"53902": "鈴仙優曇華院イナバ",
|
||||||
|
"53903": "洩矢諏訪子",
|
||||||
|
"53904": "藤原妹紅",
|
||||||
|
"53905": "火焔猫燐",
|
||||||
|
"100101": "らいむっくま",
|
||||||
|
"100102": "れもんっくま",
|
||||||
|
"100103": "でらっくま",
|
||||||
|
"100104": "らん",
|
||||||
|
"100105": "どりー",
|
||||||
|
"100301": "壱王",
|
||||||
|
"100302": "仁王",
|
||||||
|
"100303": "雷天",
|
||||||
|
"100304": "焔天",
|
||||||
|
"100305": "黒姫",
|
||||||
|
"100401": "モモ",
|
||||||
|
"100402": "アカツキ",
|
||||||
|
"100403": "ナノハ",
|
||||||
|
"100404": "ソウ",
|
||||||
|
"100405": "ノア",
|
||||||
|
"100501": "百合咲ミカ",
|
||||||
|
"100502": "八剱月アルマ",
|
||||||
|
"100503": "白銅寺アズリ",
|
||||||
|
"100504": "白法院ラグ",
|
||||||
|
"100505": "八剱月アルマ(堕天)",
|
||||||
|
"100601": "ロー",
|
||||||
|
"100602": "マリー",
|
||||||
|
"100603": "ハンナ",
|
||||||
|
"100604": "トリスタン",
|
||||||
|
"100605": "クレメンス(悪魔)",
|
||||||
|
"105301": "アンドロメダ子",
|
||||||
|
"105302": "アンドロメダ男",
|
||||||
|
"105303": "チビキャラA",
|
||||||
|
"105304": "チビキャラB",
|
||||||
|
"105305": "チビキャラC",
|
||||||
|
"105306": "チビキャラD",
|
||||||
|
"105401": "琴葉 葵 チョコミント(Ice!)",
|
||||||
|
"105402": "琴葉 葵 チョコミント(慈悲)",
|
||||||
|
"105403": "琴葉 茜 チョコミント(?)",
|
||||||
|
"105404": "琴葉 茜 チョコミント(おかわりや)",
|
||||||
|
"105405": "チョコミン党",
|
||||||
|
"105501": "アリス・マーガトロイド",
|
||||||
|
"105502": "霧雨魔理沙",
|
||||||
|
"105503": "チルノ",
|
||||||
|
"105504": "博麗霊夢",
|
||||||
|
"105505": "射命丸文",
|
||||||
|
"105601": "光/サマー",
|
||||||
|
"105602": "対立/サマー",
|
||||||
|
"105603": "サヤ",
|
||||||
|
"105604": "叶永",
|
||||||
|
"105605": "エト",
|
||||||
|
"105606": "ルナ",
|
||||||
|
"105607": "紅",
|
||||||
|
"105608": "レーテー",
|
||||||
|
"105701": "v flower/ベノム",
|
||||||
|
"105702": "GUMI/マネマネサイコトロピック",
|
||||||
|
"105703": "魔法少女リリカ/アルカリレットウセイ",
|
||||||
|
"105704": "かいりきベア",
|
||||||
|
"105705": "宍戸 美鈴",
|
||||||
|
"105901": "える",
|
||||||
|
"105902": "シスター・クレア",
|
||||||
|
"105903": "ジョー・力一",
|
||||||
|
"105904": "ドーラ",
|
||||||
|
"105905": "月ノ美兎",
|
||||||
|
"105906": "剣持刀也",
|
||||||
|
"105907": "森中花咲",
|
||||||
|
"105908": "静凛",
|
||||||
|
"105909": "鷹宮リオン",
|
||||||
|
"105910": "樋口楓",
|
||||||
|
"105911": "本間ひまわり",
|
||||||
|
"105912": "緑仙",
|
||||||
|
"106001": "踊っているくまのイラスト",
|
||||||
|
"106002": "踊っているいぬのイラスト",
|
||||||
|
"106003": "踊っているねこのイラスト",
|
||||||
|
"106004": "踊っているうさぎのイラスト",
|
||||||
|
"106005": "元気な男性のイラスト",
|
||||||
|
"106006": "元気な女性のイラスト",
|
||||||
|
"106007": "ドラム式洗濯機のイラスト",
|
||||||
|
"106008": "コウテイペンギンのイラスト",
|
||||||
|
"106009": "コウテイペンギンのヒナのイラスト",
|
||||||
|
"106010": "バナナボートに乗る人たちのイラスト",
|
||||||
|
"106101": "柏木 美亜",
|
||||||
|
"106102": "東雲 つむぎ",
|
||||||
|
"106103": "高瀬 梨緒",
|
||||||
|
"106104": "逢坂 茜",
|
||||||
|
"106105": "珠洲島 有栖",
|
||||||
|
"150101": "乙姫",
|
||||||
|
"150102": "ラズ",
|
||||||
|
"150103": "シフォン",
|
||||||
|
"150104": "ソルト",
|
||||||
|
"150105": "しゃま",
|
||||||
|
"150106": "みるく",
|
||||||
|
"150201": "アウル(幼少期)",
|
||||||
|
"150202": "トリスタン",
|
||||||
|
"150203": "アウル",
|
||||||
|
"150301": "モモ",
|
||||||
|
"150302": "トキヤ",
|
||||||
|
"150303": "コハク",
|
||||||
|
"150304": "ノア",
|
||||||
|
"150305": "アカツキ",
|
||||||
|
"150401": "ナノ",
|
||||||
|
"150402": "アサド",
|
||||||
|
"150403": "ローヴェ",
|
||||||
|
"150404": "ドメニカ",
|
||||||
|
"150405": "テルス",
|
||||||
|
"150501": "ニギ",
|
||||||
|
"150502": "シンキョウ",
|
||||||
|
"150503": "メノウ",
|
||||||
|
"150504": "アマヒコ",
|
||||||
|
"150505": "オオヒメ",
|
||||||
|
"155201": "ひよこ?",
|
||||||
|
"155202": "しろくま",
|
||||||
|
"155203": "ぺんぎん?",
|
||||||
|
"155204": "とんかつ",
|
||||||
|
"155205": "ねこ",
|
||||||
|
"155206": "とかげ",
|
||||||
|
"155207": "ざっそう",
|
||||||
|
"155208": "えびふらいのしっぽ",
|
||||||
|
"155301": "五十嵐 撫子(決意の夏合宿編)",
|
||||||
|
"155302": "萩原 七々瀬(決意の夏合宿編)",
|
||||||
|
"155303": "葛城 華",
|
||||||
|
"155304": "小野 美苗",
|
||||||
|
"155401": "t+pazolite",
|
||||||
|
"155402": "REDALiCE",
|
||||||
|
"155403": "DJ Myosuke",
|
||||||
|
"155404": "USAO",
|
||||||
|
"155405": "Massive New Krew",
|
||||||
|
"155406": "Laur",
|
||||||
|
"155407": "DORO*C",
|
||||||
|
"155501": "メルラン・プリズムリバー",
|
||||||
|
"155502": "ルナサ・プリズムリバー",
|
||||||
|
"155503": "リリカ・プリズムリバー",
|
||||||
|
"155504": "丁礼田舞",
|
||||||
|
"155505": "爾子田里乃",
|
||||||
|
"155506": "ミスティア・ローレライ",
|
||||||
|
"155507": "鬼人正邪",
|
||||||
|
"155901": "メルティ",
|
||||||
|
"155902": "青い子",
|
||||||
|
"155903": "ナナ",
|
||||||
|
"155904": "リリ",
|
||||||
|
"155905": "マカロン",
|
||||||
|
"156001": "桜井 春菜",
|
||||||
|
"156002": "早乙女 彩華",
|
||||||
|
"156003": "井之原 小星",
|
||||||
|
"156004": "柏木 咲姫",
|
||||||
|
"156005": "結城 莉玖",
|
||||||
|
"200101": "でらっくま(ゆにばーす)",
|
||||||
|
"200102": "れもんっくま(ゆにばーす)",
|
||||||
|
"200103": "らいむっくま(ゆにばーす)",
|
||||||
|
"200104": "しゃま(ゆにばーす)",
|
||||||
|
"200105": "みるく(ゆにばーす)",
|
||||||
|
"200201": "ルキ",
|
||||||
|
"200202": "ラキ",
|
||||||
|
"200203": "アトロ",
|
||||||
|
"200204": "クロト",
|
||||||
|
"200205": "ルシファー",
|
||||||
|
"200301": "濡羽",
|
||||||
|
"200302": "高麗",
|
||||||
|
"200303": "黒橡",
|
||||||
|
"200304": "赤墨",
|
||||||
|
"200305": "紫黒",
|
||||||
|
"200401": "リズ",
|
||||||
|
"200402": "シュトルツ",
|
||||||
|
"200403": "リヒティカイト",
|
||||||
|
"200404": "エーペルージュ",
|
||||||
|
"200405": "アシッド",
|
||||||
|
"200601": "エリザ",
|
||||||
|
"200602": "カイン",
|
||||||
|
"200603": "ジャック",
|
||||||
|
"200604": "アナスタシア",
|
||||||
|
"200605": "ラルフ(悪魔憑き)",
|
||||||
|
"205101": "最上 静香",
|
||||||
|
"205102": "箱崎 星梨花",
|
||||||
|
"205103": "野々原 茜",
|
||||||
|
"205104": "北沢 志保",
|
||||||
|
"205105": "北上 麗花",
|
||||||
|
"205201": "天道 輝",
|
||||||
|
"205202": "桜庭 薫",
|
||||||
|
"205203": "柏木 翼",
|
||||||
|
"205301": "cosMo@暴走P",
|
||||||
|
"205302": "cosMo@暴走P(バ美肉)",
|
||||||
|
"205303": "空気が嫁ないBoy",
|
||||||
|
"205304": "空気が嫁ないGirl",
|
||||||
|
"205305": "GOBOU",
|
||||||
|
"205306": "HACKPSY",
|
||||||
|
"205307": "うさぎのもちよ",
|
||||||
|
"205401": "オーイシマサヨシ",
|
||||||
|
"205402": "加藤純一",
|
||||||
|
"205501": "博麗 霊夢",
|
||||||
|
"205502": "霧雨 魔理沙",
|
||||||
|
"205503": "八雲 紫",
|
||||||
|
"205504": "宇佐見 菫子",
|
||||||
|
"205505": "魂魄 妖夢",
|
||||||
|
"205601": "キノシタ",
|
||||||
|
"205602": "鏡音リン(ポッピンキャンディ☆フィーバー!)",
|
||||||
|
"205603": "音街ウナ(ポッピンキャンディ☆フィーバー!)",
|
||||||
|
"205604": "音街ウナ(どぅーまいべすと!)",
|
||||||
|
"205605": "鏡音リン(スターリースカイ☆パレード)",
|
||||||
|
"205606": "音街ウナ(スターリースカイ☆パレード)",
|
||||||
|
"205607": "音街ウナ(はやくそれになりたい!)",
|
||||||
|
"205901": "緑仙",
|
||||||
|
"205902": "三枝明那",
|
||||||
|
"205903": "童田明治",
|
||||||
|
"205904": "鈴木勝",
|
||||||
|
"205905": "える",
|
||||||
|
"205906": "ジョー・力一",
|
||||||
|
"206101": "DIVA 初音ミク/アバンガード",
|
||||||
|
"206102": "DIVA 巡音ルカ/サクセサー",
|
||||||
|
"206103": "DIVA 鏡音リン/トランスミッター",
|
||||||
|
"206104": "DIVA 鏡音レン/レシーバー",
|
||||||
|
"206105": "DIVA KAITO/オンザロック",
|
||||||
|
"206106": "DIVA MEIKO/スカーレット",
|
||||||
|
"206201": "星咲 あかり(No Limit RED Force)",
|
||||||
|
"206202": "藤沢 柚子(No Limit RED Force)",
|
||||||
|
"206203": "三角 葵(No Limit RED Force)",
|
||||||
|
"206204": "皇城 セツナ",
|
||||||
|
"206205": "珠洲島 有栖(ぱくぱく☆がーる)",
|
||||||
|
"206301": "藤堂 陽南袴",
|
||||||
|
"206302": "桔梗 小夜曲",
|
||||||
|
"206303": "芒崎 奏",
|
||||||
|
"250101": "ちびみるく",
|
||||||
|
"250102": "SDしゃま",
|
||||||
|
"250103": "SDみるく",
|
||||||
|
"250104": "金の牛乳瓶",
|
||||||
|
"250105": "Joker",
|
||||||
|
"250201": "家菊",
|
||||||
|
"250202": "橘花",
|
||||||
|
"250203": "黒桜",
|
||||||
|
"250204": "紫藤",
|
||||||
|
"250205": "藪椿",
|
||||||
|
"250301": "百合咲ミカ",
|
||||||
|
"250302": "白銅寺アズリ",
|
||||||
|
"250303": "白法院ラグ",
|
||||||
|
"250304": "兎花宮イオフィ",
|
||||||
|
"250305": "庭白ガヴィ",
|
||||||
|
"250401": "リズ",
|
||||||
|
"250402": "アシッド",
|
||||||
|
"250403": "ゲルプテディ",
|
||||||
|
"250404": "オーランジェット",
|
||||||
|
"250405": "W?K?Y?",
|
||||||
|
"250601": "クレメンス",
|
||||||
|
"250602": "バイロン",
|
||||||
|
"250603": "エリー",
|
||||||
|
"255201": "くらべられっ子ちゃん",
|
||||||
|
"255202": "あのバスちゃん",
|
||||||
|
"255203": "天使ちゃん",
|
||||||
|
"255204": "ナイ",
|
||||||
|
"255301": "出雲咲姫",
|
||||||
|
"255302": "新島衣舞紀",
|
||||||
|
"255303": "花巻乙和",
|
||||||
|
"255304": "福島ノア",
|
||||||
|
"255305": "桜田美夢",
|
||||||
|
"255306": "春日春奈",
|
||||||
|
"255307": "白鳥胡桃",
|
||||||
|
"255308": "竹下みいこ",
|
||||||
|
"255401": "大空 彩",
|
||||||
|
"255402": "白戒",
|
||||||
|
"255403": "silky6",
|
||||||
|
"255404": "削除",
|
||||||
|
"255405": "BADASS",
|
||||||
|
"255601": "有野課長",
|
||||||
|
"255602": "12代目AD松井",
|
||||||
|
"255603": "16代目AD加賀",
|
||||||
|
"255604": "MA谷澤&14代目AD大須賀",
|
||||||
|
"255605": "カメラマン阿部",
|
||||||
|
"255606": "王様",
|
||||||
|
"255801": "No.9_ニナ",
|
||||||
|
"255802": "シルヴィアス",
|
||||||
|
"255803": "マゼラン・マゼラン",
|
||||||
|
"255804": "ミゼラン・ミゼラン",
|
||||||
|
"255805": "チュウニペンギン",
|
||||||
|
"255806": "ショウニペンギン",
|
||||||
|
"255901": "すりぃ",
|
||||||
|
"255902": "ナース",
|
||||||
|
"255903": "ボーイ",
|
||||||
|
"255904": "ガール",
|
||||||
|
"255905": "審査員",
|
||||||
|
"255906": "親衛隊",
|
||||||
|
"255907": "ひょっとこJK",
|
||||||
|
"255908": "ピエロ",
|
||||||
|
"255909": "侍",
|
||||||
|
"255910": "牛男",
|
||||||
|
"255911": "舞踏会の姉貴",
|
||||||
|
"255912": "黒須 紘",
|
||||||
|
"256001": "星咲 あかり(Transcend Lights)",
|
||||||
|
"256002": "藤沢 柚子(Transcend Lights)",
|
||||||
|
"256003": "三角 葵(Transcend Lights)",
|
||||||
|
"256004": "日向 千夏(Transcend Lights)",
|
||||||
|
"256005": "皇城 セツナ(Transcend Lights)",
|
||||||
|
"256006": "高瀬 梨緒(シュータードレス)",
|
||||||
|
"256007": "結城 莉玖(シュータードレス)",
|
||||||
|
"256008": "藍原 椿(シュータードレス)",
|
||||||
|
"300101": "ラズ(ふぇすてぃばる)",
|
||||||
|
"300102": "シフォン(ふぇすてぃばる)",
|
||||||
|
"300103": "ソルト(ふぇすてぃばる)",
|
||||||
|
"300104": "でらっくま(ふぇすてぃばる)",
|
||||||
|
"300105": "らいむっくま(ふぇすてぃばる)",
|
||||||
|
"300106": "れもんっくま(ふぇすてぃばる)",
|
||||||
|
"300201": "黒姫",
|
||||||
|
"300202": "紫黒",
|
||||||
|
"300203": "高麗",
|
||||||
|
"300204": "濡羽",
|
||||||
|
"300205": "イーシュ",
|
||||||
|
"300301": "アカツキ",
|
||||||
|
"300302": "コハク",
|
||||||
|
"300303": "暁",
|
||||||
|
"300304": "ノア",
|
||||||
|
"300305": "ソウ",
|
||||||
|
"300401": "ディアン",
|
||||||
|
"300402": "レヌス",
|
||||||
|
"300403": "ルフタ",
|
||||||
|
"300404": "ヴァハ",
|
||||||
|
"300405": "ブリギット",
|
||||||
|
"300601": "アウル",
|
||||||
|
"300602": "ヒュド・ルー",
|
||||||
|
"300603": "エリー",
|
||||||
|
"300604": "マスティマ",
|
||||||
|
"300605": "バイロン(堕天使)",
|
||||||
|
"305201": "初音ミク(ヴァンパイア)",
|
||||||
|
"305202": "初音ミク(アニマル)",
|
||||||
|
"305203": "初音ミク(状態異常彼女)",
|
||||||
|
"305204": "初音ミク(U)",
|
||||||
|
"305205": "初音ミク(シンデレラ)",
|
||||||
|
"305206": "初音ミク(ケサランパサラン)",
|
||||||
|
"305207": "初音ミク(ギフト)",
|
||||||
|
"305208": "初音ミク(パラサイト)",
|
||||||
|
"305209": "初音ミク(ジレンマ)",
|
||||||
|
"305210": "DECO*27",
|
||||||
|
"305401": "博麗 霊夢",
|
||||||
|
"305402": "霧雨 魔理沙",
|
||||||
|
"305403": "チルノ",
|
||||||
|
"305404": "レミリア・スカーレット",
|
||||||
|
"305405": "フランドール・スカーレット",
|
||||||
|
"305501": "名取さな(パレードコーデ)",
|
||||||
|
"305502": "名取さな(制服さん)",
|
||||||
|
"305503": "名取さな(いつものお洋服)",
|
||||||
|
"305504": "名取さな(さなちゃんねる王)",
|
||||||
|
"305505": "名取さな(ていねいな王様)",
|
||||||
|
"305506": "うさちゃんせんせえ",
|
||||||
|
"305509": "アヘエビ",
|
||||||
|
"305507": "ねこちゃんせんせえ",
|
||||||
|
"305508": "サーナくん",
|
||||||
|
"305701": "樋口楓",
|
||||||
|
"305702": "樋口楓(AIM)",
|
||||||
|
"305703": "樋口楓(アーティスト衣装)",
|
||||||
|
"305704": "ぷち樋口楓",
|
||||||
|
"305705": "ぷち樋口楓(自転車通学)",
|
||||||
|
"305706": "ぷち樋口楓(アーティスト衣装)",
|
||||||
|
"305707": "ささみちゃん",
|
||||||
|
"305801": "日高零奈",
|
||||||
|
"305802": "東雲和音",
|
||||||
|
"305803": "茅野ふたば",
|
||||||
|
"305804": "鳳凰火凛",
|
||||||
|
"305805": "瀬戸海月",
|
||||||
|
"305806": "大賀ルキア",
|
||||||
|
"305901": "クラウン",
|
||||||
|
"305907": "メリム",
|
||||||
|
"305904": "七海 あおい",
|
||||||
|
"305905": "高砂 瑞穂",
|
||||||
|
"305906": "アストライア",
|
||||||
|
"305902": "哲学主 ジェフティ",
|
||||||
|
"305903": "憎悪の始まりたる古竜",
|
||||||
|
"306001": "キュートなカノジョ",
|
||||||
|
"306003": "アマノ ダイキ",
|
||||||
|
"306002": "ユウヤ",
|
||||||
|
"306004": "ユウヤ(へべれけ)",
|
||||||
|
"306005": "syudou",
|
||||||
|
"306101": "光/Fracture",
|
||||||
|
"306102": "対立/Tempest",
|
||||||
|
"306103": "アリス&テニエル",
|
||||||
|
"306104": "ラグランジュ",
|
||||||
|
"350101": "ラズ(ツムギボシ)",
|
||||||
|
"350102": "シフォン(ツムギボシ)",
|
||||||
|
"350103": "ソルト(ツムギボシ)",
|
||||||
|
"350104": "ダンディ・ダン(ツムギボシ)",
|
||||||
|
"350105": "エリザビー(ツムギボシ)",
|
||||||
|
"350301": "アカツキ",
|
||||||
|
"350302": "ノア(過去)",
|
||||||
|
"350303": "コハク",
|
||||||
|
"350304": "アカツキ(正装)",
|
||||||
|
"350401": "アスク",
|
||||||
|
"350402": "LED",
|
||||||
|
"350403": "エムブラ",
|
||||||
|
"350601": "ルイ(幼少期)",
|
||||||
|
"350602": "SDニック",
|
||||||
|
"350603": "SDブラット",
|
||||||
|
"350604": "SDアウル",
|
||||||
|
"350605": "ニック&ブラット",
|
||||||
|
"350701": "でらっくま(10周年)",
|
||||||
|
"350702": "らいむっくま(10周年)",
|
||||||
|
"350703": "れもんっくま(10周年)",
|
||||||
|
"350704": "ラズ(10周年)",
|
||||||
|
"350705": "シフォン(10周年)",
|
||||||
|
"350706": "ソルト(10周年)",
|
||||||
|
"350707": "乙姫(10周年)",
|
||||||
|
"350708": "みるく(10周年)",
|
||||||
|
"350709": "しゃま(10周年)",
|
||||||
|
"350710": "maimaiちゃん(10周年)",
|
||||||
|
"350711": "はっぴー(10周年)",
|
||||||
|
"350712": "カメ(10周年)",
|
||||||
|
"350713": "タイ(10周年)",
|
||||||
|
"350714": "ニャイン(10周年)",
|
||||||
|
"350715": "ナカムラさん(10周年)",
|
||||||
|
"350716": "ブクロ(10周年)",
|
||||||
|
"350717": "maimai筐体",
|
||||||
|
"350718": "maimai筐体(GreeN)",
|
||||||
|
"350719": "maimai筐体(ORANGE)",
|
||||||
|
"350720": "maimai筐体(PiNK)",
|
||||||
|
"350721": "maimai筐体(MURASAKi)",
|
||||||
|
"350722": "maimai筐体(MiLK)",
|
||||||
|
"350723": "maimai筐体(FiNALE)",
|
||||||
|
"350724": "maimai筐体(でらっくす)",
|
||||||
|
"350725": "maimai筐体(Splash)",
|
||||||
|
"350726": "maimai筐体(UNiVERSE)",
|
||||||
|
"350727": "maimai筐体(FESTiVAL)",
|
||||||
|
"355101": "田中ヒメ",
|
||||||
|
"355102": "田中ヒメ(藍の華)",
|
||||||
|
"355103": "田中ヒメ(希織歌)",
|
||||||
|
"355104": "鈴木ヒナ",
|
||||||
|
"355105": "鈴木ヒナ(藍の華)",
|
||||||
|
"355106": "鈴木ヒナ(希織歌)",
|
||||||
|
"355201": "シスター(神っぽいな)",
|
||||||
|
"355202": "魔法少女(魔法少女とチョコレゐト)",
|
||||||
|
"355203": "アイマイナ",
|
||||||
|
"355204": "どうしてちゃん",
|
||||||
|
"355205": "アルティメットセンパイ",
|
||||||
|
"355206": "ピノキオピー",
|
||||||
|
"355301": "リン(ベーシスト)",
|
||||||
|
"355302": "リン(不良少女)",
|
||||||
|
"355303": "ブロウ(パイロット)",
|
||||||
|
"355304": "ブロウ(ゾンビガール)",
|
||||||
|
"355305": "マリヤ(バイオリニスト)",
|
||||||
|
"355306": "マリヤ(小悪魔)",
|
||||||
|
"355307": "リン(ニャ宇宙!)",
|
||||||
|
"355308": "ブロウ(ニャ宇宙!)",
|
||||||
|
"355309": "マリヤ(ニャ宇宙!)",
|
||||||
|
"355501": "御伽野ひめ",
|
||||||
|
"355502": "ハイテックニンジャ",
|
||||||
|
"355503": "ぱんしー",
|
||||||
|
"355504": "まめゆ",
|
||||||
|
"355505": "ダッコ & パンセ",
|
||||||
|
"355506": "ナーガ・ネギ",
|
||||||
|
"355507": "ネコらぴす",
|
||||||
|
"355508": "ネコまめゆねこ",
|
||||||
|
"355509": "ネコぽよし",
|
||||||
|
"355510": "ジン・スサノ",
|
||||||
|
"355401": "明坂 芹菜(東方Project:射命丸 文)",
|
||||||
|
"355402": "御形 アリシアナ(東方Project:小野塚 小町)",
|
||||||
|
"355403": "天王洲 なずな(東方Project:風見 幽香)",
|
||||||
|
"355404": "小仏 凪(東方Project:四季映姫・ヤマザナドゥ)",
|
||||||
|
"355405": "箱部 なる(東方Project:チルノ ウソテイver.)",
|
||||||
|
"355406": "月鈴 那知(東方Project:因幡 てゐ)",
|
||||||
|
"355407": "月鈴 白奈(東方Project:鈴仙・優曇華院・イナバ)",
|
||||||
|
"355408": "明坂 芹菜(東方Project:蓬莱山 輝夜)",
|
||||||
|
"355409": "御形 アリシアナ(東方Project:八意 永琳)",
|
||||||
|
"355410": "天王洲 なずな(東方Project:因幡 てゐ)",
|
||||||
|
"355411": "小仏 凪(東方Project:博麗 霊夢)",
|
||||||
|
"355412": "箱部 なる(東方Project:チルノ)",
|
||||||
|
"355413": "月鈴 那知(東方Project:伊吹 萃香)",
|
||||||
|
"355414": "月鈴 白奈(東方Project:霧雨 魔理沙)",
|
||||||
|
"355601": "ねこ",
|
||||||
|
"355602": "ぐるん",
|
||||||
|
"355603": "ペンギン",
|
||||||
|
"355604": "ウーパールーパー",
|
||||||
|
"355605": "デンゲンくん",
|
||||||
|
"355606": "うさぎくん",
|
||||||
|
"355607": "いぬくん",
|
||||||
|
"355608": "あんはっぴーちゃん",
|
||||||
|
"355609": "野生のでらっくま",
|
||||||
|
"355610": "右肩",
|
||||||
|
"355611": "真ん中",
|
||||||
|
"355612": "左肩",
|
||||||
|
"355701": "可不",
|
||||||
|
"355702": "可不(花となれ)",
|
||||||
|
"355703": "可不(私のドッペルゲンガー)",
|
||||||
|
"355801": "星咲 あかり(STARRED HEART)",
|
||||||
|
"355802": "結城 莉玖(STARRED HEART)",
|
||||||
|
"355803": "珠洲島 有栖(STARRED HEART)",
|
||||||
|
"355804": "九條 楓(STARRED HEART)",
|
||||||
|
"355805": "東雲 つむぎ(STARRED HEART)",
|
||||||
|
"355806": "逢坂 茜(シュータードレス)",
|
||||||
|
"355807": "珠洲島 有栖(シュータードレス)",
|
||||||
|
"355808": "九條 楓(シュータードレス)",
|
||||||
|
"355809": "皇城 セツナ(シュータードレス)",
|
||||||
|
"400101": "乙姫(ばでぃーず)",
|
||||||
|
"400102": "ラズ(ばでぃーず)",
|
||||||
|
"400103": "SDダンディ・ダン",
|
||||||
|
"400104": "SD亀",
|
||||||
|
"400105": "SD鯛",
|
||||||
|
"400106": "SD光吉 猛修",
|
||||||
|
"400107": "しゃま(Party☆People☆Princess)",
|
||||||
|
"400108": "みるく(Party☆People☆Princess)",
|
||||||
|
"400201": "プロトタイプI",
|
||||||
|
"400202": "ケファ",
|
||||||
|
"400203": "バルトルメ",
|
||||||
|
"400204": "マトフェイ",
|
||||||
|
"400205": "黒姫",
|
||||||
|
"400301": "ノア",
|
||||||
|
"400302": "ソウ",
|
||||||
|
"400303": "トキヤ",
|
||||||
|
"400304": "ナノハ",
|
||||||
|
"400305": "ユウキ",
|
||||||
|
"400401": "リズ",
|
||||||
|
"400402": "フルーンシュピラー",
|
||||||
|
"400403": "シュヴァルツローゼ",
|
||||||
|
"400404": "ヘルブラオ",
|
||||||
|
"400405": "アシッド(幼少期)",
|
||||||
|
"400601": "フィッツ公",
|
||||||
|
"400602": "マティルダ",
|
||||||
|
"400603": "クリーノス",
|
||||||
|
"400604": "クリーノス(天使)",
|
||||||
|
"400605": "リッツ(悪魔)",
|
||||||
|
"405101": "くらりちゃん",
|
||||||
|
"405102": "いまわさん",
|
||||||
|
"405103": "1000年ちゃん",
|
||||||
|
"405104": "足立レイ",
|
||||||
|
"405105": "いよわ",
|
||||||
|
"405201": "リンカ",
|
||||||
|
"405202": "セイネ",
|
||||||
|
"405203": "ユメ",
|
||||||
|
"405204": "ユウ",
|
||||||
|
"405205": "グルーヴコースター筐体",
|
||||||
|
"405206": "HEADPHONE CRAB",
|
||||||
|
"405301": "茅森月歌",
|
||||||
|
"405302": "和泉ユキ",
|
||||||
|
"405303": "逢川めぐみ",
|
||||||
|
"405304": "東城つかさ",
|
||||||
|
"405305": "朝倉可憐",
|
||||||
|
"405306": "國見タマ",
|
||||||
|
"405307": "蒼井えりか",
|
||||||
|
"405308": "水瀬いちご",
|
||||||
|
"405309": "水瀬すもも",
|
||||||
|
"405310": "樋口聖華",
|
||||||
|
"405311": "柊木梢",
|
||||||
|
"405312": "ビャッコ",
|
||||||
|
"405313": "七瀬七海",
|
||||||
|
"405401": "エリザベス",
|
||||||
|
"405402": "リリィ",
|
||||||
|
"405403": "ルーン",
|
||||||
|
"405404": "【裏】ルーン",
|
||||||
|
"405405": "WACCA筐体",
|
||||||
|
"405601": "sasakure.UK",
|
||||||
|
"405602": "テラ(トンデモワンダーズ)",
|
||||||
|
"405603": "カラス(トンデモワンダーズ)",
|
||||||
|
"405604": "初音ミク(*ハロー、プラネット。)",
|
||||||
|
"405701": "TJ.hangneil",
|
||||||
|
"405702": "男の子(神威)",
|
||||||
|
"405703": "女の子(神威)",
|
||||||
|
"405901": "宇宙飛行士(Apollo)",
|
||||||
|
"406101": "東北ずん子",
|
||||||
|
"406102": "東北ずん子(チア)",
|
||||||
|
"406103": "東北イタコ",
|
||||||
|
"406104": "東北イタコ(チア)",
|
||||||
|
"406105": "東北きりたん",
|
||||||
|
"406106": "東北きりたん(チア)",
|
||||||
|
"406107": "四国めたん",
|
||||||
|
"406108": "九州そら",
|
||||||
|
"406109": "ずんだもん",
|
||||||
|
"406201": "縁",
|
||||||
|
"406202": "冴川 芽依",
|
||||||
|
"406203": "ロト・トゥエルヴ",
|
||||||
|
"406204": "不来方 とあ",
|
||||||
|
"406205": "ヴェルゼビュートネメシス",
|
||||||
|
"406206": "リヒトシュッツェ"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"version": "Ver.CN 1.40",
|
||||||
|
"date": "1970-01-01 00:00:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
81313
nonebot_plugin_maimai_helper/game_data/diving_music_list.json
Normal file
81313
nonebot_plugin_maimai_helper/game_data/diving_music_list.json
Normal file
File diff suppressed because it is too large
Load Diff
230
nonebot_plugin_maimai_helper/game_data/frame_list.json
Normal file
230
nonebot_plugin_maimai_helper/game_data/frame_list.json
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"1": "デフォルト",
|
||||||
|
"150051": "タケモトピアノ",
|
||||||
|
"100101": "しゅわしゅわちほー",
|
||||||
|
"100301": "メトロポリスちほー3",
|
||||||
|
"100401": "スカイストリートちほー",
|
||||||
|
"100501": "天界ちほー3",
|
||||||
|
"100601": "BLACK ROSEちほー3",
|
||||||
|
"100701": "竜宮城のなつやすみ",
|
||||||
|
"100702": "本日のCAFE MiLKはおやすみです。",
|
||||||
|
"100703": "クリームソーダ、ひとくちほしいにゃ~!",
|
||||||
|
"106101": "オンゲキちほー2",
|
||||||
|
"150101": "しゅわしゅわちほー2",
|
||||||
|
"150201": "BLACK ROSEちほー4",
|
||||||
|
"150301": "スカイストリートちほー2",
|
||||||
|
"150401": "kawaiiちほー",
|
||||||
|
"150501": "高天原ちほー",
|
||||||
|
"150601": "らいむっくま&れもんっくま",
|
||||||
|
"150602": "すりりんぐでしゅわりんぐ、じゃ!",
|
||||||
|
"150603": "光吉カーニバル",
|
||||||
|
"156001": "オンゲキちほー3",
|
||||||
|
"259101": "Thank you for playing -でらっくす-",
|
||||||
|
"109101": "PERFECT Jewel [Diamond]",
|
||||||
|
"109102": "SYNC Jewel [Diamond]",
|
||||||
|
"159501": "黒姫",
|
||||||
|
"159502": "百合咲ミカ",
|
||||||
|
"200101": "宇宙すてーしょんちほー",
|
||||||
|
"200102": "宇宙すてーしょんちほー おまけ",
|
||||||
|
"200201": "天界ちほー4",
|
||||||
|
"200202": "天界ちほー4 おまけ",
|
||||||
|
"200301": "メトロポリスちほー4",
|
||||||
|
"200302": "メトロポリスちほー4 おまけ",
|
||||||
|
"200401": "7sRefちほー",
|
||||||
|
"200402": "7sRefちほー おまけ",
|
||||||
|
"200501": "ユニバースちほー",
|
||||||
|
"200502": "でらっくmaimai♪てんてこまい!",
|
||||||
|
"200503": "絡めトリック利己ライザー",
|
||||||
|
"200601": "BLACK ROSEちほー5",
|
||||||
|
"200602": "BLACK ROSEちほー5 おまけ",
|
||||||
|
"205901": "Rain Dropsちほー",
|
||||||
|
"206201": "オンゲキちほー4",
|
||||||
|
"209101": "Thank you for playing -Splash-",
|
||||||
|
"209103": "PERFECT Jewel [Emerald]",
|
||||||
|
"209102": "SYNC Jewel [Emerald]",
|
||||||
|
"209504": "ここからはじまるプロローグ。",
|
||||||
|
"209506": "モ゜ルモ゜ル",
|
||||||
|
"250051": "SEGA本社【虹】",
|
||||||
|
"250053": "若い力",
|
||||||
|
"250054": "BLUE ZONE",
|
||||||
|
"250101": "宇宙すてーしょんちほー2",
|
||||||
|
"250102": "宇宙すてーしょんちほー2 おまけ",
|
||||||
|
"250201": "メトロポリスちほー5",
|
||||||
|
"250202": "メトロポリスちほー5 おまけ",
|
||||||
|
"250301": "天界ちほー5",
|
||||||
|
"250302": "天界ちほー5 おまけ",
|
||||||
|
"250401": "7sRefちほー2",
|
||||||
|
"250402": "7sRefちほー2 おまけ",
|
||||||
|
"250501": "ユニバースちほー2",
|
||||||
|
"250601": "BLACK ROSEちほー6",
|
||||||
|
"250602": "BLACK ROSEちほー6 おまけ",
|
||||||
|
"250701": "ホワイトボード(はっぴー)",
|
||||||
|
"250702": "maistagram",
|
||||||
|
"250703": "maimai CAFE MiLK",
|
||||||
|
"250704": "竜宮城",
|
||||||
|
"250705": "maimai PiNK",
|
||||||
|
"250706": "maimai ORANGE",
|
||||||
|
"250707": "maimai GreeN B",
|
||||||
|
"250708": "maimai Dots Black",
|
||||||
|
"250709": "QZKago Requiem しゃま1",
|
||||||
|
"250710": "QZKago Requiem みるく1",
|
||||||
|
"250711": "Schwarzschild 1",
|
||||||
|
"250712": "Alea jacta est! 1",
|
||||||
|
"250713": "FFT 1",
|
||||||
|
"250714": "雷切-RAIKIRI- 2",
|
||||||
|
"250715": "the EmpErroR 2",
|
||||||
|
"250716": "Believe the Rainbow 2",
|
||||||
|
"250717": "PANDORA PARADOXXX 1",
|
||||||
|
"250718": "花と、雪と、ドラムンベース。 1",
|
||||||
|
"250719": "花と、雪と、ドラムンベース。 2",
|
||||||
|
"250720": "みるくの大人専用お子様ランチコースにゃフレーム",
|
||||||
|
"250721": "Magical Flavor 1",
|
||||||
|
"250722": "Excalibur ~Revived resolution~",
|
||||||
|
"250723": "夢花火",
|
||||||
|
"250724": "ユビキリ",
|
||||||
|
"250725": "宴じゃ!乙姫の大盤振る舞舞フレーム",
|
||||||
|
"250726": "いっしそう電☆舞舞神拳!",
|
||||||
|
"250727": "Our Wrenally",
|
||||||
|
"250728": "Hyper Active",
|
||||||
|
"250729": "AMAZING MIGHTYYYY!!!!",
|
||||||
|
"250730": "てってれ~♪ ラズのビビットコースフレーム",
|
||||||
|
"250731": "7thSense",
|
||||||
|
"250732": "Glorious Crown",
|
||||||
|
"250733": "Aiolos",
|
||||||
|
"250734": "Oshama Scramble!",
|
||||||
|
"250735": "おしゃま牛乳社長のしゃまでございますコースフレーム",
|
||||||
|
"250736": "oboro",
|
||||||
|
"250737": "Caliburne",
|
||||||
|
"250738": "ニャイン",
|
||||||
|
"250739": "mai-Star",
|
||||||
|
"250740": "シフォンのヨリドリ♪ミドリ♪コースですわ!フレーム",
|
||||||
|
"250741": "System “Z”",
|
||||||
|
"250742": "Garakuta Doll Play",
|
||||||
|
"250743": "Starlight Disco",
|
||||||
|
"250744": "Fragrance",
|
||||||
|
"250745": "ソルトの新感覚コースなのですフレーム",
|
||||||
|
"250746": "SONIC THE HEDGEHOG(SUPER SONIC)",
|
||||||
|
"250747": "ジングルベル",
|
||||||
|
"250749": "龍宮茶館 店内",
|
||||||
|
"250750": "CafeMiLK 店内",
|
||||||
|
"250751": "LOPIT Halloween",
|
||||||
|
"250752": "LOPIT Snowfield",
|
||||||
|
"250753": "はっぴー(10周年)",
|
||||||
|
"255201": "ツユちほー",
|
||||||
|
"255301": "D4DJ Groovy Mixちほー",
|
||||||
|
"255302": "Photon Maiden",
|
||||||
|
"255303": "Lyrical Lily",
|
||||||
|
"255401": "Diverse Systemちほー",
|
||||||
|
"255501": "Rain Dropsちほー2",
|
||||||
|
"255601": "ゲームセンターCXちほー",
|
||||||
|
"255801": "CHUNITHMちほー",
|
||||||
|
"255802": "コスモポップファンクラブ",
|
||||||
|
"255901": "すりぃちほー",
|
||||||
|
"256001": "オンゲキちほー5",
|
||||||
|
"259505": "ふたりでばかんすにゃ♪",
|
||||||
|
"300101": "ハピフェスちほー",
|
||||||
|
"300102": "ハピフェスちほー おまけ",
|
||||||
|
"300201": "メトロポリスちほー6",
|
||||||
|
"300202": "メトロポリスちほー6 おまけ",
|
||||||
|
"300301": "スカイストリートちほー3",
|
||||||
|
"300302": "スカイストリートちほー3 おまけ",
|
||||||
|
"300401": "天界ちほー6",
|
||||||
|
"300402": "天界ちほー6 おまけ",
|
||||||
|
"300501": "フェスティバルちほー",
|
||||||
|
"300601": "BLACK ROSEちほー7",
|
||||||
|
"300602": "BLACK ROSEちほー7 おまけ",
|
||||||
|
"305201": "DECO*27ちほー",
|
||||||
|
"305202": "アニマル",
|
||||||
|
"305203": "ヴァンパイア",
|
||||||
|
"305401": "東方Project×オンゲキちほー",
|
||||||
|
"305501": "さなちゃんねるちほー",
|
||||||
|
"305502": "ば~ちゃるな~す名取さな",
|
||||||
|
"305702": "樋口楓ちほー",
|
||||||
|
"305701": "AIM",
|
||||||
|
"305801": "外神田文芸高校",
|
||||||
|
"305802": "帝音国際学院",
|
||||||
|
"305901": "CHUNITHMちほー2",
|
||||||
|
"306001": "syudouちほー",
|
||||||
|
"306101": "光/Fracture",
|
||||||
|
"306102": "対立/Tempest",
|
||||||
|
"306103": "アリス",
|
||||||
|
"306104": "ラグランジュ",
|
||||||
|
"309101": "Thank you for playing -UNiVERSE-",
|
||||||
|
"309103": "PERFECT Jewel [Sapphire]",
|
||||||
|
"309102": "SYNC Jewel [Sapphire]",
|
||||||
|
"309504": "Heavenly Blast",
|
||||||
|
"309505": "sølips",
|
||||||
|
"309507": "Rainbow Rush Story",
|
||||||
|
"350051": "ぱちんこ maimai でらっくす",
|
||||||
|
"350101": "ハピフェスちほー2",
|
||||||
|
"350301": "スカイストリートちほー4",
|
||||||
|
"350401": "ドラゴンちほー2",
|
||||||
|
"350501": "フェスティバルちほー2",
|
||||||
|
"350601": "BLACK ROSEちほー8",
|
||||||
|
"350701": "10周年記念ちほー2",
|
||||||
|
"355101": "ヒメヒナちほー その1",
|
||||||
|
"355102": "ヒメヒナちほー その2",
|
||||||
|
"355201": "ピノキオピーちほー その1",
|
||||||
|
"355202": "ピノキオピーちほー その2",
|
||||||
|
"355203": "ピノキオピーちほー その3",
|
||||||
|
"355204": "ピノキオピーちほー その4",
|
||||||
|
"355301": "Muse Dashちほー その1",
|
||||||
|
"355302": "Muse Dashちほー その2",
|
||||||
|
"355303": "Muse Dashちほー その3",
|
||||||
|
"355304": "Muse Dashちほー その4",
|
||||||
|
"355305": "Muse Dashちほー その5",
|
||||||
|
"355401": "東方Project×イロドリミドリちほー",
|
||||||
|
"355501": "MEGAREXちほー その1",
|
||||||
|
"355502": "MEGAREXちほー その2",
|
||||||
|
"355601": "からめるちほー2 その1",
|
||||||
|
"355602": "からめるちほー2 その2",
|
||||||
|
"355603": "からめるちほー2 その3",
|
||||||
|
"355604": "からめるちほー2 その4",
|
||||||
|
"409507": "ねこドアップ",
|
||||||
|
"409508": "みんないるよ",
|
||||||
|
"409509": "ウーパールーパー",
|
||||||
|
"409510": "ペンギン島流し",
|
||||||
|
"409511": "ぐるん地獄行き",
|
||||||
|
"409512": "ねこ無限増殖",
|
||||||
|
"409513": "らくがき",
|
||||||
|
"409514": "ネオンポップ",
|
||||||
|
"409515": "純粋な爆発",
|
||||||
|
"355701": "音楽的同位体 可不ちほー",
|
||||||
|
"355801": "オンゲキちほー6",
|
||||||
|
"359504": "Tricolor⁂circuS",
|
||||||
|
"400101": "パーリィちほー",
|
||||||
|
"400201": "メトロポリスちほー7",
|
||||||
|
"400301": "スカイストリートちほー5",
|
||||||
|
"400401": "7sRefちほー3",
|
||||||
|
"400501": "バディーズちほー",
|
||||||
|
"400601": "BLACK ROSEちほー9",
|
||||||
|
"405101": "いよわちほー その1",
|
||||||
|
"405102": "いよわちほー その2",
|
||||||
|
"405103": "いよわちほー その3",
|
||||||
|
"405201": "グルーヴコースターちほー その1",
|
||||||
|
"405202": "グルーヴコースターちほー その2",
|
||||||
|
"405301": "ヘブンバーンズレッドちほー",
|
||||||
|
"405401": "WACCAちほー その1",
|
||||||
|
"405402": "WACCAちほー その2",
|
||||||
|
"405403": "WACCAちほー その3",
|
||||||
|
"405601": "sasakure.UKちほー その1",
|
||||||
|
"405602": "sasakure.UKちほー その2",
|
||||||
|
"405701": "TJ.hangneilちほー",
|
||||||
|
"405801": "月面ちほー",
|
||||||
|
"405901": "裏 月面ちほー その1",
|
||||||
|
"405902": "裏 月面ちほー その2",
|
||||||
|
"406101": "東北ずん子ちほー その1",
|
||||||
|
"406102": "東北ずん子ちほー その2",
|
||||||
|
"406201": "CHUNITHMちほー3",
|
||||||
|
"409101": "Thank you for playing -FESTiVAL-",
|
||||||
|
"409102": "SYNC Jewel [Amethyst]",
|
||||||
|
"409103": "PERFECT Jewel [Amethyst]",
|
||||||
|
"409504": "mystique as iris",
|
||||||
|
"409505": "VeRForTe αRtE:VEiN"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"version": "Ver.CN 1.40",
|
||||||
|
"date": "1970-01-01 00:00:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
747
nonebot_plugin_maimai_helper/game_data/icon_list.json
Normal file
747
nonebot_plugin_maimai_helper/game_data/icon_list.json
Normal file
@@ -0,0 +1,747 @@
|
|||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"1": "デフォルト",
|
||||||
|
"10": "ユーザーアイコン",
|
||||||
|
"11": "maimai でらっくす",
|
||||||
|
"12": "らん",
|
||||||
|
"13": "どりー",
|
||||||
|
"101": "でらっくま",
|
||||||
|
"102": "いえてぃっくま",
|
||||||
|
"103": "りすっくま",
|
||||||
|
"104": "ぱんだっくま",
|
||||||
|
"105": "みつよしっくま",
|
||||||
|
"201": "水野舞衣",
|
||||||
|
"202": "青沼優",
|
||||||
|
"203": "葵巴",
|
||||||
|
"204": "花田美空",
|
||||||
|
"205": "浅葱光一",
|
||||||
|
"301": "ラズ",
|
||||||
|
"302": "ソルト",
|
||||||
|
"303": "シフォン",
|
||||||
|
"304": "乙姫",
|
||||||
|
"305": "しゃま",
|
||||||
|
"306": "みるく",
|
||||||
|
"392": "たぬっくま",
|
||||||
|
"393": "ひげっくま",
|
||||||
|
"394": "おねむっくま",
|
||||||
|
"395": "めがねっくま",
|
||||||
|
"401": "SAM_RAI",
|
||||||
|
"402": "BEN_KEI",
|
||||||
|
"403": "SIN_BA",
|
||||||
|
"404": "TO_KI",
|
||||||
|
"405": "黒姫",
|
||||||
|
"501": "バハムート",
|
||||||
|
"502": "ニーズヘッグ",
|
||||||
|
"503": "ファフニール",
|
||||||
|
"504": "ラタトスク",
|
||||||
|
"505": "フレーズベルグ",
|
||||||
|
"601": "百合咲ミカ",
|
||||||
|
"602": "白銅寺アズリ",
|
||||||
|
"603": "兎花宮イオフィ",
|
||||||
|
"604": "白王院ラグ",
|
||||||
|
"605": "兎花宮サラ",
|
||||||
|
"701": "アウル",
|
||||||
|
"702": "リッツ",
|
||||||
|
"703": "ニック",
|
||||||
|
"704": "エリー",
|
||||||
|
"705": "ヒュド・ルー",
|
||||||
|
"706": "クレメンス",
|
||||||
|
"707": "ラルフ",
|
||||||
|
"708": "バイロン",
|
||||||
|
"709": "マスティマ",
|
||||||
|
"3301": "紲星あかり",
|
||||||
|
"3302": "結月ゆかり",
|
||||||
|
"3303": "弦巻マキ",
|
||||||
|
"3304": "琴葉 茜",
|
||||||
|
"3305": "琴葉 葵",
|
||||||
|
"3306": "GYARI",
|
||||||
|
"3401": "博麗霊夢",
|
||||||
|
"3402": "霧雨魔理沙",
|
||||||
|
"3403": "十六夜咲夜",
|
||||||
|
"3404": "レミリア・スカーレット",
|
||||||
|
"3405": "フランドール・スカーレット",
|
||||||
|
"3406": "魂魄妖夢",
|
||||||
|
"3407": "八雲紫",
|
||||||
|
"3408": "鈴仙・優曇華院・イナバ",
|
||||||
|
"3409": "蓬莱山輝夜",
|
||||||
|
"3410": "藤原妹紅",
|
||||||
|
"3501": "初音ミクV3",
|
||||||
|
"3502": "エトワール",
|
||||||
|
"3503": "天袖",
|
||||||
|
"3901": "からめる/ねこ/ラーメン",
|
||||||
|
"3902": "からめる/ねこ/DJ",
|
||||||
|
"3903": "からめる/人/まいった",
|
||||||
|
"3904": "からめる/人/刺身",
|
||||||
|
"3905": "からめる/レース",
|
||||||
|
"4001": "明坂 芹菜",
|
||||||
|
"4002": "御形 アリシアナ",
|
||||||
|
"4003": "天王洲 なずな",
|
||||||
|
"4004": "小仏 凪",
|
||||||
|
"4005": "箱部 なる",
|
||||||
|
"4006": "月鈴 那知",
|
||||||
|
"4007": "月鈴 白奈",
|
||||||
|
"4008": "五十嵐 撫子",
|
||||||
|
"4009": "萩原 七々瀬",
|
||||||
|
"4201": "結月ゆかり/幾望の月",
|
||||||
|
"4202": "結月ゆかり/フリィダム ロリィタ",
|
||||||
|
"4203": "結月ゆかり/チュルリラ・チュルリラ・ダッダッダ!",
|
||||||
|
"4204": "結月ゆかり/幸せになれる隠しコマンドがあるらしい",
|
||||||
|
"4205": "結月ゆかり/サヨナラチェーンソー",
|
||||||
|
"50101": "あおはるっくま",
|
||||||
|
"50102": "にんじゃっくま",
|
||||||
|
"50103": "どらごっくま",
|
||||||
|
"50104": "えんじぇっくま",
|
||||||
|
"50105": "くろばらっくま",
|
||||||
|
"50201": "ピリポ",
|
||||||
|
"50202": "ケファ",
|
||||||
|
"50203": "バルトルメ",
|
||||||
|
"50204": "アンドレアス",
|
||||||
|
"50205": "イーシュ",
|
||||||
|
"50401": "萌木ゆずか",
|
||||||
|
"50402": "萌木ほのか",
|
||||||
|
"50403": "萌木はるか",
|
||||||
|
"50404": "萌木いよか",
|
||||||
|
"50405": "萌木せとか",
|
||||||
|
"50601": "ブリュンヒルデ",
|
||||||
|
"50602": "ジグニュー",
|
||||||
|
"50603": "ジークルーネ",
|
||||||
|
"50604": "グリムゲルデ",
|
||||||
|
"50605": "シュヴェルトライテ",
|
||||||
|
"50606": "ヴァルトラウテ",
|
||||||
|
"50607": "オーディン",
|
||||||
|
"50701": "maimaiちゃん",
|
||||||
|
"50702": "はっぴー",
|
||||||
|
"50703": "カメ",
|
||||||
|
"50704": "タイ",
|
||||||
|
"50705": "エリザビー",
|
||||||
|
"50801": "ルイ",
|
||||||
|
"50802": "ニック(悪魔憑き)",
|
||||||
|
"50803": "ティノ",
|
||||||
|
"50804": "エレノラ",
|
||||||
|
"53301": "星咲 あかり",
|
||||||
|
"53302": "藤沢 柚子",
|
||||||
|
"53303": "三角 葵",
|
||||||
|
"53304": "日向 千夏",
|
||||||
|
"53305": "藍原 椿",
|
||||||
|
"53306": "九條 楓",
|
||||||
|
"53401": "グスタフ ハイドリヒ",
|
||||||
|
"53402": "マリア=S=レオンブルク",
|
||||||
|
"53403": "ヴィーナス ポロロッチョ",
|
||||||
|
"53404": "メグメグ",
|
||||||
|
"53405": "Voidoll",
|
||||||
|
"53406": "リリカ",
|
||||||
|
"53407": "ルチアーノ",
|
||||||
|
"53408": "双挽 乃保",
|
||||||
|
"53409": "桜華 忠臣",
|
||||||
|
"53601": "カク",
|
||||||
|
"53602": "イムラ",
|
||||||
|
"53603": "ミツイ",
|
||||||
|
"53604": "クロヌマ",
|
||||||
|
"53605": "ツチダ",
|
||||||
|
"53701": "DIVA 初音ミク/スクール",
|
||||||
|
"53702": "DIVA 初音ミク/マジシャン",
|
||||||
|
"53703": "DIVA 初音ミク/リボンガール",
|
||||||
|
"53704": "DIVA 初音ミク/クリスマス",
|
||||||
|
"53705": "DIVA 初音ミク/∞",
|
||||||
|
"53901": "霧雨魔理沙",
|
||||||
|
"53902": "鈴仙優曇華院イナバ",
|
||||||
|
"53903": "洩矢諏訪子",
|
||||||
|
"53904": "藤原妹紅",
|
||||||
|
"53905": "火焔猫燐",
|
||||||
|
"100101": "らいむっくま",
|
||||||
|
"100102": "れもんっくま",
|
||||||
|
"100103": "でらっくま",
|
||||||
|
"100104": "らん",
|
||||||
|
"100105": "どりー",
|
||||||
|
"100301": "壱王",
|
||||||
|
"100302": "仁王",
|
||||||
|
"100303": "雷天",
|
||||||
|
"100304": "焔天",
|
||||||
|
"100305": "黒姫",
|
||||||
|
"100401": "モモ",
|
||||||
|
"100402": "アカツキ",
|
||||||
|
"100403": "ナノハ",
|
||||||
|
"100404": "ソウ",
|
||||||
|
"100405": "ノア",
|
||||||
|
"100501": "百合咲ミカ",
|
||||||
|
"100502": "八剱月アルマ",
|
||||||
|
"100503": "白銅寺アズリ",
|
||||||
|
"100504": "白法院ラグ",
|
||||||
|
"100505": "八剱月アルマ(堕天)",
|
||||||
|
"100601": "ロー",
|
||||||
|
"100602": "マリー",
|
||||||
|
"100603": "ハンナ",
|
||||||
|
"100604": "トリスタン",
|
||||||
|
"100605": "クレメンス(悪魔)",
|
||||||
|
"105301": "アンドロメダ子",
|
||||||
|
"105302": "アンドロメダ男",
|
||||||
|
"105303": "チビキャラA",
|
||||||
|
"105304": "チビキャラB",
|
||||||
|
"105305": "チビキャラC",
|
||||||
|
"105306": "チビキャラD",
|
||||||
|
"105401": "琴葉 葵 チョコミント(Ice!)",
|
||||||
|
"105402": "琴葉 葵 チョコミント(慈悲)",
|
||||||
|
"105403": "琴葉 茜 チョコミント(?)",
|
||||||
|
"105404": "琴葉 茜 チョコミント(おかわりや)",
|
||||||
|
"105405": "チョコミン党",
|
||||||
|
"105501": "アリス・マーガトロイド",
|
||||||
|
"105502": "霧雨魔理沙",
|
||||||
|
"105503": "チルノ",
|
||||||
|
"105504": "博麗霊夢",
|
||||||
|
"105505": "射命丸文",
|
||||||
|
"105601": "光/サマー",
|
||||||
|
"105602": "対立/サマー",
|
||||||
|
"105603": "サヤ",
|
||||||
|
"105604": "叶永",
|
||||||
|
"105605": "エト",
|
||||||
|
"105606": "ルナ",
|
||||||
|
"105607": "紅",
|
||||||
|
"105608": "レーテー",
|
||||||
|
"105701": "v flower/ベノム",
|
||||||
|
"105702": "GUMI/マネマネサイコトロピック",
|
||||||
|
"105703": "魔法少女リリカ/アルカリレットウセイ",
|
||||||
|
"105704": "かいりきベア",
|
||||||
|
"105705": "宍戸 美鈴",
|
||||||
|
"105901": "える",
|
||||||
|
"105902": "シスター・クレア",
|
||||||
|
"105903": "ジョー・力一",
|
||||||
|
"105904": "ドーラ",
|
||||||
|
"105905": "月ノ美兎",
|
||||||
|
"105906": "剣持刀也",
|
||||||
|
"105907": "森中花咲",
|
||||||
|
"105908": "静凛",
|
||||||
|
"105909": "鷹宮リオン",
|
||||||
|
"105910": "樋口楓",
|
||||||
|
"105911": "本間ひまわり",
|
||||||
|
"105912": "緑仙",
|
||||||
|
"106001": "踊っているくまのイラスト",
|
||||||
|
"106002": "踊っているいぬのイラスト",
|
||||||
|
"106003": "踊っているねこのイラスト",
|
||||||
|
"106004": "踊っているうさぎのイラスト",
|
||||||
|
"106005": "元気な男性のイラスト",
|
||||||
|
"106006": "元気な女性のイラスト",
|
||||||
|
"106007": "ドラム式洗濯機のイラスト",
|
||||||
|
"106008": "コウテイペンギンのイラスト",
|
||||||
|
"106009": "コウテイペンギンのヒナのイラスト",
|
||||||
|
"106010": "バナナボートに乗る人たちのイラスト",
|
||||||
|
"106101": "柏木 美亜",
|
||||||
|
"106102": "東雲 つむぎ",
|
||||||
|
"106103": "高瀬 梨緒",
|
||||||
|
"106104": "逢坂 茜",
|
||||||
|
"106105": "珠洲島 有栖",
|
||||||
|
"150101": "乙姫",
|
||||||
|
"150102": "ラズ",
|
||||||
|
"150103": "シフォン",
|
||||||
|
"150104": "ソルト",
|
||||||
|
"150105": "しゃま",
|
||||||
|
"150106": "みるく",
|
||||||
|
"150201": "アウル(幼少期)",
|
||||||
|
"150202": "トリスタン",
|
||||||
|
"150203": "アウル",
|
||||||
|
"150301": "モモ",
|
||||||
|
"150302": "トキヤ",
|
||||||
|
"150303": "コハク",
|
||||||
|
"150304": "ノア",
|
||||||
|
"150305": "アカツキ",
|
||||||
|
"150401": "ナノ",
|
||||||
|
"150402": "アサド",
|
||||||
|
"150403": "ローヴェ",
|
||||||
|
"150404": "ドメニカ",
|
||||||
|
"150405": "テルス",
|
||||||
|
"150501": "ニギ",
|
||||||
|
"150502": "シンキョウ",
|
||||||
|
"150503": "メノウ",
|
||||||
|
"150504": "アマヒコ",
|
||||||
|
"150505": "オオヒメ",
|
||||||
|
"155201": "ひよこ?",
|
||||||
|
"155202": "しろくま",
|
||||||
|
"155203": "ぺんぎん?",
|
||||||
|
"155204": "とんかつ",
|
||||||
|
"155205": "ねこ",
|
||||||
|
"155206": "とかげ",
|
||||||
|
"155207": "ざっそう",
|
||||||
|
"155208": "えびふらいのしっぽ",
|
||||||
|
"155301": "五十嵐 撫子(決意の夏合宿編)",
|
||||||
|
"155302": "萩原 七々瀬(決意の夏合宿編)",
|
||||||
|
"155303": "葛城 華",
|
||||||
|
"155304": "小野 美苗",
|
||||||
|
"155401": "t+pazolite",
|
||||||
|
"155402": "REDALiCE",
|
||||||
|
"155403": "DJ Myosuke",
|
||||||
|
"155404": "USAO",
|
||||||
|
"155405": "Massive New Krew",
|
||||||
|
"155406": "Laur",
|
||||||
|
"155407": "DORO*C",
|
||||||
|
"155501": "メルラン・プリズムリバー",
|
||||||
|
"155502": "ルナサ・プリズムリバー",
|
||||||
|
"155503": "リリカ・プリズムリバー",
|
||||||
|
"155504": "丁礼田舞",
|
||||||
|
"155505": "爾子田里乃",
|
||||||
|
"155506": "ミスティア・ローレライ",
|
||||||
|
"155507": "鬼人正邪",
|
||||||
|
"155901": "メルティ",
|
||||||
|
"155902": "青い子",
|
||||||
|
"155903": "ナナ",
|
||||||
|
"155904": "リリ",
|
||||||
|
"155905": "マカロン",
|
||||||
|
"156001": "桜井 春菜",
|
||||||
|
"156002": "早乙女 彩華",
|
||||||
|
"156003": "井之原 小星",
|
||||||
|
"156004": "柏木 咲姫",
|
||||||
|
"156005": "結城 莉玖",
|
||||||
|
"200101": "でらっくま(ゆにばーす)",
|
||||||
|
"200102": "れもんっくま(ゆにばーす)",
|
||||||
|
"200103": "らいむっくま(ゆにばーす)",
|
||||||
|
"200104": "しゃま(ゆにばーす)",
|
||||||
|
"200105": "みるく(ゆにばーす)",
|
||||||
|
"200201": "ルキ",
|
||||||
|
"200202": "ラキ",
|
||||||
|
"200203": "アトロ",
|
||||||
|
"200204": "クロト",
|
||||||
|
"200205": "ルシファー",
|
||||||
|
"200301": "濡羽",
|
||||||
|
"200302": "高麗",
|
||||||
|
"200303": "黒橡",
|
||||||
|
"200304": "赤墨",
|
||||||
|
"200305": "紫黒",
|
||||||
|
"200401": "リズ",
|
||||||
|
"200402": "シュトルツ",
|
||||||
|
"200403": "リヒティカイト",
|
||||||
|
"200404": "エーペルージュ",
|
||||||
|
"200405": "アシッド",
|
||||||
|
"200601": "エリザ",
|
||||||
|
"200602": "カイン",
|
||||||
|
"200603": "ジャック",
|
||||||
|
"200604": "アナスタシア",
|
||||||
|
"200605": "ラルフ(悪魔憑き)",
|
||||||
|
"205101": "最上 静香",
|
||||||
|
"205102": "箱崎 星梨花",
|
||||||
|
"205103": "野々原 茜",
|
||||||
|
"205104": "北沢 志保",
|
||||||
|
"205105": "北上 麗花",
|
||||||
|
"205201": "天道 輝",
|
||||||
|
"205202": "桜庭 薫",
|
||||||
|
"205203": "柏木 翼",
|
||||||
|
"205301": "cosMo@暴走P",
|
||||||
|
"205302": "cosMo@暴走P(バ美肉)",
|
||||||
|
"205303": "空気が嫁ないBoy",
|
||||||
|
"205304": "空気が嫁ないGirl",
|
||||||
|
"205305": "GOBOU",
|
||||||
|
"205306": "HACKPSY",
|
||||||
|
"205307": "うさぎのもちよ",
|
||||||
|
"205401": "オーイシマサヨシ",
|
||||||
|
"205402": "加藤純一",
|
||||||
|
"205501": "博麗 霊夢",
|
||||||
|
"205502": "霧雨 魔理沙",
|
||||||
|
"205503": "八雲 紫",
|
||||||
|
"205504": "宇佐見 菫子",
|
||||||
|
"205505": "魂魄 妖夢",
|
||||||
|
"205601": "キノシタ",
|
||||||
|
"205602": "鏡音リン(ポッピンキャンディ☆フィーバー!)",
|
||||||
|
"205603": "音街ウナ(ポッピンキャンディ☆フィーバー!)",
|
||||||
|
"205604": "音街ウナ(どぅーまいべすと!)",
|
||||||
|
"205605": "鏡音リン(スターリースカイ☆パレード)",
|
||||||
|
"205606": "音街ウナ(スターリースカイ☆パレード)",
|
||||||
|
"205607": "音街ウナ(はやくそれになりたい!)",
|
||||||
|
"205901": "緑仙",
|
||||||
|
"205902": "三枝明那",
|
||||||
|
"205903": "童田明治",
|
||||||
|
"205904": "鈴木勝",
|
||||||
|
"205905": "える",
|
||||||
|
"205906": "ジョー・力一",
|
||||||
|
"206101": "DIVA 初音ミク/アバンガード",
|
||||||
|
"206102": "DIVA 巡音ルカ/サクセサー",
|
||||||
|
"206103": "DIVA 鏡音リン/トランスミッター",
|
||||||
|
"206104": "DIVA 鏡音レン/レシーバー",
|
||||||
|
"206105": "DIVA KAITO/オンザロック",
|
||||||
|
"206106": "DIVA MEIKO/スカーレット",
|
||||||
|
"206201": "星咲 あかり(No Limit RED Force)",
|
||||||
|
"206202": "藤沢 柚子(No Limit RED Force)",
|
||||||
|
"206203": "三角 葵(No Limit RED Force)",
|
||||||
|
"206204": "皇城 セツナ",
|
||||||
|
"206205": "珠洲島 有栖(ぱくぱく☆がーる)",
|
||||||
|
"206301": "藤堂 陽南袴",
|
||||||
|
"206302": "桔梗 小夜曲",
|
||||||
|
"206303": "芒崎 奏",
|
||||||
|
"209501": "UNiVERSE",
|
||||||
|
"209502": "UNiVERSE しゃま&みるく",
|
||||||
|
"250101": "ちびみるく",
|
||||||
|
"250102": "SDしゃま",
|
||||||
|
"250103": "SDみるく",
|
||||||
|
"250104": "金の牛乳瓶",
|
||||||
|
"250105": "Joker",
|
||||||
|
"250201": "家菊",
|
||||||
|
"250202": "橘花",
|
||||||
|
"250203": "黒桜",
|
||||||
|
"250204": "紫藤",
|
||||||
|
"250205": "藪椿",
|
||||||
|
"250301": "百合咲ミカ",
|
||||||
|
"250302": "白銅寺アズリ",
|
||||||
|
"250303": "白法院ラグ",
|
||||||
|
"250304": "兎花宮イオフィ",
|
||||||
|
"250305": "庭白ガヴィ",
|
||||||
|
"250401": "リズ",
|
||||||
|
"250402": "アシッド",
|
||||||
|
"250403": "ゲルプテディ",
|
||||||
|
"250404": "オーランジェット",
|
||||||
|
"250405": "W?K?Y?",
|
||||||
|
"250601": "クレメンス",
|
||||||
|
"250602": "バイロン",
|
||||||
|
"250603": "エリー",
|
||||||
|
"250701": "maimai FiNALE",
|
||||||
|
"250702": "maimai MiLK",
|
||||||
|
"250703": "maimai MURASAKi",
|
||||||
|
"250704": "maimai PiNK",
|
||||||
|
"250705": "maimai ORANGE",
|
||||||
|
"250706": "maimai GreeN",
|
||||||
|
"250707": "maimai",
|
||||||
|
"255201": "くらべられっ子ちゃん",
|
||||||
|
"255202": "あのバスちゃん",
|
||||||
|
"255203": "天使ちゃん",
|
||||||
|
"255204": "ナイ",
|
||||||
|
"255301": "出雲咲姫",
|
||||||
|
"255302": "新島衣舞紀",
|
||||||
|
"255303": "花巻乙和",
|
||||||
|
"255304": "福島ノア",
|
||||||
|
"255305": "桜田美夢",
|
||||||
|
"255306": "春日春奈",
|
||||||
|
"255307": "白鳥胡桃",
|
||||||
|
"255308": "竹下みいこ",
|
||||||
|
"255401": "大空 彩",
|
||||||
|
"255402": "白戒",
|
||||||
|
"255403": "silky6",
|
||||||
|
"255404": "削除",
|
||||||
|
"255405": "BADASS",
|
||||||
|
"255406": "Feryquitous",
|
||||||
|
"255407": "Sakuzyo",
|
||||||
|
"255408": "xi",
|
||||||
|
"255409": "YsK439",
|
||||||
|
"255601": "有野課長",
|
||||||
|
"255602": "12代目AD松井",
|
||||||
|
"255603": "16代目AD加賀",
|
||||||
|
"255604": "MA谷澤&14代目AD大須賀",
|
||||||
|
"255605": "カメラマン阿部",
|
||||||
|
"255606": "王様",
|
||||||
|
"255801": "No.9_ニナ",
|
||||||
|
"255802": "シルヴィアス",
|
||||||
|
"255803": "マゼラン・マゼラン",
|
||||||
|
"255804": "ミゼラン・ミゼラン",
|
||||||
|
"255805": "チュウニペンギン",
|
||||||
|
"255806": "ショウニペンギン",
|
||||||
|
"255901": "すりぃ",
|
||||||
|
"255902": "ナース",
|
||||||
|
"255903": "ボーイ",
|
||||||
|
"255904": "ガール",
|
||||||
|
"255905": "審査員",
|
||||||
|
"255906": "親衛隊",
|
||||||
|
"255907": "ひょっとこJK",
|
||||||
|
"255908": "ピエロ",
|
||||||
|
"255909": "侍",
|
||||||
|
"255910": "牛男",
|
||||||
|
"255911": "舞踏会の姉貴",
|
||||||
|
"255912": "黒須 紘",
|
||||||
|
"256001": "星咲 あかり(Transcend Lights)",
|
||||||
|
"256002": "藤沢 柚子(Transcend Lights)",
|
||||||
|
"256003": "三角 葵(Transcend Lights)",
|
||||||
|
"256004": "日向 千夏(Transcend Lights)",
|
||||||
|
"256005": "皇城 セツナ(Transcend Lights)",
|
||||||
|
"256006": "高瀬 梨緒(シュータードレス)",
|
||||||
|
"256007": "結城 莉玖(シュータードレス)",
|
||||||
|
"256008": "藍原 椿(シュータードレス)",
|
||||||
|
"259501": "SEGA本社",
|
||||||
|
"300101": "ラズ(ふぇすてぃばる)",
|
||||||
|
"300102": "シフォン(ふぇすてぃばる)",
|
||||||
|
"300103": "ソルト(ふぇすてぃばる)",
|
||||||
|
"300104": "でらっくま(ふぇすてぃばる)",
|
||||||
|
"300105": "らいむっくま(ふぇすてぃばる)",
|
||||||
|
"300106": "れもんっくま(ふぇすてぃばる)",
|
||||||
|
"300201": "黒姫",
|
||||||
|
"300202": "紫黒",
|
||||||
|
"300203": "高麗",
|
||||||
|
"300204": "濡羽",
|
||||||
|
"300205": "イーシュ",
|
||||||
|
"300301": "アカツキ",
|
||||||
|
"300302": "コハク",
|
||||||
|
"300303": "暁",
|
||||||
|
"300304": "ノア",
|
||||||
|
"300305": "ソウ",
|
||||||
|
"300401": "ディアン",
|
||||||
|
"300402": "レヌス",
|
||||||
|
"300403": "ルフタ",
|
||||||
|
"300404": "ヴァハ",
|
||||||
|
"300405": "ブリギット",
|
||||||
|
"300601": "アウル",
|
||||||
|
"300602": "ヒュド・ルー",
|
||||||
|
"300603": "エリー",
|
||||||
|
"300604": "マスティマ",
|
||||||
|
"300605": "バイロン(堕天使)",
|
||||||
|
"305201": "初音ミク(ヴァンパイア)",
|
||||||
|
"305202": "初音ミク(アニマル)",
|
||||||
|
"305203": "初音ミク(状態異常彼女)",
|
||||||
|
"305204": "初音ミク(U)",
|
||||||
|
"305205": "初音ミク(シンデレラ)",
|
||||||
|
"305206": "初音ミク(ケサランパサラン)",
|
||||||
|
"305207": "初音ミク(ギフト)",
|
||||||
|
"305208": "初音ミク(パラサイト)",
|
||||||
|
"305209": "初音ミク(ジレンマ)",
|
||||||
|
"305210": "DECO*27",
|
||||||
|
"305401": "博麗 霊夢",
|
||||||
|
"305402": "霧雨 魔理沙",
|
||||||
|
"305403": "チルノ",
|
||||||
|
"305404": "レミリア・スカーレット",
|
||||||
|
"305405": "フランドール・スカーレット",
|
||||||
|
"305501": "名取さな(パレードコーデ)",
|
||||||
|
"305502": "名取さな(制服さん)",
|
||||||
|
"305503": "名取さな(いつものお洋服)",
|
||||||
|
"305504": "名取さな(さなちゃんねる王)",
|
||||||
|
"305505": "名取さな(ていねいな王様)",
|
||||||
|
"305506": "うさちゃんせんせえ",
|
||||||
|
"305507": "ねこちゃんせんせえ",
|
||||||
|
"305508": "サーナくん",
|
||||||
|
"305509": "アヘエビ",
|
||||||
|
"305701": "樋口楓",
|
||||||
|
"305702": "樋口楓(AIM)",
|
||||||
|
"305703": "樋口楓(アーティスト衣装)",
|
||||||
|
"305704": "ぷち樋口楓",
|
||||||
|
"305705": "ぷち樋口楓(自転車通学)",
|
||||||
|
"305706": "ぷち樋口楓(アーティスト衣装)",
|
||||||
|
"305707": "ささみちゃん",
|
||||||
|
"305801": "日高零奈",
|
||||||
|
"305802": "東雲和音",
|
||||||
|
"305803": "茅野ふたば",
|
||||||
|
"305804": "鳳凰火凛",
|
||||||
|
"305805": "瀬戸海月",
|
||||||
|
"305806": "大賀ルキア",
|
||||||
|
"305901": "クラウン",
|
||||||
|
"305902": "哲学主 ジェフティ",
|
||||||
|
"305903": "憎悪の始まりたる古竜",
|
||||||
|
"305904": "七海 あおい",
|
||||||
|
"305905": "高砂 瑞穂",
|
||||||
|
"305906": "アストライア",
|
||||||
|
"305907": "メリム",
|
||||||
|
"306001": "キュートなカノジョ",
|
||||||
|
"306002": "ユウヤ",
|
||||||
|
"306003": "アマノ ダイキ",
|
||||||
|
"306004": "ユウヤ(へべれけ)",
|
||||||
|
"306005": "syudou",
|
||||||
|
"306101": "光/Fracture",
|
||||||
|
"306102": "対立/Tempest",
|
||||||
|
"306103": "アリス&テニエル",
|
||||||
|
"306104": "ラグランジュ",
|
||||||
|
"309501": "FESTiVAL",
|
||||||
|
"309502": "Lia=Fail",
|
||||||
|
"309503": "FESTiVAL ラズ&シフォン&ソルト",
|
||||||
|
"350101": "ラズ(ツムギボシ)",
|
||||||
|
"350102": "シフォン(ツムギボシ)",
|
||||||
|
"350103": "ソルト(ツムギボシ)",
|
||||||
|
"350104": "ダンディ・ダン(ツムギボシ)",
|
||||||
|
"350105": "エリザビー(ツムギボシ)",
|
||||||
|
"350301": "アカツキ",
|
||||||
|
"350302": "ノア(過去)",
|
||||||
|
"350303": "コハク",
|
||||||
|
"350304": "アカツキ(正装)",
|
||||||
|
"350401": "アスク",
|
||||||
|
"350402": "LED",
|
||||||
|
"350403": "エムブラ",
|
||||||
|
"350601": "ルイ(幼少期)",
|
||||||
|
"350602": "SDニック",
|
||||||
|
"350603": "SDブラット",
|
||||||
|
"350604": "SDアウル",
|
||||||
|
"350605": "ニック&ブラット",
|
||||||
|
"350701": "でらっくま(10周年)",
|
||||||
|
"350702": "らいむっくま(10周年)",
|
||||||
|
"350703": "れもんっくま(10周年)",
|
||||||
|
"350704": "ラズ(10周年)",
|
||||||
|
"350705": "シフォン(10周年)",
|
||||||
|
"350706": "ソルト(10周年)",
|
||||||
|
"350707": "乙姫(10周年)",
|
||||||
|
"350708": "みるく(10周年)",
|
||||||
|
"350709": "しゃま(10周年)",
|
||||||
|
"350710": "maimaiちゃん(10周年)",
|
||||||
|
"350711": "はっぴー(10周年)",
|
||||||
|
"350712": "カメ(10周年)",
|
||||||
|
"350713": "タイ(10周年)",
|
||||||
|
"350714": "ニャイン(10周年)",
|
||||||
|
"350715": "ナカムラさん(10周年)",
|
||||||
|
"350716": "ブクロ(10周年)",
|
||||||
|
"350717": "maimai筐体",
|
||||||
|
"350718": "maimai筐体(GreeN)",
|
||||||
|
"350719": "maimai筐体(ORANGE)",
|
||||||
|
"350720": "maimai筐体(PiNK)",
|
||||||
|
"350721": "maimai筐体(MURASAKi)",
|
||||||
|
"350722": "maimai筐体(MiLK)",
|
||||||
|
"350723": "maimai筐体(FiNALE)",
|
||||||
|
"350724": "maimai筐体(でらっくす)",
|
||||||
|
"350725": "maimai筐体(Splash)",
|
||||||
|
"350726": "maimai筐体(UNiVERSE)",
|
||||||
|
"350727": "maimai筐体(FESTiVAL)",
|
||||||
|
"355101": "田中ヒメ",
|
||||||
|
"355102": "田中ヒメ(藍の華)",
|
||||||
|
"355103": "田中ヒメ(希織歌)",
|
||||||
|
"355104": "鈴木ヒナ",
|
||||||
|
"355105": "鈴木ヒナ(藍の華)",
|
||||||
|
"355106": "鈴木ヒナ(希織歌)",
|
||||||
|
"355201": "シスター(神っぽいな)",
|
||||||
|
"355202": "魔法少女(魔法少女とチョコレゐト)",
|
||||||
|
"355203": "アイマイナ",
|
||||||
|
"355204": "どうしてちゃん",
|
||||||
|
"355205": "アルティメットセンパイ",
|
||||||
|
"355206": "ピノキオピー",
|
||||||
|
"355301": "リン(ベーシスト)",
|
||||||
|
"355302": "リン(不良少女)",
|
||||||
|
"355303": "ブロウ(パイロット)",
|
||||||
|
"355304": "ブロウ(ゾンビガール)",
|
||||||
|
"355305": "マリヤ(バイオリニスト)",
|
||||||
|
"355306": "マリヤ(小悪魔)",
|
||||||
|
"355307": "リン(ニャ宇宙!)",
|
||||||
|
"355308": "ブロウ(ニャ宇宙!)",
|
||||||
|
"355309": "マリヤ(ニャ宇宙!)",
|
||||||
|
"355401": "明坂 芹菜(東方Project:射命丸 文)",
|
||||||
|
"355402": "御形 アリシアナ(東方Project:小野塚 小町)",
|
||||||
|
"355403": "天王洲 なずな(東方Project:風見 幽香)",
|
||||||
|
"355404": "小仏 凪(東方Project:四季映姫・ヤマザナドゥ)",
|
||||||
|
"355405": "箱部 なる(東方Project:チルノ ウソテイver.)",
|
||||||
|
"355406": "月鈴 那知(東方Project:因幡 てゐ)",
|
||||||
|
"355407": "月鈴 白奈(東方Project:鈴仙・優曇華院・イナバ)",
|
||||||
|
"355408": "明坂 芹菜(東方Project:蓬莱山 輝夜)",
|
||||||
|
"355409": "御形 アリシアナ(東方Project:八意 永琳)",
|
||||||
|
"355410": "天王洲 なずな(東方Project:因幡 てゐ)",
|
||||||
|
"355411": "小仏 凪(東方Project:博麗 霊夢)",
|
||||||
|
"355412": "箱部 なる(東方Project:チルノ)",
|
||||||
|
"355413": "月鈴 那知(東方Project:伊吹 萃香)",
|
||||||
|
"355414": "月鈴 白奈(東方Project:霧雨 魔理沙)",
|
||||||
|
"355501": "御伽野ひめ",
|
||||||
|
"355502": "ハイテックニンジャ",
|
||||||
|
"355503": "ぱんしー",
|
||||||
|
"355504": "まめゆ",
|
||||||
|
"355505": "ダッコ & パンセ",
|
||||||
|
"355506": "ナーガ・ネギ",
|
||||||
|
"355507": "ネコらぴす",
|
||||||
|
"355508": "ネコまめゆねこ",
|
||||||
|
"355509": "ネコぽよし",
|
||||||
|
"355510": "ジン・スサノ",
|
||||||
|
"355511": "MEGAREX",
|
||||||
|
"355512": "DJPoyoshi",
|
||||||
|
"355513": "lapix",
|
||||||
|
"355514": "rejection",
|
||||||
|
"355515": "Zekk",
|
||||||
|
"355516": "DJ勝也",
|
||||||
|
"355517": "Mameyudoufu",
|
||||||
|
"355518": "Blacklolita",
|
||||||
|
"355519": "YUKIYANAGI",
|
||||||
|
"355601": "ねこ",
|
||||||
|
"355602": "ぐるん",
|
||||||
|
"355603": "ペンギン",
|
||||||
|
"355604": "ウーパールーパー",
|
||||||
|
"355605": "デンゲンくん",
|
||||||
|
"355606": "うさぎくん",
|
||||||
|
"355607": "いぬくん",
|
||||||
|
"355608": "あんはっぴーちゃん",
|
||||||
|
"355609": "野生のでらっくま",
|
||||||
|
"355610": "右肩",
|
||||||
|
"355611": "真ん中",
|
||||||
|
"355612": "左肩",
|
||||||
|
"355701": "可不",
|
||||||
|
"355702": "可不(花となれ)",
|
||||||
|
"355703": "可不(私のドッペルゲンガー)",
|
||||||
|
"355801": "星咲 あかり(STARRED HEART)",
|
||||||
|
"355802": "結城 莉玖(STARRED HEART)",
|
||||||
|
"355803": "珠洲島 有栖(STARRED HEART)",
|
||||||
|
"355804": "九條 楓(STARRED HEART)",
|
||||||
|
"355805": "東雲 つむぎ(STARRED HEART)",
|
||||||
|
"355806": "逢坂 茜(シュータードレス)",
|
||||||
|
"355807": "珠洲島 有栖(シュータードレス)",
|
||||||
|
"355808": "九條 楓(シュータードレス)",
|
||||||
|
"355809": "皇城 セツナ(シュータードレス)",
|
||||||
|
"400101": "乙姫(ばでぃーず)",
|
||||||
|
"400102": "ラズ(ばでぃーず)",
|
||||||
|
"400103": "SDダンディ・ダン",
|
||||||
|
"400104": "SD亀",
|
||||||
|
"400105": "SD鯛",
|
||||||
|
"400106": "SD光吉 猛修",
|
||||||
|
"400107": "しゃま(Party☆People☆Princess)",
|
||||||
|
"400108": "みるく(Party☆People☆Princess)",
|
||||||
|
"400201": "プロトタイプI",
|
||||||
|
"400202": "ケファ",
|
||||||
|
"400203": "バルトルメ",
|
||||||
|
"400204": "マトフェイ",
|
||||||
|
"400205": "黒姫",
|
||||||
|
"400301": "ノア",
|
||||||
|
"400302": "ソウ",
|
||||||
|
"400303": "トキヤ",
|
||||||
|
"400304": "ナノハ",
|
||||||
|
"400305": "ユウキ",
|
||||||
|
"400401": "リズ",
|
||||||
|
"400402": "フルーンシュピラー",
|
||||||
|
"400403": "シュヴァルツローゼ",
|
||||||
|
"400404": "ヘルブラオ",
|
||||||
|
"400405": "アシッド(幼少期)",
|
||||||
|
"400601": "フィッツ公",
|
||||||
|
"400602": "マティルダ",
|
||||||
|
"400603": "クリーノス",
|
||||||
|
"400604": "クリーノス(天使)",
|
||||||
|
"400605": "リッツ(悪魔)",
|
||||||
|
"405101": "くらりちゃん",
|
||||||
|
"405102": "いまわさん",
|
||||||
|
"405103": "1000年ちゃん",
|
||||||
|
"405104": "足立レイ",
|
||||||
|
"405105": "いよわ",
|
||||||
|
"405201": "リンカ",
|
||||||
|
"405202": "セイネ",
|
||||||
|
"405203": "ユメ",
|
||||||
|
"405204": "ユウ",
|
||||||
|
"405205": "グルーヴコースター筐体",
|
||||||
|
"405206": "HEADPHONE CRAB",
|
||||||
|
"405301": "茅森月歌",
|
||||||
|
"405302": "和泉ユキ",
|
||||||
|
"405303": "逢川めぐみ",
|
||||||
|
"405304": "東城つかさ",
|
||||||
|
"405305": "朝倉可憐",
|
||||||
|
"405306": "國見タマ",
|
||||||
|
"405307": "蒼井えりか",
|
||||||
|
"405308": "水瀬いちご",
|
||||||
|
"405309": "水瀬すもも",
|
||||||
|
"405310": "樋口聖華",
|
||||||
|
"405311": "柊木梢",
|
||||||
|
"405312": "ビャッコ",
|
||||||
|
"405313": "七瀬七海",
|
||||||
|
"405401": "エリザベス",
|
||||||
|
"405402": "リリィ",
|
||||||
|
"405403": "ルーン",
|
||||||
|
"405404": "【裏】ルーン",
|
||||||
|
"405405": "WACCA筐体",
|
||||||
|
"405601": "sasakure.UK",
|
||||||
|
"405602": "テラ(トンデモワンダーズ)",
|
||||||
|
"405603": "カラス(トンデモワンダーズ)",
|
||||||
|
"405604": "初音ミク(*ハロー、プラネット。)",
|
||||||
|
"409505": "旅行スタンプ(月面基地)",
|
||||||
|
"405701": "TJ.hangneil",
|
||||||
|
"405702": "男の子(神威)",
|
||||||
|
"405703": "女の子(神威)",
|
||||||
|
"405901": "宇宙飛行士(Apollo)",
|
||||||
|
"409506": "旅行スタンプ(???)",
|
||||||
|
"406101": "東北ずん子",
|
||||||
|
"406102": "東北ずん子(チア)",
|
||||||
|
"406103": "東北イタコ",
|
||||||
|
"406104": "東北イタコ(チア)",
|
||||||
|
"406105": "東北きりたん",
|
||||||
|
"406106": "東北きりたん(チア)",
|
||||||
|
"406107": "四国めたん",
|
||||||
|
"406108": "九州そら",
|
||||||
|
"406109": "ずんだもん",
|
||||||
|
"406201": "縁",
|
||||||
|
"406202": "冴川 芽依",
|
||||||
|
"406203": "ロト・トゥエルヴ",
|
||||||
|
"406204": "不来方 とあ",
|
||||||
|
"406205": "ヴェルゼビュートネメシス",
|
||||||
|
"406206": "リヒトシュッツェ",
|
||||||
|
"409501": "BUDDiES",
|
||||||
|
"409502": "共に走る",
|
||||||
|
"409503": "女の子",
|
||||||
|
"409504": "かわいい女の子"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"version": "Ver.CN 1.40",
|
||||||
|
"date": "1970-01-01 00:00:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
2963
nonebot_plugin_maimai_helper/game_data/music_alias_list.json
Normal file
2963
nonebot_plugin_maimai_helper/game_data/music_alias_list.json
Normal file
File diff suppressed because it is too large
Load Diff
12886
nonebot_plugin_maimai_helper/game_data/music_list.json
Normal file
12886
nonebot_plugin_maimai_helper/game_data/music_list.json
Normal file
File diff suppressed because it is too large
Load Diff
28
nonebot_plugin_maimai_helper/game_data/partner_list.json
Normal file
28
nonebot_plugin_maimai_helper/game_data/partner_list.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"1": "でらっくま",
|
||||||
|
"17": "らいむっくま&れもんっくま",
|
||||||
|
"11": "乙姫",
|
||||||
|
"12": "ラズ",
|
||||||
|
"13": "シフォン",
|
||||||
|
"14": "ソルト",
|
||||||
|
"15": "しゃま",
|
||||||
|
"16": "みるく",
|
||||||
|
"18": "乙姫(すぷらっしゅ)",
|
||||||
|
"19": "しゃま(ゆにばーす)",
|
||||||
|
"20": "みるく(ゆにばーす)",
|
||||||
|
"21": "ちびみるく",
|
||||||
|
"22": "百合咲ミカ",
|
||||||
|
"23": "ラズ(ふぇすてぃばる)",
|
||||||
|
"24": "シフォン(ふぇすてぃばる)",
|
||||||
|
"25": "ソルト(ふぇすてぃばる)",
|
||||||
|
"26": "黒姫",
|
||||||
|
"27": "ずんだもん",
|
||||||
|
"28": "乙姫(ばでぃーず)",
|
||||||
|
"29": "らいむっくま&れもんっくま(ばでぃーず)"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"version": "Ver.CN 1.40",
|
||||||
|
"date": "1970-01-01 00:00:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
267
nonebot_plugin_maimai_helper/game_data/plate_list.json
Normal file
267
nonebot_plugin_maimai_helper/game_data/plate_list.json
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"1": "デフォルト",
|
||||||
|
"11": "maimai でらっくす",
|
||||||
|
"250051": "真初段",
|
||||||
|
"250052": "真二段",
|
||||||
|
"250053": "真三段",
|
||||||
|
"250054": "真四段",
|
||||||
|
"250055": "真五段",
|
||||||
|
"250056": "真六段",
|
||||||
|
"250057": "真七段",
|
||||||
|
"250058": "真八段",
|
||||||
|
"250059": "真九段",
|
||||||
|
"250060": "真十段",
|
||||||
|
"101": "はじまりのちほー",
|
||||||
|
"201": "青春ちほー",
|
||||||
|
"301": "でらっくすちほー caféMiLK",
|
||||||
|
"302": "でらっくすちほー 竜宮茶館",
|
||||||
|
"303": "でらっくすちほー おしゃま牛乳",
|
||||||
|
"401": "メトロポリスちほー",
|
||||||
|
"501": "ドラゴンちほー",
|
||||||
|
"601": "天界ちほー",
|
||||||
|
"701": "BLACK ROSEちほー",
|
||||||
|
"3301": "GYARIちほー",
|
||||||
|
"3501": "Project DIVAちほー",
|
||||||
|
"3901": "からめるちほー",
|
||||||
|
"3401": "東方Projectちほー",
|
||||||
|
"4001": "イロドリミドリちほー",
|
||||||
|
"4201": "結月ゆかりちほー",
|
||||||
|
"50101": "はじまりのちほー2",
|
||||||
|
"50201": "メトロポリスちほー2 イーシュ襲来",
|
||||||
|
"50301": "メトロポリスちほー2 黒姫の逆襲",
|
||||||
|
"50401": "みかんヶ岡ちほー 朝焼け通り",
|
||||||
|
"50501": "みかんヶ岡ちほー 月夜通り",
|
||||||
|
"50601": "天界ちほー2",
|
||||||
|
"50701": "HAPPYYYY DX",
|
||||||
|
"50702": "maimai 集合",
|
||||||
|
"50703": "maimai しゃまみるく",
|
||||||
|
"50801": "黒薔薇病患者の内面",
|
||||||
|
"50901": "ヒュド・ルー/ルイの二面性",
|
||||||
|
"53301": "オンゲキちほー",
|
||||||
|
"53401": "#コンパスちほー",
|
||||||
|
"53601": "ポンコツクエストちほー",
|
||||||
|
"53701": "Project DIVAちほー2",
|
||||||
|
"53901": "東方Project×アトレ秋葉原ちほー",
|
||||||
|
"100101": "しゅわしゅわちほー",
|
||||||
|
"100301": "メトロポリスちほー3",
|
||||||
|
"100401": "スカイストリートちほー",
|
||||||
|
"100501": "天界ちほー3",
|
||||||
|
"100601": "BLACK ROSEちほー3",
|
||||||
|
"100701": "しゅわっしゅわ! ~りゅうぐう~",
|
||||||
|
"100702": "しゅわっしゅわ! ~かふぇみるく~",
|
||||||
|
"100703": "しゅわっしゅわ! ~しゃまみるく~",
|
||||||
|
"105301": "ナユタン星人ちほー",
|
||||||
|
"105401": "GYARIちほー2",
|
||||||
|
"105501": "東方Projectリバイバルちほー",
|
||||||
|
"105601": "Arcaeaちほー",
|
||||||
|
"105701": "かいりきベアちほー",
|
||||||
|
"105901": "にじさんじちほー",
|
||||||
|
"106001": "いらすとやちほー",
|
||||||
|
"106101": "オンゲキちほー2",
|
||||||
|
"150101": "しゅわしゅわちほー2",
|
||||||
|
"150201": "BLACK ROSEちほー4",
|
||||||
|
"150301": "スカイストリートちほー2",
|
||||||
|
"150401": "kawaiiちほー",
|
||||||
|
"150501": "高天原ちほー",
|
||||||
|
"150601": "約束のしゅわーランド",
|
||||||
|
"150602": "ぱりぴっくま",
|
||||||
|
"150603": "はっぴーばかんす",
|
||||||
|
"155201": "すみっコぐらしちほー",
|
||||||
|
"155301": "HaNaMiNaちほー",
|
||||||
|
"155401": "HARDCORE TANO*Cちほー",
|
||||||
|
"155501": "東方Projectリバイバルちほー2",
|
||||||
|
"155901": "はるまきごはんちほー",
|
||||||
|
"156001": "オンゲキちほー3",
|
||||||
|
"200101": "宇宙すてーしょんちほー",
|
||||||
|
"200201": "天界ちほー4",
|
||||||
|
"200301": "メトロポリスちほー4",
|
||||||
|
"200401": "7sRefちほー",
|
||||||
|
"200501": "ユニバースちほー",
|
||||||
|
"200502": "でらっくmaimai♪てんてこまい!",
|
||||||
|
"200503": "絡めトリック利己ライザー",
|
||||||
|
"200601": "BLACK ROSEちほー5",
|
||||||
|
"205101": "アイドルマスター ミリオンライブ!ちほー",
|
||||||
|
"205201": "アイドルマスター SideMちほー",
|
||||||
|
"205301": "cosMo@暴走Pちほー",
|
||||||
|
"205401": "オーイシ×加藤のピザラジオちほー",
|
||||||
|
"205501": "東方ダンマクカグラちほー",
|
||||||
|
"205601": "キノシタちほー",
|
||||||
|
"205901": "Rain Dropsちほー",
|
||||||
|
"206101": "Project DIVAちほー3",
|
||||||
|
"206201": "オンゲキちほー4",
|
||||||
|
"206301": "舞ヶ原シンセ研究会ちほー",
|
||||||
|
"209502": "はっぴー(ゆにばーす)",
|
||||||
|
"250101": "宇宙すてーしょんちほー2",
|
||||||
|
"250201": "メトロポリスちほー5",
|
||||||
|
"250301": "天界ちほー5",
|
||||||
|
"250401": "7sRefちほー2",
|
||||||
|
"250501": "ユニバースちほー2",
|
||||||
|
"250601": "BLACK ROSEちほー6",
|
||||||
|
"255201": "ツユちほー",
|
||||||
|
"255301": "Photon Maiden",
|
||||||
|
"255302": "Lyrical Lily",
|
||||||
|
"255401": "Diverse Systemちほー",
|
||||||
|
"255501": "Rain Dropsちほー2",
|
||||||
|
"255601": "ゲームセンターCXちほー",
|
||||||
|
"255801": "CHUNITHMちほー",
|
||||||
|
"255901": "すりぃちほー",
|
||||||
|
"256001": "オンゲキちほー5",
|
||||||
|
"300101": "ハピフェスちほー",
|
||||||
|
"300201": "メトロポリスちほー6",
|
||||||
|
"300301": "スカイストリートちほー3",
|
||||||
|
"300401": "天界ちほー6",
|
||||||
|
"300501": "フェスティバルちほー",
|
||||||
|
"300601": "BLACK ROSEちほー7",
|
||||||
|
"305201": "DECO*27ちほー その1",
|
||||||
|
"305202": "DECO*27ちほー その2",
|
||||||
|
"305401": "東方Project×オンゲキちほー",
|
||||||
|
"305501": "さなちゃんねるちほー その1",
|
||||||
|
"305502": "さなちゃんねるちほー その2",
|
||||||
|
"305701": "樋口楓ちほー その1",
|
||||||
|
"305702": "樋口楓ちほー その2",
|
||||||
|
"305801": "外神田文芸高校 その1",
|
||||||
|
"305802": "帝音国際学院 その1",
|
||||||
|
"305803": "外神田文芸高校 その2",
|
||||||
|
"305804": "帝音国際学院 その2",
|
||||||
|
"305901": "CHUNITHMちほー2",
|
||||||
|
"306001": "syudouちほー",
|
||||||
|
"306101": "Arcaeaちほー2",
|
||||||
|
"350101": "ハピフェスちほー2",
|
||||||
|
"350301": "スカイストリートちほー4",
|
||||||
|
"350401": "ドラゴンちほー2",
|
||||||
|
"350501": "フェスティバルちほー2",
|
||||||
|
"350601": "BLACK ROSEちほー8",
|
||||||
|
"350701": "10周年記念ちほー2",
|
||||||
|
"355101": "ヒメヒナちほー",
|
||||||
|
"355201": "ピノキオピーちほー",
|
||||||
|
"355301": "Muse Dashちほー",
|
||||||
|
"355501": "MEGAREXちほー",
|
||||||
|
"355401": "東方Project×イロドリミドリちほー その1",
|
||||||
|
"355402": "東方Project×イロドリミドリちほー その2",
|
||||||
|
"355403": "東方Project×イロドリミドリちほー その3",
|
||||||
|
"355601": "からめるちほー2 その1",
|
||||||
|
"355602": "からめるちほー2 その2",
|
||||||
|
"355603": "からめるちほー2 その3",
|
||||||
|
"355604": "からめるちほー2 その4",
|
||||||
|
"409501": "ねこCOOL",
|
||||||
|
"409502": "ウーパールーパー",
|
||||||
|
"409503": "みんないるよ",
|
||||||
|
"409504": "まいまいネ申",
|
||||||
|
"409505": "業界に\"ゲキシン\"が走る卵焼き",
|
||||||
|
"409506": "USM二人三脚",
|
||||||
|
"409507": "大量ねこクローン",
|
||||||
|
"409508": "ぐるん",
|
||||||
|
"409509": "ペンギン",
|
||||||
|
"355701": "音楽的同位体 可不ちほー",
|
||||||
|
"355801": "オンゲキちほー6",
|
||||||
|
"400101": "パーリィちほー",
|
||||||
|
"400201": "メトロポリスちほー7",
|
||||||
|
"400301": "スカイストリートちほー5",
|
||||||
|
"400401": "7sRefちほー3",
|
||||||
|
"400501": "バディーズちほー",
|
||||||
|
"400601": "BLACK ROSEちほー9",
|
||||||
|
"405101": "いよわちほー",
|
||||||
|
"405201": "グルーヴコースターちほー",
|
||||||
|
"405301": "ヘブンバーンズレッドちほー その1",
|
||||||
|
"405302": "ヘブンバーンズレッドちほー その2",
|
||||||
|
"405401": "WACCAちほー その1",
|
||||||
|
"405402": "WACCAちほー その2",
|
||||||
|
"405601": "sasakure.UKちほー その1",
|
||||||
|
"405602": "sasakure.UKちほー その2",
|
||||||
|
"405603": "sasakure.UKちほー その3",
|
||||||
|
"405604": "宇宙旅行券",
|
||||||
|
"405701": "TJ.hangneilちほー",
|
||||||
|
"406101": "東北ずん子ちほー その1",
|
||||||
|
"406102": "東北ずん子ちほー その2",
|
||||||
|
"406201": "CHUNITHMちほー3",
|
||||||
|
"6101": "真極",
|
||||||
|
"6102": "真神",
|
||||||
|
"6103": "真舞舞",
|
||||||
|
"6104": "超極",
|
||||||
|
"6105": "超将",
|
||||||
|
"6106": "超神",
|
||||||
|
"6107": "超舞舞",
|
||||||
|
"6108": "檄極",
|
||||||
|
"6109": "檄将",
|
||||||
|
"6110": "檄神",
|
||||||
|
"6111": "檄舞舞",
|
||||||
|
"6112": "橙極",
|
||||||
|
"6113": "橙将",
|
||||||
|
"6114": "橙神",
|
||||||
|
"6115": "橙舞舞",
|
||||||
|
"6116": "暁極",
|
||||||
|
"6117": "暁将",
|
||||||
|
"6118": "暁神",
|
||||||
|
"6119": "暁舞舞",
|
||||||
|
"6120": "桃極",
|
||||||
|
"6121": "桃将",
|
||||||
|
"6122": "桃神",
|
||||||
|
"6123": "桃舞舞",
|
||||||
|
"6124": "櫻極",
|
||||||
|
"6125": "櫻将",
|
||||||
|
"6126": "櫻神",
|
||||||
|
"6127": "櫻舞舞",
|
||||||
|
"6128": "紫極",
|
||||||
|
"6129": "紫将",
|
||||||
|
"6130": "紫神",
|
||||||
|
"6131": "紫舞舞",
|
||||||
|
"6132": "菫極",
|
||||||
|
"6133": "菫将",
|
||||||
|
"6134": "菫神",
|
||||||
|
"6135": "菫舞舞",
|
||||||
|
"6136": "白極",
|
||||||
|
"6137": "白将",
|
||||||
|
"6138": "白神",
|
||||||
|
"6139": "白舞舞",
|
||||||
|
"6140": "雪極",
|
||||||
|
"6141": "雪将",
|
||||||
|
"6142": "雪神",
|
||||||
|
"6143": "雪舞舞",
|
||||||
|
"6144": "輝極",
|
||||||
|
"6145": "輝将",
|
||||||
|
"6146": "輝神",
|
||||||
|
"6147": "輝舞舞",
|
||||||
|
"6148": "覇者",
|
||||||
|
"6149": "舞極",
|
||||||
|
"6150": "舞将",
|
||||||
|
"6151": "舞神",
|
||||||
|
"6152": "舞舞舞",
|
||||||
|
"55101": "熊極",
|
||||||
|
"55102": "熊将",
|
||||||
|
"55103": "熊神",
|
||||||
|
"55104": "熊舞舞",
|
||||||
|
"109101": "華極",
|
||||||
|
"109102": "華将",
|
||||||
|
"109103": "華神",
|
||||||
|
"109104": "華舞舞",
|
||||||
|
"159101": "爽極",
|
||||||
|
"159102": "爽将",
|
||||||
|
"159103": "爽神",
|
||||||
|
"159104": "爽舞舞",
|
||||||
|
"209101": "煌極",
|
||||||
|
"209102": "煌将",
|
||||||
|
"209103": "煌神",
|
||||||
|
"209104": "煌舞舞",
|
||||||
|
"259101": "宙極",
|
||||||
|
"259102": "宙将",
|
||||||
|
"259103": "宙神",
|
||||||
|
"259104": "宙舞舞",
|
||||||
|
"309101": "星極",
|
||||||
|
"309102": "星将",
|
||||||
|
"309103": "星神",
|
||||||
|
"309104": "星舞舞",
|
||||||
|
"359101": "祭極",
|
||||||
|
"359102": "祭将",
|
||||||
|
"359103": "祭神",
|
||||||
|
"359104": "祭舞舞",
|
||||||
|
"409101": "祝極",
|
||||||
|
"409102": "祝将",
|
||||||
|
"409103": "祝神",
|
||||||
|
"409104": "祝舞舞"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"version": "Ver.CN 1.40",
|
||||||
|
"date": "1970-01-01 00:00:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
8624
nonebot_plugin_maimai_helper/game_data/title_list.json
Normal file
8624
nonebot_plugin_maimai_helper/game_data/title_list.json
Normal file
File diff suppressed because it is too large
Load Diff
0
nonebot_plugin_maimai_helper/helper/__init__.py
Normal file
0
nonebot_plugin_maimai_helper/helper/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
47
nonebot_plugin_maimai_helper/helper/convert.py
Normal file
47
nonebot_plugin_maimai_helper/helper/convert.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import cv2
|
||||||
|
from pyzbar.pyzbar import decode
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.setrecursionlimit(3000) # 增加最大递归深度
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 配置日
|
||||||
|
def convert_to_grayscale(image_path: str) -> str:
|
||||||
|
"""
|
||||||
|
将输入图片转换为灰度图并保存
|
||||||
|
:param image_path: 输入图片的路径
|
||||||
|
:return: 灰度图的保存路径
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 读取图片
|
||||||
|
image = cv2.imread(image_path)
|
||||||
|
if image is None:
|
||||||
|
print(f"无法读取图片: {image_path}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 转换为灰度图
|
||||||
|
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
||||||
|
|
||||||
|
# 保存灰度图
|
||||||
|
gray_image_path = image_path.replace(".jpg", "_gray.jpg").replace(".png", "_gray.png")
|
||||||
|
cv2.imwrite(gray_image_path, gray_image)
|
||||||
|
print(f"灰度图已保存到 {gray_image_path}")
|
||||||
|
return gray_image_path
|
||||||
|
except Exception as e:
|
||||||
|
print(f"转换为灰度图时发生错误: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# 输入图片路径
|
||||||
|
image_path = input("请输入图片的路径: ")
|
||||||
|
|
||||||
|
# 转换为灰度图
|
||||||
|
gray_image_path = convert_to_grayscale(image_path)
|
||||||
|
if gray_image_path:
|
||||||
|
print(f"灰度图已保存到 {gray_image_path}")
|
||||||
|
else:
|
||||||
|
print("无法转换为灰度图")
|
||||||
89
nonebot_plugin_maimai_helper/helper/diving_fish.py
Normal file
89
nonebot_plugin_maimai_helper/helper/diving_fish.py
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from nonebot_plugin_maimai_helper.data import root_path
|
||||||
|
|
||||||
|
URL = "https://www.diving-fish.com/api/maimaidxprober/player/update_records"
|
||||||
|
|
||||||
|
|
||||||
|
def sega_data_pre_format(sega_data):
|
||||||
|
with open(root_path + '/game_data/diving_music_list.json', 'r', encoding='utf-8') as file:
|
||||||
|
music_list = json.load(file)
|
||||||
|
for old in sega_data:
|
||||||
|
old['title'] = None
|
||||||
|
old['type'] = None
|
||||||
|
for music in music_list:
|
||||||
|
if music['id'] == f"{old['musicId']}":
|
||||||
|
old['title'] = music['title']
|
||||||
|
old['type'] = music['type']
|
||||||
|
if old['comboStatus'] == 0:
|
||||||
|
old['comboStatus'] = ""
|
||||||
|
elif old['comboStatus'] == 1:
|
||||||
|
old['comboStatus'] = "fc"
|
||||||
|
elif old['comboStatus'] == 2:
|
||||||
|
old['comboStatus'] = "fcp"
|
||||||
|
elif old['comboStatus'] == 3:
|
||||||
|
old['comboStatus'] = "ap"
|
||||||
|
elif old['comboStatus'] == 4:
|
||||||
|
old['comboStatus'] = "app"
|
||||||
|
else:
|
||||||
|
old['comboStatus'] = ""
|
||||||
|
if old['syncStatus'] == 0:
|
||||||
|
old['syncStatus'] = ""
|
||||||
|
elif old['syncStatus'] == 1:
|
||||||
|
old['syncStatus'] = "fs"
|
||||||
|
elif old['syncStatus'] == 2:
|
||||||
|
old['syncStatus'] = "fsp"
|
||||||
|
elif old['syncStatus'] == 3:
|
||||||
|
old['syncStatus'] = "fsd"
|
||||||
|
elif old['syncStatus'] == 4:
|
||||||
|
old['syncStatus'] = "fsdp"
|
||||||
|
elif old['syncStatus'] == 5:
|
||||||
|
old['syncStatus'] = "sync"
|
||||||
|
else:
|
||||||
|
old['syncStatus'] = ""
|
||||||
|
return sega_data
|
||||||
|
|
||||||
|
|
||||||
|
def change_data(sega_data):
|
||||||
|
sega_data = sega_data_pre_format(sega_data)
|
||||||
|
print(sega_data)
|
||||||
|
diving_fish_data = []
|
||||||
|
count = 0
|
||||||
|
for old in sega_data:
|
||||||
|
if old['title'] == None:
|
||||||
|
continue
|
||||||
|
diving_fish_data.append({
|
||||||
|
"achievements": old['achievement'] / 10000.0,
|
||||||
|
"dxScore": old['deluxscoreMax'],
|
||||||
|
"fc": old['comboStatus'],
|
||||||
|
"fs": old['syncStatus'],
|
||||||
|
"level_index": old['level'],
|
||||||
|
"title": old['title'],
|
||||||
|
"type": old['type'],
|
||||||
|
})
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
return diving_fish_data, count
|
||||||
|
|
||||||
|
|
||||||
|
def send_user_data(data, token):
|
||||||
|
back = {"status": None, "msg": None}
|
||||||
|
data = json.dumps(data, ensure_ascii=False)
|
||||||
|
print(data)
|
||||||
|
headers = {
|
||||||
|
"Import-Token": token,
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
request = requests.post(URL, headers=headers, data=data.encode('utf-8'))
|
||||||
|
request.encoding = 'utf-8'
|
||||||
|
back['status'] = request.status_code
|
||||||
|
back['msg'] = json.loads(request.text)
|
||||||
|
return back
|
||||||
|
except Exception as e:
|
||||||
|
back['status'] = 0
|
||||||
|
back['msg'] = str(e)
|
||||||
|
return back
|
||||||
|
|
||||||
|
|
||||||
45
nonebot_plugin_maimai_helper/helper/download.py
Normal file
45
nonebot_plugin_maimai_helper/helper/download.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import httpx
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
# 配置日志
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def download_image(url: str, save_path: str):
|
||||||
|
"""
|
||||||
|
使用 httpx 下载图片并保存到本地
|
||||||
|
:param url: 图片的 URL
|
||||||
|
:param save_path: 保存图片的本地路径
|
||||||
|
:return: 保存的文件路径或 None(失败时)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 发起 HTTP GET 请求
|
||||||
|
with httpx.Client() as client:
|
||||||
|
response = client.get(url)
|
||||||
|
if response.status_code == 200:
|
||||||
|
# 确保保存路径的目录存在
|
||||||
|
os.makedirs(os.path.dirname(save_path), exist_ok=True)
|
||||||
|
# 保存图片到本地
|
||||||
|
with open(save_path, "wb") as f:
|
||||||
|
f.write(response.content)
|
||||||
|
logger.info(f"图片已保存到 {save_path}")
|
||||||
|
return save_path
|
||||||
|
else:
|
||||||
|
logger.warning(f"下载失败,状态码: {response.status_code}")
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"下载图片时发生错误: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# 示例用法
|
||||||
|
image_url = input("请输入图片的 URL: ")
|
||||||
|
save_path = input("请输入保存路径(例如 E:/img/test.png): ")
|
||||||
|
|
||||||
|
result = download_image(image_url, save_path)
|
||||||
|
if result:
|
||||||
|
print(f"图片已成功保存到 {result}")
|
||||||
|
else:
|
||||||
|
print("下载图片失败,请检查 URL 和路径是否正确。")
|
||||||
45
nonebot_plugin_maimai_helper/helper/qrcode.py
Normal file
45
nonebot_plugin_maimai_helper/helper/qrcode.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import cv2
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.setrecursionlimit(5000)
|
||||||
|
|
||||||
|
|
||||||
|
def decode_qr_code(image_path: str) -> str:
|
||||||
|
"""
|
||||||
|
使用 OpenCV 识别二维码并返回内容
|
||||||
|
:param image_path: 输入图片的路径
|
||||||
|
:return: 二维码的内容
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 读取图片
|
||||||
|
image = cv2.imread(image_path)
|
||||||
|
if image is None:
|
||||||
|
print(f"无法读取图片: {image_path}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 创建 QRCodeDetector 对象
|
||||||
|
qr_code_detector = cv2.QRCodeDetector()
|
||||||
|
|
||||||
|
# 解码二维码
|
||||||
|
data, points, straight_qrcode = qr_code_detector.detectAndDecode(image)
|
||||||
|
if data:
|
||||||
|
print(f"二维码内容: {data}")
|
||||||
|
return data
|
||||||
|
else:
|
||||||
|
print("未找到二维码")
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"解码二维码时发生错误: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# 输入图片路径
|
||||||
|
image_path = input("请输入图片的路径: ")
|
||||||
|
|
||||||
|
# 识别二维码
|
||||||
|
qr_code_content = decode_qr_code(image_path)
|
||||||
|
if qr_code_content:
|
||||||
|
print(f"二维码内容: {qr_code_content}")
|
||||||
|
else:
|
||||||
|
print("无法识别二维码")
|
||||||
499
nonebot_plugin_maimai_helper/helper/simai.py
Normal file
499
nonebot_plugin_maimai_helper/helper/simai.py
Normal file
@@ -0,0 +1,499 @@
|
|||||||
|
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
|
||||||
0
nonebot_plugin_maimai_helper/img/__init__.py
Normal file
0
nonebot_plugin_maimai_helper/img/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
512
nonebot_plugin_maimai_helper/img/generate_img.py
Normal file
512
nonebot_plugin_maimai_helper/img/generate_img.py
Normal file
@@ -0,0 +1,512 @@
|
|||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import math
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import nonebot
|
||||||
|
import colorsys
|
||||||
|
from PIL import Image, ImageDraw, ImageFont, ImageFilter
|
||||||
|
from nonebot_plugin_maimai_helper.helper.simai import *
|
||||||
|
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message , MessageSegment
|
||||||
|
from nonebot_plugin_maimai_helper.util.utils import *
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
config = nonebot.get_driver().config
|
||||||
|
maimaiImgPath = getattr(config, 'user_imgpath', 'E:/res/images') + '/'
|
||||||
|
materialPath = getattr(config, 'user_fontpath', 'E:/res/material') + '/'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_preview(event: GroupMessageEvent):
|
||||||
|
result = {"is_success": False, "is_error": False, "user_id": 0, "data": {}, "msg_body": "",
|
||||||
|
"is_in_whitelist": False, "is_got_qr_code": False}
|
||||||
|
user_qq = event.get_user_id()
|
||||||
|
user_id = None
|
||||||
|
if is_userid_exist(user_qq):
|
||||||
|
user_id = get_userid(user_qq)
|
||||||
|
else:
|
||||||
|
logger.error("查无此人")
|
||||||
|
if user_id != -1:
|
||||||
|
data = get_preview_detailed(user_id)
|
||||||
|
if data["is_got_qr_code"]:
|
||||||
|
user_preview = data
|
||||||
|
else:
|
||||||
|
logger.error("用户未获取二维码")
|
||||||
|
result["msg_body"] = "请在微信「舞萌 | 中二」公众号上点击一次「玩家二维码」按钮后再试一遍吧~"
|
||||||
|
logger.error("获取用户数据失败")
|
||||||
|
user_preview = user_preview
|
||||||
|
return user_preview, result
|
||||||
|
|
||||||
|
user_data = {
|
||||||
|
"nickname": {get_user_preview['user_preview']['userName']},
|
||||||
|
"title": {get_user_preview['user_preview']['titleName']},
|
||||||
|
"icon": {get_user_preview['user_preview']['iconId']},
|
||||||
|
"frame": {get_user_preview['user_preview']['frameId']},
|
||||||
|
"plate": {get_user_preview['user_preview']['plateId']},
|
||||||
|
"rating": {get_user_preview['user_preview']['playerRating']},
|
||||||
|
"classRank": 5,
|
||||||
|
"courseRank": 8,
|
||||||
|
"titleRare": {get_user_preview['user_preview']['titleRare']},
|
||||||
|
"chara": {get_user_preview['user_preview']['charaId']},
|
||||||
|
"charaLevel": {get_user_preview['user_preview']['charaLevel']},
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_star_info(level):
|
||||||
|
# 定义星级觉醒的等级区间
|
||||||
|
awakening_levels = [9, 49, 99, 299, 999, 9999]
|
||||||
|
max_stars = len(awakening_levels)
|
||||||
|
|
||||||
|
# 计算当前星级
|
||||||
|
current_star = 0
|
||||||
|
for awakening_level in awakening_levels:
|
||||||
|
if level >= awakening_level:
|
||||||
|
current_star += 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
# 如果已经满星
|
||||||
|
if current_star == max_stars:
|
||||||
|
return current_star, 100
|
||||||
|
|
||||||
|
# 计算距离下一星级的百分比
|
||||||
|
current_awakening_level = awakening_levels[current_star - 1] if current_star > 0 else 0
|
||||||
|
next_awakening_level = awakening_levels[current_star]
|
||||||
|
progress = (level - current_awakening_level) / (next_awakening_level - current_awakening_level) * 100
|
||||||
|
|
||||||
|
return current_star, int((progress // 10) * 10)
|
||||||
|
|
||||||
|
def circle_corner(img, radii=30):
|
||||||
|
# 白色区域透明可见,黑色区域不可见
|
||||||
|
circle = Image.new('L', (radii * 2, radii * 2), 0)
|
||||||
|
draw = ImageDraw.Draw(circle)
|
||||||
|
draw.ellipse((0, 0, radii * 2, radii * 2), fill=255)
|
||||||
|
|
||||||
|
img = img.convert("RGBA")
|
||||||
|
w, h = img.size
|
||||||
|
|
||||||
|
# 画角
|
||||||
|
alpha = Image.new('L', img.size, 255)
|
||||||
|
alpha.paste(circle.crop((0, 0, radii, radii)), (0, 0)) # 左上角
|
||||||
|
alpha.paste(circle.crop((radii, 0, radii * 2, radii)), (w - radii, 0)) # 右上角
|
||||||
|
alpha.paste(circle.crop((radii, radii, radii * 2, radii * 2)), (w - radii, h - radii)) # 右下角
|
||||||
|
alpha.paste(circle.crop((0, radii, radii, radii * 2)), (0, h - radii)) # 左下角
|
||||||
|
|
||||||
|
img.putalpha(alpha)
|
||||||
|
|
||||||
|
return img
|
||||||
|
|
||||||
|
def drawUserImg(title,totalRating,rankRating,userName,icon,plate,title_rare="Normal",classRank=-1):
|
||||||
|
UserImg = Image.new('RGBA', (724, 120))
|
||||||
|
|
||||||
|
plateImg = Image.open(plate).resize((720,116))
|
||||||
|
UserImg.paste(plateImg, (0, 2), plateImg)
|
||||||
|
|
||||||
|
iconImg = Image.open(icon).resize((100,100))
|
||||||
|
UserImg.paste(iconImg,(8,10),iconImg)
|
||||||
|
|
||||||
|
ratingPlateImg = Image.open(rf"{maimaiImgPath}/Rating/{getRatingBgImg(totalRating)}").resize((174,36))
|
||||||
|
UserImg.paste(ratingPlateImg, (110, 6), ratingPlateImg)
|
||||||
|
|
||||||
|
# 定义偏移量和初始x坐标
|
||||||
|
offset = 14
|
||||||
|
start_x = 250
|
||||||
|
x_positions = [start_x - i * offset for i in range(len(str(totalRating)))][:5]
|
||||||
|
|
||||||
|
# 根据totalRating的位数处理图片
|
||||||
|
for i, x_pos in enumerate(x_positions):
|
||||||
|
# 计算当前位上的数字
|
||||||
|
digit = int(totalRating / (10 ** i) % 10)
|
||||||
|
# 打开并调整图片大小
|
||||||
|
numImg = Image.open(rf"{maimaiImgPath}/num/UI_NUM_Drating_{digit}.png").resize((19, 23))
|
||||||
|
# 粘贴图片
|
||||||
|
UserImg.paste(numImg, (x_pos, 13), numImg)
|
||||||
|
|
||||||
|
if 25 >= int(classRank) >= 0:
|
||||||
|
classRankImg = Image.open(rf"{maimaiImgPath}/classRank/UI_CMN_Class_S_{int(classRank):02d}.png").resize((100, 60))
|
||||||
|
UserImg.paste(classRankImg, (284, -8), classRankImg)
|
||||||
|
|
||||||
|
|
||||||
|
UserIdImg = circle_corner(Image.new('RGBA', (270, 40), color=(255, 255, 255)),5)
|
||||||
|
UserIdDraw = ImageDraw.Draw(UserIdImg)
|
||||||
|
UserIdDraw.text((7, 8), f"{userName}", font=ImageFont.truetype(rf'{materialPath}/GenSenMaruGothicTW-Medium.ttf', 20),fill=(0, 0, 0))
|
||||||
|
UserImg.paste(UserIdImg, (113, 44), UserIdImg)
|
||||||
|
|
||||||
|
if 23 >= int(rankRating) >= 0:
|
||||||
|
rankImg = Image.open(rf"{maimaiImgPath}/Ranks/{int(rankRating)}.png").resize((94, 44))
|
||||||
|
UserImg.paste(rankImg, (290, 42), rankImg)
|
||||||
|
|
||||||
|
totalRatingImg = Image.open(rf"{maimaiImgPath}/shougou/UI_CMN_Shougou_{title_rare.title()}.png")
|
||||||
|
totalRatingDraw = ImageDraw.Draw(totalRatingImg)
|
||||||
|
font = ImageFont.truetype(rf'{materialPath}/GenSenMaruGothicTW-Bold.ttf', 14)
|
||||||
|
_, _, text_width, text_height = totalRatingDraw.textbbox((0, 0), title, font=font)
|
||||||
|
draw_text_with_stroke_and_spacing(
|
||||||
|
totalRatingDraw,
|
||||||
|
(abs(250-text_width)//2, 7),
|
||||||
|
title,
|
||||||
|
font=font,
|
||||||
|
fill_color="white",
|
||||||
|
stroke_width=2,
|
||||||
|
stroke_color='black',
|
||||||
|
spacing=1
|
||||||
|
)
|
||||||
|
UserImg.paste(totalRatingImg, (113, 83), totalRatingImg)
|
||||||
|
|
||||||
|
return UserImg
|
||||||
|
|
||||||
|
def _getCharWidth(o) -> int:
|
||||||
|
widths = [
|
||||||
|
(126, 1), (159, 0), (687, 1), (710, 0), (711, 1), (727, 0), (733, 1), (879, 0), (1154, 1), (1161, 0),
|
||||||
|
(4347, 1), (4447, 2), (7467, 1), (7521, 0), (8369, 1), (8426, 0), (9000, 1), (9002, 2), (11021, 1),
|
||||||
|
(12350, 2), (12351, 1), (12438, 2), (12442, 0), (19893, 2), (19967, 1), (55203, 2), (63743, 1),
|
||||||
|
(64106, 2), (65039, 1), (65059, 0), (65131, 2), (65279, 1), (65376, 2), (65500, 1), (65510, 2),
|
||||||
|
(120831, 1), (262141, 2), (1114109, 1),
|
||||||
|
]
|
||||||
|
if o == 0xe or o == 0xf:
|
||||||
|
return 0
|
||||||
|
for num, wid in widths:
|
||||||
|
if o <= num:
|
||||||
|
return wid
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def getRatingBgImg(rating):
|
||||||
|
totalRating = int(rating)
|
||||||
|
if 0 <= totalRating <= 999:
|
||||||
|
ratingPlate = "UI_CMN_DXRating_01.png"
|
||||||
|
elif 1000 <= totalRating <= 1999:
|
||||||
|
ratingPlate = "UI_CMN_DXRating_02.png"
|
||||||
|
elif 2000 <= totalRating <= 3999:
|
||||||
|
ratingPlate = "UI_CMN_DXRating_03.png"
|
||||||
|
elif 4000 <= totalRating <= 6999:
|
||||||
|
ratingPlate = "UI_CMN_DXRating_04.png"
|
||||||
|
elif 7000 <= totalRating <= 9999:
|
||||||
|
ratingPlate = "UI_CMN_DXRating_05.png"
|
||||||
|
elif 10000 <= totalRating <= 11999:
|
||||||
|
ratingPlate = "UI_CMN_DXRating_06.png"
|
||||||
|
elif 12000 <= totalRating <= 12999:
|
||||||
|
ratingPlate = "UI_CMN_DXRating_07.png"
|
||||||
|
elif 13000 <= totalRating <= 13999:
|
||||||
|
ratingPlate = "UI_CMN_DXRating_08.png"
|
||||||
|
elif 14000 <= totalRating <= 14499:
|
||||||
|
ratingPlate = "UI_CMN_DXRating_09.png"
|
||||||
|
elif 14500 <= totalRating <= 14999:
|
||||||
|
ratingPlate = "UI_CMN_DXRating_10.png"
|
||||||
|
else:
|
||||||
|
ratingPlate = "UI_CMN_DXRating_11.png"
|
||||||
|
return ratingPlate
|
||||||
|
|
||||||
|
def apply_gradient_blur(image, blur_radius=10, start_height=0, end_height=35):
|
||||||
|
# 创建一个与原始图像大小相同的空白渐变蒙版
|
||||||
|
mask = Image.new("L", image.size, 0)
|
||||||
|
draw = ImageDraw.Draw(mask)
|
||||||
|
|
||||||
|
# 将 start_height 和 end_height 转换为绝对像素位置
|
||||||
|
start_pixel = int(start_height * image.height)
|
||||||
|
end_pixel = int(end_height * image.height)
|
||||||
|
|
||||||
|
# 绘制渐变蒙版,模糊从 start_pixel 开始,到 end_pixel 结束
|
||||||
|
for y in range(image.height):
|
||||||
|
if y < start_pixel:
|
||||||
|
intensity = 0
|
||||||
|
elif y > end_pixel:
|
||||||
|
intensity = 255
|
||||||
|
else:
|
||||||
|
# 根据 y 位置线性插值计算模糊程度
|
||||||
|
intensity = int(255 * (y - start_pixel) / (end_pixel - start_pixel))
|
||||||
|
draw.line((0, y, image.width, y), fill=intensity)
|
||||||
|
|
||||||
|
# 对图像进行模糊处理
|
||||||
|
blurred_image = image.filter(ImageFilter.GaussianBlur(blur_radius))
|
||||||
|
|
||||||
|
# 将模糊图像和原始图像混合,使用渐变蒙版控制模糊区域
|
||||||
|
result = Image.composite(blurred_image, image, mask)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def drawCharaImgNewSub(charaId, charaLevel):
|
||||||
|
if int(charaLevel) > 9999:
|
||||||
|
charaLevel = 9999
|
||||||
|
if int(charaLevel) < 0:
|
||||||
|
charaLevel = 0
|
||||||
|
star, progress = get_star_info(int(charaLevel))
|
||||||
|
alpha = Image.open(rf"{maimaiImgPath}/maicard/alpha.png").convert("L")
|
||||||
|
base = Image.open(rf"{maimaiImgPath}/maicard/UI_Chara_RBase.png").convert("RGBA")
|
||||||
|
frame = Image.open(rf"{maimaiImgPath}/maicard/UI_Chara_RFrame.png").convert("RGBA").resize((152, 268))
|
||||||
|
level_img = Image.open(rf"{maimaiImgPath}/maicard/UI_NUM_MLevelDAMMY_14.png").convert("RGBA").resize((20, 14))
|
||||||
|
|
||||||
|
if not os.path.exists(rf"{maimaiImgPath}/Chara/UI_Chara_{charaId:06d}.png"):
|
||||||
|
charaId = 0
|
||||||
|
chara_img = Image.new("RGBA", (264, 300), (255, 255, 255, 0))
|
||||||
|
c = Image.open(rf"{maimaiImgPath}/Chara/UI_Chara_{charaId:06d}.png").convert("RGBA").resize((170, 170))
|
||||||
|
chara_img.paste(c, (0, 40), c)
|
||||||
|
|
||||||
|
chara_img = chara_img.crop((12, -32, 12 + alpha.width, alpha.height - 32))
|
||||||
|
|
||||||
|
base.paste(chara_img, (0, 0), chara_img)
|
||||||
|
base.paste(frame, (-2, -2), frame)
|
||||||
|
base.putalpha(alpha)
|
||||||
|
|
||||||
|
new_base = Image.new(mode="RGBA", size=(152, 298), color=(255, 255, 255, 0))
|
||||||
|
new_base.paste(base, (0, 0), base)
|
||||||
|
|
||||||
|
if star >= 6:
|
||||||
|
main_star = Image.open(rf"{maimaiImgPath}/maicard/UI_CMN_Chara_star_big_MAX.png").convert("RGBA").resize((53, 50))
|
||||||
|
sub_star = Image.open(rf"{maimaiImgPath}/maicard/UI_CMN_Chara_star_small_MAX.png").convert("RGBA").resize((35, 35))
|
||||||
|
elif star >= 5:
|
||||||
|
main_star = Image.open(rf"{maimaiImgPath}/maicard/UI_CMN_Chara_Star_big.png").convert("RGBA").resize((53, 50))
|
||||||
|
sub_star = Image.open(rf"{maimaiImgPath}/maicard/UI_CMN_Chara_Star_Small.png").convert("RGBA").resize((35, 35))
|
||||||
|
else:
|
||||||
|
main_star = Image.open(rf"{maimaiImgPath}/maicard/UI_CMN_Chara_Star_Big_Gauge01_{progress}.png").convert("RGBA").resize((53, 50))
|
||||||
|
sub_star = Image.open(rf"{maimaiImgPath}/maicard/UI_CMN_Chara_Star_Small.png").convert("RGBA").resize((35, 35))
|
||||||
|
|
||||||
|
if star >= 1:
|
||||||
|
new_base.paste(main_star, (47, 234), main_star)
|
||||||
|
if star >= 2:
|
||||||
|
new_base.paste(sub_star, (16, 226), sub_star)
|
||||||
|
if star >= 3:
|
||||||
|
new_base.paste(sub_star, (97, 226), sub_star)
|
||||||
|
if star >= 4:
|
||||||
|
sub_star = sub_star.resize((26, 26))
|
||||||
|
new_base.paste(sub_star, (6, 206), sub_star)
|
||||||
|
if star >= 5:
|
||||||
|
new_base.paste(sub_star, (116, 206), sub_star)
|
||||||
|
|
||||||
|
new_base.paste(level_img, (20, 17), level_img)
|
||||||
|
num_x = 46
|
||||||
|
for num in str(charaLevel):
|
||||||
|
num_img = Image.open(rf"{maimaiImgPath}/maicard/UI_CMN_Num_26p_{num}.png").convert("RGBA").resize((25, 28))
|
||||||
|
new_base.paste(num_img, (num_x, 6), num_img)
|
||||||
|
num_x += 18
|
||||||
|
|
||||||
|
return new_base
|
||||||
|
|
||||||
|
def drawCharaImgNewMain(charaId, charaLevel):
|
||||||
|
if int(charaLevel) > 9999:
|
||||||
|
charaLevel = 9999
|
||||||
|
if int(charaLevel) < 0:
|
||||||
|
charaLevel = 0
|
||||||
|
star, progress = get_star_info(int(charaLevel))
|
||||||
|
|
||||||
|
frame = Image.open(rf"{maimaiImgPath}/maicard/UI_Chara_LFrame.png").convert("RGBA").resize((235, 101))
|
||||||
|
level_img = Image.open(rf"{maimaiImgPath}/maicard/UI_NUM_MLevelDAMMY_14.png").convert("RGBA").resize((36, 23))
|
||||||
|
|
||||||
|
if not os.path.exists(rf"{maimaiImgPath}/Chara/UI_Chara_{charaId:06d}.png"):
|
||||||
|
charaId = 0
|
||||||
|
base = Image.open(rf"{maimaiImgPath}/Chara/UI_Chara_{charaId:06d}.png").convert("RGBA").resize((512, 512))
|
||||||
|
|
||||||
|
base.paste(frame, (140, 381), frame)
|
||||||
|
|
||||||
|
if star >= 6:
|
||||||
|
main_star = Image.open(rf"{maimaiImgPath}/maicard/UI_CMN_Chara_star_big_MAX.png").convert("RGBA").resize((65, 61))
|
||||||
|
sub_star = Image.open(rf"{maimaiImgPath}/maicard/UI_CMN_Chara_star_small_MAX.png").convert("RGBA").resize((45, 45))
|
||||||
|
elif star >= 5:
|
||||||
|
main_star = Image.open(rf"{maimaiImgPath}/maicard/UI_CMN_Chara_Star_big.png").convert("RGBA").resize((65, 61))
|
||||||
|
sub_star = Image.open(rf"{maimaiImgPath}/maicard/UI_CMN_Chara_Star_Small.png").convert("RGBA").resize((45, 45))
|
||||||
|
else:
|
||||||
|
main_star = Image.open(rf"{maimaiImgPath}/maicard/UI_CMN_Chara_Star_Big_Gauge01_{progress}.png").convert("RGBA").resize((65, 61))
|
||||||
|
sub_star = Image.open(rf"{maimaiImgPath}/maicard/UI_CMN_Chara_Star_Small.png").convert("RGBA").resize((45, 45))
|
||||||
|
|
||||||
|
if star >= 1:
|
||||||
|
base.paste(main_star, (225, 443), main_star)
|
||||||
|
if star >= 2:
|
||||||
|
base.paste(sub_star, (185, 446), sub_star)
|
||||||
|
if star >= 3:
|
||||||
|
base.paste(sub_star, (285, 446), sub_star)
|
||||||
|
if star >= 4:
|
||||||
|
sub_star = sub_star.resize((30, 30))
|
||||||
|
base.paste(sub_star, (158, 438), sub_star)
|
||||||
|
if star >= 5:
|
||||||
|
base.paste(sub_star, (327, 438), sub_star)
|
||||||
|
|
||||||
|
|
||||||
|
base.paste(level_img, (170, 405), level_img)
|
||||||
|
num_x = 229
|
||||||
|
for num in str(charaLevel):
|
||||||
|
num_img = Image.open(rf"{maimaiImgPath}/maicard/UI_CMN_Num_26p_{num}.png").convert("RGBA").resize((38, 44))
|
||||||
|
base.paste(num_img, (num_x, 394), num_img)
|
||||||
|
num_x += 27
|
||||||
|
|
||||||
|
return apply_gradient_blur(base.resize((264, 264)), 100)
|
||||||
|
|
||||||
|
def get_dominant_color(image):
|
||||||
|
# 颜色模式转换,以便输出rgb颜色值
|
||||||
|
image = image.convert('RGBA')
|
||||||
|
# 生成缩略图,减少计算量,减小cpu压力
|
||||||
|
image.thumbnail((200, 200))
|
||||||
|
max_score = 0
|
||||||
|
dominant_color = (0,0,0)
|
||||||
|
for count, (r, g, b, a) in image.getcolors(image.size[0] * image.size[1]):
|
||||||
|
# 跳过纯黑色
|
||||||
|
if (a == 0) or (sum((r, g, b, a)) == 0):
|
||||||
|
continue
|
||||||
|
saturation = colorsys.rgb_to_hsv(r / 255.0, g / 255.0, b / 255.0)[1]
|
||||||
|
y = min(abs(r * 2104 + g * 4130 + b * 802 + 4096 + 131072) >> 13, 235)
|
||||||
|
y = (y - 16.0) / (235 - 16)
|
||||||
|
# 忽略高亮色
|
||||||
|
if y > 0.9:
|
||||||
|
continue
|
||||||
|
score = (saturation + 0.1) * count
|
||||||
|
if score > max_score:
|
||||||
|
max_score = score
|
||||||
|
dominant_color = (r, g, b)
|
||||||
|
return dominant_color
|
||||||
|
|
||||||
|
def draw_text_with_stroke(draw: ImageDraw, pos, text, font, fill_color, stroke_width=2, stroke_color='white'):
|
||||||
|
# 绘制描边
|
||||||
|
for x_offset in range(-stroke_width+1, stroke_width):
|
||||||
|
for y_offset in range(-stroke_width+1, stroke_width):
|
||||||
|
if x_offset == 0 and y_offset == 0:
|
||||||
|
continue
|
||||||
|
draw.text((pos[0] + x_offset, pos[1] + y_offset), text, font=font, fill=stroke_color)
|
||||||
|
|
||||||
|
# 在正确位置绘制文本
|
||||||
|
draw.text(pos, text, font=font, fill=fill_color)
|
||||||
|
|
||||||
|
def draw_text_with_stroke_and_spacing(draw: ImageDraw.ImageDraw, pos, text, font, fill_color, stroke_width=2, stroke_color='white', spacing=5):
|
||||||
|
# 绘制描边
|
||||||
|
for x_offset in range(-stroke_width+1, stroke_width):
|
||||||
|
for y_offset in range(-stroke_width+1, stroke_width):
|
||||||
|
if x_offset == 0 and y_offset == 0:
|
||||||
|
continue
|
||||||
|
xx, yy = (pos[0] + x_offset, pos[1] + y_offset)
|
||||||
|
draw_text_with_spacing(draw, (xx, yy), text, font, stroke_color, spacing)
|
||||||
|
|
||||||
|
draw_text_with_spacing(draw, pos, text, font, fill_color, spacing)
|
||||||
|
|
||||||
|
def draw_text_with_spacing(draw: ImageDraw.ImageDraw, pos, text, font, fill_color, spacing=5):
|
||||||
|
# 逐字符绘制并调整位置
|
||||||
|
x, y = pos
|
||||||
|
for char in text:
|
||||||
|
_, _, char_width, _ = draw.textbbox((0, 0), char, font=font)
|
||||||
|
draw.text((x, y), char, font=font, fill=fill_color)
|
||||||
|
x += char_width + spacing # 增加间距
|
||||||
|
|
||||||
|
def call_user_img(user_data, no_chara=False):
|
||||||
|
try:
|
||||||
|
frame_path = rf"{maimaiImgPath}/Frame/UI_Frame_{user_data['frame']:06d}.png"
|
||||||
|
frame_img = Image.open(frame_path).resize((1080, 452))
|
||||||
|
except:
|
||||||
|
frame_path = rf"{maimaiImgPath}/Frame/UI_Frame_000000.png"
|
||||||
|
frame_img = Image.open(frame_path).resize((1080, 452))
|
||||||
|
|
||||||
|
theme_color = get_dominant_color(frame_img)
|
||||||
|
img = Image.new("RGBA", (1080, 477), theme_color)
|
||||||
|
text_color = tuple(abs(c-100)%255 for c in theme_color)
|
||||||
|
|
||||||
|
img.paste(frame_img, (0, 0))
|
||||||
|
|
||||||
|
plate = rf"{maimaiImgPath}/Plate/UI_Plate_{user_data['plate']:06d}.png"
|
||||||
|
icon = rf"{maimaiImgPath}/Icon/UI_Icon_{user_data['icon']:06d}.png"
|
||||||
|
|
||||||
|
UserImg: Image = drawUserImg(user_data["title"], user_data["rating"], user_data['courseRank'], user_data['nickname'], icon, plate,user_data["titleRare"],user_data["classRank"])
|
||||||
|
img.paste(UserImg, (25, 25), UserImg)
|
||||||
|
|
||||||
|
network_status_img = Image.open(rf"{maimaiImgPath}/network/on.png")
|
||||||
|
img.paste(network_status_img, (1014, 25), network_status_img)
|
||||||
|
|
||||||
|
if not no_chara:
|
||||||
|
main_chara = drawCharaImgNewMain(user_data["chara"][0], user_data["charaLevel"][0]).resize((309, 309))
|
||||||
|
img.paste(main_chara, (-36, 143), main_chara)
|
||||||
|
chara_start_x = 204
|
||||||
|
chara_start_y = 170
|
||||||
|
for chara in zip(user_data["chara"][1:], user_data["charaLevel"][1:]):
|
||||||
|
chara_img = drawCharaImgNewSub(*chara).resize((147, 290))
|
||||||
|
img.paste(chara_img, (chara_start_x, chara_start_y), chara_img)
|
||||||
|
chara_start_x += 138
|
||||||
|
|
||||||
|
designDraw = ImageDraw.Draw(img)
|
||||||
|
# 保留这些可以喵?
|
||||||
|
designDraw.text((20, 457),
|
||||||
|
f"Generated by SaltBot at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} Code by Error063 Plugin Edit by NingYu - 图片仅供参考",
|
||||||
|
font=ImageFont.truetype(rf'{materialPath}/GenSenMaruGothicTW-Bold.ttf', 12), fill=text_color)
|
||||||
|
|
||||||
|
return img
|
||||||
|
|
||||||
|
def call_user_img_preview(user_data):
|
||||||
|
base_img = Image.open(f"{maimaiImgPath}/prof/UI_ENT_Base_Myprof.png")
|
||||||
|
|
||||||
|
draw = ImageDraw.Draw(base_img)
|
||||||
|
draw.text((268,101), f"{user_data['nickname']}", font=ImageFont.truetype(rf'{materialPath}/GenSenMaruGothicTW-Medium.ttf', 20), fill="black")
|
||||||
|
|
||||||
|
icon = rf"{maimaiImgPath}/Icon/UI_Icon_{user_data['icon']:06d}.png"
|
||||||
|
iconImg = Image.open(icon).resize((156, 156))
|
||||||
|
base_img.paste(iconImg, (68, 114), iconImg)
|
||||||
|
|
||||||
|
awake_star_img = Image.open(rf"{maimaiImgPath}/prof/UI_ENT_Base_Myprof_Starchip.png").resize((80, 52))
|
||||||
|
base_img.paste(awake_star_img, (311, 253), awake_star_img)
|
||||||
|
|
||||||
|
draw_text_with_stroke(
|
||||||
|
draw,
|
||||||
|
(411, 256),
|
||||||
|
str(user_data["awake"]),
|
||||||
|
ImageFont.truetype(rf'{materialPath}/GenSenMaruGothicTW-Bold.ttf', 46),
|
||||||
|
"white",
|
||||||
|
stroke_width=2,
|
||||||
|
stroke_color='black'
|
||||||
|
)
|
||||||
|
|
||||||
|
ratingPlateImg = Image.open(rf"{maimaiImgPath}/Rating_big/{getRatingBgImg(int(user_data['rating']))}").resize((312,58))
|
||||||
|
base_img.paste(ratingPlateImg, (253, 163), ratingPlateImg)
|
||||||
|
|
||||||
|
# 定义偏移量和初始x坐标
|
||||||
|
offset = 25
|
||||||
|
start_x = 496
|
||||||
|
start_y = 177
|
||||||
|
x_positions = [start_x - i * offset for i in range(len(str(int(user_data["rating"]))))][-5:]
|
||||||
|
|
||||||
|
# 根据totalRating的位数处理图片
|
||||||
|
for i, x_pos in enumerate(x_positions):
|
||||||
|
# 计算当前位上的数字
|
||||||
|
digit = int(int(user_data["rating"]) / (10 ** i) % 10)
|
||||||
|
# 打开并调整图片大小
|
||||||
|
numImg = Image.open(rf"{maimaiImgPath}/num/UI_NUM_Drating_{digit}.png")
|
||||||
|
# 粘贴图片
|
||||||
|
base_img.paste(numImg, (x_pos, start_y), numImg)
|
||||||
|
|
||||||
|
return base_img
|
||||||
|
|
||||||
|
a = call_user_img(user_data, False)
|
||||||
|
a.save("E:/img/output.png")
|
||||||
|
|
||||||
|
'''
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="基于Python的玩家收藏品组合的图片生成器", formatter_class=argparse.ArgumentDefaultsHelpFormatter, add_help=True)
|
||||||
|
parser.add_argument("--nickname", type=str, default="NingYu☆", help="玩家昵称")
|
||||||
|
parser.add_argument("--title", type=str, default="ソルト 推し", help="玩家称号")
|
||||||
|
parser.add_argument("--icon", type=int, default=302, help="玩家头像ID")
|
||||||
|
parser.add_argument("--frame", type=int, default=300501, help="玩家背景板ID")
|
||||||
|
parser.add_argument("--plate", type=int, default=50702, help="玩家姓名框ID")
|
||||||
|
parser.add_argument("--rating", type=int, default=14225, help="玩家Rating")
|
||||||
|
parser.add_argument("--classRank", type=int, default=7, help="玩家友人对战等级")
|
||||||
|
parser.add_argument("--courseRank", type=int, default=10, help="玩家段位认定等级")
|
||||||
|
parser.add_argument("--titleRare", type=str, default="Sliver", help="玩家称号稀有度")
|
||||||
|
parser.add_argument("--chara", nargs='+', type=int, default=[101, 104, 355610, 355611, 355612], help="玩家设置的旅行伙伴ID列表")
|
||||||
|
parser.add_argument("--charaLevel", nargs='+', type=int, default=[1000, 9999, 1000, 9999, 9999], help="玩家设置的旅行伙伴等级列表")
|
||||||
|
parser.add_argument("--output", type=str, default="./output.png", help="图片输出路径")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
user_data = {
|
||||||
|
"nickname": 1,
|
||||||
|
"title": args.title,
|
||||||
|
"icon": args.icon,
|
||||||
|
"frame": args.frame,
|
||||||
|
"plate": args.plate,
|
||||||
|
"rating": args.rating,
|
||||||
|
"classRank": args.classRank,
|
||||||
|
"courseRank": args.courseRank,
|
||||||
|
"titleRare": args.titleRare,
|
||||||
|
"chara": args.chara,
|
||||||
|
"charaLevel": args.charaLevel,
|
||||||
|
}
|
||||||
|
for k, v in user_data.items():
|
||||||
|
print(f"{k}: {v}")
|
||||||
|
|
||||||
|
a = call_user_img(user_data, False)
|
||||||
|
a.save(args.output)
|
||||||
|
print("\nDone")
|
||||||
|
print(f"File path: {args.output}")
|
||||||
|
# a.show()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
'''
|
||||||
44
nonebot_plugin_maimai_helper/leak/authlite.py
Normal file
44
nonebot_plugin_maimai_helper/leak/authlite.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import dataclasses
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
from Crypto.Util.Padding import pad
|
||||||
|
import base64
|
||||||
|
import urllib3
|
||||||
|
|
||||||
|
def enc(key, iv, data):
|
||||||
|
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||||
|
encrypted = cipher.encrypt(data)
|
||||||
|
return encrypted
|
||||||
|
|
||||||
|
def dec(key, iv ,data):
|
||||||
|
de_cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||||
|
decrypted = de_cipher.decrypt(data)
|
||||||
|
return decrypted
|
||||||
|
|
||||||
|
def hello():
|
||||||
|
key = bytes([ 47, 63, 106, 111, 43, 34, 76, 38, 92, 67, 114, 57, 40, 61, 107, 71 ])
|
||||||
|
#key = bytes([ 45, 97, 53, 55, 85, 88, 52, 121, 57, 47, 104, 40, 73, 109, 65, 81 ])
|
||||||
|
iv = bytes.fromhex('00000000000000000000000000000000')
|
||||||
|
ua = 'SDGB;Windows/Lite'
|
||||||
|
#ua = 'SDHJ;Windows/Lite'
|
||||||
|
content = bytes([0] * 16) + b'title_id=SDGB&title_ver=1.41&client_id=A63E01C2805&token=205648745'
|
||||||
|
#content = bytes([0] * 16) + b'title_id=SDHJ&title_ver=1.11&client_id=A63E01E1326&token=205648745'
|
||||||
|
header = bytes.fromhex('00000000000000000000000000000000')
|
||||||
|
bytes_data = pad(header + content, 16)
|
||||||
|
encrypted = enc(key, iv, bytes_data)
|
||||||
|
http = urllib3.PoolManager()
|
||||||
|
r = http.request(
|
||||||
|
'POST',
|
||||||
|
'http://at.sys-allnet.cn/net/delivery/instruction',
|
||||||
|
body=encrypted,
|
||||||
|
headers={
|
||||||
|
'User-Agent': ua,
|
||||||
|
'Pragma': 'DFI'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
resp_data = r.data
|
||||||
|
decrypted = dec(key, resp_data[:16], resp_data)
|
||||||
|
decrypted_bytes = decrypted[16:]
|
||||||
|
decrypted_str = decrypted_bytes.decode('UTF-8')
|
||||||
|
print(decrypted_str)
|
||||||
|
|
||||||
|
hello()
|
||||||
26
nonebot_plugin_maimai_helper/leak/login.py
Normal file
26
nonebot_plugin_maimai_helper/leak/login.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import json
|
||||||
|
import pytz
|
||||||
|
|
||||||
|
from sdgb import sdgb_api
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from settings import userId
|
||||||
|
from settings import regionId, clientId, placeId
|
||||||
|
|
||||||
|
def login(timestamp):
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": userId,
|
||||||
|
"accessCode": "",
|
||||||
|
"regionId": regionId,
|
||||||
|
"placeId": placeId,
|
||||||
|
"clientId": clientId,
|
||||||
|
"dateTime": timestamp,
|
||||||
|
"isContinue": False,
|
||||||
|
"genericFlag": 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
login_result = sdgb_api(data, "UserLoginApi", userId)
|
||||||
|
return login_result
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(login(int(input())))
|
||||||
26
nonebot_plugin_maimai_helper/leak/logout.py
Normal file
26
nonebot_plugin_maimai_helper/leak/logout.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import json
|
||||||
|
import pytz
|
||||||
|
|
||||||
|
from sdgb import sdgb_api
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from settings import userId
|
||||||
|
from settings import regionId, clientId, placeId
|
||||||
|
|
||||||
|
def logout(timestamp):
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": userId,
|
||||||
|
"accessCode": "",
|
||||||
|
"regionId": regionId,
|
||||||
|
"placeId": placeId,
|
||||||
|
"clientId": clientId,
|
||||||
|
"dateTime": timestamp,
|
||||||
|
"type": 1
|
||||||
|
})
|
||||||
|
|
||||||
|
logout_result = sdgb_api(data, "UserLogoutApi", userId)
|
||||||
|
return logout_result
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(logout(int(input())))
|
||||||
396
nonebot_plugin_maimai_helper/leak/mapstock.py
Normal file
396
nonebot_plugin_maimai_helper/leak/mapstock.py
Normal file
@@ -0,0 +1,396 @@
|
|||||||
|
import json
|
||||||
|
import pytz
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
|
||||||
|
from sdgb import sdgb_api
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from settings import userId
|
||||||
|
from settings import music_data
|
||||||
|
from settings import regionId, clientId, placeId, regionName, placeName
|
||||||
|
|
||||||
|
from login import login
|
||||||
|
from logout import logout
|
||||||
|
|
||||||
|
def CalcRandom():
|
||||||
|
max = 1037933
|
||||||
|
num2 = random.randint(1, max) * 2069
|
||||||
|
|
||||||
|
num2 += 1024 # specialnum
|
||||||
|
num3 = 0
|
||||||
|
for i in range(0, 32):
|
||||||
|
num3 <<= 1
|
||||||
|
num3 += num2 % 2
|
||||||
|
num2 >>= 1
|
||||||
|
|
||||||
|
return num3
|
||||||
|
|
||||||
|
timestamp = int(time.time()) - 60
|
||||||
|
|
||||||
|
def music():
|
||||||
|
|
||||||
|
music = music_data
|
||||||
|
|
||||||
|
musicId = music['musicId']
|
||||||
|
level = music['level']
|
||||||
|
playCount = music['playCount']
|
||||||
|
achievement = music['achievement']
|
||||||
|
comboStatus = music['comboStatus']
|
||||||
|
syncStatus = music['syncStatus']
|
||||||
|
deluxscoreMax = music['deluxscoreMax']
|
||||||
|
scoreRank = music['scoreRank']
|
||||||
|
extNum1 = music['extNum1']
|
||||||
|
|
||||||
|
print(timestamp)
|
||||||
|
|
||||||
|
# UserLogin
|
||||||
|
|
||||||
|
login_result = json.loads(login(timestamp))
|
||||||
|
print(login_result)
|
||||||
|
|
||||||
|
login_id = login_result['loginId']
|
||||||
|
login_date = login_result['lastLoginDate']
|
||||||
|
|
||||||
|
|
||||||
|
# UserData
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
userdata = json.loads(sdgb_api(data, "GetUserDataApi", userId))
|
||||||
|
|
||||||
|
# UserLog
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"userPlaylog": {
|
||||||
|
"userId": 0,
|
||||||
|
"orderId": 0,
|
||||||
|
"playlogId": login_id,
|
||||||
|
"version": 1041000,
|
||||||
|
"placeId": placeId,
|
||||||
|
"placeName": placeName,
|
||||||
|
"loginDate": int(time.time()),
|
||||||
|
"playDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d'),
|
||||||
|
"userPlayDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"type": 0,
|
||||||
|
"musicId": int(musicId),
|
||||||
|
"level": int(level),
|
||||||
|
"trackNo": 1,
|
||||||
|
"vsMode": 0,
|
||||||
|
"vsUserName": "",
|
||||||
|
"vsStatus": 0,
|
||||||
|
"vsUserRating": 0,
|
||||||
|
"vsUserAchievement": 0,
|
||||||
|
"vsUserGradeRank": 0,
|
||||||
|
"vsRank": 0,
|
||||||
|
"playerNum": 1,
|
||||||
|
"playedUserId1": 0,
|
||||||
|
"playedUserName1": "",
|
||||||
|
"playedMusicLevel1": 0,
|
||||||
|
"playedUserId2": 0,
|
||||||
|
"playedUserName2": "",
|
||||||
|
"playedMusicLevel2": 0,
|
||||||
|
"playedUserId3": 0,
|
||||||
|
"playedUserName3": "",
|
||||||
|
"playedMusicLevel3": 0,
|
||||||
|
"characterId1": userdata['userData']['charaSlot'][0],
|
||||||
|
"characterLevel1": random.randint(1000,6500),
|
||||||
|
"characterAwakening1": 5,
|
||||||
|
"characterId2": userdata['userData']['charaSlot'][1],
|
||||||
|
"characterLevel2": random.randint(1000,6500),
|
||||||
|
"characterAwakening2": 5,
|
||||||
|
"characterId3": userdata['userData']['charaSlot'][2],
|
||||||
|
"characterLevel3": random.randint(1000,6500),
|
||||||
|
"characterAwakening3": 5,
|
||||||
|
"characterId4": userdata['userData']['charaSlot'][3],
|
||||||
|
"characterLevel4": random.randint(1000,6500),
|
||||||
|
"characterAwakening4": 5,
|
||||||
|
"characterId5": userdata['userData']['charaSlot'][4],
|
||||||
|
"characterLevel5": random.randint(1000,6500),
|
||||||
|
"characterAwakening5": 5,
|
||||||
|
"achievement": int(achievement),
|
||||||
|
"deluxscore": int(deluxscoreMax),
|
||||||
|
"scoreRank": int(scoreRank),
|
||||||
|
"maxCombo": random.randint(400,500),
|
||||||
|
"totalCombo": random.randint(700,900),
|
||||||
|
"maxSync": 0,
|
||||||
|
"totalSync": 0,
|
||||||
|
"tapCriticalPerfect": random.randint(200,400),
|
||||||
|
"tapPerfect": random.randint(100,250),
|
||||||
|
"tapGreat": random.randint(0,10),
|
||||||
|
"tapGood": random.randint(0,10),
|
||||||
|
"tapMiss": random.randint(0,10),
|
||||||
|
"holdCriticalPerfect": random.randint(20,40),
|
||||||
|
"holdPerfect": random.randint(0,15),
|
||||||
|
"holdGreat": 0,
|
||||||
|
"holdGood": 0,
|
||||||
|
"holdMiss": 0,
|
||||||
|
"slideCriticalPerfect": random.randint(34,60),
|
||||||
|
"slidePerfect": 0,
|
||||||
|
"slideGreat": 0,
|
||||||
|
"slideGood": 0,
|
||||||
|
"slideMiss": 0,
|
||||||
|
"touchCriticalPerfect": random.randint(20,70),
|
||||||
|
"touchPerfect": 0,
|
||||||
|
"touchGreat": 0,
|
||||||
|
"touchGood": 0,
|
||||||
|
"touchMiss": 0,
|
||||||
|
"breakCriticalPerfect": random.randint(8,30),
|
||||||
|
"breakPerfect": random.randint(7,10),
|
||||||
|
"breakGreat": 0,
|
||||||
|
"breakGood": 0,
|
||||||
|
"breakMiss": 0,
|
||||||
|
"isTap": True,
|
||||||
|
"isHold": True,
|
||||||
|
"isSlide": True,
|
||||||
|
"isTouch": True,
|
||||||
|
"isBreak": True,
|
||||||
|
"isCriticalDisp": True,
|
||||||
|
"isFastLateDisp": True,
|
||||||
|
"fastCount": random.randint(20,30),
|
||||||
|
"lateCount": random.randint(50,70),
|
||||||
|
"isAchieveNewRecord": True,
|
||||||
|
"isDeluxscoreNewRecord": True,
|
||||||
|
"comboStatus": 0,
|
||||||
|
"syncStatus": 0,
|
||||||
|
"isClear": True,
|
||||||
|
'beforeRating': userdata['userData']['playerRating'],
|
||||||
|
'afterRating': userdata['userData']['playerRating'],
|
||||||
|
"beforeGrade": 0,
|
||||||
|
"afterGrade": 0,
|
||||||
|
"afterGradeRank": 2,
|
||||||
|
'beforeDeluxRating': userdata['userData']['playerRating'],
|
||||||
|
'afterDeluxRating': userdata['userData']['playerRating'],
|
||||||
|
"isPlayTutorial": False,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isFreedomMode": False,
|
||||||
|
"playMode": 0,
|
||||||
|
"isNewFree": False,
|
||||||
|
"trialPlayAchievement": -1,
|
||||||
|
"extNum1": 0,
|
||||||
|
"extNum2": 0,
|
||||||
|
"extNum4": 3020,
|
||||||
|
"extBool1": False
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
userlog_result = json.loads(sdgb_api(data, "UploadUserPlaylogApi", userId))
|
||||||
|
|
||||||
|
print(userlog_result)
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Extend
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_extend = json.loads(sdgb_api(data, "GetUserExtendApi", userId))
|
||||||
|
|
||||||
|
# 获取 User Option
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_option = json.loads(sdgb_api(data, "GetUserOptionApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Rating
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_rating = json.loads(sdgb_api(data, "GetUserRatingApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Activity
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_activity = json.loads(sdgb_api(data, "GetUserActivityApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取账号功能票
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_charge = json.loads(sdgb_api(data, "GetUserChargeApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# UserAll
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"playlogId": login_id,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isFreePlay": False,
|
||||||
|
"upsertUserAll": {
|
||||||
|
"userData": [
|
||||||
|
{
|
||||||
|
"accessCode": "",
|
||||||
|
"userName": userdata['userData']['userName'],
|
||||||
|
"isNetMember": 1,
|
||||||
|
"iconId": userdata['userData']['iconId'],
|
||||||
|
"plateId": userdata['userData']['plateId'],
|
||||||
|
"titleId": userdata['userData']['titleId'],
|
||||||
|
"partnerId": userdata['userData']['partnerId'],
|
||||||
|
"frameId": userdata['userData']['frameId'],
|
||||||
|
"selectMapId": userdata['userData']['selectMapId'],
|
||||||
|
"totalAwake": userdata['userData']['totalAwake'],
|
||||||
|
"gradeRating": userdata['userData']['gradeRating'],
|
||||||
|
"musicRating": userdata['userData']['musicRating'],
|
||||||
|
"playerRating": userdata['userData']['playerRating'],
|
||||||
|
"highestRating": userdata['userData']['highestRating'],
|
||||||
|
"gradeRank": userdata['userData']['gradeRank'],
|
||||||
|
"classRank": userdata['userData']['classRank'],
|
||||||
|
"courseRank": userdata['userData']['courseRank'],
|
||||||
|
"charaSlot": userdata['userData']['charaSlot'],
|
||||||
|
"charaLockSlot": userdata['userData']['charaLockSlot'],
|
||||||
|
"contentBit": userdata['userData']['contentBit'],
|
||||||
|
"playCount": userdata['userData']['playCount'],
|
||||||
|
"currentPlayCount": userdata['userData']['currentPlayCount'],
|
||||||
|
"renameCredit": 0,
|
||||||
|
"mapStock": 99000,
|
||||||
|
"eventWatchedDate": userdata['userData']['eventWatchedDate'],
|
||||||
|
"lastGameId": "SDGB",
|
||||||
|
"lastRomVersion": userdata['userData']['lastRomVersion'],
|
||||||
|
"lastDataVersion": userdata['userData']['lastDataVersion'],
|
||||||
|
"lastLoginDate": login_date,
|
||||||
|
"lastPlayDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"lastPlayCredit": 1,
|
||||||
|
"lastPlayMode": 0,
|
||||||
|
"lastPlaceId": placeId,
|
||||||
|
"lastPlaceName": placeName,
|
||||||
|
"lastAllNetId": 0,
|
||||||
|
"lastRegionId": regionId,
|
||||||
|
"lastRegionName": regionName,
|
||||||
|
"lastClientId": clientId,
|
||||||
|
"lastCountryCode": "CHN",
|
||||||
|
"lastSelectEMoney": 0,
|
||||||
|
"lastSelectTicket": 0,
|
||||||
|
"lastSelectCourse": userdata['userData']['lastSelectCourse'],
|
||||||
|
"lastCountCourse": 0,
|
||||||
|
"firstGameId": "SDGB",
|
||||||
|
"firstRomVersion": userdata['userData']['firstRomVersion'],
|
||||||
|
"firstDataVersion": userdata['userData']['firstDataVersion'],
|
||||||
|
"firstPlayDate": userdata['userData']['firstPlayDate'],
|
||||||
|
"compatibleCmVersion": userdata['userData']['compatibleCmVersion'],
|
||||||
|
"dailyBonusDate": userdata['userData']['dailyBonusDate'],
|
||||||
|
"dailyCourseBonusDate": userdata['userData']['dailyCourseBonusDate'],
|
||||||
|
"lastPairLoginDate": userdata['userData']['lastPairLoginDate'],
|
||||||
|
"lastTrialPlayDate": userdata['userData']['lastTrialPlayDate'],
|
||||||
|
"playVsCount": 0,
|
||||||
|
"playSyncCount": 0,
|
||||||
|
"winCount": 0,
|
||||||
|
"helpCount": 0,
|
||||||
|
"comboCount": 0,
|
||||||
|
"totalDeluxscore": userdata['userData']['totalDeluxscore'],
|
||||||
|
"totalBasicDeluxscore": userdata['userData']['totalBasicDeluxscore'],
|
||||||
|
"totalAdvancedDeluxscore": userdata['userData']['totalAdvancedDeluxscore'],
|
||||||
|
"totalExpertDeluxscore": userdata['userData']['totalExpertDeluxscore'],
|
||||||
|
"totalMasterDeluxscore": userdata['userData']['totalMasterDeluxscore'],
|
||||||
|
"totalReMasterDeluxscore": userdata['userData']['totalReMasterDeluxscore'],
|
||||||
|
"totalSync": userdata['userData']['totalSync'],
|
||||||
|
"totalBasicSync": userdata['userData']['totalBasicSync'],
|
||||||
|
"totalAdvancedSync": userdata['userData']['totalAdvancedSync'],
|
||||||
|
"totalExpertSync": userdata['userData']['totalExpertSync'],
|
||||||
|
"totalMasterSync": userdata['userData']['totalMasterSync'],
|
||||||
|
"totalReMasterSync": userdata['userData']['totalReMasterSync'],
|
||||||
|
"totalAchievement": userdata['userData']['totalAchievement'],
|
||||||
|
"totalBasicAchievement": userdata['userData']['totalBasicAchievement'],
|
||||||
|
"totalAdvancedAchievement": userdata['userData']['totalAdvancedAchievement'],
|
||||||
|
"totalExpertAchievement": userdata['userData']['totalExpertAchievement'],
|
||||||
|
"totalMasterAchievement": userdata['userData']['totalMasterAchievement'],
|
||||||
|
"totalReMasterAchievement": userdata['userData']['totalReMasterAchievement'],
|
||||||
|
"playerOldRating": userdata['userData']['playerOldRating'],
|
||||||
|
"playerNewRating": userdata['userData']['playerNewRating'],
|
||||||
|
"banState": 0,
|
||||||
|
"dateTime": timestamp
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userExtend": [user_extend['userExtend']],
|
||||||
|
"userOption": [user_option['userOption']],
|
||||||
|
"userCharacterList": [],
|
||||||
|
"userGhost": [],
|
||||||
|
"userMapList": [],
|
||||||
|
"userLoginBonusList": [],
|
||||||
|
"userRatingList": [user_rating['userRating']],
|
||||||
|
"userItemList": [],
|
||||||
|
"userMusicDetailList": [
|
||||||
|
{
|
||||||
|
"musicId": musicId,
|
||||||
|
"level": level,
|
||||||
|
"playCount": playCount,
|
||||||
|
"achievement": achievement,
|
||||||
|
"comboStatus": comboStatus,
|
||||||
|
"syncStatus": syncStatus,
|
||||||
|
"deluxscoreMax": deluxscoreMax,
|
||||||
|
"scoreRank": scoreRank,
|
||||||
|
"extNum1": extNum1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userCourseList": [],
|
||||||
|
"userFriendSeasonRankingList": [],
|
||||||
|
"userChargeList": user_charge['userChargeList'],
|
||||||
|
"userFavoriteList": [],
|
||||||
|
"userActivityList": [user_activity['userActivity']],
|
||||||
|
"userGamePlaylogList": [
|
||||||
|
{
|
||||||
|
"playlogId": login_id,
|
||||||
|
"version": "1.41.00",
|
||||||
|
"playDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"playMode": 0,
|
||||||
|
"useTicketId": -1,
|
||||||
|
"playCredit": 1,
|
||||||
|
"playTrack": 1,
|
||||||
|
"clientId": clientId,
|
||||||
|
"isPlayTutorial": False,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isNewFree": False,
|
||||||
|
"playCount": 0,
|
||||||
|
"playSpecial": CalcRandom(),
|
||||||
|
"playOtherUserId": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"user2pPlaylog": {
|
||||||
|
"userId1": 0,
|
||||||
|
"userId2": 0,
|
||||||
|
"userName1": "",
|
||||||
|
"userName2": "",
|
||||||
|
"regionId": 0,
|
||||||
|
"placeId": 0,
|
||||||
|
"user2pPlaylogDetailList": []
|
||||||
|
},
|
||||||
|
"isNewCharacterList": "",
|
||||||
|
"isNewMapList": "",
|
||||||
|
"isNewLoginBonusList": "",
|
||||||
|
"isNewItemList": "",
|
||||||
|
"isNewMusicDetailList": "1",
|
||||||
|
"isNewCourseList": "0",
|
||||||
|
"isNewFavoriteList": "",
|
||||||
|
"isNewFriendSeasonRankingList": ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
userall_result = json.loads(sdgb_api(data, "UpsertUserAllApi", userId))
|
||||||
|
return userall_result
|
||||||
|
|
||||||
|
def music_with_retry(max_retries=10): # 这里是重试次数
|
||||||
|
for i in range(max_retries):
|
||||||
|
try:
|
||||||
|
print(music())
|
||||||
|
return logout(timestamp)
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"尝试 {i+1} 失败,错误:{e}")
|
||||||
|
print(logout(timestamp))
|
||||||
|
time.sleep(5) # 等待 5 秒后重试
|
||||||
|
return "重试次数超过限制,乐曲上传失败"
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(music_with_retry())
|
||||||
666
nonebot_plugin_maimai_helper/leak/music.py
Normal file
666
nonebot_plugin_maimai_helper/leak/music.py
Normal file
@@ -0,0 +1,666 @@
|
|||||||
|
import json
|
||||||
|
import pytz
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
|
||||||
|
from sdgb import sdgb_api
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from settings import userId
|
||||||
|
from settings import music_data
|
||||||
|
from settings import regionId, clientId, placeId, regionName, placeName
|
||||||
|
|
||||||
|
|
||||||
|
from login import login
|
||||||
|
from logout import logout
|
||||||
|
|
||||||
|
def CalcRandom():
|
||||||
|
max = 1037933
|
||||||
|
num2 = random.randint(1, max) * 2069
|
||||||
|
|
||||||
|
num2 += 1024 # specialnum
|
||||||
|
num3 = 0
|
||||||
|
for i in range(0, 32):
|
||||||
|
num3 <<= 1
|
||||||
|
num3 += num2 % 2
|
||||||
|
num2 >>= 1
|
||||||
|
|
||||||
|
return num3
|
||||||
|
|
||||||
|
timestamp = int(time.time()) - 60
|
||||||
|
|
||||||
|
def music():
|
||||||
|
|
||||||
|
music = music_data
|
||||||
|
|
||||||
|
musicId = music['musicId']
|
||||||
|
level = music['level']
|
||||||
|
playCount = music['playCount']
|
||||||
|
achievement = music['achievement']
|
||||||
|
comboStatus = music['comboStatus']
|
||||||
|
syncStatus = music['syncStatus']
|
||||||
|
deluxscoreMax = music['deluxscoreMax']
|
||||||
|
scoreRank = music['scoreRank']
|
||||||
|
extNum1 = music['extNum1']
|
||||||
|
|
||||||
|
print(timestamp)
|
||||||
|
|
||||||
|
# UserLogin
|
||||||
|
|
||||||
|
login_result = json.loads(login(timestamp))
|
||||||
|
print(login_result)
|
||||||
|
|
||||||
|
login_id = login_result['loginId']
|
||||||
|
login_date = login_result['lastLoginDate']
|
||||||
|
|
||||||
|
|
||||||
|
# UserData
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
userdata = json.loads(sdgb_api(data, "GetUserDataApi", userId))
|
||||||
|
|
||||||
|
# UserMusic 随机两首
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"nextIndex":random.randint(11000,11500),
|
||||||
|
"maxCount":2
|
||||||
|
})
|
||||||
|
|
||||||
|
music_details = json.loads(sdgb_api(data, "GetUserMusicApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# UserLog
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"userPlaylog": {
|
||||||
|
"userId": 0,
|
||||||
|
"orderId": 0,
|
||||||
|
"playlogId": login_id,
|
||||||
|
"version": 1041000,
|
||||||
|
"placeId": placeId,
|
||||||
|
"placeName": placeName,
|
||||||
|
"loginDate": int(time.time()),
|
||||||
|
"playDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d'),
|
||||||
|
"userPlayDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"type": 0,
|
||||||
|
"musicId": int(musicId),
|
||||||
|
"level": int(level),
|
||||||
|
"trackNo": 1,
|
||||||
|
"vsMode": 0,
|
||||||
|
"vsUserName": "",
|
||||||
|
"vsStatus": 0,
|
||||||
|
"vsUserRating": 0,
|
||||||
|
"vsUserAchievement": 0,
|
||||||
|
"vsUserGradeRank": 0,
|
||||||
|
"vsRank": 0,
|
||||||
|
"playerNum": 1,
|
||||||
|
"playedUserId1": 0,
|
||||||
|
"playedUserName1": "",
|
||||||
|
"playedMusicLevel1": 0,
|
||||||
|
"playedUserId2": 0,
|
||||||
|
"playedUserName2": "",
|
||||||
|
"playedMusicLevel2": 0,
|
||||||
|
"playedUserId3": 0,
|
||||||
|
"playedUserName3": "",
|
||||||
|
"playedMusicLevel3": 0,
|
||||||
|
"characterId1": userdata['userData']['charaSlot'][0],
|
||||||
|
"characterLevel1": random.randint(1000,6500),
|
||||||
|
"characterAwakening1": 5,
|
||||||
|
"characterId2": userdata['userData']['charaSlot'][1],
|
||||||
|
"characterLevel2": random.randint(1000,6500),
|
||||||
|
"characterAwakening2": 5,
|
||||||
|
"characterId3": userdata['userData']['charaSlot'][2],
|
||||||
|
"characterLevel3": random.randint(1000,6500),
|
||||||
|
"characterAwakening3": 5,
|
||||||
|
"characterId4": userdata['userData']['charaSlot'][3],
|
||||||
|
"characterLevel4": random.randint(1000,6500),
|
||||||
|
"characterAwakening4": 5,
|
||||||
|
"characterId5": userdata['userData']['charaSlot'][4],
|
||||||
|
"characterLevel5": random.randint(1000,6500),
|
||||||
|
"characterAwakening5": 5,
|
||||||
|
"achievement": int(achievement),
|
||||||
|
"deluxscore": int(deluxscoreMax),
|
||||||
|
"scoreRank": int(scoreRank),
|
||||||
|
"maxCombo": random.randint(400,500),
|
||||||
|
"totalCombo": random.randint(700,900),
|
||||||
|
"maxSync": 0,
|
||||||
|
"totalSync": 0,
|
||||||
|
"tapCriticalPerfect": random.randint(200,400),
|
||||||
|
"tapPerfect": random.randint(100,250),
|
||||||
|
"tapGreat": random.randint(0,10),
|
||||||
|
"tapGood": random.randint(0,10),
|
||||||
|
"tapMiss": random.randint(0,10),
|
||||||
|
"holdCriticalPerfect": random.randint(20,40),
|
||||||
|
"holdPerfect": random.randint(0,15),
|
||||||
|
"holdGreat": 0,
|
||||||
|
"holdGood": 0,
|
||||||
|
"holdMiss": 0,
|
||||||
|
"slideCriticalPerfect": random.randint(34,60),
|
||||||
|
"slidePerfect": 0,
|
||||||
|
"slideGreat": 0,
|
||||||
|
"slideGood": 0,
|
||||||
|
"slideMiss": 0,
|
||||||
|
"touchCriticalPerfect": random.randint(20,70),
|
||||||
|
"touchPerfect": 0,
|
||||||
|
"touchGreat": 0,
|
||||||
|
"touchGood": 0,
|
||||||
|
"touchMiss": 0,
|
||||||
|
"breakCriticalPerfect": random.randint(8,30),
|
||||||
|
"breakPerfect": random.randint(7,10),
|
||||||
|
"breakGreat": 0,
|
||||||
|
"breakGood": 0,
|
||||||
|
"breakMiss": 0,
|
||||||
|
"isTap": True,
|
||||||
|
"isHold": True,
|
||||||
|
"isSlide": True,
|
||||||
|
"isTouch": True,
|
||||||
|
"isBreak": True,
|
||||||
|
"isCriticalDisp": True,
|
||||||
|
"isFastLateDisp": True,
|
||||||
|
"fastCount": random.randint(20,30),
|
||||||
|
"lateCount": random.randint(50,70),
|
||||||
|
"isAchieveNewRecord": True,
|
||||||
|
"isDeluxscoreNewRecord": True,
|
||||||
|
"comboStatus": 0,
|
||||||
|
"syncStatus": 0,
|
||||||
|
"isClear": True,
|
||||||
|
'beforeRating': userdata['userData']['playerRating'],
|
||||||
|
'afterRating': userdata['userData']['playerRating'],
|
||||||
|
"beforeGrade": 0,
|
||||||
|
"afterGrade": 0,
|
||||||
|
"afterGradeRank": 2,
|
||||||
|
'beforeDeluxRating': userdata['userData']['playerRating'],
|
||||||
|
'afterDeluxRating': userdata['userData']['playerRating'],
|
||||||
|
"isPlayTutorial": False,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isFreedomMode": False,
|
||||||
|
"playMode": 0,
|
||||||
|
"isNewFree": False,
|
||||||
|
"trialPlayAchievement": -1,
|
||||||
|
"extNum1": 0,
|
||||||
|
"extNum2": 0,
|
||||||
|
"extNum4": 3020,
|
||||||
|
"extBool1": False
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
userlog_result = json.loads(sdgb_api(data, "UploadUserPlaylogApi", userId))
|
||||||
|
|
||||||
|
print(userlog_result)
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"userPlaylog": {
|
||||||
|
"userId": 0,
|
||||||
|
"orderId": 0,
|
||||||
|
"playlogId": login_id,
|
||||||
|
"version": 1041000,
|
||||||
|
"placeId": placeId,
|
||||||
|
"placeName": placeName,
|
||||||
|
"loginDate": int(time.time()),
|
||||||
|
"playDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d'),
|
||||||
|
"userPlayDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"type": 0,
|
||||||
|
"musicId": music_details['userMusicList'][0]['userMusicDetailList'][0]['musicId'],
|
||||||
|
"level": music_details['userMusicList'][0]['userMusicDetailList'][0]['level'],
|
||||||
|
"trackNo": 2,
|
||||||
|
"vsMode": 0,
|
||||||
|
"vsUserName": "",
|
||||||
|
"vsStatus": 0,
|
||||||
|
"vsUserRating": 0,
|
||||||
|
"vsUserAchievement": 0,
|
||||||
|
"vsUserGradeRank": 0,
|
||||||
|
"vsRank": 0,
|
||||||
|
"playerNum": 1,
|
||||||
|
"playedUserId1": 0,
|
||||||
|
"playedUserName1": "",
|
||||||
|
"playedMusicLevel1": 0,
|
||||||
|
"playedUserId2": 0,
|
||||||
|
"playedUserName2": "",
|
||||||
|
"playedMusicLevel2": 0,
|
||||||
|
"playedUserId3": 0,
|
||||||
|
"playedUserName3": "",
|
||||||
|
"playedMusicLevel3": 0,
|
||||||
|
"characterId1": userdata['userData']['charaSlot'][0],
|
||||||
|
"characterLevel1": random.randint(1000,6500),
|
||||||
|
"characterAwakening1": 5,
|
||||||
|
"characterId2": userdata['userData']['charaSlot'][1],
|
||||||
|
"characterLevel2": random.randint(1000,6500),
|
||||||
|
"characterAwakening2": 5,
|
||||||
|
"characterId3": userdata['userData']['charaSlot'][2],
|
||||||
|
"characterLevel3": random.randint(1000,6500),
|
||||||
|
"characterAwakening3": 5,
|
||||||
|
"characterId4": userdata['userData']['charaSlot'][3],
|
||||||
|
"characterLevel4": random.randint(1000,6500),
|
||||||
|
"characterAwakening4": 5,
|
||||||
|
"characterId5": userdata['userData']['charaSlot'][4],
|
||||||
|
"characterLevel5": random.randint(1000,6500),
|
||||||
|
"characterAwakening5": 5,
|
||||||
|
"achievement": music_details['userMusicList'][0]['userMusicDetailList'][0]['achievement'],
|
||||||
|
"deluxscore": music_details['userMusicList'][0]['userMusicDetailList'][0]['deluxscoreMax'],
|
||||||
|
"scoreRank": music_details['userMusicList'][0]['userMusicDetailList'][0]['scoreRank'],
|
||||||
|
"maxCombo": random.randint(400,500),
|
||||||
|
"totalCombo": random.randint(700,900),
|
||||||
|
"maxSync": 0,
|
||||||
|
"totalSync": 0,
|
||||||
|
"tapCriticalPerfect": random.randint(200,400),
|
||||||
|
"tapPerfect": random.randint(100,250),
|
||||||
|
"tapGreat": random.randint(0,10),
|
||||||
|
"tapGood": random.randint(0,10),
|
||||||
|
"tapMiss": random.randint(0,10),
|
||||||
|
"holdCriticalPerfect": random.randint(20,40),
|
||||||
|
"holdPerfect": random.randint(0,15),
|
||||||
|
"holdGreat": 0,
|
||||||
|
"holdGood": 0,
|
||||||
|
"holdMiss": 0,
|
||||||
|
"slideCriticalPerfect": random.randint(34,60),
|
||||||
|
"slidePerfect": 0,
|
||||||
|
"slideGreat": 0,
|
||||||
|
"slideGood": 0,
|
||||||
|
"slideMiss": 0,
|
||||||
|
"touchCriticalPerfect": random.randint(20,70),
|
||||||
|
"touchPerfect": 0,
|
||||||
|
"touchGreat": 0,
|
||||||
|
"touchGood": 0,
|
||||||
|
"touchMiss": 0,
|
||||||
|
"breakCriticalPerfect": random.randint(8,30),
|
||||||
|
"breakPerfect": random.randint(7,10),
|
||||||
|
"breakGreat": 0,
|
||||||
|
"breakGood": 0,
|
||||||
|
"breakMiss": 0,
|
||||||
|
"isTap": True,
|
||||||
|
"isHold": True,
|
||||||
|
"isSlide": True,
|
||||||
|
"isTouch": True,
|
||||||
|
"isBreak": True,
|
||||||
|
"isCriticalDisp": True,
|
||||||
|
"isFastLateDisp": True,
|
||||||
|
"fastCount": random.randint(20,30),
|
||||||
|
"lateCount": random.randint(50,70),
|
||||||
|
"isAchieveNewRecord": False,
|
||||||
|
"isDeluxscoreNewRecord": False,
|
||||||
|
"comboStatus": 0,
|
||||||
|
"syncStatus": 0,
|
||||||
|
"isClear": True,
|
||||||
|
'beforeRating': userdata['userData']['playerRating'],
|
||||||
|
'afterRating': userdata['userData']['playerRating'],
|
||||||
|
"beforeGrade": 0,
|
||||||
|
"afterGrade": 0,
|
||||||
|
"afterGradeRank": 2,
|
||||||
|
'beforeDeluxRating': userdata['userData']['playerRating'],
|
||||||
|
'afterDeluxRating': userdata['userData']['playerRating'],
|
||||||
|
"isPlayTutorial": False,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isFreedomMode": False,
|
||||||
|
"playMode": 0,
|
||||||
|
"isNewFree": False,
|
||||||
|
"trialPlayAchievement": -1,
|
||||||
|
"extNum1": 0,
|
||||||
|
"extNum2": 0,
|
||||||
|
"extNum4": 3020,
|
||||||
|
"extBool1": False
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
userlog_result = json.loads(sdgb_api(data, "UploadUserPlaylogApi", userId))
|
||||||
|
|
||||||
|
print(userlog_result)
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"userPlaylog": {
|
||||||
|
"userId": 0,
|
||||||
|
"orderId": 0,
|
||||||
|
"playlogId": login_id,
|
||||||
|
"version": 1041000,
|
||||||
|
"placeId": placeId,
|
||||||
|
"placeName": placeName,
|
||||||
|
"loginDate": int(time.time()),
|
||||||
|
"playDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d'),
|
||||||
|
"userPlayDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"type": 0,
|
||||||
|
"musicId": music_details['userMusicList'][1]['userMusicDetailList'][0]['musicId'],
|
||||||
|
"level": music_details['userMusicList'][1]['userMusicDetailList'][0]['level'],
|
||||||
|
"trackNo": 3,
|
||||||
|
"vsMode": 0,
|
||||||
|
"vsUserName": "",
|
||||||
|
"vsStatus": 0,
|
||||||
|
"vsUserRating": 0,
|
||||||
|
"vsUserAchievement": 0,
|
||||||
|
"vsUserGradeRank": 0,
|
||||||
|
"vsRank": 0,
|
||||||
|
"playerNum": 1,
|
||||||
|
"playedUserId1": 0,
|
||||||
|
"playedUserName1": "",
|
||||||
|
"playedMusicLevel1": 0,
|
||||||
|
"playedUserId2": 0,
|
||||||
|
"playedUserName2": "",
|
||||||
|
"playedMusicLevel2": 0,
|
||||||
|
"playedUserId3": 0,
|
||||||
|
"playedUserName3": "",
|
||||||
|
"playedMusicLevel3": 0,
|
||||||
|
"characterId1": userdata['userData']['charaSlot'][0],
|
||||||
|
"characterLevel1": random.randint(1000,6500),
|
||||||
|
"characterAwakening1": 5,
|
||||||
|
"characterId2": userdata['userData']['charaSlot'][1],
|
||||||
|
"characterLevel2": random.randint(1000,6500),
|
||||||
|
"characterAwakening2": 5,
|
||||||
|
"characterId3": userdata['userData']['charaSlot'][2],
|
||||||
|
"characterLevel3": random.randint(1000,6500),
|
||||||
|
"characterAwakening3": 5,
|
||||||
|
"characterId4": userdata['userData']['charaSlot'][3],
|
||||||
|
"characterLevel4": random.randint(1000,6500),
|
||||||
|
"characterAwakening4": 5,
|
||||||
|
"characterId5": userdata['userData']['charaSlot'][4],
|
||||||
|
"characterLevel5": random.randint(1000,6500),
|
||||||
|
"characterAwakening5": 5,
|
||||||
|
"achievement": music_details['userMusicList'][1]['userMusicDetailList'][0]['achievement'],
|
||||||
|
"deluxscore": music_details['userMusicList'][1]['userMusicDetailList'][0]['deluxscoreMax'],
|
||||||
|
"scoreRank": music_details['userMusicList'][1]['userMusicDetailList'][0]['scoreRank'],
|
||||||
|
"maxCombo": random.randint(400,500),
|
||||||
|
"totalCombo": random.randint(700,900),
|
||||||
|
"maxSync": 0,
|
||||||
|
"totalSync": 0,
|
||||||
|
"tapCriticalPerfect": random.randint(200,400),
|
||||||
|
"tapPerfect": random.randint(100,250),
|
||||||
|
"tapGreat": random.randint(0,10),
|
||||||
|
"tapGood": random.randint(0,10),
|
||||||
|
"tapMiss": random.randint(0,10),
|
||||||
|
"holdCriticalPerfect": random.randint(20,40),
|
||||||
|
"holdPerfect": random.randint(0,15),
|
||||||
|
"holdGreat": 0,
|
||||||
|
"holdGood": 0,
|
||||||
|
"holdMiss": 0,
|
||||||
|
"slideCriticalPerfect": random.randint(34,60),
|
||||||
|
"slidePerfect": 0,
|
||||||
|
"slideGreat": 0,
|
||||||
|
"slideGood": 0,
|
||||||
|
"slideMiss": 0,
|
||||||
|
"touchCriticalPerfect": random.randint(20,70),
|
||||||
|
"touchPerfect": 0,
|
||||||
|
"touchGreat": 0,
|
||||||
|
"touchGood": 0,
|
||||||
|
"touchMiss": 0,
|
||||||
|
"breakCriticalPerfect": random.randint(8,30),
|
||||||
|
"breakPerfect": random.randint(7,10),
|
||||||
|
"breakGreat": 0,
|
||||||
|
"breakGood": 0,
|
||||||
|
"breakMiss": 0,
|
||||||
|
"isTap": True,
|
||||||
|
"isHold": True,
|
||||||
|
"isSlide": True,
|
||||||
|
"isTouch": True,
|
||||||
|
"isBreak": True,
|
||||||
|
"isCriticalDisp": True,
|
||||||
|
"isFastLateDisp": True,
|
||||||
|
"fastCount": random.randint(20,30),
|
||||||
|
"lateCount": random.randint(50,70),
|
||||||
|
"isAchieveNewRecord": False,
|
||||||
|
"isDeluxscoreNewRecord": False,
|
||||||
|
"comboStatus": 0,
|
||||||
|
"syncStatus": 0,
|
||||||
|
"isClear": True,
|
||||||
|
'beforeRating': userdata['userData']['playerRating'],
|
||||||
|
'afterRating': userdata['userData']['playerRating'],
|
||||||
|
"beforeGrade": 0,
|
||||||
|
"afterGrade": 0,
|
||||||
|
"afterGradeRank": 2,
|
||||||
|
'beforeDeluxRating': userdata['userData']['playerRating'],
|
||||||
|
'afterDeluxRating': userdata['userData']['playerRating'],
|
||||||
|
"isPlayTutorial": False,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isFreedomMode": False,
|
||||||
|
"playMode": 0,
|
||||||
|
"isNewFree": False,
|
||||||
|
"trialPlayAchievement": -1,
|
||||||
|
"extNum1": 0,
|
||||||
|
"extNum2": 0,
|
||||||
|
"extNum4": 3020,
|
||||||
|
"extBool1": False
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
userlog_result = json.loads(sdgb_api(data, "UploadUserPlaylogApi", userId))
|
||||||
|
|
||||||
|
print(userlog_result)
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Extend
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_extend = json.loads(sdgb_api(data, "GetUserExtendApi", userId))
|
||||||
|
|
||||||
|
# 获取 User Option
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_option = json.loads(sdgb_api(data, "GetUserOptionApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Rating
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_rating = json.loads(sdgb_api(data, "GetUserRatingApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Activity
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_activity = json.loads(sdgb_api(data, "GetUserActivityApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取账号功能票
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_charge = json.loads(sdgb_api(data, "GetUserChargeApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# UserAll
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"playlogId": login_id,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isFreePlay": False,
|
||||||
|
"upsertUserAll": {
|
||||||
|
"userData": [
|
||||||
|
{
|
||||||
|
"accessCode": "",
|
||||||
|
"userName": userdata['userData']['userName'],
|
||||||
|
"isNetMember": 1,
|
||||||
|
"iconId": userdata['userData']['iconId'],
|
||||||
|
"plateId": userdata['userData']['plateId'],
|
||||||
|
"titleId": userdata['userData']['titleId'],
|
||||||
|
"partnerId": userdata['userData']['partnerId'],
|
||||||
|
"frameId": userdata['userData']['frameId'],
|
||||||
|
"selectMapId": userdata['userData']['selectMapId'],
|
||||||
|
"totalAwake": userdata['userData']['totalAwake'],
|
||||||
|
"gradeRating": userdata['userData']['gradeRating'],
|
||||||
|
"musicRating": userdata['userData']['musicRating'],
|
||||||
|
"playerRating": userdata['userData']['playerRating'],
|
||||||
|
"highestRating": userdata['userData']['highestRating'],
|
||||||
|
"gradeRank": userdata['userData']['gradeRank'],
|
||||||
|
"classRank": userdata['userData']['classRank'],
|
||||||
|
"courseRank": userdata['userData']['courseRank'],
|
||||||
|
"charaSlot": userdata['userData']['charaSlot'],
|
||||||
|
"charaLockSlot": userdata['userData']['charaLockSlot'],
|
||||||
|
"contentBit": userdata['userData']['contentBit'],
|
||||||
|
"playCount": userdata['userData']['playCount'],
|
||||||
|
"currentPlayCount": userdata['userData']['currentPlayCount'],
|
||||||
|
"renameCredit": 0,
|
||||||
|
"mapStock": userdata['userData']['mapStock'],
|
||||||
|
"eventWatchedDate": userdata['userData']['eventWatchedDate'],
|
||||||
|
"lastGameId": "SDGB",
|
||||||
|
"lastRomVersion": userdata['userData']['lastRomVersion'],
|
||||||
|
"lastDataVersion": userdata['userData']['lastDataVersion'],
|
||||||
|
"lastLoginDate": login_date,
|
||||||
|
"lastPlayDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"lastPlayCredit": 1,
|
||||||
|
"lastPlayMode": 0,
|
||||||
|
"lastPlaceId": placeId,
|
||||||
|
"lastPlaceName": placeName,
|
||||||
|
"lastAllNetId": 0,
|
||||||
|
"lastRegionId": regionId,
|
||||||
|
"lastRegionName": regionName,
|
||||||
|
"lastClientId": clientId,
|
||||||
|
"lastCountryCode": "CHN",
|
||||||
|
"lastSelectEMoney": 0,
|
||||||
|
"lastSelectTicket": 0,
|
||||||
|
"lastSelectCourse": userdata['userData']['lastSelectCourse'],
|
||||||
|
"lastCountCourse": 0,
|
||||||
|
"firstGameId": "SDGB",
|
||||||
|
"firstRomVersion": userdata['userData']['firstRomVersion'],
|
||||||
|
"firstDataVersion": userdata['userData']['firstDataVersion'],
|
||||||
|
"firstPlayDate": userdata['userData']['firstPlayDate'],
|
||||||
|
"compatibleCmVersion": userdata['userData']['compatibleCmVersion'],
|
||||||
|
"dailyBonusDate": userdata['userData']['dailyBonusDate'],
|
||||||
|
"dailyCourseBonusDate": userdata['userData']['dailyCourseBonusDate'],
|
||||||
|
"lastPairLoginDate": userdata['userData']['lastPairLoginDate'],
|
||||||
|
"lastTrialPlayDate": userdata['userData']['lastTrialPlayDate'],
|
||||||
|
"playVsCount": 0,
|
||||||
|
"playSyncCount": 0,
|
||||||
|
"winCount": 0,
|
||||||
|
"helpCount": 0,
|
||||||
|
"comboCount": 0,
|
||||||
|
"totalDeluxscore": userdata['userData']['totalDeluxscore'],
|
||||||
|
"totalBasicDeluxscore": userdata['userData']['totalBasicDeluxscore'],
|
||||||
|
"totalAdvancedDeluxscore": userdata['userData']['totalAdvancedDeluxscore'],
|
||||||
|
"totalExpertDeluxscore": userdata['userData']['totalExpertDeluxscore'],
|
||||||
|
"totalMasterDeluxscore": userdata['userData']['totalMasterDeluxscore'],
|
||||||
|
"totalReMasterDeluxscore": userdata['userData']['totalReMasterDeluxscore'],
|
||||||
|
"totalSync": userdata['userData']['totalSync'],
|
||||||
|
"totalBasicSync": userdata['userData']['totalBasicSync'],
|
||||||
|
"totalAdvancedSync": userdata['userData']['totalAdvancedSync'],
|
||||||
|
"totalExpertSync": userdata['userData']['totalExpertSync'],
|
||||||
|
"totalMasterSync": userdata['userData']['totalMasterSync'],
|
||||||
|
"totalReMasterSync": userdata['userData']['totalReMasterSync'],
|
||||||
|
"totalAchievement": userdata['userData']['totalAchievement'],
|
||||||
|
"totalBasicAchievement": userdata['userData']['totalBasicAchievement'],
|
||||||
|
"totalAdvancedAchievement": userdata['userData']['totalAdvancedAchievement'],
|
||||||
|
"totalExpertAchievement": userdata['userData']['totalExpertAchievement'],
|
||||||
|
"totalMasterAchievement": userdata['userData']['totalMasterAchievement'],
|
||||||
|
"totalReMasterAchievement": userdata['userData']['totalReMasterAchievement'],
|
||||||
|
"playerOldRating": userdata['userData']['playerOldRating'],
|
||||||
|
"playerNewRating": userdata['userData']['playerNewRating'],
|
||||||
|
"banState": 0,
|
||||||
|
"dateTime": timestamp
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userExtend": [user_extend['userExtend']],
|
||||||
|
"userOption": [user_option['userOption']],
|
||||||
|
"userCharacterList": [],
|
||||||
|
"userGhost": [],
|
||||||
|
"userMapList": [],
|
||||||
|
"userLoginBonusList": [],
|
||||||
|
"userRatingList": [user_rating['userRating']],
|
||||||
|
"userItemList": [],
|
||||||
|
"userMusicDetailList": [
|
||||||
|
{
|
||||||
|
"musicId": musicId,
|
||||||
|
"level": level,
|
||||||
|
"playCount": playCount,
|
||||||
|
"achievement": achievement,
|
||||||
|
"comboStatus": comboStatus,
|
||||||
|
"syncStatus": syncStatus,
|
||||||
|
"deluxscoreMax": deluxscoreMax,
|
||||||
|
"scoreRank": scoreRank,
|
||||||
|
"extNum1": extNum1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"musicId": music_details['userMusicList'][0]['userMusicDetailList'][0]['musicId'],
|
||||||
|
"level": music_details['userMusicList'][0]['userMusicDetailList'][0]['level'],
|
||||||
|
"playCount": music_details['userMusicList'][0]['userMusicDetailList'][0]['playCount'],
|
||||||
|
"achievement": music_details['userMusicList'][0]['userMusicDetailList'][0]['achievement'],
|
||||||
|
"comboStatus": music_details['userMusicList'][0]['userMusicDetailList'][0]['comboStatus'],
|
||||||
|
"syncStatus": music_details['userMusicList'][0]['userMusicDetailList'][0]['syncStatus'],
|
||||||
|
"deluxscoreMax": music_details['userMusicList'][0]['userMusicDetailList'][0]['deluxscoreMax'],
|
||||||
|
"scoreRank": music_details['userMusicList'][0]['userMusicDetailList'][0]['scoreRank'],
|
||||||
|
"extNum1": music_details['userMusicList'][0]['userMusicDetailList'][0]['extNum1']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"musicId": music_details['userMusicList'][1]['userMusicDetailList'][0]['musicId'],
|
||||||
|
"level": music_details['userMusicList'][1]['userMusicDetailList'][0]['level'],
|
||||||
|
"playCount": music_details['userMusicList'][1]['userMusicDetailList'][0]['playCount'],
|
||||||
|
"achievement": music_details['userMusicList'][1]['userMusicDetailList'][0]['achievement'],
|
||||||
|
"comboStatus": music_details['userMusicList'][1]['userMusicDetailList'][0]['comboStatus'],
|
||||||
|
"syncStatus": music_details['userMusicList'][1]['userMusicDetailList'][0]['syncStatus'],
|
||||||
|
"deluxscoreMax": music_details['userMusicList'][1]['userMusicDetailList'][0]['deluxscoreMax'],
|
||||||
|
"scoreRank": music_details['userMusicList'][1]['userMusicDetailList'][0]['scoreRank'],
|
||||||
|
"extNum1": music_details['userMusicList'][1]['userMusicDetailList'][0]['extNum1']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userCourseList": [],
|
||||||
|
"userFriendSeasonRankingList": [],
|
||||||
|
"userChargeList": user_charge['userChargeList'],
|
||||||
|
"userFavoriteList": [],
|
||||||
|
"userActivityList": [user_activity['userActivity']],
|
||||||
|
"userGamePlaylogList": [
|
||||||
|
{
|
||||||
|
"playlogId": login_id,
|
||||||
|
"version": "1.41.00",
|
||||||
|
"playDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"playMode": 0,
|
||||||
|
"useTicketId": -1,
|
||||||
|
"playCredit": 1,
|
||||||
|
"playTrack": 3,
|
||||||
|
"clientId": clientId,
|
||||||
|
"isPlayTutorial": False,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isNewFree": False,
|
||||||
|
"playCount": 0,
|
||||||
|
"playSpecial": CalcRandom(),
|
||||||
|
"playOtherUserId": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"user2pPlaylog": {
|
||||||
|
"userId1": 0,
|
||||||
|
"userId2": 0,
|
||||||
|
"userName1": "",
|
||||||
|
"userName2": "",
|
||||||
|
"regionId": 0,
|
||||||
|
"placeId": 0,
|
||||||
|
"user2pPlaylogDetailList": []
|
||||||
|
},
|
||||||
|
"isNewCharacterList": "",
|
||||||
|
"isNewMapList": "",
|
||||||
|
"isNewLoginBonusList": "",
|
||||||
|
"isNewItemList": "",
|
||||||
|
"isNewMusicDetailList": "100",
|
||||||
|
"isNewCourseList": "0",
|
||||||
|
"isNewFavoriteList": "",
|
||||||
|
"isNewFriendSeasonRankingList": ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
userall_result = json.loads(sdgb_api(data, "UpsertUserAllApi", userId))
|
||||||
|
return userall_result
|
||||||
|
|
||||||
|
def music_with_retry(max_retries=10): # 这里是重试次数
|
||||||
|
for i in range(max_retries):
|
||||||
|
try:
|
||||||
|
print(music())
|
||||||
|
return logout(timestamp)
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"尝试 {i+1} 失败,错误:{e}")
|
||||||
|
print(logout(timestamp))
|
||||||
|
time.sleep(5) # 等待 5 秒后重试
|
||||||
|
return "重试次数超过限制,乐曲上传失败"
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(music_with_retry())
|
||||||
598
nonebot_plugin_maimai_helper/leak/musicSort.txt
Normal file
598
nonebot_plugin_maimai_helper/leak/musicSort.txt
Normal file
@@ -0,0 +1,598 @@
|
|||||||
|
10734
|
||||||
|
10706
|
||||||
|
10702
|
||||||
|
10690
|
||||||
|
10665
|
||||||
|
10641
|
||||||
|
10625
|
||||||
|
10602
|
||||||
|
10593
|
||||||
|
10572
|
||||||
|
10552
|
||||||
|
10536
|
||||||
|
10420
|
||||||
|
10404
|
||||||
|
10363
|
||||||
|
10319
|
||||||
|
10316
|
||||||
|
10315
|
||||||
|
10302
|
||||||
|
10301
|
||||||
|
10288
|
||||||
|
10256
|
||||||
|
10235
|
||||||
|
10202
|
||||||
|
10193
|
||||||
|
10191
|
||||||
|
10190
|
||||||
|
10188
|
||||||
|
10146
|
||||||
|
10145
|
||||||
|
10070
|
||||||
|
01235
|
||||||
|
01085
|
||||||
|
01081
|
||||||
|
01051
|
||||||
|
01020
|
||||||
|
11001
|
||||||
|
11002
|
||||||
|
11003
|
||||||
|
11004
|
||||||
|
11005
|
||||||
|
11006
|
||||||
|
11007
|
||||||
|
11008
|
||||||
|
11009
|
||||||
|
11010
|
||||||
|
11014
|
||||||
|
11015
|
||||||
|
11016
|
||||||
|
11017
|
||||||
|
11018
|
||||||
|
11019
|
||||||
|
11020
|
||||||
|
11021
|
||||||
|
11022
|
||||||
|
11023
|
||||||
|
11024
|
||||||
|
11025
|
||||||
|
11026
|
||||||
|
11027
|
||||||
|
11028
|
||||||
|
11029
|
||||||
|
11030
|
||||||
|
11031
|
||||||
|
11032
|
||||||
|
11034
|
||||||
|
11037
|
||||||
|
11043
|
||||||
|
11044
|
||||||
|
11046
|
||||||
|
11048
|
||||||
|
11049
|
||||||
|
11050
|
||||||
|
11051
|
||||||
|
11052
|
||||||
|
11058
|
||||||
|
11059
|
||||||
|
11060
|
||||||
|
11061
|
||||||
|
11064
|
||||||
|
11065
|
||||||
|
11066
|
||||||
|
11067
|
||||||
|
11069
|
||||||
|
11070
|
||||||
|
11073
|
||||||
|
11075
|
||||||
|
11077
|
||||||
|
11078
|
||||||
|
11080
|
||||||
|
11081
|
||||||
|
11083
|
||||||
|
11084
|
||||||
|
11085
|
||||||
|
11086
|
||||||
|
11087
|
||||||
|
11088
|
||||||
|
11089
|
||||||
|
11090
|
||||||
|
11091
|
||||||
|
11092
|
||||||
|
11093
|
||||||
|
11094
|
||||||
|
11095
|
||||||
|
11096
|
||||||
|
11097
|
||||||
|
11098
|
||||||
|
11099
|
||||||
|
11100
|
||||||
|
11101
|
||||||
|
11102
|
||||||
|
11103
|
||||||
|
11104
|
||||||
|
11105
|
||||||
|
11106
|
||||||
|
11107
|
||||||
|
11108
|
||||||
|
11109
|
||||||
|
11110
|
||||||
|
11111
|
||||||
|
11113
|
||||||
|
11115
|
||||||
|
11121
|
||||||
|
11122
|
||||||
|
11123
|
||||||
|
11124
|
||||||
|
11125
|
||||||
|
11126
|
||||||
|
11127
|
||||||
|
11128
|
||||||
|
11129
|
||||||
|
11130
|
||||||
|
11131
|
||||||
|
11132
|
||||||
|
11133
|
||||||
|
11134
|
||||||
|
11135
|
||||||
|
11136
|
||||||
|
11137
|
||||||
|
11138
|
||||||
|
11139
|
||||||
|
11140
|
||||||
|
11141
|
||||||
|
11142
|
||||||
|
11143
|
||||||
|
11150
|
||||||
|
11152
|
||||||
|
11153
|
||||||
|
11154
|
||||||
|
11155
|
||||||
|
11157
|
||||||
|
11158
|
||||||
|
11159
|
||||||
|
11160
|
||||||
|
11161
|
||||||
|
11162
|
||||||
|
11163
|
||||||
|
11164
|
||||||
|
11165
|
||||||
|
11166
|
||||||
|
11167
|
||||||
|
11168
|
||||||
|
11169
|
||||||
|
11170
|
||||||
|
11171
|
||||||
|
11172
|
||||||
|
11173
|
||||||
|
11174
|
||||||
|
11175
|
||||||
|
11176
|
||||||
|
11177
|
||||||
|
11184
|
||||||
|
11185
|
||||||
|
11186
|
||||||
|
11187
|
||||||
|
11188
|
||||||
|
11189
|
||||||
|
11190
|
||||||
|
11191
|
||||||
|
11192
|
||||||
|
11193
|
||||||
|
11194
|
||||||
|
11195
|
||||||
|
11198
|
||||||
|
11199
|
||||||
|
11200
|
||||||
|
11201
|
||||||
|
11202
|
||||||
|
11204
|
||||||
|
11205
|
||||||
|
11206
|
||||||
|
11207
|
||||||
|
11208
|
||||||
|
11209
|
||||||
|
11210
|
||||||
|
11211
|
||||||
|
11212
|
||||||
|
11213
|
||||||
|
11214
|
||||||
|
11215
|
||||||
|
11216
|
||||||
|
11219
|
||||||
|
11221
|
||||||
|
11222
|
||||||
|
11223
|
||||||
|
11224
|
||||||
|
11225
|
||||||
|
11226
|
||||||
|
11227
|
||||||
|
11228
|
||||||
|
11229
|
||||||
|
11230
|
||||||
|
11231
|
||||||
|
11232
|
||||||
|
11233
|
||||||
|
11234
|
||||||
|
11235
|
||||||
|
11236
|
||||||
|
11237
|
||||||
|
11238
|
||||||
|
11239
|
||||||
|
11240
|
||||||
|
11241
|
||||||
|
11242
|
||||||
|
11243
|
||||||
|
11246
|
||||||
|
11247
|
||||||
|
11248
|
||||||
|
11249
|
||||||
|
11253
|
||||||
|
11255
|
||||||
|
11260
|
||||||
|
11261
|
||||||
|
11262
|
||||||
|
11263
|
||||||
|
11264
|
||||||
|
11265
|
||||||
|
11266
|
||||||
|
11267
|
||||||
|
11268
|
||||||
|
11269
|
||||||
|
11270
|
||||||
|
11271
|
||||||
|
11272
|
||||||
|
11273
|
||||||
|
11274
|
||||||
|
11275
|
||||||
|
11276
|
||||||
|
11277
|
||||||
|
11278
|
||||||
|
11279
|
||||||
|
11280
|
||||||
|
11281
|
||||||
|
11282
|
||||||
|
11283
|
||||||
|
11284
|
||||||
|
11285
|
||||||
|
11286
|
||||||
|
11287
|
||||||
|
11288
|
||||||
|
11289
|
||||||
|
11290
|
||||||
|
11291
|
||||||
|
11292
|
||||||
|
11293
|
||||||
|
11294
|
||||||
|
11295
|
||||||
|
11296
|
||||||
|
11297
|
||||||
|
11298
|
||||||
|
11299
|
||||||
|
11300
|
||||||
|
11301
|
||||||
|
11302
|
||||||
|
11303
|
||||||
|
11304
|
||||||
|
11305
|
||||||
|
11306
|
||||||
|
11307
|
||||||
|
11308
|
||||||
|
11309
|
||||||
|
11310
|
||||||
|
11311
|
||||||
|
11312
|
||||||
|
11313
|
||||||
|
11314
|
||||||
|
11315
|
||||||
|
11316
|
||||||
|
11317
|
||||||
|
11318
|
||||||
|
11319
|
||||||
|
11321
|
||||||
|
11322
|
||||||
|
11323
|
||||||
|
11324
|
||||||
|
11325
|
||||||
|
11327
|
||||||
|
11328
|
||||||
|
11330
|
||||||
|
11331
|
||||||
|
11333
|
||||||
|
11334
|
||||||
|
11335
|
||||||
|
11336
|
||||||
|
11340
|
||||||
|
11341
|
||||||
|
11342
|
||||||
|
11343
|
||||||
|
11344
|
||||||
|
11345
|
||||||
|
11346
|
||||||
|
11347
|
||||||
|
11348
|
||||||
|
11349
|
||||||
|
11350
|
||||||
|
11351
|
||||||
|
11353
|
||||||
|
11354
|
||||||
|
11355
|
||||||
|
11358
|
||||||
|
11359
|
||||||
|
11360
|
||||||
|
11361
|
||||||
|
11362
|
||||||
|
11363
|
||||||
|
11364
|
||||||
|
11365
|
||||||
|
11367
|
||||||
|
11369
|
||||||
|
11370
|
||||||
|
11373
|
||||||
|
11374
|
||||||
|
11375
|
||||||
|
11376
|
||||||
|
11377
|
||||||
|
11378
|
||||||
|
11379
|
||||||
|
11380
|
||||||
|
11381
|
||||||
|
11382
|
||||||
|
11383
|
||||||
|
11384
|
||||||
|
11385
|
||||||
|
11386
|
||||||
|
11387
|
||||||
|
11388
|
||||||
|
11389
|
||||||
|
11390
|
||||||
|
11391
|
||||||
|
11392
|
||||||
|
11393
|
||||||
|
11394
|
||||||
|
11395
|
||||||
|
11396
|
||||||
|
11398
|
||||||
|
11399
|
||||||
|
11400
|
||||||
|
11401
|
||||||
|
11402
|
||||||
|
11404
|
||||||
|
11405
|
||||||
|
11407
|
||||||
|
11408
|
||||||
|
11410
|
||||||
|
11411
|
||||||
|
11412
|
||||||
|
11413
|
||||||
|
11415
|
||||||
|
11418
|
||||||
|
11419
|
||||||
|
11420
|
||||||
|
11421
|
||||||
|
11422
|
||||||
|
11423
|
||||||
|
11424
|
||||||
|
11425
|
||||||
|
11426
|
||||||
|
11427
|
||||||
|
11428
|
||||||
|
11429
|
||||||
|
11430
|
||||||
|
11431
|
||||||
|
11432
|
||||||
|
11433
|
||||||
|
11434
|
||||||
|
11435
|
||||||
|
11436
|
||||||
|
11437
|
||||||
|
11438
|
||||||
|
11439
|
||||||
|
11441
|
||||||
|
11443
|
||||||
|
11444
|
||||||
|
11445
|
||||||
|
11446
|
||||||
|
11447
|
||||||
|
11448
|
||||||
|
11449
|
||||||
|
11450
|
||||||
|
11451
|
||||||
|
11452
|
||||||
|
11453
|
||||||
|
11454
|
||||||
|
11455
|
||||||
|
11456
|
||||||
|
11457
|
||||||
|
11458
|
||||||
|
11459
|
||||||
|
11460
|
||||||
|
11461
|
||||||
|
11462
|
||||||
|
11463
|
||||||
|
11464
|
||||||
|
11465
|
||||||
|
11466
|
||||||
|
11467
|
||||||
|
11468
|
||||||
|
11469
|
||||||
|
11470
|
||||||
|
11471
|
||||||
|
11472
|
||||||
|
11473
|
||||||
|
11474
|
||||||
|
11475
|
||||||
|
11477
|
||||||
|
11478
|
||||||
|
11479
|
||||||
|
11481
|
||||||
|
11482
|
||||||
|
11483
|
||||||
|
11484
|
||||||
|
11485
|
||||||
|
11486
|
||||||
|
11487
|
||||||
|
11488
|
||||||
|
11489
|
||||||
|
11490
|
||||||
|
11491
|
||||||
|
11495
|
||||||
|
11496
|
||||||
|
11497
|
||||||
|
11498
|
||||||
|
11499
|
||||||
|
11500
|
||||||
|
11502
|
||||||
|
11503
|
||||||
|
11504
|
||||||
|
11505
|
||||||
|
11506
|
||||||
|
11507
|
||||||
|
11508
|
||||||
|
11509
|
||||||
|
11510
|
||||||
|
11511
|
||||||
|
11512
|
||||||
|
11513
|
||||||
|
11514
|
||||||
|
11516
|
||||||
|
11517
|
||||||
|
11518
|
||||||
|
11519
|
||||||
|
11520
|
||||||
|
11521
|
||||||
|
11523
|
||||||
|
11524
|
||||||
|
11525
|
||||||
|
11526
|
||||||
|
11527
|
||||||
|
11528
|
||||||
|
11529
|
||||||
|
11530
|
||||||
|
11532
|
||||||
|
11533
|
||||||
|
11534
|
||||||
|
11535
|
||||||
|
11536
|
||||||
|
11537
|
||||||
|
11538
|
||||||
|
11539
|
||||||
|
11540
|
||||||
|
11541
|
||||||
|
11542
|
||||||
|
11543
|
||||||
|
11544
|
||||||
|
11545
|
||||||
|
11546
|
||||||
|
11547
|
||||||
|
11548
|
||||||
|
11549
|
||||||
|
11550
|
||||||
|
11551
|
||||||
|
11552
|
||||||
|
11553
|
||||||
|
11554
|
||||||
|
11555
|
||||||
|
11556
|
||||||
|
11557
|
||||||
|
11558
|
||||||
|
11559
|
||||||
|
11560
|
||||||
|
11561
|
||||||
|
11562
|
||||||
|
11563
|
||||||
|
11564
|
||||||
|
11565
|
||||||
|
11566
|
||||||
|
11567
|
||||||
|
11568
|
||||||
|
11569
|
||||||
|
11570
|
||||||
|
11571
|
||||||
|
11572
|
||||||
|
11573
|
||||||
|
11574
|
||||||
|
11575
|
||||||
|
11576
|
||||||
|
11577
|
||||||
|
11578
|
||||||
|
11580
|
||||||
|
11583
|
||||||
|
11584
|
||||||
|
11585
|
||||||
|
11586
|
||||||
|
11587
|
||||||
|
11588
|
||||||
|
11589
|
||||||
|
11590
|
||||||
|
11591
|
||||||
|
11592
|
||||||
|
11593
|
||||||
|
11594
|
||||||
|
11596
|
||||||
|
11597
|
||||||
|
11598
|
||||||
|
11599
|
||||||
|
11600
|
||||||
|
11601
|
||||||
|
11602
|
||||||
|
11603
|
||||||
|
11604
|
||||||
|
11605
|
||||||
|
11606
|
||||||
|
11607
|
||||||
|
11608
|
||||||
|
11609
|
||||||
|
11610
|
||||||
|
11611
|
||||||
|
11612
|
||||||
|
11613
|
||||||
|
11614
|
||||||
|
11615
|
||||||
|
11616
|
||||||
|
11617
|
||||||
|
11618
|
||||||
|
11619
|
||||||
|
11620
|
||||||
|
11621
|
||||||
|
11622
|
||||||
|
11623
|
||||||
|
11624
|
||||||
|
11625
|
||||||
|
11626
|
||||||
|
11627
|
||||||
|
11628
|
||||||
|
11629
|
||||||
|
11630
|
||||||
|
11631
|
||||||
|
11632
|
||||||
|
11633
|
||||||
|
11635
|
||||||
|
11636
|
||||||
|
11637
|
||||||
|
11638
|
||||||
|
11639
|
||||||
|
11640
|
||||||
|
11641
|
||||||
|
11642
|
||||||
|
11643
|
||||||
|
11645
|
||||||
|
11646
|
||||||
|
11647
|
||||||
|
11648
|
||||||
|
11650
|
||||||
|
11651
|
||||||
|
11652
|
||||||
|
11653
|
||||||
|
11654
|
||||||
|
11655
|
||||||
|
11656
|
||||||
|
11657
|
||||||
|
11658
|
||||||
|
11659
|
||||||
|
11660
|
||||||
|
11661
|
||||||
|
11662
|
||||||
|
11663
|
||||||
|
11664
|
||||||
|
11668
|
||||||
464
nonebot_plugin_maimai_helper/leak/music_custom.py
Normal file
464
nonebot_plugin_maimai_helper/leak/music_custom.py
Normal file
@@ -0,0 +1,464 @@
|
|||||||
|
import json
|
||||||
|
import pytz
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
|
||||||
|
from sdgb import sdgb_api
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
regionId = 1
|
||||||
|
regionName = "北京"
|
||||||
|
placeId = 1403
|
||||||
|
placeName = "插电师电玩北京西单大悦城店"
|
||||||
|
clientId = "A63E01C2805"
|
||||||
|
|
||||||
|
|
||||||
|
#from settings import userId
|
||||||
|
#from settings import music_data
|
||||||
|
#from settings import regionId
|
||||||
|
#from settings import regionName
|
||||||
|
#from settings import clientId
|
||||||
|
#from settings import placeId
|
||||||
|
#from settings import placeName
|
||||||
|
|
||||||
|
from login import login
|
||||||
|
from logout import logout
|
||||||
|
|
||||||
|
def CalcRandom():
|
||||||
|
max = 1037933
|
||||||
|
num2 = random.randint(1, max) * 2069
|
||||||
|
|
||||||
|
num2 += 1024 # specialnum
|
||||||
|
num3 = 0
|
||||||
|
for i in range(0, 32):
|
||||||
|
num3 <<= 1
|
||||||
|
num3 += num2 % 2
|
||||||
|
num2 >>= 1
|
||||||
|
|
||||||
|
return num3
|
||||||
|
|
||||||
|
timestamp = int(time.time()) - 60
|
||||||
|
|
||||||
|
def music():
|
||||||
|
music_data = ({
|
||||||
|
"musicId": music_Id,
|
||||||
|
"level": LevelID,
|
||||||
|
"playCount": Play_Count,
|
||||||
|
"achievement": Acc,
|
||||||
|
"comboStatus": Combo,
|
||||||
|
"syncStatus": Sync,
|
||||||
|
"deluxscoreMax": DXsc,
|
||||||
|
"scoreRank": Rank,
|
||||||
|
"extNum1": 0
|
||||||
|
})
|
||||||
|
music = music_data
|
||||||
|
|
||||||
|
musicId = music['musicId']
|
||||||
|
level = music['level']
|
||||||
|
playCount = music['playCount']
|
||||||
|
achievement = music['achievement']
|
||||||
|
comboStatus = music['comboStatus']
|
||||||
|
syncStatus = music['syncStatus']
|
||||||
|
deluxscoreMax = music['deluxscoreMax']
|
||||||
|
scoreRank = music['scoreRank']
|
||||||
|
extNum1 = music['extNum1']
|
||||||
|
|
||||||
|
print(timestamp)
|
||||||
|
|
||||||
|
# UserLogin
|
||||||
|
|
||||||
|
login_result = json.loads(login(timestamp))
|
||||||
|
print(login_result)
|
||||||
|
|
||||||
|
login_id = login_result['loginId']
|
||||||
|
login_date = login_result['lastLoginDate']
|
||||||
|
|
||||||
|
|
||||||
|
# UserData
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
userdata = json.loads(sdgb_api(data, "GetUserDataApi", userId))
|
||||||
|
|
||||||
|
# UserMusic 随机两首
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"nextIndex":random.randint(11000,11500),
|
||||||
|
"maxCount":2
|
||||||
|
})
|
||||||
|
|
||||||
|
music_details = json.loads(sdgb_api(data, "GetUserMusicApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# UserLog
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"userPlaylog": {
|
||||||
|
"userId": 0,
|
||||||
|
"orderId": 0,
|
||||||
|
"playlogId": login_id,
|
||||||
|
"version": 1041000,
|
||||||
|
"placeId": placeId,
|
||||||
|
"placeName": placeName,
|
||||||
|
"loginDate": int(time.time()),
|
||||||
|
"playDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d'),
|
||||||
|
"userPlayDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"type": 0,
|
||||||
|
"musicId": int(musicId),
|
||||||
|
"level": int(level),
|
||||||
|
"trackNo": 1,
|
||||||
|
"vsMode": 0,
|
||||||
|
"vsUserName": "",
|
||||||
|
"vsStatus": 0,
|
||||||
|
"vsUserRating": 0,
|
||||||
|
"vsUserAchievement": 0,
|
||||||
|
"vsUserGradeRank": 0,
|
||||||
|
"vsRank": 0,
|
||||||
|
"playerNum": 1,
|
||||||
|
"playedUserId1": 0,
|
||||||
|
"playedUserName1": "",
|
||||||
|
"playedMusicLevel1": 0,
|
||||||
|
"playedUserId2": 0,
|
||||||
|
"playedUserName2": "",
|
||||||
|
"playedMusicLevel2": 0,
|
||||||
|
"playedUserId3": 0,
|
||||||
|
"playedUserName3": "",
|
||||||
|
"playedMusicLevel3": 0,
|
||||||
|
"characterId1": userdata['userData']['charaSlot'][0],
|
||||||
|
"characterLevel1": random.randint(1000,6500),
|
||||||
|
"characterAwakening1": 5,
|
||||||
|
"characterId2": userdata['userData']['charaSlot'][1],
|
||||||
|
"characterLevel2": random.randint(1000,6500),
|
||||||
|
"characterAwakening2": 5,
|
||||||
|
"characterId3": userdata['userData']['charaSlot'][2],
|
||||||
|
"characterLevel3": random.randint(1000,6500),
|
||||||
|
"characterAwakening3": 5,
|
||||||
|
"characterId4": userdata['userData']['charaSlot'][3],
|
||||||
|
"characterLevel4": random.randint(1000,6500),
|
||||||
|
"characterAwakening4": 5,
|
||||||
|
"characterId5": userdata['userData']['charaSlot'][4],
|
||||||
|
"characterLevel5": random.randint(1000,6500),
|
||||||
|
"characterAwakening5": 5,
|
||||||
|
"achievement": int(achievement),
|
||||||
|
"deluxscore": int(deluxscoreMax),
|
||||||
|
"scoreRank": int(scoreRank),
|
||||||
|
"maxCombo": random.randint(400,500),
|
||||||
|
"totalCombo": random.randint(700,900),
|
||||||
|
"maxSync": 0,
|
||||||
|
"totalSync": 0,
|
||||||
|
"tapCriticalPerfect": random.randint(200,400),
|
||||||
|
"tapPerfect": random.randint(100,250),
|
||||||
|
"tapGreat": random.randint(0,10),
|
||||||
|
"tapGood": random.randint(0,10),
|
||||||
|
"tapMiss": random.randint(0,10),
|
||||||
|
"holdCriticalPerfect": random.randint(20,40),
|
||||||
|
"holdPerfect": random.randint(0,15),
|
||||||
|
"holdGreat": 0,
|
||||||
|
"holdGood": 0,
|
||||||
|
"holdMiss": 0,
|
||||||
|
"slideCriticalPerfect": random.randint(34,60),
|
||||||
|
"slidePerfect": 0,
|
||||||
|
"slideGreat": 0,
|
||||||
|
"slideGood": 0,
|
||||||
|
"slideMiss": 0,
|
||||||
|
"touchCriticalPerfect": random.randint(20,70),
|
||||||
|
"touchPerfect": 0,
|
||||||
|
"touchGreat": 0,
|
||||||
|
"touchGood": 0,
|
||||||
|
"touchMiss": 0,
|
||||||
|
"breakCriticalPerfect": random.randint(8,30),
|
||||||
|
"breakPerfect": random.randint(7,10),
|
||||||
|
"breakGreat": 0,
|
||||||
|
"breakGood": 0,
|
||||||
|
"breakMiss": 0,
|
||||||
|
"isTap": True,
|
||||||
|
"isHold": True,
|
||||||
|
"isSlide": True,
|
||||||
|
"isTouch": True,
|
||||||
|
"isBreak": True,
|
||||||
|
"isCriticalDisp": True,
|
||||||
|
"isFastLateDisp": True,
|
||||||
|
"fastCount": random.randint(20,30),
|
||||||
|
"lateCount": random.randint(50,70),
|
||||||
|
"isAchieveNewRecord": isAccNew,
|
||||||
|
"isDeluxscoreNewRecord": isDXCNew,
|
||||||
|
"comboStatus": 0,
|
||||||
|
"syncStatus": 0,
|
||||||
|
"isClear": Clear_Status,
|
||||||
|
'beforeRating': userdata['userData']['playerRating'],
|
||||||
|
'afterRating': userdata['userData']['playerRating'],
|
||||||
|
"beforeGrade": 0,
|
||||||
|
"afterGrade": 0,
|
||||||
|
"afterGradeRank": 2,
|
||||||
|
'beforeDeluxRating': userdata['userData']['playerRating'],
|
||||||
|
'afterDeluxRating': userdata['userData']['playerRating'],
|
||||||
|
"isPlayTutorial": False,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isFreedomMode": False,
|
||||||
|
"playMode": 0,
|
||||||
|
"isNewFree": False,
|
||||||
|
"trialPlayAchievement": -1,
|
||||||
|
"extNum1": 0,
|
||||||
|
"extNum2": 0,
|
||||||
|
"extNum4": 3020,
|
||||||
|
"extBool1": False
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
userlog_result = json.loads(sdgb_api(data, "UploadUserPlaylogApi", userId))
|
||||||
|
|
||||||
|
print(userlog_result)
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Extend
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_extend = json.loads(sdgb_api(data, "GetUserExtendApi", userId))
|
||||||
|
|
||||||
|
# 获取 User Option
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_option = json.loads(sdgb_api(data, "GetUserOptionApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Rating
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_rating = json.loads(sdgb_api(data, "GetUserRatingApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Activity
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_activity = json.loads(sdgb_api(data, "GetUserActivityApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取账号功能票
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_charge = json.loads(sdgb_api(data, "GetUserChargeApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# UserAll
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"playlogId": login_id,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isFreePlay": False,
|
||||||
|
"upsertUserAll": {
|
||||||
|
"userData": [
|
||||||
|
{
|
||||||
|
"accessCode": "",
|
||||||
|
"userName": userdata['userData']['userName'],
|
||||||
|
"isNetMember": 1,
|
||||||
|
"iconId": userdata['userData']['iconId'],
|
||||||
|
"plateId": userdata['userData']['plateId'],
|
||||||
|
"titleId": userdata['userData']['titleId'],
|
||||||
|
"partnerId": userdata['userData']['partnerId'],
|
||||||
|
"frameId": userdata['userData']['frameId'],
|
||||||
|
"selectMapId": userdata['userData']['selectMapId'],
|
||||||
|
"totalAwake": userdata['userData']['totalAwake'],
|
||||||
|
"gradeRating": userdata['userData']['gradeRating'],
|
||||||
|
"musicRating": userdata['userData']['musicRating'],
|
||||||
|
"playerRating": userdata['userData']['playerRating'],
|
||||||
|
"highestRating": userdata['userData']['highestRating'],
|
||||||
|
"gradeRank": userdata['userData']['gradeRank'],
|
||||||
|
"classRank": userdata['userData']['classRank'],
|
||||||
|
"courseRank": userdata['userData']['courseRank'],
|
||||||
|
"charaSlot": userdata['userData']['charaSlot'],
|
||||||
|
"charaLockSlot": userdata['userData']['charaLockSlot'],
|
||||||
|
"contentBit": userdata['userData']['contentBit'],
|
||||||
|
"playCount": userdata['userData']['playCount'],
|
||||||
|
"currentPlayCount": userdata['userData']['currentPlayCount'],
|
||||||
|
"renameCredit": 0,
|
||||||
|
"mapStock": userdata['userData']['mapStock'],
|
||||||
|
"eventWatchedDate": userdata['userData']['eventWatchedDate'],
|
||||||
|
"lastGameId": "SDGB",
|
||||||
|
"lastRomVersion": userdata['userData']['lastRomVersion'],
|
||||||
|
"lastDataVersion": userdata['userData']['lastDataVersion'],
|
||||||
|
"lastLoginDate": login_date,
|
||||||
|
"lastPlayDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"lastPlayCredit": 1,
|
||||||
|
"lastPlayMode": 0,
|
||||||
|
"lastPlaceId": placeId,
|
||||||
|
"lastPlaceName": placeName,
|
||||||
|
"lastAllNetId": 0,
|
||||||
|
"lastRegionId": regionId,
|
||||||
|
"lastRegionName": regionName,
|
||||||
|
"lastClientId": clientId,
|
||||||
|
"lastCountryCode": "CHN",
|
||||||
|
"lastSelectEMoney": 0,
|
||||||
|
"lastSelectTicket": 0,
|
||||||
|
"lastSelectCourse": userdata['userData']['lastSelectCourse'],
|
||||||
|
"lastCountCourse": 0,
|
||||||
|
"firstGameId": "SDGB",
|
||||||
|
"firstRomVersion": userdata['userData']['firstRomVersion'],
|
||||||
|
"firstDataVersion": userdata['userData']['firstDataVersion'],
|
||||||
|
"firstPlayDate": userdata['userData']['firstPlayDate'],
|
||||||
|
"compatibleCmVersion": userdata['userData']['compatibleCmVersion'],
|
||||||
|
"dailyBonusDate": userdata['userData']['dailyBonusDate'],
|
||||||
|
"dailyCourseBonusDate": userdata['userData']['dailyCourseBonusDate'],
|
||||||
|
"lastPairLoginDate": userdata['userData']['lastPairLoginDate'],
|
||||||
|
"lastTrialPlayDate": userdata['userData']['lastTrialPlayDate'],
|
||||||
|
"playVsCount": 0,
|
||||||
|
"playSyncCount": 0,
|
||||||
|
"winCount": 0,
|
||||||
|
"helpCount": 0,
|
||||||
|
"comboCount": 0,
|
||||||
|
"totalDeluxscore": userdata['userData']['totalDeluxscore'],
|
||||||
|
"totalBasicDeluxscore": userdata['userData']['totalBasicDeluxscore'],
|
||||||
|
"totalAdvancedDeluxscore": userdata['userData']['totalAdvancedDeluxscore'],
|
||||||
|
"totalExpertDeluxscore": userdata['userData']['totalExpertDeluxscore'],
|
||||||
|
"totalMasterDeluxscore": userdata['userData']['totalMasterDeluxscore'],
|
||||||
|
"totalReMasterDeluxscore": userdata['userData']['totalReMasterDeluxscore'],
|
||||||
|
"totalSync": userdata['userData']['totalSync'],
|
||||||
|
"totalBasicSync": userdata['userData']['totalBasicSync'],
|
||||||
|
"totalAdvancedSync": userdata['userData']['totalAdvancedSync'],
|
||||||
|
"totalExpertSync": userdata['userData']['totalExpertSync'],
|
||||||
|
"totalMasterSync": userdata['userData']['totalMasterSync'],
|
||||||
|
"totalReMasterSync": userdata['userData']['totalReMasterSync'],
|
||||||
|
"totalAchievement": userdata['userData']['totalAchievement'],
|
||||||
|
"totalBasicAchievement": userdata['userData']['totalBasicAchievement'],
|
||||||
|
"totalAdvancedAchievement": userdata['userData']['totalAdvancedAchievement'],
|
||||||
|
"totalExpertAchievement": userdata['userData']['totalExpertAchievement'],
|
||||||
|
"totalMasterAchievement": userdata['userData']['totalMasterAchievement'],
|
||||||
|
"totalReMasterAchievement": userdata['userData']['totalReMasterAchievement'],
|
||||||
|
"playerOldRating": userdata['userData']['playerOldRating'],
|
||||||
|
"playerNewRating": userdata['userData']['playerNewRating'],
|
||||||
|
"banState": 0,
|
||||||
|
"dateTime": timestamp
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userExtend": [user_extend['userExtend']],
|
||||||
|
"userOption": [user_option['userOption']],
|
||||||
|
"userCharacterList": [],
|
||||||
|
"userGhost": [],
|
||||||
|
"userMapList": [],
|
||||||
|
"userLoginBonusList": [],
|
||||||
|
"userRatingList": [user_rating['userRating']],
|
||||||
|
"userItemList": [],
|
||||||
|
"userMusicDetailList": [
|
||||||
|
{
|
||||||
|
"musicId": musicId,
|
||||||
|
"level": level,
|
||||||
|
"playCount": playCount,
|
||||||
|
"achievement": achievement,
|
||||||
|
"comboStatus": comboStatus,
|
||||||
|
"syncStatus": syncStatus,
|
||||||
|
"deluxscoreMax": deluxscoreMax,
|
||||||
|
"scoreRank": scoreRank,
|
||||||
|
"extNum1": extNum1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userCourseList": [],
|
||||||
|
"userFriendSeasonRankingList": [],
|
||||||
|
"userChargeList": user_charge['userChargeList'],
|
||||||
|
"userFavoriteList": [],
|
||||||
|
"userActivityList": [user_activity['userActivity']],
|
||||||
|
"userGamePlaylogList": [
|
||||||
|
{
|
||||||
|
"playlogId": login_id,
|
||||||
|
"version": "1.41.00",
|
||||||
|
"playDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"playMode": 0,
|
||||||
|
"useTicketId": -1,
|
||||||
|
"playCredit": 1,
|
||||||
|
"playTrack": 1,
|
||||||
|
"clientId": clientId,
|
||||||
|
"isPlayTutorial": False,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isNewFree": False,
|
||||||
|
"playCount": 0,
|
||||||
|
"playSpecial": CalcRandom(),
|
||||||
|
"playOtherUserId": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"user2pPlaylog": {
|
||||||
|
"userId1": 0,
|
||||||
|
"userId2": 0,
|
||||||
|
"userName1": "",
|
||||||
|
"userName2": "",
|
||||||
|
"regionId": 0,
|
||||||
|
"placeId": 0,
|
||||||
|
"user2pPlaylogDetailList": []
|
||||||
|
},
|
||||||
|
"isNewCharacterList": "",
|
||||||
|
"isNewMapList": "",
|
||||||
|
"isNewLoginBonusList": "",
|
||||||
|
"isNewItemList": "",
|
||||||
|
"isNewMusicDetailList": f"{isCover}",
|
||||||
|
"isNewCourseList": "0",
|
||||||
|
"isNewFavoriteList": "",
|
||||||
|
"isNewFriendSeasonRankingList": ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
userall_result = json.loads(sdgb_api(data, "UpsertUserAllApi", userId))
|
||||||
|
return userall_result
|
||||||
|
|
||||||
|
def music_with_retry(max_retries=10): # 这里是重试次数
|
||||||
|
for i in range(max_retries):
|
||||||
|
try:
|
||||||
|
print(music())
|
||||||
|
return logout(timestamp)
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"尝试 {i+1} 失败,错误:{e}")
|
||||||
|
print(logout(timestamp))
|
||||||
|
time.sleep(5) # 等待 5 秒后重试
|
||||||
|
return "重试次数超过限制,乐曲上传失败"
|
||||||
|
|
||||||
|
|
||||||
|
#zh_cn ver.
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
userId = int(input("请输入你的userid: "))
|
||||||
|
music_Id = int(input("请输入要发送的乐曲id: "))
|
||||||
|
LevelID = int(input("请输入乐曲难度(0:绿 1:黄 2:红 3:紫 4:白): "))
|
||||||
|
Play_Count = int(input("请输入游玩次数(如果你不知道这啥,请随便输入一些数字,别太离谱就行 比如 \'11\'): "))
|
||||||
|
Acc = int(input("请输入准确率(比如, S:970000 SSS:100000,别用小数点): "))
|
||||||
|
Clear_Status = input("请选择是否通关(True 或者 False,大小写敏感): ")
|
||||||
|
Rank = int(input("请输入等级(0:D 1:C 2:B 3:BB 4:BBB 5:A 6:AA 7:AAA 8:S 9:S+ 10:SS 11:SS+ 12:SSS 13:SSS+): "))
|
||||||
|
Combo = int(input("请输入是否fc/ap(0:None 1:FC 2:FC+ 3:AP 4:AP+): "))
|
||||||
|
Sync = int(input("请输入SyncStatus(0:None 1:FS 2:FS+ 3:FDX 4:FDX+ 5:SyncPlay): "))
|
||||||
|
DXsc = int(input("请输入DX分(别超过这首歌的总DX分): "))
|
||||||
|
isAccNew = input("请选择是否覆盖准确率(True:覆盖 False:不覆盖 大小写敏感): ")
|
||||||
|
isDXCNew = input("请选择是否覆盖DX分(True:覆盖 False:不覆盖 大小写敏感): ")
|
||||||
|
isCover = input("请选择是否删除乐曲信息(1:不删除*一般情况下请选择此项* 0:删除*若想删除成绩请选择此项*): ")
|
||||||
|
WARN = input("最后的警告,如果你检查好了全部数据正确,请按下Enter来确认操作,若没有,请立刻按下Ctrl+C。我不会对任何账号的bs2作出赔偿/道歉。怕别用用别怕封别叫。")
|
||||||
|
LASTWARN = input("最后最后的警告,你的数据真的全都对吗?准确率和等级对的上吗?DX分有没有超过这个难度或者歌曲的总值?如果真的真的确认了,请按下Enter继续操作,否则立刻按下Ctrl+C。")
|
||||||
|
print(music_with_retry())
|
||||||
|
|
||||||
|
#en_us ver.
|
||||||
|
|
||||||
|
#if __name__ == "__main__":
|
||||||
|
# userId = int(input("Please Input Your UserID: "))
|
||||||
|
# music_Id = int(input("Please Input MusicID: "))
|
||||||
|
# LevelID = int(input("Please Input MusicLevel(0BAS 1ADV 2EXP 3MAS 4ReMAS): "))
|
||||||
|
# Play_Count = int(input("Please Input Your PlayCount(if u dont know whats this, just use a random number like \'11\'): "))
|
||||||
|
# Acc = int(input("Please Input ACC(For example, S:970000 SSS:100000,just use num dont use another things): "))
|
||||||
|
# Clear_Status = input("Please Input ClearStatus(True or False,Caps Must): ")
|
||||||
|
# Rank = int(input("Please Input Rank(0:D 1:C 2:B 3:BB 4:BBB 5:A 6:AA 7:AAA 8:S 9:S+ 10:SS 11:SS+ 12:SSS 13:SSS+): "))
|
||||||
|
# Combo = int(input("Please Input ComboStatus(0:None 1:FC 2:FC+ 3:AP 4:AP+): "))
|
||||||
|
# Sync = int(input("Please Input SyncStatus(0:None 1:FS 2:FS+ 3:FDX 4:FDX+ 5:SyncPlay): "))
|
||||||
|
# DXsc = int(input("Please Input DXScore(DONT OVER THE SONG!): "))
|
||||||
|
# isAccNew = input("Please Input AccNewStatus(True:will overwrite or False:will not overwrite): ")
|
||||||
|
# isDXCNew = input("Please Input DXCStatus(True:will overwrite or False:will not overwrite): ")
|
||||||
|
# WARN = input("This is the LAST WARN. If your account has banned, DONT come and ask me. I will NOT pay anything for your bannned account. If you confirmed all data is currect, Press Enter. If NOT, Press Ctrl+C right NOW.")
|
||||||
|
# print(music_with_retry())
|
||||||
16
nonebot_plugin_maimai_helper/leak/preview.py
Normal file
16
nonebot_plugin_maimai_helper/leak/preview.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
from sdgb import sdgb_api
|
||||||
|
from settings import userId
|
||||||
|
|
||||||
|
def preview(userId):
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
preview_result = sdgb_api(data, "GetUserPreviewApi", userId)
|
||||||
|
|
||||||
|
return preview_result
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(preview(userId))
|
||||||
106
nonebot_plugin_maimai_helper/leak/sdgb.py
Normal file
106
nonebot_plugin_maimai_helper/leak/sdgb.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
import json
|
||||||
|
import zlib
|
||||||
|
import pytz
|
||||||
|
import base64
|
||||||
|
import hashlib
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
from Crypto.Util.Padding import pad, unpad
|
||||||
|
|
||||||
|
AesKey = "n7bx6:@Fg_:2;5E89Phy7AyIcpxEQ:R@"
|
||||||
|
AesIV = ";;KjR1C3hgB1ovXa"
|
||||||
|
ObfuscateParam = "BEs2D5vW"
|
||||||
|
KeychipID = "A63E-01C28055905"
|
||||||
|
|
||||||
|
class aes_pkcs7(object):
|
||||||
|
def __init__(self, key: str, iv: str):
|
||||||
|
self.key = key.encode('utf-8')
|
||||||
|
self.iv = iv.encode('utf-8')
|
||||||
|
self.mode = AES.MODE_CBC
|
||||||
|
|
||||||
|
def encrypt(self, content):
|
||||||
|
cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
|
||||||
|
content_padding = self.pkcs7padding(content)
|
||||||
|
encrypt_bytes = cipher.encrypt(content_padding.encode('utf-8'))
|
||||||
|
return encrypt_bytes
|
||||||
|
return base64.b64encode(encrypt_bytes)
|
||||||
|
|
||||||
|
def decrypt(self, content):
|
||||||
|
cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
|
||||||
|
#content = base64.b64decode(content)
|
||||||
|
return cipher.decrypt(content)
|
||||||
|
text = cipher.decrypt(content).decode('utf-8')
|
||||||
|
return self.pkcs7unpadding(text)
|
||||||
|
|
||||||
|
def pkcs7unpadding(self, text):
|
||||||
|
length = len(text)
|
||||||
|
unpadding = ord(text[length - 1])
|
||||||
|
return text[0:length - unpadding]
|
||||||
|
|
||||||
|
def pkcs7padding(self, text):
|
||||||
|
bs = 16
|
||||||
|
length = len(text)
|
||||||
|
bytes_length = len(text.encode('utf-8'))
|
||||||
|
padding_size = length if (bytes_length == length) else bytes_length
|
||||||
|
padding = bs - padding_size % bs
|
||||||
|
padding_text = chr(padding) * padding
|
||||||
|
return text + padding_text
|
||||||
|
|
||||||
|
def get_hash_api(api):
|
||||||
|
return hashlib.md5((api+"MaimaiChn"+ObfuscateParam).encode()).hexdigest()
|
||||||
|
|
||||||
|
def sdgb_api(data, useApi, userId):
|
||||||
|
aes = aes_pkcs7(AesKey,AesIV)
|
||||||
|
data = data
|
||||||
|
data_enc = aes.encrypt(data)
|
||||||
|
data_def = zlib.compress(data_enc)
|
||||||
|
requests.packages.urllib3.disable_warnings()
|
||||||
|
endpoint = "https://maimai-gm.wahlap.com:42081/Maimai2Servlet/"
|
||||||
|
r = requests.post(
|
||||||
|
endpoint + get_hash_api(useApi),
|
||||||
|
headers = {
|
||||||
|
"User-Agent": "%s#%d"%(get_hash_api(useApi), userId),
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Mai-Encoding": "1.40",
|
||||||
|
"Accept-Encoding": "",
|
||||||
|
"Charset": "UTF-8",
|
||||||
|
"Content-Encoding": "deflate",
|
||||||
|
"Expect": "100-continue"
|
||||||
|
},
|
||||||
|
data = data_def
|
||||||
|
)
|
||||||
|
resp_def = r.content
|
||||||
|
|
||||||
|
try:
|
||||||
|
resp_enc = zlib.decompress(resp_def)
|
||||||
|
#print(resp_enc)
|
||||||
|
except:
|
||||||
|
resp_enc = resp_def
|
||||||
|
#print("skipped")
|
||||||
|
#print(resp_enc)
|
||||||
|
return unpad(aes.decrypt(resp_enc), 16).decode()
|
||||||
|
|
||||||
|
def qr_api(qr_code):
|
||||||
|
if len(qr_code) > 64:
|
||||||
|
qr_code = qr_code[-64:]
|
||||||
|
time_stamp = datetime.now(pytz.timezone('Asia/Tokyo')).strftime("%y%m%d%H%M%S")
|
||||||
|
auth_key = hashlib.sha256(
|
||||||
|
(KeychipID + time_stamp + "XcW5FW4cPArBXEk4vzKz3CIrMuA5EVVW").encode("UTF-8")).hexdigest().upper()
|
||||||
|
param = {
|
||||||
|
"chipID": KeychipID,
|
||||||
|
"openGameID": "MAID",
|
||||||
|
"key": auth_key,
|
||||||
|
"qrCode": qr_code,
|
||||||
|
"timestamp": time_stamp
|
||||||
|
}
|
||||||
|
headers = {
|
||||||
|
"Contention": "Keep-Alive",
|
||||||
|
"Host": "ai.sys-all.cn",
|
||||||
|
"User-Agent": "WC_AIME_LIB"
|
||||||
|
}
|
||||||
|
res = requests.post("http://ai.sys-allnet.cn/wc_aime/api/get_data", data=json.dumps(param, separators=(',', ':')), headers=headers)
|
||||||
|
# print(param) # debug打印param数据
|
||||||
|
assert res.status_code == 200, "网络错误"
|
||||||
|
return json.loads(res.content)
|
||||||
30
nonebot_plugin_maimai_helper/leak/settings.py
Normal file
30
nonebot_plugin_maimai_helper/leak/settings.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# This file contains the config of the whole project.
|
||||||
|
# DO NOT share your crtical info to others.
|
||||||
|
# Change the file name from .settings.py to settings.py.
|
||||||
|
|
||||||
|
|
||||||
|
# UserId 自行获取
|
||||||
|
userId = 11246129
|
||||||
|
|
||||||
|
# 上传的乐曲成绩
|
||||||
|
# 此成绩将覆盖原有成绩
|
||||||
|
|
||||||
|
music_data = ({
|
||||||
|
"musicId": 834,
|
||||||
|
"level": 4,
|
||||||
|
"playCount": 11,
|
||||||
|
"achievement": 912241,
|
||||||
|
"comboStatus": 0,
|
||||||
|
"syncStatus": 0,
|
||||||
|
"deluxscoreMax": 2102,
|
||||||
|
"scoreRank": 5,
|
||||||
|
"extNum1": 0
|
||||||
|
})
|
||||||
|
|
||||||
|
# 机厅信息
|
||||||
|
|
||||||
|
regionId = 1
|
||||||
|
regionName = "北京"
|
||||||
|
placeId = 1403
|
||||||
|
placeName = "插电师电玩北京西单大悦城店"
|
||||||
|
clientId = "A63E01C2805"
|
||||||
42
nonebot_plugin_maimai_helper/leak/ticket.py
Normal file
42
nonebot_plugin_maimai_helper/leak/ticket.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import json
|
||||||
|
import pytz
|
||||||
|
import time
|
||||||
|
|
||||||
|
from sdgb import sdgb_api
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from settings import userId
|
||||||
|
from settings import regionId, clientId, placeId
|
||||||
|
|
||||||
|
from logout import logout
|
||||||
|
from login import login
|
||||||
|
|
||||||
|
def get_ticket():
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": userId,
|
||||||
|
"userCharge": {
|
||||||
|
"chargeId": 6,
|
||||||
|
"stock": 1,
|
||||||
|
"purchaseDate": (datetime.now(pytz.timezone('Asia/Shanghai')) - timedelta(hours=1)).strftime("%Y-%m-%d %H:%M:%S.0"),
|
||||||
|
"validDate": (datetime.now(pytz.timezone('Asia/Shanghai')) - timedelta(hours=1) + timedelta(days=90)).replace(hour=4, minute=0, second=0).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
},
|
||||||
|
"userChargelog": {
|
||||||
|
"chargeId": 6,
|
||||||
|
"price": 4,
|
||||||
|
"purchaseDate": (datetime.now(pytz.timezone('Asia/Shanghai')) - timedelta(hours=1)).strftime("%Y-%m-%d %H:%M:%S.0"),
|
||||||
|
"placeId": placeId,
|
||||||
|
"regionId": regionId,
|
||||||
|
"clientId": clientId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ticket_result = sdgb_api(data, "UpsertUserChargelogApi", userId)
|
||||||
|
|
||||||
|
return ticket_result
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
timestamp = int(time.time())
|
||||||
|
print(timestamp)
|
||||||
|
print(login(timestamp))
|
||||||
|
print(get_ticket())
|
||||||
|
print(logout(timestamp))
|
||||||
414
nonebot_plugin_maimai_helper/leak/unlock.py
Normal file
414
nonebot_plugin_maimai_helper/leak/unlock.py
Normal file
@@ -0,0 +1,414 @@
|
|||||||
|
import json
|
||||||
|
import pytz
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
|
||||||
|
from sdgb import sdgb_api
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from settings import userId
|
||||||
|
from settings import music_data
|
||||||
|
from settings import regionId
|
||||||
|
from settings import regionName
|
||||||
|
from settings import clientId
|
||||||
|
from settings import placeId
|
||||||
|
from settings import placeName
|
||||||
|
|
||||||
|
from login import login
|
||||||
|
from logout import logout
|
||||||
|
|
||||||
|
def CalcRandom():
|
||||||
|
max = 1037933
|
||||||
|
num2 = random.randint(1, max) * 2069
|
||||||
|
|
||||||
|
num2 += 1024 # specialnum
|
||||||
|
num3 = 0
|
||||||
|
for i in range(0, 32):
|
||||||
|
num3 <<= 1
|
||||||
|
num3 += num2 % 2
|
||||||
|
num2 >>= 1
|
||||||
|
|
||||||
|
return num3
|
||||||
|
|
||||||
|
timestamp = int(time.time()) - 60
|
||||||
|
|
||||||
|
def music(unlock_id):
|
||||||
|
|
||||||
|
music = music_data
|
||||||
|
|
||||||
|
musicId = music['musicId']
|
||||||
|
level = music['level']
|
||||||
|
playCount = music['playCount']
|
||||||
|
achievement = music['achievement']
|
||||||
|
comboStatus = music['comboStatus']
|
||||||
|
syncStatus = music['syncStatus']
|
||||||
|
deluxscoreMax = music['deluxscoreMax']
|
||||||
|
scoreRank = music['scoreRank']
|
||||||
|
extNum1 = music['extNum1']
|
||||||
|
|
||||||
|
print(timestamp)
|
||||||
|
|
||||||
|
# UserLogin
|
||||||
|
|
||||||
|
login_result = json.loads(login(timestamp))
|
||||||
|
print(login_result)
|
||||||
|
|
||||||
|
login_id = login_result['loginId']
|
||||||
|
login_date = login_result['lastLoginDate']
|
||||||
|
|
||||||
|
|
||||||
|
# UserData
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
userdata = json.loads(sdgb_api(data, "GetUserDataApi", userId))
|
||||||
|
|
||||||
|
# UserLog
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"userPlaylog": {
|
||||||
|
"userId": 0,
|
||||||
|
"orderId": 0,
|
||||||
|
"playlogId": login_id,
|
||||||
|
"version": 1041000,
|
||||||
|
"placeId": placeId,
|
||||||
|
"placeName": placeName,
|
||||||
|
"loginDate": int(time.time()),
|
||||||
|
"playDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d'),
|
||||||
|
"userPlayDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"type": 0,
|
||||||
|
"musicId": int(musicId),
|
||||||
|
"level": int(level),
|
||||||
|
"trackNo": 1,
|
||||||
|
"vsMode": 0,
|
||||||
|
"vsUserName": "",
|
||||||
|
"vsStatus": 0,
|
||||||
|
"vsUserRating": 0,
|
||||||
|
"vsUserAchievement": 0,
|
||||||
|
"vsUserGradeRank": 0,
|
||||||
|
"vsRank": 0,
|
||||||
|
"playerNum": 1,
|
||||||
|
"playedUserId1": 0,
|
||||||
|
"playedUserName1": "",
|
||||||
|
"playedMusicLevel1": 0,
|
||||||
|
"playedUserId2": 0,
|
||||||
|
"playedUserName2": "",
|
||||||
|
"playedMusicLevel2": 0,
|
||||||
|
"playedUserId3": 0,
|
||||||
|
"playedUserName3": "",
|
||||||
|
"playedMusicLevel3": 0,
|
||||||
|
"characterId1": userdata['userData']['charaSlot'][0],
|
||||||
|
"characterLevel1": random.randint(1000,6500),
|
||||||
|
"characterAwakening1": 5,
|
||||||
|
"characterId2": userdata['userData']['charaSlot'][1],
|
||||||
|
"characterLevel2": random.randint(1000,6500),
|
||||||
|
"characterAwakening2": 5,
|
||||||
|
"characterId3": userdata['userData']['charaSlot'][2],
|
||||||
|
"characterLevel3": random.randint(1000,6500),
|
||||||
|
"characterAwakening3": 5,
|
||||||
|
"characterId4": userdata['userData']['charaSlot'][3],
|
||||||
|
"characterLevel4": random.randint(1000,6500),
|
||||||
|
"characterAwakening4": 5,
|
||||||
|
"characterId5": userdata['userData']['charaSlot'][4],
|
||||||
|
"characterLevel5": random.randint(1000,6500),
|
||||||
|
"characterAwakening5": 5,
|
||||||
|
"achievement": int(achievement),
|
||||||
|
"deluxscore": int(deluxscoreMax),
|
||||||
|
"scoreRank": int(scoreRank),
|
||||||
|
"maxCombo": random.randint(400,500),
|
||||||
|
"totalCombo": random.randint(700,900),
|
||||||
|
"maxSync": 0,
|
||||||
|
"totalSync": 0,
|
||||||
|
"tapCriticalPerfect": random.randint(200,400),
|
||||||
|
"tapPerfect": random.randint(100,250),
|
||||||
|
"tapGreat": random.randint(0,10),
|
||||||
|
"tapGood": random.randint(0,10),
|
||||||
|
"tapMiss": random.randint(0,10),
|
||||||
|
"holdCriticalPerfect": random.randint(20,40),
|
||||||
|
"holdPerfect": random.randint(0,15),
|
||||||
|
"holdGreat": 0,
|
||||||
|
"holdGood": 0,
|
||||||
|
"holdMiss": 0,
|
||||||
|
"slideCriticalPerfect": random.randint(34,60),
|
||||||
|
"slidePerfect": 0,
|
||||||
|
"slideGreat": 0,
|
||||||
|
"slideGood": 0,
|
||||||
|
"slideMiss": 0,
|
||||||
|
"touchCriticalPerfect": random.randint(20,70),
|
||||||
|
"touchPerfect": 0,
|
||||||
|
"touchGreat": 0,
|
||||||
|
"touchGood": 0,
|
||||||
|
"touchMiss": 0,
|
||||||
|
"breakCriticalPerfect": random.randint(8,30),
|
||||||
|
"breakPerfect": random.randint(7,10),
|
||||||
|
"breakGreat": 0,
|
||||||
|
"breakGood": 0,
|
||||||
|
"breakMiss": 0,
|
||||||
|
"isTap": True,
|
||||||
|
"isHold": True,
|
||||||
|
"isSlide": True,
|
||||||
|
"isTouch": True,
|
||||||
|
"isBreak": True,
|
||||||
|
"isCriticalDisp": True,
|
||||||
|
"isFastLateDisp": True,
|
||||||
|
"fastCount": random.randint(20,30),
|
||||||
|
"lateCount": random.randint(50,70),
|
||||||
|
"isAchieveNewRecord": True,
|
||||||
|
"isDeluxscoreNewRecord": True,
|
||||||
|
"comboStatus": 0,
|
||||||
|
"syncStatus": 0,
|
||||||
|
"isClear": True,
|
||||||
|
'beforeRating': userdata['userData']['playerRating'],
|
||||||
|
'afterRating': userdata['userData']['playerRating'],
|
||||||
|
"beforeGrade": 0,
|
||||||
|
"afterGrade": 0,
|
||||||
|
"afterGradeRank": 2,
|
||||||
|
'beforeDeluxRating': userdata['userData']['playerRating'],
|
||||||
|
'afterDeluxRating': userdata['userData']['playerRating'],
|
||||||
|
"isPlayTutorial": False,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isFreedomMode": False,
|
||||||
|
"playMode": 0,
|
||||||
|
"isNewFree": False,
|
||||||
|
"trialPlayAchievement": -1,
|
||||||
|
"extNum1": 0,
|
||||||
|
"extNum2": 0,
|
||||||
|
"extNum4": 3020,
|
||||||
|
"extBool1": False
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
userlog_result = json.loads(sdgb_api(data, "UploadUserPlaylogApi", userId))
|
||||||
|
|
||||||
|
print(userlog_result)
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Extend
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_extend = json.loads(sdgb_api(data, "GetUserExtendApi", userId))
|
||||||
|
|
||||||
|
# 获取 User Option
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_option = json.loads(sdgb_api(data, "GetUserOptionApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Rating
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_rating = json.loads(sdgb_api(data, "GetUserRatingApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Activity
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_activity = json.loads(sdgb_api(data, "GetUserActivityApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取账号功能票
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_charge = json.loads(sdgb_api(data, "GetUserChargeApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# UserAll
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"playlogId": login_id,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isFreePlay": False,
|
||||||
|
"upsertUserAll": {
|
||||||
|
"userData": [
|
||||||
|
{
|
||||||
|
"accessCode": "",
|
||||||
|
"userName": userdata['userData']['userName'],
|
||||||
|
"isNetMember": 1,
|
||||||
|
"iconId": userdata['userData']['iconId'],
|
||||||
|
"plateId": userdata['userData']['plateId'],
|
||||||
|
"titleId": userdata['userData']['titleId'],
|
||||||
|
"partnerId": userdata['userData']['partnerId'],
|
||||||
|
"frameId": userdata['userData']['frameId'],
|
||||||
|
"selectMapId": userdata['userData']['selectMapId'],
|
||||||
|
"totalAwake": userdata['userData']['totalAwake'],
|
||||||
|
"gradeRating": userdata['userData']['gradeRating'],
|
||||||
|
"musicRating": userdata['userData']['musicRating'],
|
||||||
|
"playerRating": userdata['userData']['playerRating'],
|
||||||
|
"highestRating": userdata['userData']['highestRating'],
|
||||||
|
"gradeRank": userdata['userData']['gradeRank'],
|
||||||
|
"classRank": userdata['userData']['classRank'],
|
||||||
|
"courseRank": userdata['userData']['courseRank'],
|
||||||
|
"charaSlot": userdata['userData']['charaSlot'],
|
||||||
|
"charaLockSlot": userdata['userData']['charaLockSlot'],
|
||||||
|
"contentBit": userdata['userData']['contentBit'],
|
||||||
|
"playCount": userdata['userData']['playCount'],
|
||||||
|
"currentPlayCount": userdata['userData']['currentPlayCount'],
|
||||||
|
"renameCredit": 0,
|
||||||
|
"mapStock": userdata['userData']['mapStock'],
|
||||||
|
"eventWatchedDate": userdata['userData']['eventWatchedDate'],
|
||||||
|
"lastGameId": "SDGB",
|
||||||
|
"lastRomVersion": userdata['userData']['lastRomVersion'],
|
||||||
|
"lastDataVersion": userdata['userData']['lastDataVersion'],
|
||||||
|
"lastLoginDate": login_date,
|
||||||
|
"lastPlayDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"lastPlayCredit": 1,
|
||||||
|
"lastPlayMode": 0,
|
||||||
|
"lastPlaceId": placeId,
|
||||||
|
"lastPlaceName": placeName,
|
||||||
|
"lastAllNetId": 0,
|
||||||
|
"lastRegionId": regionId,
|
||||||
|
"lastRegionName": regionName,
|
||||||
|
"lastClientId": clientId,
|
||||||
|
"lastCountryCode": "CHN",
|
||||||
|
"lastSelectEMoney": 0,
|
||||||
|
"lastSelectTicket": 0,
|
||||||
|
"lastSelectCourse": userdata['userData']['lastSelectCourse'],
|
||||||
|
"lastCountCourse": 0,
|
||||||
|
"firstGameId": "SDGB",
|
||||||
|
"firstRomVersion": userdata['userData']['firstRomVersion'],
|
||||||
|
"firstDataVersion": userdata['userData']['firstDataVersion'],
|
||||||
|
"firstPlayDate": userdata['userData']['firstPlayDate'],
|
||||||
|
"compatibleCmVersion": userdata['userData']['compatibleCmVersion'],
|
||||||
|
"dailyBonusDate": userdata['userData']['dailyBonusDate'],
|
||||||
|
"dailyCourseBonusDate": userdata['userData']['dailyCourseBonusDate'],
|
||||||
|
"lastPairLoginDate": userdata['userData']['lastPairLoginDate'],
|
||||||
|
"lastTrialPlayDate": userdata['userData']['lastTrialPlayDate'],
|
||||||
|
"playVsCount": 0,
|
||||||
|
"playSyncCount": 0,
|
||||||
|
"winCount": 0,
|
||||||
|
"helpCount": 0,
|
||||||
|
"comboCount": 0,
|
||||||
|
"totalDeluxscore": userdata['userData']['totalDeluxscore'],
|
||||||
|
"totalBasicDeluxscore": userdata['userData']['totalBasicDeluxscore'],
|
||||||
|
"totalAdvancedDeluxscore": userdata['userData']['totalAdvancedDeluxscore'],
|
||||||
|
"totalExpertDeluxscore": userdata['userData']['totalExpertDeluxscore'],
|
||||||
|
"totalMasterDeluxscore": userdata['userData']['totalMasterDeluxscore'],
|
||||||
|
"totalReMasterDeluxscore": userdata['userData']['totalReMasterDeluxscore'],
|
||||||
|
"totalSync": userdata['userData']['totalSync'],
|
||||||
|
"totalBasicSync": userdata['userData']['totalBasicSync'],
|
||||||
|
"totalAdvancedSync": userdata['userData']['totalAdvancedSync'],
|
||||||
|
"totalExpertSync": userdata['userData']['totalExpertSync'],
|
||||||
|
"totalMasterSync": userdata['userData']['totalMasterSync'],
|
||||||
|
"totalReMasterSync": userdata['userData']['totalReMasterSync'],
|
||||||
|
"totalAchievement": userdata['userData']['totalAchievement'],
|
||||||
|
"totalBasicAchievement": userdata['userData']['totalBasicAchievement'],
|
||||||
|
"totalAdvancedAchievement": userdata['userData']['totalAdvancedAchievement'],
|
||||||
|
"totalExpertAchievement": userdata['userData']['totalExpertAchievement'],
|
||||||
|
"totalMasterAchievement": userdata['userData']['totalMasterAchievement'],
|
||||||
|
"totalReMasterAchievement": userdata['userData']['totalReMasterAchievement'],
|
||||||
|
"playerOldRating": userdata['userData']['playerOldRating'],
|
||||||
|
"playerNewRating": userdata['userData']['playerNewRating'],
|
||||||
|
"banState": 0,
|
||||||
|
"dateTime": timestamp
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userExtend": [user_extend['userExtend']],
|
||||||
|
"userOption": [user_option['userOption']],
|
||||||
|
"userCharacterList": [],
|
||||||
|
"userGhost": [],
|
||||||
|
"userMapList": [],
|
||||||
|
"userLoginBonusList": [],
|
||||||
|
"userRatingList": [user_rating['userRating']],
|
||||||
|
"userItemList": [
|
||||||
|
{
|
||||||
|
"itemKind": 5,
|
||||||
|
"itemId": unlock_id,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 6,
|
||||||
|
"itemId": unlock_id,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userMusicDetailList": [
|
||||||
|
{
|
||||||
|
"musicId": musicId,
|
||||||
|
"level": level,
|
||||||
|
"playCount": playCount,
|
||||||
|
"achievement": achievement,
|
||||||
|
"comboStatus": comboStatus,
|
||||||
|
"syncStatus": syncStatus,
|
||||||
|
"deluxscoreMax": deluxscoreMax,
|
||||||
|
"scoreRank": scoreRank,
|
||||||
|
"extNum1": extNum1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userCourseList": [],
|
||||||
|
"userFriendSeasonRankingList": [],
|
||||||
|
"userChargeList": user_charge['userChargeList'],
|
||||||
|
"userFavoriteList": [],
|
||||||
|
"userActivityList": [user_activity['userActivity']],
|
||||||
|
"userGamePlaylogList": [
|
||||||
|
{
|
||||||
|
"playlogId": login_id,
|
||||||
|
"version": "1.41.00",
|
||||||
|
"playDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"playMode": 0,
|
||||||
|
"useTicketId": -1,
|
||||||
|
"playCredit": 1,
|
||||||
|
"playTrack": 1,
|
||||||
|
"clientId": clientId,
|
||||||
|
"isPlayTutorial": False,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isNewFree": False,
|
||||||
|
"playCount": 0,
|
||||||
|
"playSpecial": CalcRandom(),
|
||||||
|
"playOtherUserId": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"user2pPlaylog": {
|
||||||
|
"userId1": 0,
|
||||||
|
"userId2": 0,
|
||||||
|
"userName1": "",
|
||||||
|
"userName2": "",
|
||||||
|
"regionId": 0,
|
||||||
|
"placeId": 0,
|
||||||
|
"user2pPlaylogDetailList": []
|
||||||
|
},
|
||||||
|
"isNewCharacterList": "",
|
||||||
|
"isNewMapList": "",
|
||||||
|
"isNewLoginBonusList": "",
|
||||||
|
"isNewItemList": 11,
|
||||||
|
"isNewMusicDetailList": "0",
|
||||||
|
"isNewCourseList": "0",
|
||||||
|
"isNewFavoriteList": "",
|
||||||
|
"isNewFriendSeasonRankingList": ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
userall_result = json.loads(sdgb_api(data, "UpsertUserAllApi", userId))
|
||||||
|
return userall_result
|
||||||
|
|
||||||
|
def music_with_retry(unlock_id,max_retries=10): # 这里是重试次数
|
||||||
|
for i in range(max_retries):
|
||||||
|
try:
|
||||||
|
print(unlock_id)
|
||||||
|
print(music(unlock_id))
|
||||||
|
return logout(timestamp)
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"尝试 {i+1} 失败,错误:{e}")
|
||||||
|
print(logout(timestamp))
|
||||||
|
time.sleep(5) # 等待 5 秒后重试
|
||||||
|
return "重试次数超过限制,乐曲上传失败"
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(music_with_retry(int(input("Input MusicID: "))))
|
||||||
7513
nonebot_plugin_maimai_helper/leak/unlock_all.py
Normal file
7513
nonebot_plugin_maimai_helper/leak/unlock_all.py
Normal file
File diff suppressed because it is too large
Load Diff
429
nonebot_plugin_maimai_helper/leak/unlock_custom.py
Normal file
429
nonebot_plugin_maimai_helper/leak/unlock_custom.py
Normal file
@@ -0,0 +1,429 @@
|
|||||||
|
import json
|
||||||
|
import pytz
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
|
||||||
|
from sdgb import sdgb_api
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
regionId = 1
|
||||||
|
regionName = "北京"
|
||||||
|
placeId = 1403
|
||||||
|
placeName = "插电师电玩北京西单大悦城店"
|
||||||
|
clientId = "A63E01C2805"
|
||||||
|
music_data = ({
|
||||||
|
"musicId": 834,
|
||||||
|
"level": 4,
|
||||||
|
"playCount": 11,
|
||||||
|
"achievement": 912241,
|
||||||
|
"comboStatus": 0,
|
||||||
|
"syncStatus": 0,
|
||||||
|
"deluxscoreMax": 2102,
|
||||||
|
"scoreRank": 5,
|
||||||
|
"extNum1": 0
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
#from settings import userId
|
||||||
|
#from settings import music_data
|
||||||
|
#from settings import regionId
|
||||||
|
#from settings import regionName
|
||||||
|
#from settings import clientId
|
||||||
|
#from settings import placeId
|
||||||
|
#from settings import placeName
|
||||||
|
|
||||||
|
from login import login
|
||||||
|
from logout import logout
|
||||||
|
|
||||||
|
def CalcRandom():
|
||||||
|
max = 1037933
|
||||||
|
num2 = random.randint(1, max) * 2069
|
||||||
|
|
||||||
|
num2 += 1024 # specialnum
|
||||||
|
num3 = 0
|
||||||
|
for i in range(0, 32):
|
||||||
|
num3 <<= 1
|
||||||
|
num3 += num2 % 2
|
||||||
|
num2 >>= 1
|
||||||
|
|
||||||
|
return num3
|
||||||
|
|
||||||
|
timestamp = int(time.time()) - 60
|
||||||
|
|
||||||
|
def music(unlock_id):
|
||||||
|
|
||||||
|
music = music_data
|
||||||
|
|
||||||
|
musicId = music['musicId']
|
||||||
|
level = music['level']
|
||||||
|
playCount = music['playCount']
|
||||||
|
achievement = music['achievement']
|
||||||
|
comboStatus = music['comboStatus']
|
||||||
|
syncStatus = music['syncStatus']
|
||||||
|
deluxscoreMax = music['deluxscoreMax']
|
||||||
|
scoreRank = music['scoreRank']
|
||||||
|
extNum1 = music['extNum1']
|
||||||
|
|
||||||
|
print(timestamp)
|
||||||
|
|
||||||
|
# UserLogin
|
||||||
|
|
||||||
|
login_result = json.loads(login(timestamp))
|
||||||
|
print(login_result)
|
||||||
|
|
||||||
|
login_id = login_result['loginId']
|
||||||
|
login_date = login_result['lastLoginDate']
|
||||||
|
|
||||||
|
|
||||||
|
# UserData
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
userdata = json.loads(sdgb_api(data, "GetUserDataApi", userId))
|
||||||
|
|
||||||
|
# UserLog
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"userPlaylog": {
|
||||||
|
"userId": 0,
|
||||||
|
"orderId": 0,
|
||||||
|
"playlogId": login_id,
|
||||||
|
"version": 1041000,
|
||||||
|
"placeId": placeId,
|
||||||
|
"placeName": placeName,
|
||||||
|
"loginDate": int(time.time()),
|
||||||
|
"playDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d'),
|
||||||
|
"userPlayDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"type": 0,
|
||||||
|
"musicId": int(musicId),
|
||||||
|
"level": int(level),
|
||||||
|
"trackNo": 1,
|
||||||
|
"vsMode": 0,
|
||||||
|
"vsUserName": "",
|
||||||
|
"vsStatus": 0,
|
||||||
|
"vsUserRating": 0,
|
||||||
|
"vsUserAchievement": 0,
|
||||||
|
"vsUserGradeRank": 0,
|
||||||
|
"vsRank": 0,
|
||||||
|
"playerNum": 1,
|
||||||
|
"playedUserId1": 0,
|
||||||
|
"playedUserName1": "",
|
||||||
|
"playedMusicLevel1": 0,
|
||||||
|
"playedUserId2": 0,
|
||||||
|
"playedUserName2": "",
|
||||||
|
"playedMusicLevel2": 0,
|
||||||
|
"playedUserId3": 0,
|
||||||
|
"playedUserName3": "",
|
||||||
|
"playedMusicLevel3": 0,
|
||||||
|
"characterId1": userdata['userData']['charaSlot'][0],
|
||||||
|
"characterLevel1": random.randint(1000,6500),
|
||||||
|
"characterAwakening1": 5,
|
||||||
|
"characterId2": userdata['userData']['charaSlot'][1],
|
||||||
|
"characterLevel2": random.randint(1000,6500),
|
||||||
|
"characterAwakening2": 5,
|
||||||
|
"characterId3": userdata['userData']['charaSlot'][2],
|
||||||
|
"characterLevel3": random.randint(1000,6500),
|
||||||
|
"characterAwakening3": 5,
|
||||||
|
"characterId4": userdata['userData']['charaSlot'][3],
|
||||||
|
"characterLevel4": random.randint(1000,6500),
|
||||||
|
"characterAwakening4": 5,
|
||||||
|
"characterId5": userdata['userData']['charaSlot'][4],
|
||||||
|
"characterLevel5": random.randint(1000,6500),
|
||||||
|
"characterAwakening5": 5,
|
||||||
|
"achievement": int(achievement),
|
||||||
|
"deluxscore": int(deluxscoreMax),
|
||||||
|
"scoreRank": int(scoreRank),
|
||||||
|
"maxCombo": random.randint(400,500),
|
||||||
|
"totalCombo": random.randint(700,900),
|
||||||
|
"maxSync": 0,
|
||||||
|
"totalSync": 0,
|
||||||
|
"tapCriticalPerfect": random.randint(200,400),
|
||||||
|
"tapPerfect": random.randint(100,250),
|
||||||
|
"tapGreat": random.randint(0,10),
|
||||||
|
"tapGood": random.randint(0,10),
|
||||||
|
"tapMiss": random.randint(0,10),
|
||||||
|
"holdCriticalPerfect": random.randint(20,40),
|
||||||
|
"holdPerfect": random.randint(0,15),
|
||||||
|
"holdGreat": 0,
|
||||||
|
"holdGood": 0,
|
||||||
|
"holdMiss": 0,
|
||||||
|
"slideCriticalPerfect": random.randint(34,60),
|
||||||
|
"slidePerfect": 0,
|
||||||
|
"slideGreat": 0,
|
||||||
|
"slideGood": 0,
|
||||||
|
"slideMiss": 0,
|
||||||
|
"touchCriticalPerfect": random.randint(20,70),
|
||||||
|
"touchPerfect": 0,
|
||||||
|
"touchGreat": 0,
|
||||||
|
"touchGood": 0,
|
||||||
|
"touchMiss": 0,
|
||||||
|
"breakCriticalPerfect": random.randint(8,30),
|
||||||
|
"breakPerfect": random.randint(7,10),
|
||||||
|
"breakGreat": 0,
|
||||||
|
"breakGood": 0,
|
||||||
|
"breakMiss": 0,
|
||||||
|
"isTap": True,
|
||||||
|
"isHold": True,
|
||||||
|
"isSlide": True,
|
||||||
|
"isTouch": True,
|
||||||
|
"isBreak": True,
|
||||||
|
"isCriticalDisp": True,
|
||||||
|
"isFastLateDisp": True,
|
||||||
|
"fastCount": random.randint(20,30),
|
||||||
|
"lateCount": random.randint(50,70),
|
||||||
|
"isAchieveNewRecord": True,
|
||||||
|
"isDeluxscoreNewRecord": True,
|
||||||
|
"comboStatus": 0,
|
||||||
|
"syncStatus": 0,
|
||||||
|
"isClear": True,
|
||||||
|
'beforeRating': userdata['userData']['playerRating'],
|
||||||
|
'afterRating': userdata['userData']['playerRating'],
|
||||||
|
"beforeGrade": 0,
|
||||||
|
"afterGrade": 0,
|
||||||
|
"afterGradeRank": 2,
|
||||||
|
'beforeDeluxRating': userdata['userData']['playerRating'],
|
||||||
|
'afterDeluxRating': userdata['userData']['playerRating'],
|
||||||
|
"isPlayTutorial": False,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isFreedomMode": False,
|
||||||
|
"playMode": 0,
|
||||||
|
"isNewFree": False,
|
||||||
|
"trialPlayAchievement": -1,
|
||||||
|
"extNum1": 0,
|
||||||
|
"extNum2": 0,
|
||||||
|
"extNum4": 3020,
|
||||||
|
"extBool1": False
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
userlog_result = json.loads(sdgb_api(data, "UploadUserPlaylogApi", userId))
|
||||||
|
|
||||||
|
print(userlog_result)
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Extend
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_extend = json.loads(sdgb_api(data, "GetUserExtendApi", userId))
|
||||||
|
|
||||||
|
# 获取 User Option
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_option = json.loads(sdgb_api(data, "GetUserOptionApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Rating
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_rating = json.loads(sdgb_api(data, "GetUserRatingApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Activity
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_activity = json.loads(sdgb_api(data, "GetUserActivityApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取账号功能票
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_charge = json.loads(sdgb_api(data, "GetUserChargeApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# UserAll
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"playlogId": login_id,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isFreePlay": False,
|
||||||
|
"upsertUserAll": {
|
||||||
|
"userData": [
|
||||||
|
{
|
||||||
|
"accessCode": "",
|
||||||
|
"userName": userdata['userData']['userName'],
|
||||||
|
"isNetMember": 1,
|
||||||
|
"iconId": userdata['userData']['iconId'],
|
||||||
|
"plateId": userdata['userData']['plateId'],
|
||||||
|
"titleId": userdata['userData']['titleId'],
|
||||||
|
"partnerId": userdata['userData']['partnerId'],
|
||||||
|
"frameId": userdata['userData']['frameId'],
|
||||||
|
"selectMapId": userdata['userData']['selectMapId'],
|
||||||
|
"totalAwake": userdata['userData']['totalAwake'],
|
||||||
|
"gradeRating": userdata['userData']['gradeRating'],
|
||||||
|
"musicRating": userdata['userData']['musicRating'],
|
||||||
|
"playerRating": userdata['userData']['playerRating'],
|
||||||
|
"highestRating": userdata['userData']['highestRating'],
|
||||||
|
"gradeRank": userdata['userData']['gradeRank'],
|
||||||
|
"classRank": userdata['userData']['classRank'],
|
||||||
|
"courseRank": userdata['userData']['courseRank'],
|
||||||
|
"charaSlot": userdata['userData']['charaSlot'],
|
||||||
|
"charaLockSlot": userdata['userData']['charaLockSlot'],
|
||||||
|
"contentBit": userdata['userData']['contentBit'],
|
||||||
|
"playCount": userdata['userData']['playCount'],
|
||||||
|
"currentPlayCount": userdata['userData']['currentPlayCount'],
|
||||||
|
"renameCredit": 0,
|
||||||
|
"mapStock": userdata['userData']['mapStock'],
|
||||||
|
"eventWatchedDate": userdata['userData']['eventWatchedDate'],
|
||||||
|
"lastGameId": "SDGB",
|
||||||
|
"lastRomVersion": userdata['userData']['lastRomVersion'],
|
||||||
|
"lastDataVersion": userdata['userData']['lastDataVersion'],
|
||||||
|
"lastLoginDate": login_date,
|
||||||
|
"lastPlayDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"lastPlayCredit": 1,
|
||||||
|
"lastPlayMode": 0,
|
||||||
|
"lastPlaceId": placeId,
|
||||||
|
"lastPlaceName": placeName,
|
||||||
|
"lastAllNetId": 0,
|
||||||
|
"lastRegionId": regionId,
|
||||||
|
"lastRegionName": regionName,
|
||||||
|
"lastClientId": clientId,
|
||||||
|
"lastCountryCode": "CHN",
|
||||||
|
"lastSelectEMoney": 0,
|
||||||
|
"lastSelectTicket": 0,
|
||||||
|
"lastSelectCourse": userdata['userData']['lastSelectCourse'],
|
||||||
|
"lastCountCourse": 0,
|
||||||
|
"firstGameId": "SDGB",
|
||||||
|
"firstRomVersion": userdata['userData']['firstRomVersion'],
|
||||||
|
"firstDataVersion": userdata['userData']['firstDataVersion'],
|
||||||
|
"firstPlayDate": userdata['userData']['firstPlayDate'],
|
||||||
|
"compatibleCmVersion": userdata['userData']['compatibleCmVersion'],
|
||||||
|
"dailyBonusDate": userdata['userData']['dailyBonusDate'],
|
||||||
|
"dailyCourseBonusDate": userdata['userData']['dailyCourseBonusDate'],
|
||||||
|
"lastPairLoginDate": userdata['userData']['lastPairLoginDate'],
|
||||||
|
"lastTrialPlayDate": userdata['userData']['lastTrialPlayDate'],
|
||||||
|
"playVsCount": 0,
|
||||||
|
"playSyncCount": 0,
|
||||||
|
"winCount": 0,
|
||||||
|
"helpCount": 0,
|
||||||
|
"comboCount": 0,
|
||||||
|
"totalDeluxscore": userdata['userData']['totalDeluxscore'],
|
||||||
|
"totalBasicDeluxscore": userdata['userData']['totalBasicDeluxscore'],
|
||||||
|
"totalAdvancedDeluxscore": userdata['userData']['totalAdvancedDeluxscore'],
|
||||||
|
"totalExpertDeluxscore": userdata['userData']['totalExpertDeluxscore'],
|
||||||
|
"totalMasterDeluxscore": userdata['userData']['totalMasterDeluxscore'],
|
||||||
|
"totalReMasterDeluxscore": userdata['userData']['totalReMasterDeluxscore'],
|
||||||
|
"totalSync": userdata['userData']['totalSync'],
|
||||||
|
"totalBasicSync": userdata['userData']['totalBasicSync'],
|
||||||
|
"totalAdvancedSync": userdata['userData']['totalAdvancedSync'],
|
||||||
|
"totalExpertSync": userdata['userData']['totalExpertSync'],
|
||||||
|
"totalMasterSync": userdata['userData']['totalMasterSync'],
|
||||||
|
"totalReMasterSync": userdata['userData']['totalReMasterSync'],
|
||||||
|
"totalAchievement": userdata['userData']['totalAchievement'],
|
||||||
|
"totalBasicAchievement": userdata['userData']['totalBasicAchievement'],
|
||||||
|
"totalAdvancedAchievement": userdata['userData']['totalAdvancedAchievement'],
|
||||||
|
"totalExpertAchievement": userdata['userData']['totalExpertAchievement'],
|
||||||
|
"totalMasterAchievement": userdata['userData']['totalMasterAchievement'],
|
||||||
|
"totalReMasterAchievement": userdata['userData']['totalReMasterAchievement'],
|
||||||
|
"playerOldRating": userdata['userData']['playerOldRating'],
|
||||||
|
"playerNewRating": userdata['userData']['playerNewRating'],
|
||||||
|
"banState": 0,
|
||||||
|
"dateTime": timestamp
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userExtend": [user_extend['userExtend']],
|
||||||
|
"userOption": [user_option['userOption']],
|
||||||
|
"userCharacterList": [],
|
||||||
|
"userGhost": [],
|
||||||
|
"userMapList": [],
|
||||||
|
"userLoginBonusList": [],
|
||||||
|
"userRatingList": [user_rating['userRating']],
|
||||||
|
"userItemList": [
|
||||||
|
{
|
||||||
|
"itemKind": unlock_item,
|
||||||
|
"itemId": unlock_id,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userMusicDetailList": [
|
||||||
|
{
|
||||||
|
"musicId": musicId,
|
||||||
|
"level": level,
|
||||||
|
"playCount": playCount,
|
||||||
|
"achievement": achievement,
|
||||||
|
"comboStatus": comboStatus,
|
||||||
|
"syncStatus": syncStatus,
|
||||||
|
"deluxscoreMax": deluxscoreMax,
|
||||||
|
"scoreRank": scoreRank,
|
||||||
|
"extNum1": extNum1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userCourseList": [],
|
||||||
|
"userFriendSeasonRankingList": [],
|
||||||
|
"userChargeList": user_charge['userChargeList'],
|
||||||
|
"userFavoriteList": [],
|
||||||
|
"userActivityList": [user_activity['userActivity']],
|
||||||
|
"userGamePlaylogList": [
|
||||||
|
{
|
||||||
|
"playlogId": login_id,
|
||||||
|
"version": "1.41.00",
|
||||||
|
"playDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"playMode": 0,
|
||||||
|
"useTicketId": -1,
|
||||||
|
"playCredit": 1,
|
||||||
|
"playTrack": 1,
|
||||||
|
"clientId": clientId,
|
||||||
|
"isPlayTutorial": False,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isNewFree": False,
|
||||||
|
"playCount": 0,
|
||||||
|
"playSpecial": CalcRandom(),
|
||||||
|
"playOtherUserId": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"user2pPlaylog": {
|
||||||
|
"userId1": 0,
|
||||||
|
"userId2": 0,
|
||||||
|
"userName1": "",
|
||||||
|
"userName2": "",
|
||||||
|
"regionId": 0,
|
||||||
|
"placeId": 0,
|
||||||
|
"user2pPlaylogDetailList": []
|
||||||
|
},
|
||||||
|
"isNewCharacterList": "",
|
||||||
|
"isNewMapList": "",
|
||||||
|
"isNewLoginBonusList": "",
|
||||||
|
"isNewItemList": 11,
|
||||||
|
"isNewMusicDetailList": "0",
|
||||||
|
"isNewCourseList": "0",
|
||||||
|
"isNewFavoriteList": "",
|
||||||
|
"isNewFriendSeasonRankingList": ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
userall_result = json.loads(sdgb_api(data, "UpsertUserAllApi", userId))
|
||||||
|
return userall_result
|
||||||
|
|
||||||
|
def music_with_retry(unlock_id,max_retries=10): # 这里是重试次数
|
||||||
|
for i in range(max_retries):
|
||||||
|
try:
|
||||||
|
print(unlock_id)
|
||||||
|
print(music(unlock_id))
|
||||||
|
return logout(timestamp)
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"尝试 {i+1} 失败了... Err: {e}")
|
||||||
|
print(logout(timestamp))
|
||||||
|
time.sleep(5) # 等待 5 秒后重试
|
||||||
|
return "上传失败了...超过了重试次数...请检查网络环境后重试!!"
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
userId = int(input("请输入userid: "))
|
||||||
|
print("1 - Plate 头像框\n2 - Title 称号\n3 - Icon 头像\n5 - Music 乐曲\n6 - MusicMas 乐曲紫谱\n7 - MusicRes 乐曲白谱\n10 - Partner 搭档\n11 - Frame 背景板")
|
||||||
|
unlock_item = int(input("请输入物品类型: "))
|
||||||
|
print(music_with_retry(int(input("请输入物品id(请在https://collection.hoshino.icu/查询物品id): "))))
|
||||||
509
nonebot_plugin_maimai_helper/leak/unlock_new.py
Normal file
509
nonebot_plugin_maimai_helper/leak/unlock_new.py
Normal file
@@ -0,0 +1,509 @@
|
|||||||
|
import json
|
||||||
|
import pytz
|
||||||
|
import time
|
||||||
|
import random
|
||||||
|
|
||||||
|
from sdgb import sdgb_api
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from settings import userId
|
||||||
|
from settings import music_data
|
||||||
|
from settings import regionId
|
||||||
|
from settings import regionName
|
||||||
|
from settings import clientId
|
||||||
|
from settings import placeId
|
||||||
|
from settings import placeName
|
||||||
|
|
||||||
|
from login import login
|
||||||
|
from logout import logout
|
||||||
|
|
||||||
|
def CalcRandom():
|
||||||
|
max = 1037933
|
||||||
|
num2 = random.randint(1, max) * 2069
|
||||||
|
|
||||||
|
num2 += 1024 # specialnum
|
||||||
|
num3 = 0
|
||||||
|
for i in range(0, 32):
|
||||||
|
num3 <<= 1
|
||||||
|
num3 += num2 % 2
|
||||||
|
num2 >>= 1
|
||||||
|
|
||||||
|
return num3
|
||||||
|
|
||||||
|
timestamp = int(time.time()) - 60
|
||||||
|
|
||||||
|
def music():
|
||||||
|
|
||||||
|
music = music_data
|
||||||
|
|
||||||
|
musicId = music['musicId']
|
||||||
|
level = music['level']
|
||||||
|
playCount = music['playCount']
|
||||||
|
achievement = music['achievement']
|
||||||
|
comboStatus = music['comboStatus']
|
||||||
|
syncStatus = music['syncStatus']
|
||||||
|
deluxscoreMax = music['deluxscoreMax']
|
||||||
|
scoreRank = music['scoreRank']
|
||||||
|
extNum1 = music['extNum1']
|
||||||
|
|
||||||
|
print(timestamp)
|
||||||
|
|
||||||
|
# UserLogin
|
||||||
|
|
||||||
|
login_result = json.loads(login(timestamp))
|
||||||
|
print(login_result)
|
||||||
|
|
||||||
|
login_id = login_result['loginId']
|
||||||
|
login_date = login_result['lastLoginDate']
|
||||||
|
|
||||||
|
|
||||||
|
# UserData
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
userdata = json.loads(sdgb_api(data, "GetUserDataApi", userId))
|
||||||
|
|
||||||
|
# UserLog
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"userPlaylog": {
|
||||||
|
"userId": 0,
|
||||||
|
"orderId": 0,
|
||||||
|
"playlogId": login_id,
|
||||||
|
"version": 1041000,
|
||||||
|
"placeId": placeId,
|
||||||
|
"placeName": placeName,
|
||||||
|
"loginDate": int(time.time()),
|
||||||
|
"playDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d'),
|
||||||
|
"userPlayDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"type": 0,
|
||||||
|
"musicId": int(musicId),
|
||||||
|
"level": int(level),
|
||||||
|
"trackNo": 1,
|
||||||
|
"vsMode": 0,
|
||||||
|
"vsUserName": "",
|
||||||
|
"vsStatus": 0,
|
||||||
|
"vsUserRating": 0,
|
||||||
|
"vsUserAchievement": 0,
|
||||||
|
"vsUserGradeRank": 0,
|
||||||
|
"vsRank": 0,
|
||||||
|
"playerNum": 1,
|
||||||
|
"playedUserId1": 0,
|
||||||
|
"playedUserName1": "",
|
||||||
|
"playedMusicLevel1": 0,
|
||||||
|
"playedUserId2": 0,
|
||||||
|
"playedUserName2": "",
|
||||||
|
"playedMusicLevel2": 0,
|
||||||
|
"playedUserId3": 0,
|
||||||
|
"playedUserName3": "",
|
||||||
|
"playedMusicLevel3": 0,
|
||||||
|
"characterId1": userdata['userData']['charaSlot'][0],
|
||||||
|
"characterLevel1": random.randint(1000,6500),
|
||||||
|
"characterAwakening1": 5,
|
||||||
|
"characterId2": userdata['userData']['charaSlot'][1],
|
||||||
|
"characterLevel2": random.randint(1000,6500),
|
||||||
|
"characterAwakening2": 5,
|
||||||
|
"characterId3": userdata['userData']['charaSlot'][2],
|
||||||
|
"characterLevel3": random.randint(1000,6500),
|
||||||
|
"characterAwakening3": 5,
|
||||||
|
"characterId4": userdata['userData']['charaSlot'][3],
|
||||||
|
"characterLevel4": random.randint(1000,6500),
|
||||||
|
"characterAwakening4": 5,
|
||||||
|
"characterId5": userdata['userData']['charaSlot'][4],
|
||||||
|
"characterLevel5": random.randint(1000,6500),
|
||||||
|
"characterAwakening5": 5,
|
||||||
|
"achievement": int(achievement),
|
||||||
|
"deluxscore": int(deluxscoreMax),
|
||||||
|
"scoreRank": int(scoreRank),
|
||||||
|
"maxCombo": random.randint(400,500),
|
||||||
|
"totalCombo": random.randint(700,900),
|
||||||
|
"maxSync": 0,
|
||||||
|
"totalSync": 0,
|
||||||
|
"tapCriticalPerfect": random.randint(200,400),
|
||||||
|
"tapPerfect": random.randint(100,250),
|
||||||
|
"tapGreat": random.randint(0,10),
|
||||||
|
"tapGood": random.randint(0,10),
|
||||||
|
"tapMiss": random.randint(0,10),
|
||||||
|
"holdCriticalPerfect": random.randint(20,40),
|
||||||
|
"holdPerfect": random.randint(0,15),
|
||||||
|
"holdGreat": 0,
|
||||||
|
"holdGood": 0,
|
||||||
|
"holdMiss": 0,
|
||||||
|
"slideCriticalPerfect": random.randint(34,60),
|
||||||
|
"slidePerfect": 0,
|
||||||
|
"slideGreat": 0,
|
||||||
|
"slideGood": 0,
|
||||||
|
"slideMiss": 0,
|
||||||
|
"touchCriticalPerfect": random.randint(20,70),
|
||||||
|
"touchPerfect": 0,
|
||||||
|
"touchGreat": 0,
|
||||||
|
"touchGood": 0,
|
||||||
|
"touchMiss": 0,
|
||||||
|
"breakCriticalPerfect": random.randint(8,30),
|
||||||
|
"breakPerfect": random.randint(7,10),
|
||||||
|
"breakGreat": 0,
|
||||||
|
"breakGood": 0,
|
||||||
|
"breakMiss": 0,
|
||||||
|
"isTap": True,
|
||||||
|
"isHold": True,
|
||||||
|
"isSlide": True,
|
||||||
|
"isTouch": True,
|
||||||
|
"isBreak": True,
|
||||||
|
"isCriticalDisp": True,
|
||||||
|
"isFastLateDisp": True,
|
||||||
|
"fastCount": random.randint(20,30),
|
||||||
|
"lateCount": random.randint(50,70),
|
||||||
|
"isAchieveNewRecord": True,
|
||||||
|
"isDeluxscoreNewRecord": True,
|
||||||
|
"comboStatus": 0,
|
||||||
|
"syncStatus": 0,
|
||||||
|
"isClear": True,
|
||||||
|
'beforeRating': userdata['userData']['playerRating'],
|
||||||
|
'afterRating': userdata['userData']['playerRating'],
|
||||||
|
"beforeGrade": 0,
|
||||||
|
"afterGrade": 0,
|
||||||
|
"afterGradeRank": 2,
|
||||||
|
'beforeDeluxRating': userdata['userData']['playerRating'],
|
||||||
|
'afterDeluxRating': userdata['userData']['playerRating'],
|
||||||
|
"isPlayTutorial": False,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isFreedomMode": False,
|
||||||
|
"playMode": 0,
|
||||||
|
"isNewFree": False,
|
||||||
|
"trialPlayAchievement": -1,
|
||||||
|
"extNum1": 0,
|
||||||
|
"extNum2": 0,
|
||||||
|
"extNum4": 3020,
|
||||||
|
"extBool1": False
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
userlog_result = json.loads(sdgb_api(data, "UploadUserPlaylogApi", userId))
|
||||||
|
|
||||||
|
print(userlog_result)
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Extend
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_extend = json.loads(sdgb_api(data, "GetUserExtendApi", userId))
|
||||||
|
|
||||||
|
# 获取 User Option
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_option = json.loads(sdgb_api(data, "GetUserOptionApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Rating
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_rating = json.loads(sdgb_api(data, "GetUserRatingApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取 User Activity
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_activity = json.loads(sdgb_api(data, "GetUserActivityApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
# 获取账号功能票
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
user_charge = json.loads(sdgb_api(data, "GetUserChargeApi", userId))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# UserAll
|
||||||
|
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"playlogId": login_id,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isFreePlay": False,
|
||||||
|
"upsertUserAll": {
|
||||||
|
"userData": [
|
||||||
|
{
|
||||||
|
"accessCode": "",
|
||||||
|
"userName": userdata['userData']['userName'],
|
||||||
|
"isNetMember": 1,
|
||||||
|
"iconId": userdata['userData']['iconId'],
|
||||||
|
"plateId": userdata['userData']['plateId'],
|
||||||
|
"titleId": userdata['userData']['titleId'],
|
||||||
|
"partnerId": userdata['userData']['partnerId'],
|
||||||
|
"frameId": userdata['userData']['frameId'],
|
||||||
|
"selectMapId": userdata['userData']['selectMapId'],
|
||||||
|
"totalAwake": userdata['userData']['totalAwake'],
|
||||||
|
"gradeRating": userdata['userData']['gradeRating'],
|
||||||
|
"musicRating": userdata['userData']['musicRating'],
|
||||||
|
"playerRating": userdata['userData']['playerRating'],
|
||||||
|
"highestRating": userdata['userData']['highestRating'],
|
||||||
|
"gradeRank": userdata['userData']['gradeRank'],
|
||||||
|
"classRank": userdata['userData']['classRank'],
|
||||||
|
"courseRank": userdata['userData']['courseRank'],
|
||||||
|
"charaSlot": userdata['userData']['charaSlot'],
|
||||||
|
"charaLockSlot": userdata['userData']['charaLockSlot'],
|
||||||
|
"contentBit": userdata['userData']['contentBit'],
|
||||||
|
"playCount": userdata['userData']['playCount'],
|
||||||
|
"currentPlayCount": userdata['userData']['currentPlayCount'],
|
||||||
|
"renameCredit": 0,
|
||||||
|
"mapStock": userdata['userData']['mapStock'],
|
||||||
|
"eventWatchedDate": userdata['userData']['eventWatchedDate'],
|
||||||
|
"lastGameId": "SDGB",
|
||||||
|
"lastRomVersion": userdata['userData']['lastRomVersion'],
|
||||||
|
"lastDataVersion": userdata['userData']['lastDataVersion'],
|
||||||
|
"lastLoginDate": login_date,
|
||||||
|
"lastPlayDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"lastPlayCredit": 1,
|
||||||
|
"lastPlayMode": 0,
|
||||||
|
"lastPlaceId": placeId,
|
||||||
|
"lastPlaceName": placeName,
|
||||||
|
"lastAllNetId": 0,
|
||||||
|
"lastRegionId": regionId,
|
||||||
|
"lastRegionName": regionName,
|
||||||
|
"lastClientId": clientId,
|
||||||
|
"lastCountryCode": "CHN",
|
||||||
|
"lastSelectEMoney": 0,
|
||||||
|
"lastSelectTicket": 0,
|
||||||
|
"lastSelectCourse": userdata['userData']['lastSelectCourse'],
|
||||||
|
"lastCountCourse": 0,
|
||||||
|
"firstGameId": "SDGB",
|
||||||
|
"firstRomVersion": userdata['userData']['firstRomVersion'],
|
||||||
|
"firstDataVersion": userdata['userData']['firstDataVersion'],
|
||||||
|
"firstPlayDate": userdata['userData']['firstPlayDate'],
|
||||||
|
"compatibleCmVersion": userdata['userData']['compatibleCmVersion'],
|
||||||
|
"dailyBonusDate": userdata['userData']['dailyBonusDate'],
|
||||||
|
"dailyCourseBonusDate": userdata['userData']['dailyCourseBonusDate'],
|
||||||
|
"lastPairLoginDate": userdata['userData']['lastPairLoginDate'],
|
||||||
|
"lastTrialPlayDate": userdata['userData']['lastTrialPlayDate'],
|
||||||
|
"playVsCount": 0,
|
||||||
|
"playSyncCount": 0,
|
||||||
|
"winCount": 0,
|
||||||
|
"helpCount": 0,
|
||||||
|
"comboCount": 0,
|
||||||
|
"totalDeluxscore": userdata['userData']['totalDeluxscore'],
|
||||||
|
"totalBasicDeluxscore": userdata['userData']['totalBasicDeluxscore'],
|
||||||
|
"totalAdvancedDeluxscore": userdata['userData']['totalAdvancedDeluxscore'],
|
||||||
|
"totalExpertDeluxscore": userdata['userData']['totalExpertDeluxscore'],
|
||||||
|
"totalMasterDeluxscore": userdata['userData']['totalMasterDeluxscore'],
|
||||||
|
"totalReMasterDeluxscore": userdata['userData']['totalReMasterDeluxscore'],
|
||||||
|
"totalSync": userdata['userData']['totalSync'],
|
||||||
|
"totalBasicSync": userdata['userData']['totalBasicSync'],
|
||||||
|
"totalAdvancedSync": userdata['userData']['totalAdvancedSync'],
|
||||||
|
"totalExpertSync": userdata['userData']['totalExpertSync'],
|
||||||
|
"totalMasterSync": userdata['userData']['totalMasterSync'],
|
||||||
|
"totalReMasterSync": userdata['userData']['totalReMasterSync'],
|
||||||
|
"totalAchievement": userdata['userData']['totalAchievement'],
|
||||||
|
"totalBasicAchievement": userdata['userData']['totalBasicAchievement'],
|
||||||
|
"totalAdvancedAchievement": userdata['userData']['totalAdvancedAchievement'],
|
||||||
|
"totalExpertAchievement": userdata['userData']['totalExpertAchievement'],
|
||||||
|
"totalMasterAchievement": userdata['userData']['totalMasterAchievement'],
|
||||||
|
"totalReMasterAchievement": userdata['userData']['totalReMasterAchievement'],
|
||||||
|
"playerOldRating": userdata['userData']['playerOldRating'],
|
||||||
|
"playerNewRating": userdata['userData']['playerNewRating'],
|
||||||
|
"banState": 0,
|
||||||
|
"dateTime": timestamp
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userExtend": [user_extend['userExtend']],
|
||||||
|
"userOption": [user_option['userOption']],
|
||||||
|
"userCharacterList": [],
|
||||||
|
"userGhost": [],
|
||||||
|
"userMapList": [],
|
||||||
|
"userLoginBonusList": [],
|
||||||
|
"userRatingList": [user_rating['userRating']],
|
||||||
|
"userItemList": [
|
||||||
|
{
|
||||||
|
"itemKind": 5,
|
||||||
|
"itemId": 11642,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 6,
|
||||||
|
"itemId": 11642,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 5,
|
||||||
|
"itemId": 11643,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 6,
|
||||||
|
"itemId": 11643,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 5,
|
||||||
|
"itemId": 10242,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 6,
|
||||||
|
"itemId": 10242,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 5,
|
||||||
|
"itemId": 11618,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 6,
|
||||||
|
"itemId": 11618,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 5,
|
||||||
|
"itemId": 11624,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 6,
|
||||||
|
"itemId": 11624,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 5,
|
||||||
|
"itemId": 11641,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 6,
|
||||||
|
"itemId": 11641,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 5,
|
||||||
|
"itemId": 11640,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 6,
|
||||||
|
"itemId": 11640,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 5,
|
||||||
|
"itemId": 11614,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 6,
|
||||||
|
"itemId": 11614,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 5,
|
||||||
|
"itemId": 11613,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"itemKind": 6,
|
||||||
|
"itemId": 11613,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userMusicDetailList": [
|
||||||
|
{
|
||||||
|
"musicId": musicId,
|
||||||
|
"level": level,
|
||||||
|
"playCount": playCount,
|
||||||
|
"achievement": achievement,
|
||||||
|
"comboStatus": comboStatus,
|
||||||
|
"syncStatus": syncStatus,
|
||||||
|
"deluxscoreMax": deluxscoreMax,
|
||||||
|
"scoreRank": scoreRank,
|
||||||
|
"extNum1": extNum1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userCourseList": [],
|
||||||
|
"userFriendSeasonRankingList": [],
|
||||||
|
"userChargeList": user_charge['userChargeList'],
|
||||||
|
"userFavoriteList": [],
|
||||||
|
"userActivityList": [user_activity['userActivity']],
|
||||||
|
"userGamePlaylogList": [
|
||||||
|
{
|
||||||
|
"playlogId": login_id,
|
||||||
|
"version": "1.41.00",
|
||||||
|
"playDate": datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S') + '.0',
|
||||||
|
"playMode": 0,
|
||||||
|
"useTicketId": -1,
|
||||||
|
"playCredit": 1,
|
||||||
|
"playTrack": 1,
|
||||||
|
"clientId": clientId,
|
||||||
|
"isPlayTutorial": False,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isNewFree": False,
|
||||||
|
"playCount": 0,
|
||||||
|
"playSpecial": CalcRandom(),
|
||||||
|
"playOtherUserId": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"user2pPlaylog": {
|
||||||
|
"userId1": 0,
|
||||||
|
"userId2": 0,
|
||||||
|
"userName1": "",
|
||||||
|
"userName2": "",
|
||||||
|
"regionId": 0,
|
||||||
|
"placeId": 0,
|
||||||
|
"user2pPlaylogDetailList": []
|
||||||
|
},
|
||||||
|
"isNewCharacterList": "",
|
||||||
|
"isNewMapList": "",
|
||||||
|
"isNewLoginBonusList": "",
|
||||||
|
"isNewItemList": 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111,
|
||||||
|
"isNewMusicDetailList": "1",
|
||||||
|
"isNewCourseList": "0",
|
||||||
|
"isNewFavoriteList": "",
|
||||||
|
"isNewFriendSeasonRankingList": ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
userall_result = json.loads(sdgb_api(data, "UpsertUserAllApi", userId))
|
||||||
|
return userall_result
|
||||||
|
|
||||||
|
def music_with_retry(max_retries=10): # 这里是重试次数
|
||||||
|
for i in range(max_retries):
|
||||||
|
try:
|
||||||
|
print(music())
|
||||||
|
return logout(timestamp)
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"尝试 {i+1} 失败,错误:{e}")
|
||||||
|
print(logout(timestamp))
|
||||||
|
time.sleep(5) # 等待 5 秒后重试
|
||||||
|
return "重试次数超过限制,乐曲上传失败"
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(music_with_retry())
|
||||||
47
nonebot_plugin_maimai_helper/leak/userdata.py
Normal file
47
nonebot_plugin_maimai_helper/leak/userdata.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
from sdgb import sdgb_api
|
||||||
|
|
||||||
|
def login(userId):
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"acsessCode": "",
|
||||||
|
"regionId": 1,
|
||||||
|
"placeId": "0570",
|
||||||
|
"clientId": "A63E01C2805",
|
||||||
|
"dateTime": 1,
|
||||||
|
"isContinue": 'false',
|
||||||
|
"genericFlag": 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
login_result = sdgb_api(data, "UserLoginApi", userId)
|
||||||
|
return login_result
|
||||||
|
|
||||||
|
def logout(userId):
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId),
|
||||||
|
"accessCode":"",
|
||||||
|
"regionId": 1,
|
||||||
|
"placeId": "0570",
|
||||||
|
"clientId": "A63E01C2805",
|
||||||
|
"dateTime": 1,
|
||||||
|
"type": 1
|
||||||
|
})
|
||||||
|
|
||||||
|
logout_result = sdgb_api(data, "UserLogoutApi", userId)
|
||||||
|
return logout_result
|
||||||
|
|
||||||
|
def userdata(userId):
|
||||||
|
data = json.dumps({
|
||||||
|
"userId": int(userId)
|
||||||
|
})
|
||||||
|
|
||||||
|
userdata_result = sdgb_api(data, "GetUserDataApi", userId)
|
||||||
|
|
||||||
|
return userdata_result
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
userId = int(input())
|
||||||
|
login(userId)
|
||||||
|
print(userdata(userId))
|
||||||
|
logout(userId)
|
||||||
0
nonebot_plugin_maimai_helper/manager/__init__.py
Normal file
0
nonebot_plugin_maimai_helper/manager/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
26
nonebot_plugin_maimai_helper/manager/game_data.py
Normal file
26
nonebot_plugin_maimai_helper/manager/game_data.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
from nonebot_plugin_maimai_helper.data import root_path
|
||||||
|
|
||||||
|
|
||||||
|
class GameDataManager:
|
||||||
|
def __init__(self, resource_type: str):
|
||||||
|
resource = self._load_resource_info(os.path.join(root_path, "game_data", f"{resource_type}_list.json"))
|
||||||
|
self.resource = resource["data"]
|
||||||
|
self.resource_info = resource["info"]
|
||||||
|
|
||||||
|
# 加载资源信息的封装函数
|
||||||
|
def _load_resource_info(self, path):
|
||||||
|
try:
|
||||||
|
with open(path, "r", encoding="utf-8") as f:
|
||||||
|
return json.load(f)
|
||||||
|
except:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
# 改进后的 get_resource 和 have_resource 函数
|
||||||
|
def get_resource(self, resource_id: int):
|
||||||
|
return self.resource.get(str(resource_id), None)
|
||||||
|
|
||||||
|
def have_resource(self, resource_id: int):
|
||||||
|
return str(resource_id) in self.resource
|
||||||
41
nonebot_plugin_maimai_helper/manager/usage_count.py
Normal file
41
nonebot_plugin_maimai_helper/manager/usage_count.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
class UsageCount:
|
||||||
|
handled_user_count = dict(unknown=0)
|
||||||
|
|
||||||
|
def add(self, wxid="unknown"):
|
||||||
|
if wxid not in self.handled_user_count:
|
||||||
|
self.handled_user_count[wxid] = 0
|
||||||
|
self.handled_user_count[wxid] += 1
|
||||||
|
|
||||||
|
def get(self, wxid="unknown"):
|
||||||
|
my_count = 0
|
||||||
|
if wxid is not None:
|
||||||
|
my_count = self.handled_user_count.get(wxid, 0)
|
||||||
|
return len(self.handled_user_count.keys()) - 1, sum(self.handled_user_count.values()), my_count
|
||||||
|
|
||||||
|
|
||||||
|
class NetworkCount:
|
||||||
|
average_delay = 0
|
||||||
|
request_failed_count = 0
|
||||||
|
request_count = 0
|
||||||
|
zlib_compress_skip_count = 0
|
||||||
|
|
||||||
|
def update_average_delay(self, delay: int):
|
||||||
|
if self.request_count == 0:
|
||||||
|
self.average_delay = delay
|
||||||
|
else:
|
||||||
|
self.average_delay = (self.average_delay * self.request_count + delay) / (self.request_count + 1)
|
||||||
|
|
||||||
|
def add_request_count(self):
|
||||||
|
self.request_count += 1
|
||||||
|
|
||||||
|
def add_failed_request_count(self):
|
||||||
|
self.request_count -= 1
|
||||||
|
|
||||||
|
def add_zlib_compress_skip_count(self):
|
||||||
|
self.zlib_compress_skip_count += 1
|
||||||
|
|
||||||
|
def add_request_failed_count(self):
|
||||||
|
self.request_failed_count += 1
|
||||||
|
|
||||||
|
def get_network_status(self):
|
||||||
|
return self.request_count, self.request_failed_count, self.zlib_compress_skip_count, self.average_delay
|
||||||
BIN
nonebot_plugin_maimai_helper/requirements.txt
Normal file
BIN
nonebot_plugin_maimai_helper/requirements.txt
Normal file
Binary file not shown.
23
nonebot_plugin_maimai_helper/update_music_list.py
Normal file
23
nonebot_plugin_maimai_helper/update_music_list.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from nonebot.log import logger
|
||||||
|
from nonebot_plugin_maimai_helper.data import root_path
|
||||||
|
|
||||||
|
|
||||||
|
URL = "https://www.diving-fish.com/api/maimaidxprober/music_data"
|
||||||
|
|
||||||
|
|
||||||
|
def update_music_list():
|
||||||
|
logger.success("开始更新music_list")
|
||||||
|
logger.success("开始删除文件")
|
||||||
|
if os.path.isfile(root_path + '/game_data/diving_music_list.json'):
|
||||||
|
os.remove(root_path + '/game_data/diving_music_list.json')
|
||||||
|
new_data = requests.get(URL)
|
||||||
|
new_data.encoding = 'utf-8'
|
||||||
|
data = json.loads(new_data.text)
|
||||||
|
logger.success("开始更新文件")
|
||||||
|
with open(root_path + '/game_data/diving_music_list.json', 'w', encoding='utf-8') as old_data:
|
||||||
|
json.dump(data, old_data, ensure_ascii=False, indent=4)
|
||||||
|
|
||||||
0
nonebot_plugin_maimai_helper/util/__init__.py
Normal file
0
nonebot_plugin_maimai_helper/util/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,760 @@
|
|||||||
|
@Switch01
|
||||||
|
A_Rog
|
||||||
|
Aakanksha Agrawal
|
||||||
|
Abhinav Sagar
|
||||||
|
ABHYUDAY PRATAP SINGH
|
||||||
|
abs51295
|
||||||
|
AceGentile
|
||||||
|
Adam Chainz
|
||||||
|
Adam Tse
|
||||||
|
Adam Wentz
|
||||||
|
admin
|
||||||
|
Adrien Morison
|
||||||
|
ahayrapetyan
|
||||||
|
Ahilya
|
||||||
|
AinsworthK
|
||||||
|
Akash Srivastava
|
||||||
|
Alan Yee
|
||||||
|
Albert Tugushev
|
||||||
|
Albert-Guan
|
||||||
|
albertg
|
||||||
|
Alberto Sottile
|
||||||
|
Aleks Bunin
|
||||||
|
Ales Erjavec
|
||||||
|
Alethea Flowers
|
||||||
|
Alex Gaynor
|
||||||
|
Alex Grönholm
|
||||||
|
Alex Hedges
|
||||||
|
Alex Loosley
|
||||||
|
Alex Morega
|
||||||
|
Alex Stachowiak
|
||||||
|
Alexander Shtyrov
|
||||||
|
Alexandre Conrad
|
||||||
|
Alexey Popravka
|
||||||
|
Aleš Erjavec
|
||||||
|
Alli
|
||||||
|
Ami Fischman
|
||||||
|
Ananya Maiti
|
||||||
|
Anatoly Techtonik
|
||||||
|
Anders Kaseorg
|
||||||
|
Andre Aguiar
|
||||||
|
Andreas Lutro
|
||||||
|
Andrei Geacar
|
||||||
|
Andrew Gaul
|
||||||
|
Andrew Shymanel
|
||||||
|
Andrey Bienkowski
|
||||||
|
Andrey Bulgakov
|
||||||
|
Andrés Delfino
|
||||||
|
Andy Freeland
|
||||||
|
Andy Kluger
|
||||||
|
Ani Hayrapetyan
|
||||||
|
Aniruddha Basak
|
||||||
|
Anish Tambe
|
||||||
|
Anrs Hu
|
||||||
|
Anthony Sottile
|
||||||
|
Antoine Musso
|
||||||
|
Anton Ovchinnikov
|
||||||
|
Anton Patrushev
|
||||||
|
Antonio Alvarado Hernandez
|
||||||
|
Antony Lee
|
||||||
|
Antti Kaihola
|
||||||
|
Anubhav Patel
|
||||||
|
Anudit Nagar
|
||||||
|
Anuj Godase
|
||||||
|
AQNOUCH Mohammed
|
||||||
|
AraHaan
|
||||||
|
Arindam Choudhury
|
||||||
|
Armin Ronacher
|
||||||
|
Artem
|
||||||
|
Arun Babu Neelicattu
|
||||||
|
Ashley Manton
|
||||||
|
Ashwin Ramaswami
|
||||||
|
atse
|
||||||
|
Atsushi Odagiri
|
||||||
|
Avinash Karhana
|
||||||
|
Avner Cohen
|
||||||
|
Awit (Ah-Wit) Ghirmai
|
||||||
|
Baptiste Mispelon
|
||||||
|
Barney Gale
|
||||||
|
barneygale
|
||||||
|
Bartek Ogryczak
|
||||||
|
Bastian Venthur
|
||||||
|
Ben Bodenmiller
|
||||||
|
Ben Darnell
|
||||||
|
Ben Hoyt
|
||||||
|
Ben Mares
|
||||||
|
Ben Rosser
|
||||||
|
Bence Nagy
|
||||||
|
Benjamin Peterson
|
||||||
|
Benjamin VanEvery
|
||||||
|
Benoit Pierre
|
||||||
|
Berker Peksag
|
||||||
|
Bernard
|
||||||
|
Bernard Tyers
|
||||||
|
Bernardo B. Marques
|
||||||
|
Bernhard M. Wiedemann
|
||||||
|
Bertil Hatt
|
||||||
|
Bhavam Vidyarthi
|
||||||
|
Blazej Michalik
|
||||||
|
Bogdan Opanchuk
|
||||||
|
BorisZZZ
|
||||||
|
Brad Erickson
|
||||||
|
Bradley Ayers
|
||||||
|
Brandon L. Reiss
|
||||||
|
Brandt Bucher
|
||||||
|
Brett Randall
|
||||||
|
Brett Rosen
|
||||||
|
Brian Cristante
|
||||||
|
Brian Rosner
|
||||||
|
briantracy
|
||||||
|
BrownTruck
|
||||||
|
Bruno Oliveira
|
||||||
|
Bruno Renié
|
||||||
|
Bruno S
|
||||||
|
Bstrdsmkr
|
||||||
|
Buck Golemon
|
||||||
|
burrows
|
||||||
|
Bussonnier Matthias
|
||||||
|
bwoodsend
|
||||||
|
c22
|
||||||
|
Caleb Martinez
|
||||||
|
Calvin Smith
|
||||||
|
Carl Meyer
|
||||||
|
Carlos Liam
|
||||||
|
Carol Willing
|
||||||
|
Carter Thayer
|
||||||
|
Cass
|
||||||
|
Chandrasekhar Atina
|
||||||
|
Chih-Hsuan Yen
|
||||||
|
Chris Brinker
|
||||||
|
Chris Hunt
|
||||||
|
Chris Jerdonek
|
||||||
|
Chris Kuehl
|
||||||
|
Chris McDonough
|
||||||
|
Chris Pawley
|
||||||
|
Chris Pryer
|
||||||
|
Chris Wolfe
|
||||||
|
Christian Clauss
|
||||||
|
Christian Heimes
|
||||||
|
Christian Oudard
|
||||||
|
Christoph Reiter
|
||||||
|
Christopher Hunt
|
||||||
|
Christopher Snyder
|
||||||
|
cjc7373
|
||||||
|
Clark Boylan
|
||||||
|
Claudio Jolowicz
|
||||||
|
Clay McClure
|
||||||
|
Cody
|
||||||
|
Cody Soyland
|
||||||
|
Colin Watson
|
||||||
|
Collin Anderson
|
||||||
|
Connor Osborn
|
||||||
|
Cooper Lees
|
||||||
|
Cooper Ry Lees
|
||||||
|
Cory Benfield
|
||||||
|
Cory Wright
|
||||||
|
Craig Kerstiens
|
||||||
|
Cristian Sorinel
|
||||||
|
Cristina
|
||||||
|
Cristina Muñoz
|
||||||
|
Curtis Doty
|
||||||
|
cytolentino
|
||||||
|
Daan De Meyer
|
||||||
|
Dale
|
||||||
|
Damian
|
||||||
|
Damian Quiroga
|
||||||
|
Damian Shaw
|
||||||
|
Dan Black
|
||||||
|
Dan Savilonis
|
||||||
|
Dan Sully
|
||||||
|
Dane Hillard
|
||||||
|
daniel
|
||||||
|
Daniel Collins
|
||||||
|
Daniel Hahler
|
||||||
|
Daniel Holth
|
||||||
|
Daniel Jost
|
||||||
|
Daniel Katz
|
||||||
|
Daniel Shaulov
|
||||||
|
Daniele Esposti
|
||||||
|
Daniele Nicolodi
|
||||||
|
Daniele Procida
|
||||||
|
Daniil Konovalenko
|
||||||
|
Danny Hermes
|
||||||
|
Danny McClanahan
|
||||||
|
Darren Kavanagh
|
||||||
|
Dav Clark
|
||||||
|
Dave Abrahams
|
||||||
|
Dave Jones
|
||||||
|
David Aguilar
|
||||||
|
David Black
|
||||||
|
David Bordeynik
|
||||||
|
David Caro
|
||||||
|
David D Lowe
|
||||||
|
David Evans
|
||||||
|
David Hewitt
|
||||||
|
David Linke
|
||||||
|
David Poggi
|
||||||
|
David Pursehouse
|
||||||
|
David Runge
|
||||||
|
David Tucker
|
||||||
|
David Wales
|
||||||
|
Davidovich
|
||||||
|
ddelange
|
||||||
|
Deepak Sharma
|
||||||
|
Deepyaman Datta
|
||||||
|
Denise Yu
|
||||||
|
dependabot[bot]
|
||||||
|
derwolfe
|
||||||
|
Desetude
|
||||||
|
Devesh Kumar Singh
|
||||||
|
Diego Caraballo
|
||||||
|
Diego Ramirez
|
||||||
|
DiegoCaraballo
|
||||||
|
Dimitri Merejkowsky
|
||||||
|
Dimitri Papadopoulos
|
||||||
|
Dirk Stolle
|
||||||
|
Dmitry Gladkov
|
||||||
|
Dmitry Volodin
|
||||||
|
Domen Kožar
|
||||||
|
Dominic Davis-Foster
|
||||||
|
Donald Stufft
|
||||||
|
Dongweiming
|
||||||
|
doron zarhi
|
||||||
|
Dos Moonen
|
||||||
|
Douglas Thor
|
||||||
|
DrFeathers
|
||||||
|
Dustin Ingram
|
||||||
|
Dwayne Bailey
|
||||||
|
Ed Morley
|
||||||
|
Edgar Ramírez
|
||||||
|
Edgar Ramírez Mondragón
|
||||||
|
Ee Durbin
|
||||||
|
Efflam Lemaillet
|
||||||
|
efflamlemaillet
|
||||||
|
Eitan Adler
|
||||||
|
ekristina
|
||||||
|
elainechan
|
||||||
|
Eli Schwartz
|
||||||
|
Elisha Hollander
|
||||||
|
Ellen Marie Dash
|
||||||
|
Emil Burzo
|
||||||
|
Emil Styrke
|
||||||
|
Emmanuel Arias
|
||||||
|
Endoh Takanao
|
||||||
|
enoch
|
||||||
|
Erdinc Mutlu
|
||||||
|
Eric Cousineau
|
||||||
|
Eric Gillingham
|
||||||
|
Eric Hanchrow
|
||||||
|
Eric Hopper
|
||||||
|
Erik M. Bray
|
||||||
|
Erik Rose
|
||||||
|
Erwin Janssen
|
||||||
|
Eugene Vereshchagin
|
||||||
|
everdimension
|
||||||
|
Federico
|
||||||
|
Felipe Peter
|
||||||
|
Felix Yan
|
||||||
|
fiber-space
|
||||||
|
Filip Kokosiński
|
||||||
|
Filipe Laíns
|
||||||
|
Finn Womack
|
||||||
|
finnagin
|
||||||
|
Flavio Amurrio
|
||||||
|
Florian Briand
|
||||||
|
Florian Rathgeber
|
||||||
|
Francesco
|
||||||
|
Francesco Montesano
|
||||||
|
Frost Ming
|
||||||
|
Gabriel Curio
|
||||||
|
Gabriel de Perthuis
|
||||||
|
Garry Polley
|
||||||
|
gavin
|
||||||
|
gdanielson
|
||||||
|
Geoffrey Sneddon
|
||||||
|
George Song
|
||||||
|
Georgi Valkov
|
||||||
|
Georgy Pchelkin
|
||||||
|
ghost
|
||||||
|
Giftlin Rajaiah
|
||||||
|
gizmoguy1
|
||||||
|
gkdoc
|
||||||
|
Godefroid Chapelle
|
||||||
|
Gopinath M
|
||||||
|
GOTO Hayato
|
||||||
|
gousaiyang
|
||||||
|
gpiks
|
||||||
|
Greg Roodt
|
||||||
|
Greg Ward
|
||||||
|
Guilherme Espada
|
||||||
|
Guillaume Seguin
|
||||||
|
gutsytechster
|
||||||
|
Guy Rozendorn
|
||||||
|
Guy Tuval
|
||||||
|
gzpan123
|
||||||
|
Hanjun Kim
|
||||||
|
Hari Charan
|
||||||
|
Harsh Vardhan
|
||||||
|
harupy
|
||||||
|
Harutaka Kawamura
|
||||||
|
hauntsaninja
|
||||||
|
Henrich Hartzer
|
||||||
|
Henry Schreiner
|
||||||
|
Herbert Pfennig
|
||||||
|
Holly Stotelmyer
|
||||||
|
Honnix
|
||||||
|
Hsiaoming Yang
|
||||||
|
Hugo Lopes Tavares
|
||||||
|
Hugo van Kemenade
|
||||||
|
Hugues Bruant
|
||||||
|
Hynek Schlawack
|
||||||
|
Ian Bicking
|
||||||
|
Ian Cordasco
|
||||||
|
Ian Lee
|
||||||
|
Ian Stapleton Cordasco
|
||||||
|
Ian Wienand
|
||||||
|
Igor Kuzmitshov
|
||||||
|
Igor Sobreira
|
||||||
|
Ilan Schnell
|
||||||
|
Illia Volochii
|
||||||
|
Ilya Baryshev
|
||||||
|
Inada Naoki
|
||||||
|
Ionel Cristian Mărieș
|
||||||
|
Ionel Maries Cristian
|
||||||
|
Itamar Turner-Trauring
|
||||||
|
Ivan Pozdeev
|
||||||
|
J. Nick Koston
|
||||||
|
Jacob Kim
|
||||||
|
Jacob Walls
|
||||||
|
Jaime Sanz
|
||||||
|
jakirkham
|
||||||
|
Jakub Kuczys
|
||||||
|
Jakub Stasiak
|
||||||
|
Jakub Vysoky
|
||||||
|
Jakub Wilk
|
||||||
|
James Cleveland
|
||||||
|
James Curtin
|
||||||
|
James Firth
|
||||||
|
James Gerity
|
||||||
|
James Polley
|
||||||
|
Jan Pokorný
|
||||||
|
Jannis Leidel
|
||||||
|
Jarek Potiuk
|
||||||
|
jarondl
|
||||||
|
Jason Curtis
|
||||||
|
Jason R. Coombs
|
||||||
|
JasonMo
|
||||||
|
JasonMo1
|
||||||
|
Jay Graves
|
||||||
|
Jean Abou Samra
|
||||||
|
Jean-Christophe Fillion-Robin
|
||||||
|
Jeff Barber
|
||||||
|
Jeff Dairiki
|
||||||
|
Jeff Widman
|
||||||
|
Jelmer Vernooij
|
||||||
|
jenix21
|
||||||
|
Jeremy Stanley
|
||||||
|
Jeremy Zafran
|
||||||
|
Jesse Rittner
|
||||||
|
Jiashuo Li
|
||||||
|
Jim Fisher
|
||||||
|
Jim Garrison
|
||||||
|
Jiun Bae
|
||||||
|
Jivan Amara
|
||||||
|
Joe Bylund
|
||||||
|
Joe Michelini
|
||||||
|
John Paton
|
||||||
|
John T. Wodder II
|
||||||
|
John-Scott Atlakson
|
||||||
|
johnthagen
|
||||||
|
Jon Banafato
|
||||||
|
Jon Dufresne
|
||||||
|
Jon Parise
|
||||||
|
Jonas Nockert
|
||||||
|
Jonathan Herbert
|
||||||
|
Joonatan Partanen
|
||||||
|
Joost Molenaar
|
||||||
|
Jorge Niedbalski
|
||||||
|
Joseph Bylund
|
||||||
|
Joseph Long
|
||||||
|
Josh Bronson
|
||||||
|
Josh Hansen
|
||||||
|
Josh Schneier
|
||||||
|
Joshua
|
||||||
|
Juan Luis Cano Rodríguez
|
||||||
|
Juanjo Bazán
|
||||||
|
Judah Rand
|
||||||
|
Julian Berman
|
||||||
|
Julian Gethmann
|
||||||
|
Julien Demoor
|
||||||
|
Jussi Kukkonen
|
||||||
|
jwg4
|
||||||
|
Jyrki Pulliainen
|
||||||
|
Kai Chen
|
||||||
|
Kai Mueller
|
||||||
|
Kamal Bin Mustafa
|
||||||
|
kasium
|
||||||
|
kaustav haldar
|
||||||
|
keanemind
|
||||||
|
Keith Maxwell
|
||||||
|
Kelsey Hightower
|
||||||
|
Kenneth Belitzky
|
||||||
|
Kenneth Reitz
|
||||||
|
Kevin Burke
|
||||||
|
Kevin Carter
|
||||||
|
Kevin Frommelt
|
||||||
|
Kevin R Patterson
|
||||||
|
Kexuan Sun
|
||||||
|
Kit Randel
|
||||||
|
Klaas van Schelven
|
||||||
|
KOLANICH
|
||||||
|
kpinc
|
||||||
|
Krishna Oza
|
||||||
|
Kumar McMillan
|
||||||
|
Kurt McKee
|
||||||
|
Kyle Persohn
|
||||||
|
lakshmanaram
|
||||||
|
Laszlo Kiss-Kollar
|
||||||
|
Laurent Bristiel
|
||||||
|
Laurent LAPORTE
|
||||||
|
Laurie O
|
||||||
|
Laurie Opperman
|
||||||
|
layday
|
||||||
|
Leon Sasson
|
||||||
|
Lev Givon
|
||||||
|
Lincoln de Sousa
|
||||||
|
Lipis
|
||||||
|
lorddavidiii
|
||||||
|
Loren Carvalho
|
||||||
|
Lucas Cimon
|
||||||
|
Ludovic Gasc
|
||||||
|
Lukas Geiger
|
||||||
|
Lukas Juhrich
|
||||||
|
Luke Macken
|
||||||
|
Luo Jiebin
|
||||||
|
luojiebin
|
||||||
|
luz.paz
|
||||||
|
László Kiss Kollár
|
||||||
|
M00nL1ght
|
||||||
|
Marc Abramowitz
|
||||||
|
Marc Tamlyn
|
||||||
|
Marcus Smith
|
||||||
|
Mariatta
|
||||||
|
Mark Kohler
|
||||||
|
Mark Williams
|
||||||
|
Markus Hametner
|
||||||
|
Martey Dodoo
|
||||||
|
Martin Fischer
|
||||||
|
Martin Häcker
|
||||||
|
Martin Pavlasek
|
||||||
|
Masaki
|
||||||
|
Masklinn
|
||||||
|
Matej Stuchlik
|
||||||
|
Mathew Jennings
|
||||||
|
Mathieu Bridon
|
||||||
|
Mathieu Kniewallner
|
||||||
|
Matt Bacchi
|
||||||
|
Matt Good
|
||||||
|
Matt Maker
|
||||||
|
Matt Robenolt
|
||||||
|
matthew
|
||||||
|
Matthew Einhorn
|
||||||
|
Matthew Feickert
|
||||||
|
Matthew Gilliard
|
||||||
|
Matthew Iversen
|
||||||
|
Matthew Treinish
|
||||||
|
Matthew Trumbell
|
||||||
|
Matthew Willson
|
||||||
|
Matthias Bussonnier
|
||||||
|
mattip
|
||||||
|
Maurits van Rees
|
||||||
|
Max W Chase
|
||||||
|
Maxim Kurnikov
|
||||||
|
Maxime Rouyrre
|
||||||
|
mayeut
|
||||||
|
mbaluna
|
||||||
|
mdebi
|
||||||
|
memoselyk
|
||||||
|
meowmeowcat
|
||||||
|
Michael
|
||||||
|
Michael Aquilina
|
||||||
|
Michael E. Karpeles
|
||||||
|
Michael Klich
|
||||||
|
Michael Mintz
|
||||||
|
Michael Williamson
|
||||||
|
michaelpacer
|
||||||
|
Michał Górny
|
||||||
|
Mickaël Schoentgen
|
||||||
|
Miguel Araujo Perez
|
||||||
|
Mihir Singh
|
||||||
|
Mike
|
||||||
|
Mike Hendricks
|
||||||
|
Min RK
|
||||||
|
MinRK
|
||||||
|
Miro Hrončok
|
||||||
|
Monica Baluna
|
||||||
|
montefra
|
||||||
|
Monty Taylor
|
||||||
|
Muha Ajjan
|
||||||
|
Nadav Wexler
|
||||||
|
Nahuel Ambrosini
|
||||||
|
Nate Coraor
|
||||||
|
Nate Prewitt
|
||||||
|
Nathan Houghton
|
||||||
|
Nathaniel J. Smith
|
||||||
|
Nehal J Wani
|
||||||
|
Neil Botelho
|
||||||
|
Nguyễn Gia Phong
|
||||||
|
Nicholas Serra
|
||||||
|
Nick Coghlan
|
||||||
|
Nick Stenning
|
||||||
|
Nick Timkovich
|
||||||
|
Nicolas Bock
|
||||||
|
Nicole Harris
|
||||||
|
Nikhil Benesch
|
||||||
|
Nikhil Ladha
|
||||||
|
Nikita Chepanov
|
||||||
|
Nikolay Korolev
|
||||||
|
Nipunn Koorapati
|
||||||
|
Nitesh Sharma
|
||||||
|
Niyas Sait
|
||||||
|
Noah
|
||||||
|
Noah Gorny
|
||||||
|
Nowell Strite
|
||||||
|
NtaleGrey
|
||||||
|
nvdv
|
||||||
|
OBITORASU
|
||||||
|
Ofek Lev
|
||||||
|
ofrinevo
|
||||||
|
Oliver Freund
|
||||||
|
Oliver Jeeves
|
||||||
|
Oliver Mannion
|
||||||
|
Oliver Tonnhofer
|
||||||
|
Olivier Girardot
|
||||||
|
Olivier Grisel
|
||||||
|
Ollie Rutherfurd
|
||||||
|
OMOTO Kenji
|
||||||
|
Omry Yadan
|
||||||
|
onlinejudge95
|
||||||
|
Oren Held
|
||||||
|
Oscar Benjamin
|
||||||
|
Oz N Tiram
|
||||||
|
Pachwenko
|
||||||
|
Patrick Dubroy
|
||||||
|
Patrick Jenkins
|
||||||
|
Patrick Lawson
|
||||||
|
patricktokeeffe
|
||||||
|
Patrik Kopkan
|
||||||
|
Paul Ganssle
|
||||||
|
Paul Kehrer
|
||||||
|
Paul Moore
|
||||||
|
Paul Nasrat
|
||||||
|
Paul Oswald
|
||||||
|
Paul van der Linden
|
||||||
|
Paulus Schoutsen
|
||||||
|
Pavel Safronov
|
||||||
|
Pavithra Eswaramoorthy
|
||||||
|
Pawel Jasinski
|
||||||
|
Paweł Szramowski
|
||||||
|
Pekka Klärck
|
||||||
|
Peter Gessler
|
||||||
|
Peter Lisák
|
||||||
|
Peter Waller
|
||||||
|
petr-tik
|
||||||
|
Phaneendra Chiruvella
|
||||||
|
Phil Elson
|
||||||
|
Phil Freo
|
||||||
|
Phil Pennock
|
||||||
|
Phil Whelan
|
||||||
|
Philip Jägenstedt
|
||||||
|
Philip Molloy
|
||||||
|
Philippe Ombredanne
|
||||||
|
Pi Delport
|
||||||
|
Pierre-Yves Rofes
|
||||||
|
Pieter Degroote
|
||||||
|
pip
|
||||||
|
Prabakaran Kumaresshan
|
||||||
|
Prabhjyotsing Surjit Singh Sodhi
|
||||||
|
Prabhu Marappan
|
||||||
|
Pradyun Gedam
|
||||||
|
Prashant Sharma
|
||||||
|
Pratik Mallya
|
||||||
|
pre-commit-ci[bot]
|
||||||
|
Preet Thakkar
|
||||||
|
Preston Holmes
|
||||||
|
Przemek Wrzos
|
||||||
|
Pulkit Goyal
|
||||||
|
q0w
|
||||||
|
Qiangning Hong
|
||||||
|
Qiming Xu
|
||||||
|
Quentin Lee
|
||||||
|
Quentin Pradet
|
||||||
|
R. David Murray
|
||||||
|
Rafael Caricio
|
||||||
|
Ralf Schmitt
|
||||||
|
Razzi Abuissa
|
||||||
|
rdb
|
||||||
|
Reece Dunham
|
||||||
|
Remi Rampin
|
||||||
|
Rene Dudfield
|
||||||
|
Riccardo Magliocchetti
|
||||||
|
Riccardo Schirone
|
||||||
|
Richard Jones
|
||||||
|
Richard Si
|
||||||
|
Ricky Ng-Adam
|
||||||
|
Rishi
|
||||||
|
RobberPhex
|
||||||
|
Robert Collins
|
||||||
|
Robert McGibbon
|
||||||
|
Robert Pollak
|
||||||
|
Robert T. McGibbon
|
||||||
|
robin elisha robinson
|
||||||
|
Roey Berman
|
||||||
|
Rohan Jain
|
||||||
|
Roman Bogorodskiy
|
||||||
|
Roman Donchenko
|
||||||
|
Romuald Brunet
|
||||||
|
ronaudinho
|
||||||
|
Ronny Pfannschmidt
|
||||||
|
Rory McCann
|
||||||
|
Ross Brattain
|
||||||
|
Roy Wellington Ⅳ
|
||||||
|
Ruairidh MacLeod
|
||||||
|
Russell Keith-Magee
|
||||||
|
Ryan Shepherd
|
||||||
|
Ryan Wooden
|
||||||
|
ryneeverett
|
||||||
|
Sachi King
|
||||||
|
Salvatore Rinchiera
|
||||||
|
sandeepkiran-js
|
||||||
|
Sander Van Balen
|
||||||
|
Savio Jomton
|
||||||
|
schlamar
|
||||||
|
Scott Kitterman
|
||||||
|
Sean
|
||||||
|
seanj
|
||||||
|
Sebastian Jordan
|
||||||
|
Sebastian Schaetz
|
||||||
|
Segev Finer
|
||||||
|
SeongSoo Cho
|
||||||
|
Sergey Vasilyev
|
||||||
|
Seth Michael Larson
|
||||||
|
Seth Woodworth
|
||||||
|
Shahar Epstein
|
||||||
|
Shantanu
|
||||||
|
shireenrao
|
||||||
|
Shivansh-007
|
||||||
|
Shlomi Fish
|
||||||
|
Shovan Maity
|
||||||
|
Simeon Visser
|
||||||
|
Simon Cross
|
||||||
|
Simon Pichugin
|
||||||
|
sinoroc
|
||||||
|
sinscary
|
||||||
|
snook92
|
||||||
|
socketubs
|
||||||
|
Sorin Sbarnea
|
||||||
|
Srinivas Nyayapati
|
||||||
|
Stavros Korokithakis
|
||||||
|
Stefan Scherfke
|
||||||
|
Stefano Rivera
|
||||||
|
Stephan Erb
|
||||||
|
Stephen Rosen
|
||||||
|
stepshal
|
||||||
|
Steve (Gadget) Barnes
|
||||||
|
Steve Barnes
|
||||||
|
Steve Dower
|
||||||
|
Steve Kowalik
|
||||||
|
Steven Myint
|
||||||
|
Steven Silvester
|
||||||
|
stonebig
|
||||||
|
studioj
|
||||||
|
Stéphane Bidoul
|
||||||
|
Stéphane Bidoul (ACSONE)
|
||||||
|
Stéphane Klein
|
||||||
|
Sumana Harihareswara
|
||||||
|
Surbhi Sharma
|
||||||
|
Sviatoslav Sydorenko
|
||||||
|
Swat009
|
||||||
|
Sylvain
|
||||||
|
Takayuki SHIMIZUKAWA
|
||||||
|
Taneli Hukkinen
|
||||||
|
tbeswick
|
||||||
|
Thiago
|
||||||
|
Thijs Triemstra
|
||||||
|
Thomas Fenzl
|
||||||
|
Thomas Grainger
|
||||||
|
Thomas Guettler
|
||||||
|
Thomas Johansson
|
||||||
|
Thomas Kluyver
|
||||||
|
Thomas Smith
|
||||||
|
Thomas VINCENT
|
||||||
|
Tim D. Smith
|
||||||
|
Tim Gates
|
||||||
|
Tim Harder
|
||||||
|
Tim Heap
|
||||||
|
tim smith
|
||||||
|
tinruufu
|
||||||
|
Tobias Hermann
|
||||||
|
Tom Forbes
|
||||||
|
Tom Freudenheim
|
||||||
|
Tom V
|
||||||
|
Tomas Hrnciar
|
||||||
|
Tomas Orsava
|
||||||
|
Tomer Chachamu
|
||||||
|
Tommi Enenkel | AnB
|
||||||
|
Tomáš Hrnčiar
|
||||||
|
Tony Beswick
|
||||||
|
Tony Narlock
|
||||||
|
Tony Zhaocheng Tan
|
||||||
|
TonyBeswick
|
||||||
|
toonarmycaptain
|
||||||
|
Toshio Kuratomi
|
||||||
|
toxinu
|
||||||
|
Travis Swicegood
|
||||||
|
Tushar Sadhwani
|
||||||
|
Tzu-ping Chung
|
||||||
|
Valentin Haenel
|
||||||
|
Victor Stinner
|
||||||
|
victorvpaulo
|
||||||
|
Vikram - Google
|
||||||
|
Viktor Szépe
|
||||||
|
Ville Skyttä
|
||||||
|
Vinay Sajip
|
||||||
|
Vincent Philippon
|
||||||
|
Vinicyus Macedo
|
||||||
|
Vipul Kumar
|
||||||
|
Vitaly Babiy
|
||||||
|
Vladimir Fokow
|
||||||
|
Vladimir Rutsky
|
||||||
|
W. Trevor King
|
||||||
|
Wil Tan
|
||||||
|
Wilfred Hughes
|
||||||
|
William Edwards
|
||||||
|
William ML Leslie
|
||||||
|
William T Olson
|
||||||
|
William Woodruff
|
||||||
|
Wilson Mo
|
||||||
|
wim glenn
|
||||||
|
Winson Luk
|
||||||
|
Wolfgang Maier
|
||||||
|
Wu Zhenyu
|
||||||
|
XAMES3
|
||||||
|
Xavier Fernandez
|
||||||
|
xoviat
|
||||||
|
xtreak
|
||||||
|
YAMAMOTO Takashi
|
||||||
|
Yen Chi Hsuan
|
||||||
|
Yeray Diaz Diaz
|
||||||
|
Yoval P
|
||||||
|
Yu Jian
|
||||||
|
Yuan Jing Vincent Yan
|
||||||
|
Yusuke Hayashi
|
||||||
|
Zearin
|
||||||
|
Zhiping Deng
|
||||||
|
ziebam
|
||||||
|
Zvezdan Petkovic
|
||||||
|
Łukasz Langa
|
||||||
|
Роман Донченко
|
||||||
|
Семён Марьясин
|
||||||
|
rekcäH nitraM
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
pip
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
Copyright (c) 2008-present The pip developers (see AUTHORS.txt file)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
Metadata-Version: 2.1
|
||||||
|
Name: pip
|
||||||
|
Version: 24.0
|
||||||
|
Summary: The PyPA recommended tool for installing Python packages.
|
||||||
|
Author-email: The pip developers <distutils-sig@python.org>
|
||||||
|
License: MIT
|
||||||
|
Project-URL: Homepage, https://pip.pypa.io/
|
||||||
|
Project-URL: Documentation, https://pip.pypa.io
|
||||||
|
Project-URL: Source, https://github.com/pypa/pip
|
||||||
|
Project-URL: Changelog, https://pip.pypa.io/en/stable/news/
|
||||||
|
Classifier: Development Status :: 5 - Production/Stable
|
||||||
|
Classifier: Intended Audience :: Developers
|
||||||
|
Classifier: License :: OSI Approved :: MIT License
|
||||||
|
Classifier: Topic :: Software Development :: Build Tools
|
||||||
|
Classifier: Programming Language :: Python
|
||||||
|
Classifier: Programming Language :: Python :: 3
|
||||||
|
Classifier: Programming Language :: Python :: 3 :: Only
|
||||||
|
Classifier: Programming Language :: Python :: 3.7
|
||||||
|
Classifier: Programming Language :: Python :: 3.8
|
||||||
|
Classifier: Programming Language :: Python :: 3.9
|
||||||
|
Classifier: Programming Language :: Python :: 3.10
|
||||||
|
Classifier: Programming Language :: Python :: 3.11
|
||||||
|
Classifier: Programming Language :: Python :: 3.12
|
||||||
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||||
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||||
|
Requires-Python: >=3.7
|
||||||
|
Description-Content-Type: text/x-rst
|
||||||
|
License-File: LICENSE.txt
|
||||||
|
License-File: AUTHORS.txt
|
||||||
|
|
||||||
|
pip - The Python Package Installer
|
||||||
|
==================================
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/pypi/v/pip.svg
|
||||||
|
:target: https://pypi.org/project/pip/
|
||||||
|
:alt: PyPI
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/pypi/pyversions/pip
|
||||||
|
:target: https://pypi.org/project/pip
|
||||||
|
:alt: PyPI - Python Version
|
||||||
|
|
||||||
|
.. image:: https://readthedocs.org/projects/pip/badge/?version=latest
|
||||||
|
:target: https://pip.pypa.io/en/latest
|
||||||
|
:alt: Documentation
|
||||||
|
|
||||||
|
pip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes.
|
||||||
|
|
||||||
|
Please take a look at our documentation for how to install and use pip:
|
||||||
|
|
||||||
|
* `Installation`_
|
||||||
|
* `Usage`_
|
||||||
|
|
||||||
|
We release updates regularly, with a new version every 3 months. Find more details in our documentation:
|
||||||
|
|
||||||
|
* `Release notes`_
|
||||||
|
* `Release process`_
|
||||||
|
|
||||||
|
If you find bugs, need help, or want to talk to the developers, please use our mailing lists or chat rooms:
|
||||||
|
|
||||||
|
* `Issue tracking`_
|
||||||
|
* `Discourse channel`_
|
||||||
|
* `User IRC`_
|
||||||
|
|
||||||
|
If you want to get involved head over to GitHub to get the source code, look at our development documentation and feel free to jump on the developer mailing lists and chat rooms:
|
||||||
|
|
||||||
|
* `GitHub page`_
|
||||||
|
* `Development documentation`_
|
||||||
|
* `Development IRC`_
|
||||||
|
|
||||||
|
Code of Conduct
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Everyone interacting in the pip project's codebases, issue trackers, chat
|
||||||
|
rooms, and mailing lists is expected to follow the `PSF Code of Conduct`_.
|
||||||
|
|
||||||
|
.. _package installer: https://packaging.python.org/guides/tool-recommendations/
|
||||||
|
.. _Python Package Index: https://pypi.org
|
||||||
|
.. _Installation: https://pip.pypa.io/en/stable/installation/
|
||||||
|
.. _Usage: https://pip.pypa.io/en/stable/
|
||||||
|
.. _Release notes: https://pip.pypa.io/en/stable/news.html
|
||||||
|
.. _Release process: https://pip.pypa.io/en/latest/development/release-process/
|
||||||
|
.. _GitHub page: https://github.com/pypa/pip
|
||||||
|
.. _Development documentation: https://pip.pypa.io/en/latest/development
|
||||||
|
.. _Issue tracking: https://github.com/pypa/pip/issues
|
||||||
|
.. _Discourse channel: https://discuss.python.org/c/packaging
|
||||||
|
.. _User IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa
|
||||||
|
.. _Development IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa-dev
|
||||||
|
.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
|||||||
|
Wheel-Version: 1.0
|
||||||
|
Generator: bdist_wheel (0.42.0)
|
||||||
|
Root-Is-Purelib: true
|
||||||
|
Tag: py3-none-any
|
||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[console_scripts]
|
||||||
|
pip = pip._internal.cli.main:main
|
||||||
|
pip3 = pip._internal.cli.main:main
|
||||||
|
pip3.10 = pip._internal.cli.main:main
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
pip
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
__version__ = "24.0"
|
||||||
|
|
||||||
|
|
||||||
|
def main(args: Optional[List[str]] = None) -> int:
|
||||||
|
"""This is an internal API only meant for use by pip's own console scripts.
|
||||||
|
|
||||||
|
For additional details, see https://github.com/pypa/pip/issues/7498.
|
||||||
|
"""
|
||||||
|
from pip._internal.utils.entrypoints import _wrapper
|
||||||
|
|
||||||
|
return _wrapper(args)
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Remove '' and current working directory from the first entry
|
||||||
|
# of sys.path, if present to avoid using current directory
|
||||||
|
# in pip commands check, freeze, install, list and show,
|
||||||
|
# when invoked as python -m pip <command>
|
||||||
|
if sys.path[0] in ("", os.getcwd()):
|
||||||
|
sys.path.pop(0)
|
||||||
|
|
||||||
|
# If we are running from a wheel, add the wheel to sys.path
|
||||||
|
# This allows the usage python pip-*.whl/pip install pip-*.whl
|
||||||
|
if __package__ == "":
|
||||||
|
# __file__ is pip-*.whl/pip/__main__.py
|
||||||
|
# first dirname call strips of '/__main__.py', second strips off '/pip'
|
||||||
|
# Resulting path is the name of the wheel itself
|
||||||
|
# Add that to sys.path so we can import pip
|
||||||
|
path = os.path.dirname(os.path.dirname(__file__))
|
||||||
|
sys.path.insert(0, path)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
from pip._internal.cli.main import main as _main
|
||||||
|
|
||||||
|
sys.exit(_main())
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
"""Execute exactly this copy of pip, within a different environment.
|
||||||
|
|
||||||
|
This file is named as it is, to ensure that this module can't be imported via
|
||||||
|
an import statement.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# /!\ This version compatibility check section must be Python 2 compatible. /!\
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Copied from setup.py
|
||||||
|
PYTHON_REQUIRES = (3, 7)
|
||||||
|
|
||||||
|
|
||||||
|
def version_str(version): # type: ignore
|
||||||
|
return ".".join(str(v) for v in version)
|
||||||
|
|
||||||
|
|
||||||
|
if sys.version_info[:2] < PYTHON_REQUIRES:
|
||||||
|
raise SystemExit(
|
||||||
|
"This version of pip does not support python {} (requires >={}).".format(
|
||||||
|
version_str(sys.version_info[:2]), version_str(PYTHON_REQUIRES)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# From here on, we can use Python 3 features, but the syntax must remain
|
||||||
|
# Python 2 compatible.
|
||||||
|
|
||||||
|
import runpy # noqa: E402
|
||||||
|
from importlib.machinery import PathFinder # noqa: E402
|
||||||
|
from os.path import dirname # noqa: E402
|
||||||
|
|
||||||
|
PIP_SOURCES_ROOT = dirname(dirname(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
class PipImportRedirectingFinder:
|
||||||
|
@classmethod
|
||||||
|
def find_spec(self, fullname, path=None, target=None): # type: ignore
|
||||||
|
if fullname != "pip":
|
||||||
|
return None
|
||||||
|
|
||||||
|
spec = PathFinder.find_spec(fullname, [PIP_SOURCES_ROOT], target)
|
||||||
|
assert spec, (PIP_SOURCES_ROOT, fullname)
|
||||||
|
return spec
|
||||||
|
|
||||||
|
|
||||||
|
sys.meta_path.insert(0, PipImportRedirectingFinder())
|
||||||
|
|
||||||
|
assert __name__ == "__main__", "Cannot run __pip-runner__.py as a non-main module"
|
||||||
|
runpy.run_module("pip", run_name="__main__", alter_sys=True)
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,18 @@
|
|||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from pip._internal.utils import _log
|
||||||
|
|
||||||
|
# init_logging() must be called before any call to logging.getLogger()
|
||||||
|
# which happens at import of most modules.
|
||||||
|
_log.init_logging()
|
||||||
|
|
||||||
|
|
||||||
|
def main(args: (Optional[List[str]]) = None) -> int:
|
||||||
|
"""This is preserved for old console scripts that may still be referencing
|
||||||
|
it.
|
||||||
|
|
||||||
|
For additional details, see https://github.com/pypa/pip/issues/7498.
|
||||||
|
"""
|
||||||
|
from pip._internal.utils.entrypoints import _wrapper
|
||||||
|
|
||||||
|
return _wrapper(args)
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,311 @@
|
|||||||
|
"""Build Environment used for isolation during sdist building
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import site
|
||||||
|
import sys
|
||||||
|
import textwrap
|
||||||
|
from collections import OrderedDict
|
||||||
|
from types import TracebackType
|
||||||
|
from typing import TYPE_CHECKING, Iterable, List, Optional, Set, Tuple, Type, Union
|
||||||
|
|
||||||
|
from pip._vendor.certifi import where
|
||||||
|
from pip._vendor.packaging.requirements import Requirement
|
||||||
|
from pip._vendor.packaging.version import Version
|
||||||
|
|
||||||
|
from pip import __file__ as pip_location
|
||||||
|
from pip._internal.cli.spinners import open_spinner
|
||||||
|
from pip._internal.locations import get_platlib, get_purelib, get_scheme
|
||||||
|
from pip._internal.metadata import get_default_environment, get_environment
|
||||||
|
from pip._internal.utils.subprocess import call_subprocess
|
||||||
|
from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from pip._internal.index.package_finder import PackageFinder
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def _dedup(a: str, b: str) -> Union[Tuple[str], Tuple[str, str]]:
|
||||||
|
return (a, b) if a != b else (a,)
|
||||||
|
|
||||||
|
|
||||||
|
class _Prefix:
|
||||||
|
def __init__(self, path: str) -> None:
|
||||||
|
self.path = path
|
||||||
|
self.setup = False
|
||||||
|
scheme = get_scheme("", prefix=path)
|
||||||
|
self.bin_dir = scheme.scripts
|
||||||
|
self.lib_dirs = _dedup(scheme.purelib, scheme.platlib)
|
||||||
|
|
||||||
|
|
||||||
|
def get_runnable_pip() -> str:
|
||||||
|
"""Get a file to pass to a Python executable, to run the currently-running pip.
|
||||||
|
|
||||||
|
This is used to run a pip subprocess, for installing requirements into the build
|
||||||
|
environment.
|
||||||
|
"""
|
||||||
|
source = pathlib.Path(pip_location).resolve().parent
|
||||||
|
|
||||||
|
if not source.is_dir():
|
||||||
|
# This would happen if someone is using pip from inside a zip file. In that
|
||||||
|
# case, we can use that directly.
|
||||||
|
return str(source)
|
||||||
|
|
||||||
|
return os.fsdecode(source / "__pip-runner__.py")
|
||||||
|
|
||||||
|
|
||||||
|
def _get_system_sitepackages() -> Set[str]:
|
||||||
|
"""Get system site packages
|
||||||
|
|
||||||
|
Usually from site.getsitepackages,
|
||||||
|
but fallback on `get_purelib()/get_platlib()` if unavailable
|
||||||
|
(e.g. in a virtualenv created by virtualenv<20)
|
||||||
|
|
||||||
|
Returns normalized set of strings.
|
||||||
|
"""
|
||||||
|
if hasattr(site, "getsitepackages"):
|
||||||
|
system_sites = site.getsitepackages()
|
||||||
|
else:
|
||||||
|
# virtualenv < 20 overwrites site.py without getsitepackages
|
||||||
|
# fallback on get_purelib/get_platlib.
|
||||||
|
# this is known to miss things, but shouldn't in the cases
|
||||||
|
# where getsitepackages() has been removed (inside a virtualenv)
|
||||||
|
system_sites = [get_purelib(), get_platlib()]
|
||||||
|
return {os.path.normcase(path) for path in system_sites}
|
||||||
|
|
||||||
|
|
||||||
|
class BuildEnvironment:
|
||||||
|
"""Creates and manages an isolated environment to install build deps"""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
temp_dir = TempDirectory(kind=tempdir_kinds.BUILD_ENV, globally_managed=True)
|
||||||
|
|
||||||
|
self._prefixes = OrderedDict(
|
||||||
|
(name, _Prefix(os.path.join(temp_dir.path, name)))
|
||||||
|
for name in ("normal", "overlay")
|
||||||
|
)
|
||||||
|
|
||||||
|
self._bin_dirs: List[str] = []
|
||||||
|
self._lib_dirs: List[str] = []
|
||||||
|
for prefix in reversed(list(self._prefixes.values())):
|
||||||
|
self._bin_dirs.append(prefix.bin_dir)
|
||||||
|
self._lib_dirs.extend(prefix.lib_dirs)
|
||||||
|
|
||||||
|
# Customize site to:
|
||||||
|
# - ensure .pth files are honored
|
||||||
|
# - prevent access to system site packages
|
||||||
|
system_sites = _get_system_sitepackages()
|
||||||
|
|
||||||
|
self._site_dir = os.path.join(temp_dir.path, "site")
|
||||||
|
if not os.path.exists(self._site_dir):
|
||||||
|
os.mkdir(self._site_dir)
|
||||||
|
with open(
|
||||||
|
os.path.join(self._site_dir, "sitecustomize.py"), "w", encoding="utf-8"
|
||||||
|
) as fp:
|
||||||
|
fp.write(
|
||||||
|
textwrap.dedent(
|
||||||
|
"""
|
||||||
|
import os, site, sys
|
||||||
|
|
||||||
|
# First, drop system-sites related paths.
|
||||||
|
original_sys_path = sys.path[:]
|
||||||
|
known_paths = set()
|
||||||
|
for path in {system_sites!r}:
|
||||||
|
site.addsitedir(path, known_paths=known_paths)
|
||||||
|
system_paths = set(
|
||||||
|
os.path.normcase(path)
|
||||||
|
for path in sys.path[len(original_sys_path):]
|
||||||
|
)
|
||||||
|
original_sys_path = [
|
||||||
|
path for path in original_sys_path
|
||||||
|
if os.path.normcase(path) not in system_paths
|
||||||
|
]
|
||||||
|
sys.path = original_sys_path
|
||||||
|
|
||||||
|
# Second, add lib directories.
|
||||||
|
# ensuring .pth file are processed.
|
||||||
|
for path in {lib_dirs!r}:
|
||||||
|
assert not path in sys.path
|
||||||
|
site.addsitedir(path)
|
||||||
|
"""
|
||||||
|
).format(system_sites=system_sites, lib_dirs=self._lib_dirs)
|
||||||
|
)
|
||||||
|
|
||||||
|
def __enter__(self) -> None:
|
||||||
|
self._save_env = {
|
||||||
|
name: os.environ.get(name, None)
|
||||||
|
for name in ("PATH", "PYTHONNOUSERSITE", "PYTHONPATH")
|
||||||
|
}
|
||||||
|
|
||||||
|
path = self._bin_dirs[:]
|
||||||
|
old_path = self._save_env["PATH"]
|
||||||
|
if old_path:
|
||||||
|
path.extend(old_path.split(os.pathsep))
|
||||||
|
|
||||||
|
pythonpath = [self._site_dir]
|
||||||
|
|
||||||
|
os.environ.update(
|
||||||
|
{
|
||||||
|
"PATH": os.pathsep.join(path),
|
||||||
|
"PYTHONNOUSERSITE": "1",
|
||||||
|
"PYTHONPATH": os.pathsep.join(pythonpath),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def __exit__(
|
||||||
|
self,
|
||||||
|
exc_type: Optional[Type[BaseException]],
|
||||||
|
exc_val: Optional[BaseException],
|
||||||
|
exc_tb: Optional[TracebackType],
|
||||||
|
) -> None:
|
||||||
|
for varname, old_value in self._save_env.items():
|
||||||
|
if old_value is None:
|
||||||
|
os.environ.pop(varname, None)
|
||||||
|
else:
|
||||||
|
os.environ[varname] = old_value
|
||||||
|
|
||||||
|
def check_requirements(
|
||||||
|
self, reqs: Iterable[str]
|
||||||
|
) -> Tuple[Set[Tuple[str, str]], Set[str]]:
|
||||||
|
"""Return 2 sets:
|
||||||
|
- conflicting requirements: set of (installed, wanted) reqs tuples
|
||||||
|
- missing requirements: set of reqs
|
||||||
|
"""
|
||||||
|
missing = set()
|
||||||
|
conflicting = set()
|
||||||
|
if reqs:
|
||||||
|
env = (
|
||||||
|
get_environment(self._lib_dirs)
|
||||||
|
if hasattr(self, "_lib_dirs")
|
||||||
|
else get_default_environment()
|
||||||
|
)
|
||||||
|
for req_str in reqs:
|
||||||
|
req = Requirement(req_str)
|
||||||
|
# We're explicitly evaluating with an empty extra value, since build
|
||||||
|
# environments are not provided any mechanism to select specific extras.
|
||||||
|
if req.marker is not None and not req.marker.evaluate({"extra": ""}):
|
||||||
|
continue
|
||||||
|
dist = env.get_distribution(req.name)
|
||||||
|
if not dist:
|
||||||
|
missing.add(req_str)
|
||||||
|
continue
|
||||||
|
if isinstance(dist.version, Version):
|
||||||
|
installed_req_str = f"{req.name}=={dist.version}"
|
||||||
|
else:
|
||||||
|
installed_req_str = f"{req.name}==={dist.version}"
|
||||||
|
if not req.specifier.contains(dist.version, prereleases=True):
|
||||||
|
conflicting.add((installed_req_str, req_str))
|
||||||
|
# FIXME: Consider direct URL?
|
||||||
|
return conflicting, missing
|
||||||
|
|
||||||
|
def install_requirements(
|
||||||
|
self,
|
||||||
|
finder: "PackageFinder",
|
||||||
|
requirements: Iterable[str],
|
||||||
|
prefix_as_string: str,
|
||||||
|
*,
|
||||||
|
kind: str,
|
||||||
|
) -> None:
|
||||||
|
prefix = self._prefixes[prefix_as_string]
|
||||||
|
assert not prefix.setup
|
||||||
|
prefix.setup = True
|
||||||
|
if not requirements:
|
||||||
|
return
|
||||||
|
self._install_requirements(
|
||||||
|
get_runnable_pip(),
|
||||||
|
finder,
|
||||||
|
requirements,
|
||||||
|
prefix,
|
||||||
|
kind=kind,
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _install_requirements(
|
||||||
|
pip_runnable: str,
|
||||||
|
finder: "PackageFinder",
|
||||||
|
requirements: Iterable[str],
|
||||||
|
prefix: _Prefix,
|
||||||
|
*,
|
||||||
|
kind: str,
|
||||||
|
) -> None:
|
||||||
|
args: List[str] = [
|
||||||
|
sys.executable,
|
||||||
|
pip_runnable,
|
||||||
|
"install",
|
||||||
|
"--ignore-installed",
|
||||||
|
"--no-user",
|
||||||
|
"--prefix",
|
||||||
|
prefix.path,
|
||||||
|
"--no-warn-script-location",
|
||||||
|
]
|
||||||
|
if logger.getEffectiveLevel() <= logging.DEBUG:
|
||||||
|
args.append("-v")
|
||||||
|
for format_control in ("no_binary", "only_binary"):
|
||||||
|
formats = getattr(finder.format_control, format_control)
|
||||||
|
args.extend(
|
||||||
|
(
|
||||||
|
"--" + format_control.replace("_", "-"),
|
||||||
|
",".join(sorted(formats or {":none:"})),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
index_urls = finder.index_urls
|
||||||
|
if index_urls:
|
||||||
|
args.extend(["-i", index_urls[0]])
|
||||||
|
for extra_index in index_urls[1:]:
|
||||||
|
args.extend(["--extra-index-url", extra_index])
|
||||||
|
else:
|
||||||
|
args.append("--no-index")
|
||||||
|
for link in finder.find_links:
|
||||||
|
args.extend(["--find-links", link])
|
||||||
|
|
||||||
|
for host in finder.trusted_hosts:
|
||||||
|
args.extend(["--trusted-host", host])
|
||||||
|
if finder.allow_all_prereleases:
|
||||||
|
args.append("--pre")
|
||||||
|
if finder.prefer_binary:
|
||||||
|
args.append("--prefer-binary")
|
||||||
|
args.append("--")
|
||||||
|
args.extend(requirements)
|
||||||
|
extra_environ = {"_PIP_STANDALONE_CERT": where()}
|
||||||
|
with open_spinner(f"Installing {kind}") as spinner:
|
||||||
|
call_subprocess(
|
||||||
|
args,
|
||||||
|
command_desc=f"pip subprocess to install {kind}",
|
||||||
|
spinner=spinner,
|
||||||
|
extra_environ=extra_environ,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class NoOpBuildEnvironment(BuildEnvironment):
|
||||||
|
"""A no-op drop-in replacement for BuildEnvironment"""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __enter__(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __exit__(
|
||||||
|
self,
|
||||||
|
exc_type: Optional[Type[BaseException]],
|
||||||
|
exc_val: Optional[BaseException],
|
||||||
|
exc_tb: Optional[TracebackType],
|
||||||
|
) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def cleanup(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def install_requirements(
|
||||||
|
self,
|
||||||
|
finder: "PackageFinder",
|
||||||
|
requirements: Iterable[str],
|
||||||
|
prefix_as_string: str,
|
||||||
|
*,
|
||||||
|
kind: str,
|
||||||
|
) -> None:
|
||||||
|
raise NotImplementedError()
|
||||||
@@ -0,0 +1,290 @@
|
|||||||
|
"""Cache Management
|
||||||
|
"""
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
|
from pip._vendor.packaging.tags import Tag, interpreter_name, interpreter_version
|
||||||
|
from pip._vendor.packaging.utils import canonicalize_name
|
||||||
|
|
||||||
|
from pip._internal.exceptions import InvalidWheelFilename
|
||||||
|
from pip._internal.models.direct_url import DirectUrl
|
||||||
|
from pip._internal.models.link import Link
|
||||||
|
from pip._internal.models.wheel import Wheel
|
||||||
|
from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds
|
||||||
|
from pip._internal.utils.urls import path_to_url
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
ORIGIN_JSON_NAME = "origin.json"
|
||||||
|
|
||||||
|
|
||||||
|
def _hash_dict(d: Dict[str, str]) -> str:
|
||||||
|
"""Return a stable sha224 of a dictionary."""
|
||||||
|
s = json.dumps(d, sort_keys=True, separators=(",", ":"), ensure_ascii=True)
|
||||||
|
return hashlib.sha224(s.encode("ascii")).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
class Cache:
|
||||||
|
"""An abstract class - provides cache directories for data from links
|
||||||
|
|
||||||
|
:param cache_dir: The root of the cache.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, cache_dir: str) -> None:
|
||||||
|
super().__init__()
|
||||||
|
assert not cache_dir or os.path.isabs(cache_dir)
|
||||||
|
self.cache_dir = cache_dir or None
|
||||||
|
|
||||||
|
def _get_cache_path_parts(self, link: Link) -> List[str]:
|
||||||
|
"""Get parts of part that must be os.path.joined with cache_dir"""
|
||||||
|
|
||||||
|
# We want to generate an url to use as our cache key, we don't want to
|
||||||
|
# just re-use the URL because it might have other items in the fragment
|
||||||
|
# and we don't care about those.
|
||||||
|
key_parts = {"url": link.url_without_fragment}
|
||||||
|
if link.hash_name is not None and link.hash is not None:
|
||||||
|
key_parts[link.hash_name] = link.hash
|
||||||
|
if link.subdirectory_fragment:
|
||||||
|
key_parts["subdirectory"] = link.subdirectory_fragment
|
||||||
|
|
||||||
|
# Include interpreter name, major and minor version in cache key
|
||||||
|
# to cope with ill-behaved sdists that build a different wheel
|
||||||
|
# depending on the python version their setup.py is being run on,
|
||||||
|
# and don't encode the difference in compatibility tags.
|
||||||
|
# https://github.com/pypa/pip/issues/7296
|
||||||
|
key_parts["interpreter_name"] = interpreter_name()
|
||||||
|
key_parts["interpreter_version"] = interpreter_version()
|
||||||
|
|
||||||
|
# Encode our key url with sha224, we'll use this because it has similar
|
||||||
|
# security properties to sha256, but with a shorter total output (and
|
||||||
|
# thus less secure). However the differences don't make a lot of
|
||||||
|
# difference for our use case here.
|
||||||
|
hashed = _hash_dict(key_parts)
|
||||||
|
|
||||||
|
# We want to nest the directories some to prevent having a ton of top
|
||||||
|
# level directories where we might run out of sub directories on some
|
||||||
|
# FS.
|
||||||
|
parts = [hashed[:2], hashed[2:4], hashed[4:6], hashed[6:]]
|
||||||
|
|
||||||
|
return parts
|
||||||
|
|
||||||
|
def _get_candidates(self, link: Link, canonical_package_name: str) -> List[Any]:
|
||||||
|
can_not_cache = not self.cache_dir or not canonical_package_name or not link
|
||||||
|
if can_not_cache:
|
||||||
|
return []
|
||||||
|
|
||||||
|
path = self.get_path_for_link(link)
|
||||||
|
if os.path.isdir(path):
|
||||||
|
return [(candidate, path) for candidate in os.listdir(path)]
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_path_for_link(self, link: Link) -> str:
|
||||||
|
"""Return a directory to store cached items in for link."""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def get(
|
||||||
|
self,
|
||||||
|
link: Link,
|
||||||
|
package_name: Optional[str],
|
||||||
|
supported_tags: List[Tag],
|
||||||
|
) -> Link:
|
||||||
|
"""Returns a link to a cached item if it exists, otherwise returns the
|
||||||
|
passed link.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleWheelCache(Cache):
|
||||||
|
"""A cache of wheels for future installs."""
|
||||||
|
|
||||||
|
def __init__(self, cache_dir: str) -> None:
|
||||||
|
super().__init__(cache_dir)
|
||||||
|
|
||||||
|
def get_path_for_link(self, link: Link) -> str:
|
||||||
|
"""Return a directory to store cached wheels for link
|
||||||
|
|
||||||
|
Because there are M wheels for any one sdist, we provide a directory
|
||||||
|
to cache them in, and then consult that directory when looking up
|
||||||
|
cache hits.
|
||||||
|
|
||||||
|
We only insert things into the cache if they have plausible version
|
||||||
|
numbers, so that we don't contaminate the cache with things that were
|
||||||
|
not unique. E.g. ./package might have dozens of installs done for it
|
||||||
|
and build a version of 0.0...and if we built and cached a wheel, we'd
|
||||||
|
end up using the same wheel even if the source has been edited.
|
||||||
|
|
||||||
|
:param link: The link of the sdist for which this will cache wheels.
|
||||||
|
"""
|
||||||
|
parts = self._get_cache_path_parts(link)
|
||||||
|
assert self.cache_dir
|
||||||
|
# Store wheels within the root cache_dir
|
||||||
|
return os.path.join(self.cache_dir, "wheels", *parts)
|
||||||
|
|
||||||
|
def get(
|
||||||
|
self,
|
||||||
|
link: Link,
|
||||||
|
package_name: Optional[str],
|
||||||
|
supported_tags: List[Tag],
|
||||||
|
) -> Link:
|
||||||
|
candidates = []
|
||||||
|
|
||||||
|
if not package_name:
|
||||||
|
return link
|
||||||
|
|
||||||
|
canonical_package_name = canonicalize_name(package_name)
|
||||||
|
for wheel_name, wheel_dir in self._get_candidates(link, canonical_package_name):
|
||||||
|
try:
|
||||||
|
wheel = Wheel(wheel_name)
|
||||||
|
except InvalidWheelFilename:
|
||||||
|
continue
|
||||||
|
if canonicalize_name(wheel.name) != canonical_package_name:
|
||||||
|
logger.debug(
|
||||||
|
"Ignoring cached wheel %s for %s as it "
|
||||||
|
"does not match the expected distribution name %s.",
|
||||||
|
wheel_name,
|
||||||
|
link,
|
||||||
|
package_name,
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
if not wheel.supported(supported_tags):
|
||||||
|
# Built for a different python/arch/etc
|
||||||
|
continue
|
||||||
|
candidates.append(
|
||||||
|
(
|
||||||
|
wheel.support_index_min(supported_tags),
|
||||||
|
wheel_name,
|
||||||
|
wheel_dir,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if not candidates:
|
||||||
|
return link
|
||||||
|
|
||||||
|
_, wheel_name, wheel_dir = min(candidates)
|
||||||
|
return Link(path_to_url(os.path.join(wheel_dir, wheel_name)))
|
||||||
|
|
||||||
|
|
||||||
|
class EphemWheelCache(SimpleWheelCache):
|
||||||
|
"""A SimpleWheelCache that creates it's own temporary cache directory"""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self._temp_dir = TempDirectory(
|
||||||
|
kind=tempdir_kinds.EPHEM_WHEEL_CACHE,
|
||||||
|
globally_managed=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
super().__init__(self._temp_dir.path)
|
||||||
|
|
||||||
|
|
||||||
|
class CacheEntry:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
link: Link,
|
||||||
|
persistent: bool,
|
||||||
|
):
|
||||||
|
self.link = link
|
||||||
|
self.persistent = persistent
|
||||||
|
self.origin: Optional[DirectUrl] = None
|
||||||
|
origin_direct_url_path = Path(self.link.file_path).parent / ORIGIN_JSON_NAME
|
||||||
|
if origin_direct_url_path.exists():
|
||||||
|
try:
|
||||||
|
self.origin = DirectUrl.from_json(
|
||||||
|
origin_direct_url_path.read_text(encoding="utf-8")
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(
|
||||||
|
"Ignoring invalid cache entry origin file %s for %s (%s)",
|
||||||
|
origin_direct_url_path,
|
||||||
|
link.filename,
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class WheelCache(Cache):
|
||||||
|
"""Wraps EphemWheelCache and SimpleWheelCache into a single Cache
|
||||||
|
|
||||||
|
This Cache allows for gracefully degradation, using the ephem wheel cache
|
||||||
|
when a certain link is not found in the simple wheel cache first.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, cache_dir: str) -> None:
|
||||||
|
super().__init__(cache_dir)
|
||||||
|
self._wheel_cache = SimpleWheelCache(cache_dir)
|
||||||
|
self._ephem_cache = EphemWheelCache()
|
||||||
|
|
||||||
|
def get_path_for_link(self, link: Link) -> str:
|
||||||
|
return self._wheel_cache.get_path_for_link(link)
|
||||||
|
|
||||||
|
def get_ephem_path_for_link(self, link: Link) -> str:
|
||||||
|
return self._ephem_cache.get_path_for_link(link)
|
||||||
|
|
||||||
|
def get(
|
||||||
|
self,
|
||||||
|
link: Link,
|
||||||
|
package_name: Optional[str],
|
||||||
|
supported_tags: List[Tag],
|
||||||
|
) -> Link:
|
||||||
|
cache_entry = self.get_cache_entry(link, package_name, supported_tags)
|
||||||
|
if cache_entry is None:
|
||||||
|
return link
|
||||||
|
return cache_entry.link
|
||||||
|
|
||||||
|
def get_cache_entry(
|
||||||
|
self,
|
||||||
|
link: Link,
|
||||||
|
package_name: Optional[str],
|
||||||
|
supported_tags: List[Tag],
|
||||||
|
) -> Optional[CacheEntry]:
|
||||||
|
"""Returns a CacheEntry with a link to a cached item if it exists or
|
||||||
|
None. The cache entry indicates if the item was found in the persistent
|
||||||
|
or ephemeral cache.
|
||||||
|
"""
|
||||||
|
retval = self._wheel_cache.get(
|
||||||
|
link=link,
|
||||||
|
package_name=package_name,
|
||||||
|
supported_tags=supported_tags,
|
||||||
|
)
|
||||||
|
if retval is not link:
|
||||||
|
return CacheEntry(retval, persistent=True)
|
||||||
|
|
||||||
|
retval = self._ephem_cache.get(
|
||||||
|
link=link,
|
||||||
|
package_name=package_name,
|
||||||
|
supported_tags=supported_tags,
|
||||||
|
)
|
||||||
|
if retval is not link:
|
||||||
|
return CacheEntry(retval, persistent=False)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def record_download_origin(cache_dir: str, download_info: DirectUrl) -> None:
|
||||||
|
origin_path = Path(cache_dir) / ORIGIN_JSON_NAME
|
||||||
|
if origin_path.exists():
|
||||||
|
try:
|
||||||
|
origin = DirectUrl.from_json(origin_path.read_text(encoding="utf-8"))
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(
|
||||||
|
"Could not read origin file %s in cache entry (%s). "
|
||||||
|
"Will attempt to overwrite it.",
|
||||||
|
origin_path,
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# TODO: use DirectUrl.equivalent when
|
||||||
|
# https://github.com/pypa/pip/pull/10564 is merged.
|
||||||
|
if origin.url != download_info.url:
|
||||||
|
logger.warning(
|
||||||
|
"Origin URL %s in cache entry %s does not match download URL "
|
||||||
|
"%s. This is likely a pip bug or a cache corruption issue. "
|
||||||
|
"Will overwrite it with the new value.",
|
||||||
|
origin.url,
|
||||||
|
cache_dir,
|
||||||
|
download_info.url,
|
||||||
|
)
|
||||||
|
origin_path.write_text(download_info.to_json(), encoding="utf-8")
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
"""Subpackage containing all of pip's command line interface related code
|
||||||
|
"""
|
||||||
|
|
||||||
|
# This file intentionally does not import submodules
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,172 @@
|
|||||||
|
"""Logic that powers autocompletion installed by ``pip completion``.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import optparse
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from itertools import chain
|
||||||
|
from typing import Any, Iterable, List, Optional
|
||||||
|
|
||||||
|
from pip._internal.cli.main_parser import create_main_parser
|
||||||
|
from pip._internal.commands import commands_dict, create_command
|
||||||
|
from pip._internal.metadata import get_default_environment
|
||||||
|
|
||||||
|
|
||||||
|
def autocomplete() -> None:
|
||||||
|
"""Entry Point for completion of main and subcommand options."""
|
||||||
|
# Don't complete if user hasn't sourced bash_completion file.
|
||||||
|
if "PIP_AUTO_COMPLETE" not in os.environ:
|
||||||
|
return
|
||||||
|
cwords = os.environ["COMP_WORDS"].split()[1:]
|
||||||
|
cword = int(os.environ["COMP_CWORD"])
|
||||||
|
try:
|
||||||
|
current = cwords[cword - 1]
|
||||||
|
except IndexError:
|
||||||
|
current = ""
|
||||||
|
|
||||||
|
parser = create_main_parser()
|
||||||
|
subcommands = list(commands_dict)
|
||||||
|
options = []
|
||||||
|
|
||||||
|
# subcommand
|
||||||
|
subcommand_name: Optional[str] = None
|
||||||
|
for word in cwords:
|
||||||
|
if word in subcommands:
|
||||||
|
subcommand_name = word
|
||||||
|
break
|
||||||
|
# subcommand options
|
||||||
|
if subcommand_name is not None:
|
||||||
|
# special case: 'help' subcommand has no options
|
||||||
|
if subcommand_name == "help":
|
||||||
|
sys.exit(1)
|
||||||
|
# special case: list locally installed dists for show and uninstall
|
||||||
|
should_list_installed = not current.startswith("-") and subcommand_name in [
|
||||||
|
"show",
|
||||||
|
"uninstall",
|
||||||
|
]
|
||||||
|
if should_list_installed:
|
||||||
|
env = get_default_environment()
|
||||||
|
lc = current.lower()
|
||||||
|
installed = [
|
||||||
|
dist.canonical_name
|
||||||
|
for dist in env.iter_installed_distributions(local_only=True)
|
||||||
|
if dist.canonical_name.startswith(lc)
|
||||||
|
and dist.canonical_name not in cwords[1:]
|
||||||
|
]
|
||||||
|
# if there are no dists installed, fall back to option completion
|
||||||
|
if installed:
|
||||||
|
for dist in installed:
|
||||||
|
print(dist)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
should_list_installables = (
|
||||||
|
not current.startswith("-") and subcommand_name == "install"
|
||||||
|
)
|
||||||
|
if should_list_installables:
|
||||||
|
for path in auto_complete_paths(current, "path"):
|
||||||
|
print(path)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
subcommand = create_command(subcommand_name)
|
||||||
|
|
||||||
|
for opt in subcommand.parser.option_list_all:
|
||||||
|
if opt.help != optparse.SUPPRESS_HELP:
|
||||||
|
options += [
|
||||||
|
(opt_str, opt.nargs) for opt_str in opt._long_opts + opt._short_opts
|
||||||
|
]
|
||||||
|
|
||||||
|
# filter out previously specified options from available options
|
||||||
|
prev_opts = [x.split("=")[0] for x in cwords[1 : cword - 1]]
|
||||||
|
options = [(x, v) for (x, v) in options if x not in prev_opts]
|
||||||
|
# filter options by current input
|
||||||
|
options = [(k, v) for k, v in options if k.startswith(current)]
|
||||||
|
# get completion type given cwords and available subcommand options
|
||||||
|
completion_type = get_path_completion_type(
|
||||||
|
cwords,
|
||||||
|
cword,
|
||||||
|
subcommand.parser.option_list_all,
|
||||||
|
)
|
||||||
|
# get completion files and directories if ``completion_type`` is
|
||||||
|
# ``<file>``, ``<dir>`` or ``<path>``
|
||||||
|
if completion_type:
|
||||||
|
paths = auto_complete_paths(current, completion_type)
|
||||||
|
options = [(path, 0) for path in paths]
|
||||||
|
for option in options:
|
||||||
|
opt_label = option[0]
|
||||||
|
# append '=' to options which require args
|
||||||
|
if option[1] and option[0][:2] == "--":
|
||||||
|
opt_label += "="
|
||||||
|
print(opt_label)
|
||||||
|
else:
|
||||||
|
# show main parser options only when necessary
|
||||||
|
|
||||||
|
opts = [i.option_list for i in parser.option_groups]
|
||||||
|
opts.append(parser.option_list)
|
||||||
|
flattened_opts = chain.from_iterable(opts)
|
||||||
|
if current.startswith("-"):
|
||||||
|
for opt in flattened_opts:
|
||||||
|
if opt.help != optparse.SUPPRESS_HELP:
|
||||||
|
subcommands += opt._long_opts + opt._short_opts
|
||||||
|
else:
|
||||||
|
# get completion type given cwords and all available options
|
||||||
|
completion_type = get_path_completion_type(cwords, cword, flattened_opts)
|
||||||
|
if completion_type:
|
||||||
|
subcommands = list(auto_complete_paths(current, completion_type))
|
||||||
|
|
||||||
|
print(" ".join([x for x in subcommands if x.startswith(current)]))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def get_path_completion_type(
|
||||||
|
cwords: List[str], cword: int, opts: Iterable[Any]
|
||||||
|
) -> Optional[str]:
|
||||||
|
"""Get the type of path completion (``file``, ``dir``, ``path`` or None)
|
||||||
|
|
||||||
|
:param cwords: same as the environmental variable ``COMP_WORDS``
|
||||||
|
:param cword: same as the environmental variable ``COMP_CWORD``
|
||||||
|
:param opts: The available options to check
|
||||||
|
:return: path completion type (``file``, ``dir``, ``path`` or None)
|
||||||
|
"""
|
||||||
|
if cword < 2 or not cwords[cword - 2].startswith("-"):
|
||||||
|
return None
|
||||||
|
for opt in opts:
|
||||||
|
if opt.help == optparse.SUPPRESS_HELP:
|
||||||
|
continue
|
||||||
|
for o in str(opt).split("/"):
|
||||||
|
if cwords[cword - 2].split("=")[0] == o:
|
||||||
|
if not opt.metavar or any(
|
||||||
|
x in ("path", "file", "dir") for x in opt.metavar.split("/")
|
||||||
|
):
|
||||||
|
return opt.metavar
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def auto_complete_paths(current: str, completion_type: str) -> Iterable[str]:
|
||||||
|
"""If ``completion_type`` is ``file`` or ``path``, list all regular files
|
||||||
|
and directories starting with ``current``; otherwise only list directories
|
||||||
|
starting with ``current``.
|
||||||
|
|
||||||
|
:param current: The word to be completed
|
||||||
|
:param completion_type: path completion type(``file``, ``path`` or ``dir``)
|
||||||
|
:return: A generator of regular files and/or directories
|
||||||
|
"""
|
||||||
|
directory, filename = os.path.split(current)
|
||||||
|
current_path = os.path.abspath(directory)
|
||||||
|
# Don't complete paths if they can't be accessed
|
||||||
|
if not os.access(current_path, os.R_OK):
|
||||||
|
return
|
||||||
|
filename = os.path.normcase(filename)
|
||||||
|
# list all files that start with ``filename``
|
||||||
|
file_list = (
|
||||||
|
x for x in os.listdir(current_path) if os.path.normcase(x).startswith(filename)
|
||||||
|
)
|
||||||
|
for f in file_list:
|
||||||
|
opt = os.path.join(current_path, f)
|
||||||
|
comp_file = os.path.normcase(os.path.join(directory, f))
|
||||||
|
# complete regular files when there is not ``<dir>`` after option
|
||||||
|
# complete directories when there is ``<file>``, ``<path>`` or
|
||||||
|
# ``<dir>``after option
|
||||||
|
if completion_type != "dir" and os.path.isfile(opt):
|
||||||
|
yield comp_file
|
||||||
|
elif os.path.isdir(opt):
|
||||||
|
yield os.path.join(comp_file, "")
|
||||||
@@ -0,0 +1,236 @@
|
|||||||
|
"""Base Command class, and related routines"""
|
||||||
|
|
||||||
|
import functools
|
||||||
|
import logging
|
||||||
|
import logging.config
|
||||||
|
import optparse
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
from optparse import Values
|
||||||
|
from typing import Any, Callable, List, Optional, Tuple
|
||||||
|
|
||||||
|
from pip._vendor.rich import traceback as rich_traceback
|
||||||
|
|
||||||
|
from pip._internal.cli import cmdoptions
|
||||||
|
from pip._internal.cli.command_context import CommandContextMixIn
|
||||||
|
from pip._internal.cli.parser import ConfigOptionParser, UpdatingDefaultsHelpFormatter
|
||||||
|
from pip._internal.cli.status_codes import (
|
||||||
|
ERROR,
|
||||||
|
PREVIOUS_BUILD_DIR_ERROR,
|
||||||
|
UNKNOWN_ERROR,
|
||||||
|
VIRTUALENV_NOT_FOUND,
|
||||||
|
)
|
||||||
|
from pip._internal.exceptions import (
|
||||||
|
BadCommand,
|
||||||
|
CommandError,
|
||||||
|
DiagnosticPipError,
|
||||||
|
InstallationError,
|
||||||
|
NetworkConnectionError,
|
||||||
|
PreviousBuildDirError,
|
||||||
|
UninstallationError,
|
||||||
|
)
|
||||||
|
from pip._internal.utils.filesystem import check_path_owner
|
||||||
|
from pip._internal.utils.logging import BrokenStdoutLoggingError, setup_logging
|
||||||
|
from pip._internal.utils.misc import get_prog, normalize_path
|
||||||
|
from pip._internal.utils.temp_dir import TempDirectoryTypeRegistry as TempDirRegistry
|
||||||
|
from pip._internal.utils.temp_dir import global_tempdir_manager, tempdir_registry
|
||||||
|
from pip._internal.utils.virtualenv import running_under_virtualenv
|
||||||
|
|
||||||
|
__all__ = ["Command"]
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Command(CommandContextMixIn):
|
||||||
|
usage: str = ""
|
||||||
|
ignore_require_venv: bool = False
|
||||||
|
|
||||||
|
def __init__(self, name: str, summary: str, isolated: bool = False) -> None:
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.name = name
|
||||||
|
self.summary = summary
|
||||||
|
self.parser = ConfigOptionParser(
|
||||||
|
usage=self.usage,
|
||||||
|
prog=f"{get_prog()} {name}",
|
||||||
|
formatter=UpdatingDefaultsHelpFormatter(),
|
||||||
|
add_help_option=False,
|
||||||
|
name=name,
|
||||||
|
description=self.__doc__,
|
||||||
|
isolated=isolated,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.tempdir_registry: Optional[TempDirRegistry] = None
|
||||||
|
|
||||||
|
# Commands should add options to this option group
|
||||||
|
optgroup_name = f"{self.name.capitalize()} Options"
|
||||||
|
self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name)
|
||||||
|
|
||||||
|
# Add the general options
|
||||||
|
gen_opts = cmdoptions.make_option_group(
|
||||||
|
cmdoptions.general_group,
|
||||||
|
self.parser,
|
||||||
|
)
|
||||||
|
self.parser.add_option_group(gen_opts)
|
||||||
|
|
||||||
|
self.add_options()
|
||||||
|
|
||||||
|
def add_options(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def handle_pip_version_check(self, options: Values) -> None:
|
||||||
|
"""
|
||||||
|
This is a no-op so that commands by default do not do the pip version
|
||||||
|
check.
|
||||||
|
"""
|
||||||
|
# Make sure we do the pip version check if the index_group options
|
||||||
|
# are present.
|
||||||
|
assert not hasattr(options, "no_index")
|
||||||
|
|
||||||
|
def run(self, options: Values, args: List[str]) -> int:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def parse_args(self, args: List[str]) -> Tuple[Values, List[str]]:
|
||||||
|
# factored out for testability
|
||||||
|
return self.parser.parse_args(args)
|
||||||
|
|
||||||
|
def main(self, args: List[str]) -> int:
|
||||||
|
try:
|
||||||
|
with self.main_context():
|
||||||
|
return self._main(args)
|
||||||
|
finally:
|
||||||
|
logging.shutdown()
|
||||||
|
|
||||||
|
def _main(self, args: List[str]) -> int:
|
||||||
|
# We must initialize this before the tempdir manager, otherwise the
|
||||||
|
# configuration would not be accessible by the time we clean up the
|
||||||
|
# tempdir manager.
|
||||||
|
self.tempdir_registry = self.enter_context(tempdir_registry())
|
||||||
|
# Intentionally set as early as possible so globally-managed temporary
|
||||||
|
# directories are available to the rest of the code.
|
||||||
|
self.enter_context(global_tempdir_manager())
|
||||||
|
|
||||||
|
options, args = self.parse_args(args)
|
||||||
|
|
||||||
|
# Set verbosity so that it can be used elsewhere.
|
||||||
|
self.verbosity = options.verbose - options.quiet
|
||||||
|
|
||||||
|
level_number = setup_logging(
|
||||||
|
verbosity=self.verbosity,
|
||||||
|
no_color=options.no_color,
|
||||||
|
user_log_file=options.log,
|
||||||
|
)
|
||||||
|
|
||||||
|
always_enabled_features = set(options.features_enabled) & set(
|
||||||
|
cmdoptions.ALWAYS_ENABLED_FEATURES
|
||||||
|
)
|
||||||
|
if always_enabled_features:
|
||||||
|
logger.warning(
|
||||||
|
"The following features are always enabled: %s. ",
|
||||||
|
", ".join(sorted(always_enabled_features)),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Make sure that the --python argument isn't specified after the
|
||||||
|
# subcommand. We can tell, because if --python was specified,
|
||||||
|
# we should only reach this point if we're running in the created
|
||||||
|
# subprocess, which has the _PIP_RUNNING_IN_SUBPROCESS environment
|
||||||
|
# variable set.
|
||||||
|
if options.python and "_PIP_RUNNING_IN_SUBPROCESS" not in os.environ:
|
||||||
|
logger.critical(
|
||||||
|
"The --python option must be placed before the pip subcommand name"
|
||||||
|
)
|
||||||
|
sys.exit(ERROR)
|
||||||
|
|
||||||
|
# TODO: Try to get these passing down from the command?
|
||||||
|
# without resorting to os.environ to hold these.
|
||||||
|
# This also affects isolated builds and it should.
|
||||||
|
|
||||||
|
if options.no_input:
|
||||||
|
os.environ["PIP_NO_INPUT"] = "1"
|
||||||
|
|
||||||
|
if options.exists_action:
|
||||||
|
os.environ["PIP_EXISTS_ACTION"] = " ".join(options.exists_action)
|
||||||
|
|
||||||
|
if options.require_venv and not self.ignore_require_venv:
|
||||||
|
# If a venv is required check if it can really be found
|
||||||
|
if not running_under_virtualenv():
|
||||||
|
logger.critical("Could not find an activated virtualenv (required).")
|
||||||
|
sys.exit(VIRTUALENV_NOT_FOUND)
|
||||||
|
|
||||||
|
if options.cache_dir:
|
||||||
|
options.cache_dir = normalize_path(options.cache_dir)
|
||||||
|
if not check_path_owner(options.cache_dir):
|
||||||
|
logger.warning(
|
||||||
|
"The directory '%s' or its parent directory is not owned "
|
||||||
|
"or is not writable by the current user. The cache "
|
||||||
|
"has been disabled. Check the permissions and owner of "
|
||||||
|
"that directory. If executing pip with sudo, you should "
|
||||||
|
"use sudo's -H flag.",
|
||||||
|
options.cache_dir,
|
||||||
|
)
|
||||||
|
options.cache_dir = None
|
||||||
|
|
||||||
|
def intercepts_unhandled_exc(
|
||||||
|
run_func: Callable[..., int]
|
||||||
|
) -> Callable[..., int]:
|
||||||
|
@functools.wraps(run_func)
|
||||||
|
def exc_logging_wrapper(*args: Any) -> int:
|
||||||
|
try:
|
||||||
|
status = run_func(*args)
|
||||||
|
assert isinstance(status, int)
|
||||||
|
return status
|
||||||
|
except DiagnosticPipError as exc:
|
||||||
|
logger.error("%s", exc, extra={"rich": True})
|
||||||
|
logger.debug("Exception information:", exc_info=True)
|
||||||
|
|
||||||
|
return ERROR
|
||||||
|
except PreviousBuildDirError as exc:
|
||||||
|
logger.critical(str(exc))
|
||||||
|
logger.debug("Exception information:", exc_info=True)
|
||||||
|
|
||||||
|
return PREVIOUS_BUILD_DIR_ERROR
|
||||||
|
except (
|
||||||
|
InstallationError,
|
||||||
|
UninstallationError,
|
||||||
|
BadCommand,
|
||||||
|
NetworkConnectionError,
|
||||||
|
) as exc:
|
||||||
|
logger.critical(str(exc))
|
||||||
|
logger.debug("Exception information:", exc_info=True)
|
||||||
|
|
||||||
|
return ERROR
|
||||||
|
except CommandError as exc:
|
||||||
|
logger.critical("%s", exc)
|
||||||
|
logger.debug("Exception information:", exc_info=True)
|
||||||
|
|
||||||
|
return ERROR
|
||||||
|
except BrokenStdoutLoggingError:
|
||||||
|
# Bypass our logger and write any remaining messages to
|
||||||
|
# stderr because stdout no longer works.
|
||||||
|
print("ERROR: Pipe to stdout was broken", file=sys.stderr)
|
||||||
|
if level_number <= logging.DEBUG:
|
||||||
|
traceback.print_exc(file=sys.stderr)
|
||||||
|
|
||||||
|
return ERROR
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logger.critical("Operation cancelled by user")
|
||||||
|
logger.debug("Exception information:", exc_info=True)
|
||||||
|
|
||||||
|
return ERROR
|
||||||
|
except BaseException:
|
||||||
|
logger.critical("Exception:", exc_info=True)
|
||||||
|
|
||||||
|
return UNKNOWN_ERROR
|
||||||
|
|
||||||
|
return exc_logging_wrapper
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not options.debug_mode:
|
||||||
|
run = intercepts_unhandled_exc(self.run)
|
||||||
|
else:
|
||||||
|
run = self.run
|
||||||
|
rich_traceback.install(show_locals=True)
|
||||||
|
return run(options, args)
|
||||||
|
finally:
|
||||||
|
self.handle_pip_version_check(options)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user