12 Commits

Author SHA1 Message Date
42d3e4ddc2 Move to Fix Plugin Load Issue 2025-03-05 20:29:32 +08:00
b0e71cf4f7 Fix 2025-03-04 20:48:27 +08:00
1a5d161b5a Update README.md 2025-03-03 22:08:04 +08:00
c4d5a0fc32 Fix: Powered by Project Fragrance 2025-03-03 22:05:34 +08:00
83fabcd941 New: Upload Score(Not Test Yet) 2025-03-03 22:02:07 +08:00
bb9f931bb4 Add: Separate Plugin 2025-03-03 20:48:33 +08:00
f0dd92c3b9 Update README.md 2025-03-02 12:59:53 +08:00
90c84734ce Update README.md 2025-03-02 12:47:36 +08:00
9cd35688e5 Update README.md 2025-03-02 11:49:40 +08:00
5d6234d698 Update README.md 2025-03-02 11:42:36 +08:00
22a2a0044d Update README.md 2025-03-02 11:40:44 +08:00
5ef6fedc9b Update README.md 2025-03-02 11:39:38 +08:00
4193 changed files with 882404 additions and 6 deletions

View File

@@ -0,0 +1,586 @@
from nonebot import on_command, on_regex, on_startswith
from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message , MessageSegment, bot
from nonebot.typing import T_State
from nonebot.params import EventMessage, CommandArg, Arg, ArgPlainText
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 nonebot_plugin_maimai_helper.leak.music 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)
upload_score = on_command('amusic',aliases={'传分'}, priority=20, rule=check_time)
@upload_score.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:
music_data = str(message).strip()
music_list = music_data.split()
if len(music_list) < 9:
await seeme.send("指令格式出错啦!请按照以下格式发送(括号中内容无需发送)\namusic 417 0 11 1005245 1 0 12 13\n指令解释amusic [曲目ID] [乐曲等级] [游玩次数] [Acc] [ComboStatus] [SyncStatus] [DXScore] [Rank]\n乐曲等级(0=Basic,1=Advanced,2=Expert,3=Master,4=Re:Master)\nComboStatus(0=无,1=FC,2=FC+,3=AP,4=AP+)\nSyncStatus(0=无,1=FS,2=FS+,3=FDX,4=FDX+,5=SYNCPLAY)\nRank(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+)\n!Caution!DX分数不要超过该乐曲总值若不确定请自行查询后再使用")
command = music_list[0] # 命令
music_id = int(music_list[1]) # 第一个数字
music_level = int(music_list[2]) # 第二个数字
music_count = int(music_list[3]) # 第三个数字
music_acc = int(music_list[4]) # 第四个数字
music_combo = int(music_list[5]) # 第五个数字
music_sync = int(music_list[6]) # 第六个数字
music_dx = int(music_list[7]) # 第七个数字
music_rank = int(music_list[8]) # 第八个数字
music_return = music(music_id,music_level,music_count,music_acc,music_combo,music_sync,music_dx,music_rank,user_id)
if music_return['is_success']:
await upload_score.send("上传成功!")
else:
await upload_score.send("上传失败了...请找机修吧...")
'''
@upload_score.got("music_rank", prompt="请输入乐曲分数排名")
async def handle_func(event: GroupMessageEvent,music_id: Message = Arg()):
user_qq = event.get_user_id()
if is_userid_exist(user_qq):
user_id = get_userid(user_qq)
if user_id != -1:
music_data = ({
"musicId": music_id,
"level": music_level,
"playCount": music_count,
"achievement": music_acc,
"comboStatus": music_combo,
"syncStatus": music_sync,
"deluxscoreMax": music_dx,
"scoreRank": music_rank,
"extNum1": 0
})
music_finish = music(music_data,user_id)
'''
@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):

View 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": "niconicoVOCALOID™",
"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
}
]

View 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"
}
}

File diff suppressed because it is too large Load Diff

View 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"
}
}

View 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"
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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"
}
}

View 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"
}
}

File diff suppressed because it is too large Load Diff

View 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("无法转换为灰度图")

View 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

View 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 和路径是否正确。")

View 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("无法识别二维码")

View 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

View 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()
'''

View 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()

View 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())))

View 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())))

View 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())

View File

@@ -0,0 +1,677 @@
import json
import pytz
import time
import random
from nonebot_plugin_maimai_helper.leak.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
regionId = 1
regionName = "北京"
placeId = 1403
placeName = "插电师电玩北京西单大悦城店"
clientId = "A63E01C2805"
from nonebot_plugin_maimai_helper.leak.login import login
from nonebot_plugin_maimai_helper.leak.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_id,music_level,music_count,music_acc,music_combo,music_sync,music_dx,music_rank,userId):
result_success = {"is_success": False}
# music = music_data
musicId = music_id
level = music_level
playCount = music_count
achievement = music_acc
comboStatus = music_combo
syncStatus = music_sync
deluxscoreMax = music_dx
scoreRank = music_rank
extNum1 = 0
print(timestamp)
# UserLogin
login_result = json.loads(login(timestamp,userId))
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": ""
}
})
logout1 = logout(timestamp,userId)
print(logout1)
# userall_result = json.loads(sdgb_api(data, "UpsertUserAllApi", userId))
result_success["is_success"] = True
return result_success
# 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())

View 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

View 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())

View 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))

View 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)

View 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"

View 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))

View 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: "))))

File diff suppressed because it is too large Load Diff

View 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): "))))

View 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())

View 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)

View 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

View 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

Binary file not shown.

View 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)

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -0,0 +1,5 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.42.0)
Root-Is-Purelib: true
Tag: py3-none-any

View File

@@ -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

View File

@@ -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)

View File

@@ -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())

View File

@@ -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)

View File

@@ -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)

View File

@@ -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()

View File

@@ -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")

View File

@@ -0,0 +1,4 @@
"""Subpackage containing all of pip's command line interface related code
"""
# This file intentionally does not import submodules

View File

@@ -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, "")

Some files were not shown because too many files have changed in this diff Show More