Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 069e9aeae9 | |||
| 07e816bc83 | |||
| d2b4e01d72 | |||
| 1fba026324 | |||
| b1b9c7fc10 | |||
| 9a94fe8b4e | |||
| a3c8426786 | |||
| 17c419dca0 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
|||||||
**/__pycache__
|
**/__pycache__
|
||||||
**/settings.py
|
**/settings.py
|
||||||
**/.DS_Store
|
**/.DS_Store
|
||||||
|
|
||||||
|
*.egg-info
|
||||||
|
|||||||
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3.14
|
||||||
18
sdgb/GetUserPreviewApi.py → action/GetUserPreviewApi.py
Executable file → Normal file
18
sdgb/GetUserPreviewApi.py → action/GetUserPreviewApi.py
Executable file → Normal file
@@ -1,23 +1,29 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from chime import *
|
import httpx
|
||||||
|
|
||||||
from sdgb import MaimaiClient
|
from sdgb import MaimaiClient
|
||||||
from settings import *
|
from sdgb.chime import qr_api
|
||||||
|
from sdgb.settings import clientId, qrCode
|
||||||
|
|
||||||
maimai = MaimaiClient()
|
maimai = MaimaiClient()
|
||||||
|
|
||||||
userId = qr_api(qrCode)['userID']
|
qrResp = qr_api(qrCode)
|
||||||
token = qr_api(qrCode)['token']
|
userId = qrResp["userID"]
|
||||||
|
token = qrResp["token"]
|
||||||
|
|
||||||
async def run_workflow(maimai):
|
|
||||||
|
async def run_workflow(maimai: MaimaiClient):
|
||||||
async with httpx.AsyncClient(verify=False) as client:
|
async with httpx.AsyncClient(verify=False) as client:
|
||||||
data = {
|
data = {
|
||||||
"userId": userId,
|
"userId": userId,
|
||||||
"segaIdAuthKey": "",
|
"segaIdAuthKey": "",
|
||||||
"token": token,
|
"token": token,
|
||||||
"clientId": clientId
|
"clientId": clientId,
|
||||||
}
|
}
|
||||||
result = await maimai.call_api(client, "GetUserPreviewApi", data, userId)
|
result = await maimai.call_api(client, "GetUserPreviewApi", data, userId)
|
||||||
|
print(result)
|
||||||
|
|
||||||
|
|
||||||
# 执行入口
|
# 执行入口
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
@@ -1,46 +1,45 @@
|
|||||||
|
from urllib.parse import unquote
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from Crypto.Cipher import AES
|
from Crypto.Cipher import AES
|
||||||
from Crypto.Util.Padding import pad
|
from Crypto.Util.Padding import pad
|
||||||
from urllib.parse import unquote
|
|
||||||
|
|
||||||
def enc(key, iv, data):
|
def enc(key, iv, data):
|
||||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||||
encrypted = cipher.encrypt(data)
|
encrypted = cipher.encrypt(data)
|
||||||
return encrypted
|
return encrypted
|
||||||
|
|
||||||
|
|
||||||
def dec(key, iv, data):
|
def dec(key, iv, data):
|
||||||
de_cipher = AES.new(key, AES.MODE_CBC, iv)
|
de_cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||||
decrypted = de_cipher.decrypt(data)
|
decrypted = de_cipher.decrypt(data)
|
||||||
return decrypted
|
return decrypted
|
||||||
|
|
||||||
|
|
||||||
def hello():
|
def hello():
|
||||||
key = bytes([47, 63, 106, 111, 43, 34, 76, 38, 92, 67, 114, 57, 40, 61, 107, 71])
|
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 ])
|
# key = bytes([ 45, 97, 53, 55, 85, 88, 52, 121, 57, 47, 104, 40, 73, 109, 65, 81 ])
|
||||||
iv = bytes.fromhex('00000000000000000000000000000000')
|
iv = bytes.fromhex("00000000000000000000000000000000")
|
||||||
ua = 'SDGB;Windows/Lite'
|
ua = "SDGB;Windows/Lite"
|
||||||
# ua = 'SDHJ;Windows/Lite'
|
# ua = 'SDHJ;Windows/Lite'
|
||||||
|
|
||||||
# 构建 payload
|
# 构建 payload
|
||||||
content = bytes([0] * 16) + b'title_id=SDGB&title_ver=1.52&client_id=A63E01E6149'
|
content = bytes([0] * 16) + b"title_id=SDGB&title_ver=1.52&client_id=A63E01E6149"
|
||||||
print(f"Content: {content}")
|
print(f"Content: {content}")
|
||||||
|
|
||||||
header = bytes.fromhex('00000000000000000000000000000000')
|
header = bytes.fromhex("00000000000000000000000000000000")
|
||||||
bytes_data = pad(header + content, 16)
|
bytes_data = pad(header + content, 16)
|
||||||
encrypted = enc(key, iv, bytes_data)
|
encrypted = enc(key, iv, bytes_data)
|
||||||
|
|
||||||
# --- HTTPX 修改部分 ---
|
# --- HTTPX 修改部分 ---
|
||||||
headers = {
|
headers = {"User-Agent": ua, "Pragma": "DFI"}
|
||||||
'User-Agent': ua,
|
|
||||||
'Pragma': 'DFI'
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 发送 POST 请求
|
# 发送 POST 请求
|
||||||
# urllib3 的 body 参数在 httpx 中对应 content (用于二进制数据)
|
# urllib3 的 body 参数在 httpx 中对应 content (用于二进制数据)
|
||||||
r = httpx.post(
|
r = httpx.post(
|
||||||
'http://at.sys-allnet.cn/net/initialize',
|
"https://at.sys-allnet.cn/net/initialize", content=encrypted, headers=headers
|
||||||
content=encrypted,
|
|
||||||
headers=headers
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# 检查响应状态码 (可选,但在 httpx 中推荐)
|
# 检查响应状态码 (可选,但在 httpx 中推荐)
|
||||||
@@ -54,7 +53,7 @@ def hello():
|
|||||||
if len(resp_data) >= 16:
|
if len(resp_data) >= 16:
|
||||||
decrypted = dec(key, resp_data[:16], resp_data)
|
decrypted = dec(key, resp_data[:16], resp_data)
|
||||||
decrypted_bytes = decrypted[16:]
|
decrypted_bytes = decrypted[16:]
|
||||||
decrypted_str = unquote(decrypted_bytes.decode('UTF-8'), 'utf-8')
|
decrypted_str = unquote(decrypted_bytes.decode("UTF-8"), "utf-8")
|
||||||
print(f"Decrypted: {decrypted_str}")
|
print(f"Decrypted: {decrypted_str}")
|
||||||
else:
|
else:
|
||||||
print("Response data too short.")
|
print("Response data too short.")
|
||||||
@@ -62,5 +61,6 @@ def hello():
|
|||||||
except httpx.RequestError as e:
|
except httpx.RequestError as e:
|
||||||
print(f"An error occurred while requesting: {e}")
|
print(f"An error occurred while requesting: {e}")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
if __name__ == "__main__":
|
||||||
hello()
|
hello()
|
||||||
154
action/UnlockMusic.py
Normal file
154
action/UnlockMusic.py
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
import json
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
|
||||||
|
from sdgb import MaimaiClient
|
||||||
|
from sdgb.settings import userId, musicData
|
||||||
|
from sdgb.payload import (
|
||||||
|
requestData_UserLogin,
|
||||||
|
requestData_UserLogout,
|
||||||
|
requestData_UserPreview,
|
||||||
|
requestData_UserData,
|
||||||
|
UserAll_payload,
|
||||||
|
)
|
||||||
|
|
||||||
|
maimai = MaimaiClient()
|
||||||
|
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def music_user_all_patcher(
|
||||||
|
musicId: int,
|
||||||
|
unlock_music: bool = True,
|
||||||
|
unlock_master: bool = False,
|
||||||
|
unlock_remaster: bool = False,
|
||||||
|
) -> Callable[[dict], None]:
|
||||||
|
userItemList = []
|
||||||
|
|
||||||
|
if unlock_music:
|
||||||
|
userItemList.append(
|
||||||
|
0,
|
||||||
|
{
|
||||||
|
"itemKind": 5, # MUSIC
|
||||||
|
"itemId": musicId,
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if unlock_master:
|
||||||
|
userItemList.append(
|
||||||
|
0,
|
||||||
|
{
|
||||||
|
"itemKind": 6,
|
||||||
|
"itemId": musicId, # MASTER
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if unlock_remaster:
|
||||||
|
userItemList.append(
|
||||||
|
{
|
||||||
|
"itemKind": 7,
|
||||||
|
"itemId": musicId, # RE: MASTER
|
||||||
|
"stock": 1,
|
||||||
|
"isValid": True,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def merge(d: dict):
|
||||||
|
d.update(
|
||||||
|
{
|
||||||
|
"userMusicDetailList": [musicData],
|
||||||
|
"isNewMusicDetailList": "1",
|
||||||
|
"userItemList": userItemList,
|
||||||
|
"isNewItemList": len(userItemList) * "1",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return merge
|
||||||
|
|
||||||
|
|
||||||
|
async def run_workflow(
|
||||||
|
self: MaimaiClient,
|
||||||
|
user_all_patcher: Callable[[dict], None],
|
||||||
|
):
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(verify=False) as client:
|
||||||
|
# Preview 探测
|
||||||
|
|
||||||
|
PreviewResponse = json.loads(
|
||||||
|
await self.call_api(
|
||||||
|
client, "GetUserPreviewApi", requestData_UserPreview, userId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if PreviewResponse["isLogin"]:
|
||||||
|
logger.error("已在他处登录。")
|
||||||
|
return
|
||||||
|
|
||||||
|
# UserLogin
|
||||||
|
|
||||||
|
LoginResponse = json.loads(
|
||||||
|
await self.call_api(client, "UserLoginApi", requestData_UserLogin, userId)
|
||||||
|
)
|
||||||
|
if LoginResponse["returnCode"] != 1:
|
||||||
|
logger.error("login failed.")
|
||||||
|
return
|
||||||
|
|
||||||
|
loginId = LoginResponse["loginId"]
|
||||||
|
loginDate = LoginResponse["lastLoginDate"]
|
||||||
|
|
||||||
|
# UserData 等
|
||||||
|
|
||||||
|
tasks = [
|
||||||
|
self.call_api(client, "GetUserDataApi", requestData_UserData, userId),
|
||||||
|
self.call_api(client, "GetUserExtendApi", requestData_UserData, userId),
|
||||||
|
self.call_api(client, "GetUserOptionApi", requestData_UserData, userId),
|
||||||
|
self.call_api(client, "GetUserRatingApi", requestData_UserData, userId),
|
||||||
|
self.call_api(client, "GetUserChargeApi", requestData_UserData, userId),
|
||||||
|
self.call_api(client, "GetUserActivityApi", requestData_UserData, userId),
|
||||||
|
self.call_api(
|
||||||
|
client, "GetUserMissionDataApi", requestData_UserData, userId
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
GeneralUserInfo = await asyncio.gather(*tasks)
|
||||||
|
await asyncio.sleep(60) # 模拟游戏时间
|
||||||
|
|
||||||
|
# UserAll
|
||||||
|
|
||||||
|
requestData_UserAll = UserAll_payload(
|
||||||
|
loginId, loginDate, musicData, GeneralUserInfo
|
||||||
|
)
|
||||||
|
|
||||||
|
user_all_patcher(requestData_UserAll)
|
||||||
|
|
||||||
|
await self.call_api(client, "UpsertUserAllApi", requestData_UserAll, userId)
|
||||||
|
|
||||||
|
# UserLogout
|
||||||
|
|
||||||
|
await self.call_api(client, "UserLogoutApi", requestData_UserLogout, userId)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
patcher = music_user_all_patcher(
|
||||||
|
musicId=834,
|
||||||
|
unlock_music=False,
|
||||||
|
# unlock_master=True,
|
||||||
|
unlock_remaster=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
asyncio.run(
|
||||||
|
run_workflow(
|
||||||
|
maimai,
|
||||||
|
user_all_patcher=patcher,
|
||||||
|
)
|
||||||
|
)
|
||||||
@@ -1,43 +1,53 @@
|
|||||||
import json
|
import json
|
||||||
import asyncio
|
import asyncio
|
||||||
import httpx
|
|
||||||
import time
|
|
||||||
import logging
|
import logging
|
||||||
from sdgb import MaimaiClient
|
|
||||||
|
|
||||||
from settings import userId, musicData
|
import httpx
|
||||||
from chime import *
|
|
||||||
from payload import *
|
from sdgb import MaimaiClient
|
||||||
|
from sdgb.settings import userId, musicData
|
||||||
|
from sdgb.payload import (
|
||||||
|
requestData_UserLogin,
|
||||||
|
requestData_UserLogout,
|
||||||
|
requestData_UserPreview,
|
||||||
|
requestData_UserData,
|
||||||
|
UserAll_payload,
|
||||||
|
)
|
||||||
|
|
||||||
maimai = MaimaiClient()
|
maimai = MaimaiClient()
|
||||||
|
|
||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO,
|
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
|
||||||
format='%(asctime)s - %(levelname)s - %(message)s'
|
|
||||||
)
|
)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
async def run_workflow(self):
|
|
||||||
|
async def run_workflow(self: MaimaiClient):
|
||||||
|
|
||||||
async with httpx.AsyncClient(verify=False) as client:
|
async with httpx.AsyncClient(verify=False) as client:
|
||||||
|
|
||||||
# Preview 探测
|
# Preview 探测
|
||||||
|
|
||||||
PreviewResponse = json.loads(await self.call_api(client, "GetUserPreviewApi", requestData_UserPreview, userId))
|
PreviewResponse = json.loads(
|
||||||
if PreviewResponse["isLogin"] == True:
|
await self.call_api(
|
||||||
|
client, "GetUserPreviewApi", requestData_UserPreview, userId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if PreviewResponse["isLogin"]:
|
||||||
logger.error("已在他处登录。")
|
logger.error("已在他处登录。")
|
||||||
return
|
return
|
||||||
|
|
||||||
# UserLogin
|
# UserLogin
|
||||||
|
|
||||||
LoginResponse = json.loads(await self.call_api(client, "UserLoginApi", requestData_UserLogin, userId))
|
LoginResponse = json.loads(
|
||||||
|
await self.call_api(client, "UserLoginApi", requestData_UserLogin, userId)
|
||||||
|
)
|
||||||
if LoginResponse["returnCode"] != 1:
|
if LoginResponse["returnCode"] != 1:
|
||||||
logger.error("login failed.")
|
logger.error("login failed.")
|
||||||
return
|
return
|
||||||
|
|
||||||
loginId = LoginResponse['loginId']
|
loginId = LoginResponse["loginId"]
|
||||||
loginDate = LoginResponse['lastLoginDate']
|
loginDate = LoginResponse["lastLoginDate"]
|
||||||
|
|
||||||
# UserData 等
|
# UserData 等
|
||||||
|
|
||||||
@@ -48,7 +58,9 @@ async def run_workflow(self):
|
|||||||
self.call_api(client, "GetUserRatingApi", requestData_UserData, userId),
|
self.call_api(client, "GetUserRatingApi", requestData_UserData, userId),
|
||||||
self.call_api(client, "GetUserChargeApi", requestData_UserData, userId),
|
self.call_api(client, "GetUserChargeApi", requestData_UserData, userId),
|
||||||
self.call_api(client, "GetUserActivityApi", requestData_UserData, userId),
|
self.call_api(client, "GetUserActivityApi", requestData_UserData, userId),
|
||||||
self.call_api(client, "GetUserMissionDataApi", requestData_UserData, userId),
|
self.call_api(
|
||||||
|
client, "GetUserMissionDataApi", requestData_UserData, userId
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
GeneralUserInfo = await asyncio.gather(*tasks)
|
GeneralUserInfo = await asyncio.gather(*tasks)
|
||||||
@@ -56,7 +68,9 @@ async def run_workflow(self):
|
|||||||
|
|
||||||
# UserAll
|
# UserAll
|
||||||
|
|
||||||
requestData_UserAll = UserAll_payload(loginId, loginDate, musicData, GeneralUserInfo)
|
requestData_UserAll = UserAll_payload(
|
||||||
|
loginId, loginDate, musicData, GeneralUserInfo
|
||||||
|
)
|
||||||
|
|
||||||
await self.call_api(client, "UpsertUserAllApi", requestData_UserAll, userId)
|
await self.call_api(client, "UpsertUserAllApi", requestData_UserAll, userId)
|
||||||
|
|
||||||
@@ -64,5 +78,6 @@ async def run_workflow(self):
|
|||||||
|
|
||||||
await self.call_api(client, "UserLogoutApi", requestData_UserLogout, userId)
|
await self.call_api(client, "UserLogoutApi", requestData_UserLogout, userId)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
asyncio.run(run_workflow(maimai))
|
asyncio.run(run_workflow(maimai))
|
||||||
@@ -1,12 +1,19 @@
|
|||||||
import json
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
from sdgb import MaimaiClient
|
from sdgb import MaimaiClient
|
||||||
from settings import *
|
from sdgb.settings import (
|
||||||
|
userId,
|
||||||
|
regionId,
|
||||||
|
placeId,
|
||||||
|
clientId,
|
||||||
|
)
|
||||||
|
|
||||||
maimai = MaimaiClient()
|
maimai = MaimaiClient()
|
||||||
|
|
||||||
async def run_workflow(maimai):
|
|
||||||
|
async def run_workflow(maimai: MaimaiClient):
|
||||||
async with httpx.AsyncClient(verify=False) as client:
|
async with httpx.AsyncClient(verify=False) as client:
|
||||||
data = {
|
data = {
|
||||||
"userId": userId,
|
"userId": userId,
|
||||||
@@ -15,9 +22,11 @@ async def run_workflow(maimai):
|
|||||||
"placeId": placeId,
|
"placeId": placeId,
|
||||||
"clientId": clientId,
|
"clientId": clientId,
|
||||||
"dateTime": 1767000000,
|
"dateTime": 1767000000,
|
||||||
"type": 4
|
"type": 4,
|
||||||
}
|
}
|
||||||
await maimai.call_api(client, "UserLogoutApi", data, userId)
|
await maimai.call_api(client, "UserLogoutApi", data, userId)
|
||||||
|
|
||||||
|
|
||||||
# 执行入口
|
# 执行入口
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
asyncio.run(run_workflow(maimai))
|
asyncio.run(run_workflow(maimai))
|
||||||
10
pyproject.toml
Normal file
10
pyproject.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[project]
|
||||||
|
name = "eaquira"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Add your description here"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.14"
|
||||||
|
dependencies = ["httpx>=0.28.1", "pycryptodome>=3.23.0", "pytz>=2026.2"]
|
||||||
|
|
||||||
|
[tool.uv]
|
||||||
|
package = true
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# This file contains the config. No function inside.
|
|
||||||
# DO NOT share your env to others.
|
|
||||||
|
|
||||||
userId =
|
|
||||||
|
|
||||||
musicData = ({
|
|
||||||
"musicId": 417,
|
|
||||||
"level": 3,
|
|
||||||
"playCount": 1,
|
|
||||||
"achievement": 1010000,
|
|
||||||
"comboStatus": 4,
|
|
||||||
"syncStatus": 4,
|
|
||||||
"deluxscoreMax": 2277,
|
|
||||||
"scoreRank": 13,
|
|
||||||
"extNum1": 0
|
|
||||||
})
|
|
||||||
|
|
||||||
regionId = 1
|
|
||||||
regionName = "北京"
|
|
||||||
placeId = 1403
|
|
||||||
placeName = "插电师北京王府井银泰店"
|
|
||||||
clientId = "A63E01C2805"
|
|
||||||
KeychipID = "A63E-01C28055905"
|
|
||||||
403
sdgb/payload.py
403
sdgb/payload.py
@@ -1,403 +0,0 @@
|
|||||||
import time
|
|
||||||
import pytz
|
|
||||||
import json
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
from encrypt import CalcRandom
|
|
||||||
from settings import *
|
|
||||||
from chime import *
|
|
||||||
import logging
|
|
||||||
|
|
||||||
|
|
||||||
userId = qr_api(qrCode)['userID']
|
|
||||||
token = qr_api(qrCode)['token']
|
|
||||||
|
|
||||||
|
|
||||||
logging.basicConfig(
|
|
||||||
level=logging.INFO,
|
|
||||||
format='%(asctime)s - %(levelname)s - %(message)s'
|
|
||||||
)
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
TimeStamp = int(time.time())
|
|
||||||
|
|
||||||
|
|
||||||
requestData_UserPreview = {
|
|
||||||
"userId": userId,
|
|
||||||
"segaIdAuthKey":"",
|
|
||||||
"token": token,
|
|
||||||
"clientId": clientId
|
|
||||||
}
|
|
||||||
|
|
||||||
requestData_UserLogin = {
|
|
||||||
"userId": userId,
|
|
||||||
"accessCode": "",
|
|
||||||
"regionId": regionId,
|
|
||||||
"placeId": placeId,
|
|
||||||
"clientId": clientId,
|
|
||||||
"dateTime": TimeStamp - 600,
|
|
||||||
"loginDateTime": TimeStamp,
|
|
||||||
"isContinue": False,
|
|
||||||
"genericFlag": 0,
|
|
||||||
"token": token
|
|
||||||
}
|
|
||||||
|
|
||||||
requestData_UserData = {
|
|
||||||
"userId": userId
|
|
||||||
}
|
|
||||||
|
|
||||||
requestData_UserLogout = {
|
|
||||||
"userId": userId,
|
|
||||||
"accessCode": "",
|
|
||||||
"regionId": regionId,
|
|
||||||
"placeId": placeId,
|
|
||||||
"clientId": clientId,
|
|
||||||
"loginDateTime": TimeStamp,
|
|
||||||
"type": 1
|
|
||||||
}
|
|
||||||
|
|
||||||
def UserAll_payload(loginId: int, loginDate: str, musicData: dict, GeneralUserInfo: list):
|
|
||||||
|
|
||||||
userData = json.loads(GeneralUserInfo[0])
|
|
||||||
userExtend = json.loads(GeneralUserInfo[1])
|
|
||||||
userOption = json.loads(GeneralUserInfo[2])
|
|
||||||
userRating = json.loads(GeneralUserInfo[3])
|
|
||||||
userChargeList = json.loads(GeneralUserInfo[4])
|
|
||||||
userActivity = json.loads(GeneralUserInfo[5])
|
|
||||||
userMissionDataList = json.loads(GeneralUserInfo[6])
|
|
||||||
|
|
||||||
requestData_UserAll = {
|
|
||||||
"userId": userId,
|
|
||||||
"playlogId": loginId,
|
|
||||||
"isEventMode": False,
|
|
||||||
"isFreePlay": False,
|
|
||||||
"loginDateTime": TimeStamp,
|
|
||||||
"userPlaylogList": [
|
|
||||||
{
|
|
||||||
"userId": 0,
|
|
||||||
"orderId": 0,
|
|
||||||
"playlogId": loginId,
|
|
||||||
"version": 1053000,
|
|
||||||
"placeId": placeId,
|
|
||||||
"placeName": placeName,
|
|
||||||
"loginDate": TimeStamp,
|
|
||||||
"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": musicData['musicId'],
|
|
||||||
"level": musicData['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": 1,
|
|
||||||
"characterAwakening1": 0,
|
|
||||||
"characterId2": userData['userData']['charaSlot'][1],
|
|
||||||
"characterLevel2": 1,
|
|
||||||
"characterAwakening2": 0,
|
|
||||||
"characterId3": userData['userData']['charaSlot'][2],
|
|
||||||
"characterLevel3": 1,
|
|
||||||
"characterAwakening3": 0,
|
|
||||||
"characterId4": userData['userData']['charaSlot'][3],
|
|
||||||
"characterLevel4": 1,
|
|
||||||
"characterAwakening4": 0,
|
|
||||||
"characterId5": userData['userData']['charaSlot'][4],
|
|
||||||
"characterLevel5": 1,
|
|
||||||
"characterAwakening5": 0,
|
|
||||||
"achievement": musicData['achievement'],
|
|
||||||
"deluxscore": musicData['deluxscoreMax'],
|
|
||||||
"scoreRank": musicData['scoreRank'],
|
|
||||||
"maxCombo": 0,
|
|
||||||
"totalCombo": 128,
|
|
||||||
"maxSync": 0,
|
|
||||||
"totalSync": 0,
|
|
||||||
"tapCriticalPerfect": 101,
|
|
||||||
"tapPerfect": 0,
|
|
||||||
"tapGreat": 0,
|
|
||||||
"tapGood": 0,
|
|
||||||
"tapMiss": 0,
|
|
||||||
"holdCriticalPerfect": 9,
|
|
||||||
"holdPerfect": 0,
|
|
||||||
"holdGreat": 0,
|
|
||||||
"holdGood": 0,
|
|
||||||
"holdMiss": 0,
|
|
||||||
"slideCriticalPerfect": 4,
|
|
||||||
"slidePerfect": 0,
|
|
||||||
"slideGreat": 0,
|
|
||||||
"slideGood": 0,
|
|
||||||
"slideMiss": 0,
|
|
||||||
"touchCriticalPerfect": 0,
|
|
||||||
"touchPerfect": 0,
|
|
||||||
"touchGreat": 0,
|
|
||||||
"touchGood": 0,
|
|
||||||
"touchMiss": 0,
|
|
||||||
"breakCriticalPerfect": 1,
|
|
||||||
"breakPerfect": 0,
|
|
||||||
"breakGreat": 0,
|
|
||||||
"breakGood": 0,
|
|
||||||
"breakMiss": 0,
|
|
||||||
"isTap": True,
|
|
||||||
"isHold": True,
|
|
||||||
"isSlide": True,
|
|
||||||
"isTouch": False,
|
|
||||||
"isBreak": True,
|
|
||||||
"isCriticalDisp": True,
|
|
||||||
"isFastLateDisp": True,
|
|
||||||
"fastCount": 0,
|
|
||||||
"lateCount": 0,
|
|
||||||
"isAchieveNewRecord": False,
|
|
||||||
"isDeluxscoreNewRecord": False,
|
|
||||||
"comboStatus": musicData['comboStatus'],
|
|
||||||
"syncStatus": musicData['syncStatus'],
|
|
||||||
"isClear": True,
|
|
||||||
"beforeRating": userData['userData']['playerRating'],
|
|
||||||
"afterRating": userData['userData']['playerRating'],
|
|
||||||
"beforeGrade": 0,
|
|
||||||
"afterGrade": 0,
|
|
||||||
"afterGradeRank": 0,
|
|
||||||
"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": 101,
|
|
||||||
"extBool1": False,
|
|
||||||
"extBool2": False
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"upsertUserAll": {
|
|
||||||
"userData": [
|
|
||||||
{
|
|
||||||
"accessCode": "",
|
|
||||||
"userName": userData['userData']['userName'],
|
|
||||||
"isNetMember": 1,
|
|
||||||
"point": userData['userData']['point'],
|
|
||||||
"totalPoint": userData['userData']['totalPoint'],
|
|
||||||
"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'] + 1,
|
|
||||||
"currentPlayCount": userData['userData']['currentPlayCount'] + 1,
|
|
||||||
"renameCredit": userData['userData']['renameCredit'],
|
|
||||||
"mapStock": userData['userData']['mapStock'],
|
|
||||||
"eventWatchedDate": userData['userData']['eventWatchedDate'],
|
|
||||||
"lastGameId": "SDGB",
|
|
||||||
"lastRomVersion": userData['userData']['lastRomVersion'],
|
|
||||||
"lastDataVersion": userData['userData']['lastDataVersion'],
|
|
||||||
"lastLoginDate": loginDate,
|
|
||||||
"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": userData['userData']['lastSelectEMoney'],
|
|
||||||
"lastSelectTicket": userData['userData']['lastSelectTicket'],
|
|
||||||
"lastSelectCourse": userData['userData']['lastSelectCourse'],
|
|
||||||
"lastCountCourse": userData['userData']['lastCountCourse'],
|
|
||||||
"firstGameId": userData['userData']['firstGameId'],
|
|
||||||
"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": userData['userData']['playVsCount'],
|
|
||||||
"playSyncCount": userData['userData']['playSyncCount'],
|
|
||||||
"winCount": userData['userData']['winCount'],
|
|
||||||
"helpCount": userData['userData']['helpCount'],
|
|
||||||
"comboCount": userData['userData']['comboCount'],
|
|
||||||
"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": userData['banState'],
|
|
||||||
"friendRegistSkip": userData['userData']['friendRegistSkip'],
|
|
||||||
"dateTime": TimeStamp
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"userExtend": [userExtend['userExtend']],
|
|
||||||
"userOption": [userOption['userOption']],
|
|
||||||
"userCharacterList": [],
|
|
||||||
"userGhost": [],
|
|
||||||
"userMapList": [],
|
|
||||||
"userLoginBonusList": [],
|
|
||||||
"userRatingList": [userRating['userRating']],
|
|
||||||
"userItemList": [],
|
|
||||||
"userMusicDetailList": [musicData],
|
|
||||||
"userCourseList": [],
|
|
||||||
"userFriendSeasonRankingList": [],
|
|
||||||
"userChargeList": userChargeList['userChargeList'],
|
|
||||||
"userFavoriteList": [
|
|
||||||
{"itemKind": 3,"itemIdList": []},
|
|
||||||
{"itemKind": 1,"itemIdList": []},
|
|
||||||
{"itemKind": 2,"itemIdList": []},
|
|
||||||
{"itemKind": 10,"itemIdList": []},
|
|
||||||
{"itemKind": 11,"itemIdList": []}
|
|
||||||
],
|
|
||||||
"userActivityList": [userActivity['userActivity']],
|
|
||||||
"userMissionDataList": [
|
|
||||||
{
|
|
||||||
"type": userMissionDataList['userMissionDataList'][0]['type'],
|
|
||||||
"difficulty": userMissionDataList['userMissionDataList'][0]['difficulty'],
|
|
||||||
"targetGenreId": userMissionDataList['userMissionDataList'][0]['targetGenreId'],
|
|
||||||
"targetGenreTableId": userMissionDataList['userMissionDataList'][0]['targetGenreTableId'],
|
|
||||||
"conditionGenreId": userMissionDataList['userMissionDataList'][0]['conditionGenreId'],
|
|
||||||
"conditionGenreTableId": userMissionDataList['userMissionDataList'][0]['conditionGenreTableId'],
|
|
||||||
"clearFlag": userMissionDataList['userMissionDataList'][0]['clearFlag']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": userMissionDataList['userMissionDataList'][1]['type'],
|
|
||||||
"difficulty": userMissionDataList['userMissionDataList'][1]['difficulty'],
|
|
||||||
"targetGenreId": userMissionDataList['userMissionDataList'][1]['targetGenreId'],
|
|
||||||
"targetGenreTableId": userMissionDataList['userMissionDataList'][1]['targetGenreTableId'],
|
|
||||||
"conditionGenreId": userMissionDataList['userMissionDataList'][1]['conditionGenreId'],
|
|
||||||
"conditionGenreTableId": userMissionDataList['userMissionDataList'][1]['conditionGenreTableId'],
|
|
||||||
"clearFlag": userMissionDataList['userMissionDataList'][1]['clearFlag']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": userMissionDataList['userMissionDataList'][2]['type'],
|
|
||||||
"difficulty": userMissionDataList['userMissionDataList'][2]['difficulty'],
|
|
||||||
"targetGenreId": userMissionDataList['userMissionDataList'][2]['targetGenreId'],
|
|
||||||
"targetGenreTableId": userMissionDataList['userMissionDataList'][2]['targetGenreTableId'],
|
|
||||||
"conditionGenreId": userMissionDataList['userMissionDataList'][2]['conditionGenreId'],
|
|
||||||
"conditionGenreTableId": userMissionDataList['userMissionDataList'][2]['conditionGenreTableId'],
|
|
||||||
"clearFlag": userMissionDataList['userMissionDataList'][2]['clearFlag']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": userMissionDataList['userMissionDataList'][3]['type'],
|
|
||||||
"difficulty": userMissionDataList['userMissionDataList'][3]['difficulty'],
|
|
||||||
"targetGenreId": userMissionDataList['userMissionDataList'][3]['targetGenreId'],
|
|
||||||
"targetGenreTableId": userMissionDataList['userMissionDataList'][3]['targetGenreTableId'],
|
|
||||||
"conditionGenreId": userMissionDataList['userMissionDataList'][3]['conditionGenreId'],
|
|
||||||
"conditionGenreTableId": userMissionDataList['userMissionDataList'][3]['conditionGenreTableId'],
|
|
||||||
"clearFlag": userMissionDataList['userMissionDataList'][3]['clearFlag']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": userMissionDataList['userMissionDataList'][4]['type'],
|
|
||||||
"difficulty": userMissionDataList['userMissionDataList'][4]['difficulty'],
|
|
||||||
"targetGenreId": userMissionDataList['userMissionDataList'][4]['targetGenreId'],
|
|
||||||
"targetGenreTableId": userMissionDataList['userMissionDataList'][4]['targetGenreTableId'],
|
|
||||||
"conditionGenreId": userMissionDataList['userMissionDataList'][4]['conditionGenreId'],
|
|
||||||
"conditionGenreTableId": userMissionDataList['userMissionDataList'][4]['conditionGenreTableId'],
|
|
||||||
"clearFlag": userMissionDataList['userMissionDataList'][4]['clearFlag']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": userMissionDataList['userMissionDataList'][5]['type'],
|
|
||||||
"difficulty": userMissionDataList['userMissionDataList'][5]['difficulty'],
|
|
||||||
"targetGenreId": userMissionDataList['userMissionDataList'][5]['targetGenreId'],
|
|
||||||
"targetGenreTableId": userMissionDataList['userMissionDataList'][5]['targetGenreTableId'],
|
|
||||||
"conditionGenreId": userMissionDataList['userMissionDataList'][5]['conditionGenreId'],
|
|
||||||
"conditionGenreTableId": userMissionDataList['userMissionDataList'][5]['conditionGenreTableId'],
|
|
||||||
"clearFlag": userMissionDataList['userMissionDataList'][5]['clearFlag']
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"userWeeklyData": {
|
|
||||||
"lastLoginWeek": userMissionDataList['userWeeklyData']['lastLoginWeek'],
|
|
||||||
"beforeLoginWeek": userMissionDataList['userWeeklyData']['beforeLoginWeek'],
|
|
||||||
"friendBonusFlag": userMissionDataList['userWeeklyData']['friendBonusFlag']
|
|
||||||
},
|
|
||||||
"userGamePlaylogList": [
|
|
||||||
{
|
|
||||||
"playlogId": loginId,
|
|
||||||
"version": userData['userData']['lastRomVersion'],
|
|
||||||
"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": []
|
|
||||||
},
|
|
||||||
"userIntimateList": [],
|
|
||||||
"userShopItemStockList": [],
|
|
||||||
"userGetPointList": [],
|
|
||||||
"userTradeItemList": [],
|
|
||||||
"userFavoritemusicList": [],
|
|
||||||
"userKaleidxScopeList": [],
|
|
||||||
"isNewCharacterList": "",
|
|
||||||
"isNewMapList": "",
|
|
||||||
"isNewLoginBonusList": "",
|
|
||||||
"isNewItemList": "",
|
|
||||||
"isNewMusicDetailList": "0",
|
|
||||||
"isNewCourseList": "",
|
|
||||||
"isNewFavoriteList": "11111",
|
|
||||||
"isNewFriendSeasonRankingList": "",
|
|
||||||
"isNewUserIntimateList": "",
|
|
||||||
"isNewFavoritemusicList": "",
|
|
||||||
"isNewKaleidxScopeList": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info(f"🫥 [INFO] userId: '{userId}', loginId: '{loginId}', loginDate: '{loginDate}', timestamp: '{TimeStamp}'")
|
|
||||||
return requestData_UserAll
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
import json
|
|
||||||
import asyncio
|
|
||||||
import httpx
|
|
||||||
import time
|
|
||||||
import logging
|
|
||||||
from sdgb import MaimaiClient
|
|
||||||
|
|
||||||
from settings import userId, musicData
|
|
||||||
from payload import *
|
|
||||||
|
|
||||||
maimai = MaimaiClient()
|
|
||||||
|
|
||||||
|
|
||||||
logging.basicConfig(
|
|
||||||
level=logging.INFO,
|
|
||||||
format='%(asctime)s - %(levelname)s - %(message)s'
|
|
||||||
)
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
async def run_workflow(self):
|
|
||||||
|
|
||||||
async with httpx.AsyncClient(verify=False) as client:
|
|
||||||
|
|
||||||
# Preview 探测
|
|
||||||
|
|
||||||
PreviewResponse = json.loads(await self.call_api(client, "GetUserPreviewApi", requestData_UserPreview, userId))
|
|
||||||
if PreviewResponse["isLogin"] == True:
|
|
||||||
logger.error("已在他处登录。")
|
|
||||||
return
|
|
||||||
|
|
||||||
# UserLogin
|
|
||||||
|
|
||||||
LoginResponse = json.loads(await self.call_api(client, "UserLoginApi", requestData_UserLogin, userId))
|
|
||||||
if LoginResponse["returnCode"] == 106:
|
|
||||||
logger.error("chime verfication failed.")
|
|
||||||
return
|
|
||||||
|
|
||||||
loginId = LoginResponse['loginId']
|
|
||||||
loginDate = LoginResponse['lastLoginDate']
|
|
||||||
|
|
||||||
# UserData 等
|
|
||||||
|
|
||||||
tasks = [
|
|
||||||
self.call_api(client, "GetUserDataApi", requestData_UserData, userId),
|
|
||||||
self.call_api(client, "GetUserExtendApi", requestData_UserData, userId),
|
|
||||||
self.call_api(client, "GetUserOptionApi", requestData_UserData, userId),
|
|
||||||
self.call_api(client, "GetUserRatingApi", requestData_UserData, userId),
|
|
||||||
self.call_api(client, "GetUserChargeApi", requestData_UserData, userId),
|
|
||||||
self.call_api(client, "GetUserActivityApi", requestData_UserData, userId),
|
|
||||||
self.call_api(client, "GetUserMissionDataApi", requestData_UserData, userId),
|
|
||||||
]
|
|
||||||
|
|
||||||
GeneralUserInfo = await asyncio.gather(*tasks)
|
|
||||||
time.sleep(60) # 模拟游戏时间
|
|
||||||
|
|
||||||
# UserPlaylog
|
|
||||||
|
|
||||||
requestData_UserPlaylog = UserPlaylog_payload(loginId, musicData, GeneralUserInfo[0])
|
|
||||||
|
|
||||||
await self.call_api(client, "UploadUserPlaylogListApi", requestData_UserPlaylog, userId)
|
|
||||||
|
|
||||||
# Userall
|
|
||||||
|
|
||||||
requestData_Userall = UserAll_payload(loginId, loginDate, musicData, GeneralUserInfo)
|
|
||||||
|
|
||||||
await self.call_api(client, "UpsertUserAllApi", requestData_Userall, userId)
|
|
||||||
|
|
||||||
# UserLogout
|
|
||||||
|
|
||||||
await self.call_api(client, "UserLogoutApi", requestData_UserLogout, userId)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
asyncio.run(run_workflow(maimai))
|
|
||||||
25
src/sdgb/.settings.py
Normal file
25
src/sdgb/.settings.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# This file contains the config. No function inside.
|
||||||
|
# DO NOT share your env to others.
|
||||||
|
|
||||||
|
userId = ...
|
||||||
|
qrCode = ...
|
||||||
|
|
||||||
|
musicData = {
|
||||||
|
"musicId": 11538, # Amber Chronicle
|
||||||
|
"level": 0,
|
||||||
|
"playCount": 1,
|
||||||
|
"achievement": 0,
|
||||||
|
"comboStatus": 0,
|
||||||
|
"syncStatus": 0,
|
||||||
|
"deluxscoreMax": 0,
|
||||||
|
"scoreRank": 0,
|
||||||
|
"extNum1": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
regionId = 1
|
||||||
|
regionName = "北京"
|
||||||
|
placeId = 1403
|
||||||
|
placeName = "插电师北京王府井银泰店"
|
||||||
|
clientId = "A63E01C2805"
|
||||||
|
KeychipID = "A63E-01C28055905"
|
||||||
@@ -1,23 +1,31 @@
|
|||||||
import asyncio
|
|
||||||
import httpx
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import time
|
import zlib
|
||||||
from encrypt import *
|
|
||||||
|
import httpx
|
||||||
|
|
||||||
|
from sdgb.encrypt import (
|
||||||
|
AesKey,
|
||||||
|
AesIV,
|
||||||
|
aes_pkcs7,
|
||||||
|
get_hash_api,
|
||||||
|
)
|
||||||
|
|
||||||
# 配置日志,方便调试看请求顺序
|
# 配置日志,方便调试看请求顺序
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO,
|
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
|
||||||
format='%(asctime)s - %(levelname)s - %(message)s'
|
|
||||||
)
|
)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class MaimaiClient:
|
class MaimaiClient:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.base_url = f"https://maimai-gm.wahlap.com:42081/Maimai2Servlet/"
|
self.base_url = "https://maimai-gm.wahlap.com:42081/Maimai2Servlet/"
|
||||||
self.aes = aes_pkcs7(AesKey, AesIV)
|
self.aes = aes_pkcs7(AesKey, AesIV)
|
||||||
|
|
||||||
async def call_api(self, client: httpx.AsyncClient, ApiType: str, data: dict, userId: int):
|
async def call_api(
|
||||||
|
self, client: httpx.AsyncClient, ApiType: str, data: dict, userId: int
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
先压缩再加密请求数据,发送请求后解密再解压响应数据
|
先压缩再加密请求数据,发送请求后解密再解压响应数据
|
||||||
这里的 client 需要传入外部创建的 httpx.AsyncClient 实例
|
这里的 client 需要传入外部创建的 httpx.AsyncClient 实例
|
||||||
@@ -29,11 +37,11 @@ class MaimaiClient:
|
|||||||
headers = {
|
headers = {
|
||||||
"User-Agent": f"{ApiTypeHash}#{userId}",
|
"User-Agent": f"{ApiTypeHash}#{userId}",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"Mai-Encoding": "1.53",
|
"Mai-Encoding": "1.55",
|
||||||
"Accept-Encoding": "",
|
"Accept-Encoding": "",
|
||||||
"Charset": "UTF-8",
|
"Charset": "UTF-8",
|
||||||
"Content-Encoding": "deflate",
|
"Content-Encoding": "deflate",
|
||||||
"Host": "maimai-gm.wahlap.com:42081"
|
"Host": "maimai-gm.wahlap.com:42081",
|
||||||
}
|
}
|
||||||
|
|
||||||
data = bytes(json.dumps(data), encoding="utf-8")
|
data = bytes(json.dumps(data), encoding="utf-8")
|
||||||
@@ -42,18 +50,19 @@ class MaimaiClient:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# 这里的 timeout 设置稍微长一点,防止服务端处理慢
|
# 这里的 timeout 设置稍微长一点,防止服务端处理慢
|
||||||
resp = await client.post(url, headers=headers, data=AESEncrptedData, timeout=10.0)
|
resp = await client.post(
|
||||||
|
url, headers=headers, data=AESEncrptedData, timeout=10.0
|
||||||
|
)
|
||||||
resp.raise_for_status() # 如果状态码不是 2xx 则抛出异常
|
resp.raise_for_status() # 如果状态码不是 2xx 则抛出异常
|
||||||
|
|
||||||
AESEncrptedResponse = resp.content
|
AESEncrptedResponse = resp.content
|
||||||
DecryptedData = self.aes.decrypt(AESEncrptedResponse)
|
DecryptedData = self.aes.decrypt(AESEncrptedResponse)
|
||||||
UncompressedData = zlib.decompress(DecryptedData).decode('utf-8')
|
UncompressedData = zlib.decompress(DecryptedData).decode("utf-8")
|
||||||
|
|
||||||
logger.info(f"✅ [SUCCESS] {ApiType} - {UncompressedData}")
|
logger.info(f"✅ [SUCCESS] {ApiType} - {UncompressedData}")
|
||||||
|
|
||||||
return UncompressedData
|
return UncompressedData
|
||||||
|
|
||||||
|
|
||||||
except httpx.HTTPStatusError as e:
|
except httpx.HTTPStatusError as e:
|
||||||
logger.error(f"❌ [HTTP ERROR] {ApiType}: {e.response.status_code}")
|
logger.error(f"❌ [HTTP ERROR] {ApiType}: {e.response.status_code}")
|
||||||
return None
|
return None
|
||||||
@@ -1,32 +1,42 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
import httpx
|
|
||||||
import pytz
|
|
||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from settings import KeychipID
|
|
||||||
|
import httpx
|
||||||
|
import pytz
|
||||||
|
|
||||||
|
from sdgb.settings import KeychipID
|
||||||
|
|
||||||
|
|
||||||
def qr_api(qr_code: str):
|
def qr_api(qr_code: str):
|
||||||
if len(qr_code) > 64:
|
if len(qr_code) > 64:
|
||||||
qr_code = qr_code[-64:]
|
qr_code = qr_code[-64:]
|
||||||
time_stamp = datetime.now(pytz.timezone('Asia/Tokyo')).strftime("%y%m%d%H%M%S")
|
time_stamp = datetime.now(pytz.timezone("Asia/Tokyo")).strftime("%y%m%d%H%M%S")
|
||||||
auth_key = hashlib.sha256(
|
auth_key = (
|
||||||
(KeychipID + time_stamp + "XcW5FW4cPArBXEk4vzKz3CIrMuA5EVVW").encode("UTF-8")).hexdigest().upper()
|
hashlib.sha256(
|
||||||
|
(KeychipID + time_stamp + "XcW5FW4cPArBXEk4vzKz3CIrMuA5EVVW").encode(
|
||||||
|
"UTF-8"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.hexdigest()
|
||||||
|
.upper()
|
||||||
|
)
|
||||||
param = {
|
param = {
|
||||||
"chipID": KeychipID,
|
"chipID": KeychipID,
|
||||||
"openGameID": "MAID",
|
"openGameID": "MAID",
|
||||||
"key": auth_key,
|
"key": auth_key,
|
||||||
"qrCode": qr_code,
|
"qrCode": qr_code,
|
||||||
"timestamp": time_stamp
|
"timestamp": time_stamp,
|
||||||
}
|
}
|
||||||
headers = {
|
headers = {
|
||||||
"Contention": "Keep-Alive",
|
"Contention": "Keep-Alive",
|
||||||
"Host": "ai.sys-all.cn",
|
"Host": "ai.sys-all.cn",
|
||||||
"User-Agent": "WC_AIME_LIB"
|
"User-Agent": "WC_AIME_LIB",
|
||||||
}
|
}
|
||||||
res = httpx.post(
|
res = httpx.post(
|
||||||
"http://ai.sys-allnet.cn/wc_aime/api/get_data",
|
"http://ai.sys-allnet.cn/wc_aime/api/get_data",
|
||||||
data = json.dumps(param, separators=(',', ':')),
|
data=json.dumps(param, separators=(",", ":")),
|
||||||
headers = headers
|
headers=headers,
|
||||||
)
|
)
|
||||||
assert res.status_code == 200, "网络错误"
|
assert res.status_code == 200, "网络错误"
|
||||||
return json.loads(res.content)
|
return json.loads(res.content)
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
import zlib
|
|
||||||
import base64
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from Crypto.Cipher import AES
|
from Crypto.Cipher import AES
|
||||||
from Crypto.Util.Padding import pad, unpad
|
from Crypto.Util.Padding import pad, unpad
|
||||||
|
|
||||||
AesKey = "o2U8F6<adcYl25f_qwx_n]5_qxRcbLN>"
|
# 1.55 -> 1.56 -- 舞萌 DX 2026
|
||||||
AesIV = "AL<G:k:X6Vu7@_U]"
|
AesKey = "FKM2JX:VjZNK6hc:A0<JU:i5oR7LA]9W"
|
||||||
ObfuscateParam = "LatuAa81"
|
AesIV = "F>;24DjU9W6ZsRH["
|
||||||
|
ObfuscateParam = "8bF76dE9"
|
||||||
|
|
||||||
# 1.50 -> 1.52 -- 舞萌 DX 2025
|
# 1.50 -> 1.53 -- 舞萌 DX 2025
|
||||||
# AesKey = "a>32bVP7v<63BVLkY[xM>daZ1s9MBP<R"
|
# AesKey = "a>32bVP7v<63BVLkY[xM>daZ1s9MBP<R"
|
||||||
# AesIV = "d6xHIKq]1J]Dt^ue"
|
# AesIV = "d6xHIKq]1J]Dt^ue"
|
||||||
# ObfuscateParam = "B44df8yT"
|
# ObfuscateParam = "B44df8yT"
|
||||||
@@ -20,10 +19,11 @@ ObfuscateParam = "LatuAa81"
|
|||||||
# AesIV = ";;KjR1C3hgB1ovXa"
|
# AesIV = ";;KjR1C3hgB1ovXa"
|
||||||
# ObfuscateParam = "BEs2D5vW"
|
# ObfuscateParam = "BEs2D5vW"
|
||||||
|
|
||||||
|
|
||||||
class aes_pkcs7(object):
|
class aes_pkcs7(object):
|
||||||
def __init__(self, key: str, iv: str):
|
def __init__(self, key: str, iv: str):
|
||||||
self.key = key.encode('utf-8')
|
self.key = key.encode("utf-8")
|
||||||
self.iv = iv.encode('utf-8')
|
self.iv = iv.encode("utf-8")
|
||||||
self.mode = AES.MODE_CBC
|
self.mode = AES.MODE_CBC
|
||||||
|
|
||||||
def encrypt(self, content: bytes) -> bytes:
|
def encrypt(self, content: bytes) -> bytes:
|
||||||
@@ -46,15 +46,17 @@ class aes_pkcs7(object):
|
|||||||
def pkcs7padding(self, text):
|
def pkcs7padding(self, text):
|
||||||
bs = 16
|
bs = 16
|
||||||
length = len(text)
|
length = len(text)
|
||||||
bytes_length = len(text.encode('utf-8'))
|
bytes_length = len(text.encode("utf-8"))
|
||||||
padding_size = length if (bytes_length == length) else bytes_length
|
padding_size = length if (bytes_length == length) else bytes_length
|
||||||
padding = bs - padding_size % bs
|
padding = bs - padding_size % bs
|
||||||
padding_text = chr(padding) * padding
|
padding_text = chr(padding) * padding
|
||||||
return text + padding_text
|
return text + padding_text
|
||||||
|
|
||||||
|
|
||||||
def get_hash_api(api):
|
def get_hash_api(api):
|
||||||
return hashlib.md5((api + "MaimaiChn" + ObfuscateParam).encode()).hexdigest()
|
return hashlib.md5((api + "MaimaiChn" + ObfuscateParam).encode()).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def CalcRandom():
|
def CalcRandom():
|
||||||
max = 1037933
|
max = 1037933
|
||||||
num2 = random.randint(1, max) * 2069
|
num2 = random.randint(1, max) * 2069
|
||||||
@@ -1,46 +1,45 @@
|
|||||||
|
from urllib.parse import unquote
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from Crypto.Cipher import AES
|
from Crypto.Cipher import AES
|
||||||
from Crypto.Util.Padding import pad
|
from Crypto.Util.Padding import pad
|
||||||
from urllib.parse import unquote
|
|
||||||
|
|
||||||
def enc(key, iv, data):
|
def enc(key, iv, data):
|
||||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||||
encrypted = cipher.encrypt(data)
|
encrypted = cipher.encrypt(data)
|
||||||
return encrypted
|
return encrypted
|
||||||
|
|
||||||
|
|
||||||
def dec(key, iv, data):
|
def dec(key, iv, data):
|
||||||
de_cipher = AES.new(key, AES.MODE_CBC, iv)
|
de_cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||||
decrypted = de_cipher.decrypt(data)
|
decrypted = de_cipher.decrypt(data)
|
||||||
return decrypted
|
return decrypted
|
||||||
|
|
||||||
|
|
||||||
def hello():
|
def hello():
|
||||||
key = bytes([47, 63, 106, 111, 43, 34, 76, 38, 92, 67, 114, 57, 40, 61, 107, 71])
|
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 ])
|
# key = bytes([ 45, 97, 53, 55, 85, 88, 52, 121, 57, 47, 104, 40, 73, 109, 65, 81 ])
|
||||||
iv = bytes.fromhex('00000000000000000000000000000000')
|
iv = bytes.fromhex("00000000000000000000000000000000")
|
||||||
ua = 'SDGB;Windows/Lite'
|
ua = "SDGB;Windows/Lite"
|
||||||
# ua = 'SDHJ;Windows/Lite'
|
# ua = 'SDHJ;Windows/Lite'
|
||||||
|
|
||||||
# 构建 payload
|
# 构建 payload
|
||||||
content = bytes([0] * 16) + b'title_id=SDGB&title_ver=1.52&client_id=A63E01E6149'
|
content = bytes([0] * 16) + b"title_id=SDGB&title_ver=1.52&client_id=A63E01E6149"
|
||||||
print(f"Content: {content}")
|
print(f"Content: {content}")
|
||||||
|
|
||||||
header = bytes.fromhex('00000000000000000000000000000000')
|
header = bytes.fromhex("00000000000000000000000000000000")
|
||||||
bytes_data = pad(header + content, 16)
|
bytes_data = pad(header + content, 16)
|
||||||
encrypted = enc(key, iv, bytes_data)
|
encrypted = enc(key, iv, bytes_data)
|
||||||
|
|
||||||
# --- HTTPX 修改部分 ---
|
# --- HTTPX 修改部分 ---
|
||||||
headers = {
|
headers = {"User-Agent": ua, "Pragma": "DFI"}
|
||||||
'User-Agent': ua,
|
|
||||||
'Pragma': 'DFI'
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 发送 POST 请求
|
# 发送 POST 请求
|
||||||
# urllib3 的 body 参数在 httpx 中对应 content (用于二进制数据)
|
# urllib3 的 body 参数在 httpx 中对应 content (用于二进制数据)
|
||||||
r = httpx.post(
|
r = httpx.post(
|
||||||
'http://at.sys-allnet.cn/net/initialize',
|
"http://at.sys-allnet.cn/net/initialize", content=encrypted, headers=headers
|
||||||
content=encrypted,
|
|
||||||
headers=headers
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# 检查响应状态码 (可选,但在 httpx 中推荐)
|
# 检查响应状态码 (可选,但在 httpx 中推荐)
|
||||||
@@ -54,7 +53,7 @@ def hello():
|
|||||||
if len(resp_data) >= 16:
|
if len(resp_data) >= 16:
|
||||||
decrypted = dec(key, resp_data[:16], resp_data)
|
decrypted = dec(key, resp_data[:16], resp_data)
|
||||||
decrypted_bytes = decrypted[16:]
|
decrypted_bytes = decrypted[16:]
|
||||||
decrypted_str = unquote(decrypted_bytes.decode('UTF-8'), 'utf-8')
|
decrypted_str = unquote(decrypted_bytes.decode("UTF-8"), "utf-8")
|
||||||
print(f"Decrypted: {decrypted_str}")
|
print(f"Decrypted: {decrypted_str}")
|
||||||
else:
|
else:
|
||||||
print("Response data too short.")
|
print("Response data too short.")
|
||||||
@@ -62,5 +61,6 @@ def hello():
|
|||||||
except httpx.RequestError as e:
|
except httpx.RequestError as e:
|
||||||
print(f"An error occurred while requesting: {e}")
|
print(f"An error occurred while requesting: {e}")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
if __name__ == "__main__":
|
||||||
hello()
|
hello()
|
||||||
524
src/sdgb/payload.py
Normal file
524
src/sdgb/payload.py
Normal file
@@ -0,0 +1,524 @@
|
|||||||
|
import time
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import pytz
|
||||||
|
|
||||||
|
from sdgb.encrypt import CalcRandom
|
||||||
|
from sdgb.chime import qr_api
|
||||||
|
from sdgb.settings import (
|
||||||
|
clientId,
|
||||||
|
qrCode,
|
||||||
|
regionId,
|
||||||
|
regionName,
|
||||||
|
placeId,
|
||||||
|
placeName,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
qrResp = qr_api(qrCode)
|
||||||
|
userId = qrResp["userID"]
|
||||||
|
token = qrResp["token"]
|
||||||
|
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
TimeStamp = int(time.time())
|
||||||
|
|
||||||
|
|
||||||
|
requestData_UserPreview = {
|
||||||
|
"userId": userId,
|
||||||
|
"segaIdAuthKey": "",
|
||||||
|
"token": token,
|
||||||
|
"clientId": clientId,
|
||||||
|
}
|
||||||
|
|
||||||
|
requestData_UserLogin = {
|
||||||
|
"userId": userId,
|
||||||
|
"accessCode": "",
|
||||||
|
"regionId": regionId,
|
||||||
|
"placeId": placeId,
|
||||||
|
"clientId": clientId,
|
||||||
|
"dateTime": TimeStamp - 600,
|
||||||
|
"loginDateTime": TimeStamp,
|
||||||
|
"isContinue": False,
|
||||||
|
"genericFlag": 0,
|
||||||
|
"token": token,
|
||||||
|
}
|
||||||
|
|
||||||
|
requestData_UserData = {"userId": userId}
|
||||||
|
|
||||||
|
requestData_UserLogout = {
|
||||||
|
"userId": userId,
|
||||||
|
"accessCode": "",
|
||||||
|
"regionId": regionId,
|
||||||
|
"placeId": placeId,
|
||||||
|
"clientId": clientId,
|
||||||
|
"loginDateTime": TimeStamp,
|
||||||
|
"type": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def UserAll_payload(
|
||||||
|
loginId: int, loginDate: str, musicData: dict, GeneralUserInfo: list
|
||||||
|
):
|
||||||
|
|
||||||
|
userData = json.loads(GeneralUserInfo[0])
|
||||||
|
userExtend = json.loads(GeneralUserInfo[1])
|
||||||
|
userOption = json.loads(GeneralUserInfo[2])
|
||||||
|
userRating = json.loads(GeneralUserInfo[3])
|
||||||
|
userChargeList = json.loads(GeneralUserInfo[4])
|
||||||
|
userActivity = json.loads(GeneralUserInfo[5])
|
||||||
|
userMissionDataList = json.loads(GeneralUserInfo[6])
|
||||||
|
|
||||||
|
requestData_UserAll = {
|
||||||
|
"userId": userId,
|
||||||
|
"playlogId": loginId,
|
||||||
|
"isEventMode": False,
|
||||||
|
"isFreePlay": False,
|
||||||
|
"loginDateTime": TimeStamp,
|
||||||
|
"userPlaylogList": [
|
||||||
|
{
|
||||||
|
"userId": 0,
|
||||||
|
"orderId": 0,
|
||||||
|
"playlogId": loginId,
|
||||||
|
"version": 1053000,
|
||||||
|
"placeId": placeId,
|
||||||
|
"placeName": placeName,
|
||||||
|
"loginDate": TimeStamp,
|
||||||
|
"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": musicData["musicId"],
|
||||||
|
"level": musicData["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": 1,
|
||||||
|
"characterAwakening1": 0,
|
||||||
|
"characterId2": userData["userData"]["charaSlot"][1],
|
||||||
|
"characterLevel2": 1,
|
||||||
|
"characterAwakening2": 0,
|
||||||
|
"characterId3": userData["userData"]["charaSlot"][2],
|
||||||
|
"characterLevel3": 1,
|
||||||
|
"characterAwakening3": 0,
|
||||||
|
"characterId4": userData["userData"]["charaSlot"][3],
|
||||||
|
"characterLevel4": 1,
|
||||||
|
"characterAwakening4": 0,
|
||||||
|
"characterId5": userData["userData"]["charaSlot"][4],
|
||||||
|
"characterLevel5": 1,
|
||||||
|
"characterAwakening5": 0,
|
||||||
|
"achievement": musicData["achievement"],
|
||||||
|
"deluxscore": musicData["deluxscoreMax"],
|
||||||
|
"scoreRank": musicData["scoreRank"],
|
||||||
|
"maxCombo": 0,
|
||||||
|
"totalCombo": 128,
|
||||||
|
"maxSync": 0,
|
||||||
|
"totalSync": 0,
|
||||||
|
"tapCriticalPerfect": 101,
|
||||||
|
"tapPerfect": 0,
|
||||||
|
"tapGreat": 0,
|
||||||
|
"tapGood": 0,
|
||||||
|
"tapMiss": 0,
|
||||||
|
"holdCriticalPerfect": 9,
|
||||||
|
"holdPerfect": 0,
|
||||||
|
"holdGreat": 0,
|
||||||
|
"holdGood": 0,
|
||||||
|
"holdMiss": 0,
|
||||||
|
"slideCriticalPerfect": 4,
|
||||||
|
"slidePerfect": 0,
|
||||||
|
"slideGreat": 0,
|
||||||
|
"slideGood": 0,
|
||||||
|
"slideMiss": 0,
|
||||||
|
"touchCriticalPerfect": 0,
|
||||||
|
"touchPerfect": 0,
|
||||||
|
"touchGreat": 0,
|
||||||
|
"touchGood": 0,
|
||||||
|
"touchMiss": 0,
|
||||||
|
"breakCriticalPerfect": 1,
|
||||||
|
"breakPerfect": 0,
|
||||||
|
"breakGreat": 0,
|
||||||
|
"breakGood": 0,
|
||||||
|
"breakMiss": 0,
|
||||||
|
"isTap": True,
|
||||||
|
"isHold": True,
|
||||||
|
"isSlide": True,
|
||||||
|
"isTouch": False,
|
||||||
|
"isBreak": True,
|
||||||
|
"isCriticalDisp": True,
|
||||||
|
"isFastLateDisp": True,
|
||||||
|
"fastCount": 0,
|
||||||
|
"lateCount": 0,
|
||||||
|
"isAchieveNewRecord": False,
|
||||||
|
"isDeluxscoreNewRecord": False,
|
||||||
|
"comboStatus": musicData["comboStatus"],
|
||||||
|
"syncStatus": musicData["syncStatus"],
|
||||||
|
"isClear": True,
|
||||||
|
"beforeRating": userData["userData"]["playerRating"],
|
||||||
|
"afterRating": userData["userData"]["playerRating"],
|
||||||
|
"beforeGrade": 0,
|
||||||
|
"afterGrade": 0,
|
||||||
|
"afterGradeRank": 0,
|
||||||
|
"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": 101,
|
||||||
|
"extBool1": False,
|
||||||
|
"extBool2": False,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"upsertUserAll": {
|
||||||
|
"userData": [
|
||||||
|
{
|
||||||
|
"accessCode": "",
|
||||||
|
"userName": userData["userData"]["userName"],
|
||||||
|
"isNetMember": 1,
|
||||||
|
"point": userData["userData"]["point"],
|
||||||
|
"totalPoint": userData["userData"]["totalPoint"],
|
||||||
|
"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"] + 1,
|
||||||
|
"currentPlayCount": userData["userData"]["currentPlayCount"] + 1,
|
||||||
|
"renameCredit": userData["userData"]["renameCredit"],
|
||||||
|
"mapStock": userData["userData"]["mapStock"],
|
||||||
|
"eventWatchedDate": userData["userData"]["eventWatchedDate"],
|
||||||
|
"lastGameId": "SDGB",
|
||||||
|
"lastRomVersion": userData["userData"]["lastRomVersion"],
|
||||||
|
"lastDataVersion": userData["userData"]["lastDataVersion"],
|
||||||
|
"lastLoginDate": loginDate,
|
||||||
|
"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": userData["userData"]["lastSelectEMoney"],
|
||||||
|
"lastSelectTicket": userData["userData"]["lastSelectTicket"],
|
||||||
|
"lastSelectCourse": userData["userData"]["lastSelectCourse"],
|
||||||
|
"lastCountCourse": userData["userData"]["lastCountCourse"],
|
||||||
|
"firstGameId": userData["userData"]["firstGameId"],
|
||||||
|
"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": userData["userData"]["playVsCount"],
|
||||||
|
"playSyncCount": userData["userData"]["playSyncCount"],
|
||||||
|
"winCount": userData["userData"]["winCount"],
|
||||||
|
"helpCount": userData["userData"]["helpCount"],
|
||||||
|
"comboCount": userData["userData"]["comboCount"],
|
||||||
|
"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": userData["banState"],
|
||||||
|
"friendRegistSkip": userData["userData"]["friendRegistSkip"],
|
||||||
|
"dateTime": TimeStamp,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"userExtend": [userExtend["userExtend"]],
|
||||||
|
"userOption": [userOption["userOption"]],
|
||||||
|
"userCharacterList": [],
|
||||||
|
"userGhost": [],
|
||||||
|
"userMapList": [],
|
||||||
|
"userLoginBonusList": [],
|
||||||
|
"userRatingList": [userRating["userRating"]],
|
||||||
|
"userItemList": [],
|
||||||
|
"userMusicDetailList": [musicData],
|
||||||
|
"userCourseList": [],
|
||||||
|
"userFriendSeasonRankingList": [],
|
||||||
|
"userChargeList": userChargeList["userChargeList"],
|
||||||
|
"userFavoriteList": [
|
||||||
|
{"itemKind": 3, "itemIdList": []},
|
||||||
|
{"itemKind": 1, "itemIdList": []},
|
||||||
|
{"itemKind": 2, "itemIdList": []},
|
||||||
|
{"itemKind": 10, "itemIdList": []},
|
||||||
|
{"itemKind": 11, "itemIdList": []},
|
||||||
|
],
|
||||||
|
"userActivityList": [userActivity["userActivity"]],
|
||||||
|
"userMissionDataList": [
|
||||||
|
{
|
||||||
|
"type": userMissionDataList["userMissionDataList"][0]["type"],
|
||||||
|
"difficulty": userMissionDataList["userMissionDataList"][0][
|
||||||
|
"difficulty"
|
||||||
|
],
|
||||||
|
"targetGenreId": userMissionDataList["userMissionDataList"][0][
|
||||||
|
"targetGenreId"
|
||||||
|
],
|
||||||
|
"targetGenreTableId": userMissionDataList["userMissionDataList"][0][
|
||||||
|
"targetGenreTableId"
|
||||||
|
],
|
||||||
|
"conditionGenreId": userMissionDataList["userMissionDataList"][0][
|
||||||
|
"conditionGenreId"
|
||||||
|
],
|
||||||
|
"conditionGenreTableId": userMissionDataList["userMissionDataList"][
|
||||||
|
0
|
||||||
|
]["conditionGenreTableId"],
|
||||||
|
"clearFlag": userMissionDataList["userMissionDataList"][0][
|
||||||
|
"clearFlag"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": userMissionDataList["userMissionDataList"][1]["type"],
|
||||||
|
"difficulty": userMissionDataList["userMissionDataList"][1][
|
||||||
|
"difficulty"
|
||||||
|
],
|
||||||
|
"targetGenreId": userMissionDataList["userMissionDataList"][1][
|
||||||
|
"targetGenreId"
|
||||||
|
],
|
||||||
|
"targetGenreTableId": userMissionDataList["userMissionDataList"][1][
|
||||||
|
"targetGenreTableId"
|
||||||
|
],
|
||||||
|
"conditionGenreId": userMissionDataList["userMissionDataList"][1][
|
||||||
|
"conditionGenreId"
|
||||||
|
],
|
||||||
|
"conditionGenreTableId": userMissionDataList["userMissionDataList"][
|
||||||
|
1
|
||||||
|
]["conditionGenreTableId"],
|
||||||
|
"clearFlag": userMissionDataList["userMissionDataList"][1][
|
||||||
|
"clearFlag"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": userMissionDataList["userMissionDataList"][2]["type"],
|
||||||
|
"difficulty": userMissionDataList["userMissionDataList"][2][
|
||||||
|
"difficulty"
|
||||||
|
],
|
||||||
|
"targetGenreId": userMissionDataList["userMissionDataList"][2][
|
||||||
|
"targetGenreId"
|
||||||
|
],
|
||||||
|
"targetGenreTableId": userMissionDataList["userMissionDataList"][2][
|
||||||
|
"targetGenreTableId"
|
||||||
|
],
|
||||||
|
"conditionGenreId": userMissionDataList["userMissionDataList"][2][
|
||||||
|
"conditionGenreId"
|
||||||
|
],
|
||||||
|
"conditionGenreTableId": userMissionDataList["userMissionDataList"][
|
||||||
|
2
|
||||||
|
]["conditionGenreTableId"],
|
||||||
|
"clearFlag": userMissionDataList["userMissionDataList"][2][
|
||||||
|
"clearFlag"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": userMissionDataList["userMissionDataList"][3]["type"],
|
||||||
|
"difficulty": userMissionDataList["userMissionDataList"][3][
|
||||||
|
"difficulty"
|
||||||
|
],
|
||||||
|
"targetGenreId": userMissionDataList["userMissionDataList"][3][
|
||||||
|
"targetGenreId"
|
||||||
|
],
|
||||||
|
"targetGenreTableId": userMissionDataList["userMissionDataList"][3][
|
||||||
|
"targetGenreTableId"
|
||||||
|
],
|
||||||
|
"conditionGenreId": userMissionDataList["userMissionDataList"][3][
|
||||||
|
"conditionGenreId"
|
||||||
|
],
|
||||||
|
"conditionGenreTableId": userMissionDataList["userMissionDataList"][
|
||||||
|
3
|
||||||
|
]["conditionGenreTableId"],
|
||||||
|
"clearFlag": userMissionDataList["userMissionDataList"][3][
|
||||||
|
"clearFlag"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": userMissionDataList["userMissionDataList"][4]["type"],
|
||||||
|
"difficulty": userMissionDataList["userMissionDataList"][4][
|
||||||
|
"difficulty"
|
||||||
|
],
|
||||||
|
"targetGenreId": userMissionDataList["userMissionDataList"][4][
|
||||||
|
"targetGenreId"
|
||||||
|
],
|
||||||
|
"targetGenreTableId": userMissionDataList["userMissionDataList"][4][
|
||||||
|
"targetGenreTableId"
|
||||||
|
],
|
||||||
|
"conditionGenreId": userMissionDataList["userMissionDataList"][4][
|
||||||
|
"conditionGenreId"
|
||||||
|
],
|
||||||
|
"conditionGenreTableId": userMissionDataList["userMissionDataList"][
|
||||||
|
4
|
||||||
|
]["conditionGenreTableId"],
|
||||||
|
"clearFlag": userMissionDataList["userMissionDataList"][4][
|
||||||
|
"clearFlag"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": userMissionDataList["userMissionDataList"][5]["type"],
|
||||||
|
"difficulty": userMissionDataList["userMissionDataList"][5][
|
||||||
|
"difficulty"
|
||||||
|
],
|
||||||
|
"targetGenreId": userMissionDataList["userMissionDataList"][5][
|
||||||
|
"targetGenreId"
|
||||||
|
],
|
||||||
|
"targetGenreTableId": userMissionDataList["userMissionDataList"][5][
|
||||||
|
"targetGenreTableId"
|
||||||
|
],
|
||||||
|
"conditionGenreId": userMissionDataList["userMissionDataList"][5][
|
||||||
|
"conditionGenreId"
|
||||||
|
],
|
||||||
|
"conditionGenreTableId": userMissionDataList["userMissionDataList"][
|
||||||
|
5
|
||||||
|
]["conditionGenreTableId"],
|
||||||
|
"clearFlag": userMissionDataList["userMissionDataList"][5][
|
||||||
|
"clearFlag"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"userWeeklyData": {
|
||||||
|
"lastLoginWeek": userMissionDataList["userWeeklyData"]["lastLoginWeek"],
|
||||||
|
"beforeLoginWeek": userMissionDataList["userWeeklyData"][
|
||||||
|
"beforeLoginWeek"
|
||||||
|
],
|
||||||
|
"friendBonusFlag": userMissionDataList["userWeeklyData"][
|
||||||
|
"friendBonusFlag"
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"userGamePlaylogList": [
|
||||||
|
{
|
||||||
|
"playlogId": loginId,
|
||||||
|
"version": userData["userData"]["lastRomVersion"],
|
||||||
|
"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": [],
|
||||||
|
},
|
||||||
|
"userIntimateList": [],
|
||||||
|
"userShopItemStockList": [],
|
||||||
|
"userGetPointList": [],
|
||||||
|
"userTradeItemList": [],
|
||||||
|
"userFavoritemusicList": [],
|
||||||
|
"userKaleidxScopeList": [],
|
||||||
|
"isNewCharacterList": "",
|
||||||
|
"isNewMapList": "",
|
||||||
|
"isNewLoginBonusList": "",
|
||||||
|
"isNewItemList": "",
|
||||||
|
"isNewMusicDetailList": "0",
|
||||||
|
"isNewCourseList": "",
|
||||||
|
"isNewFavoriteList": "11111",
|
||||||
|
"isNewFriendSeasonRankingList": "",
|
||||||
|
"isNewUserIntimateList": "",
|
||||||
|
"isNewFavoritemusicList": "",
|
||||||
|
"isNewKaleidxScopeList": "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"🫥 [INFO] userId: '{userId}', loginId: '{loginId}', loginDate: '{loginDate}', timestamp: '{TimeStamp}'"
|
||||||
|
)
|
||||||
|
return requestData_UserAll
|
||||||
115
uv.lock
generated
Normal file
115
uv.lock
generated
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
version = 1
|
||||||
|
revision = 3
|
||||||
|
requires-python = ">=3.14"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyio"
|
||||||
|
version = "4.14.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "idna" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/3b/72/5562aabb8dd7181e8e860622a38bea08d17842b99ecd4c91f84ac95251b0/anyio-4.14.1.tar.gz", hash = "sha256:8d648a3544c1a700e3ff78615cd679e4c5c3f149904287e73687b2596963629e", size = 254831, upload-time = "2026-06-24T20:56:06.017Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl", hash = "sha256:4e5533c5b8ff0a24f5d7a176cbe6877129cd183893f66b537f8f227d10527d72", size = 124875, upload-time = "2026-06-24T20:56:04.413Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "certifi"
|
||||||
|
version = "2026.6.17"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/c9/c7/424b75da314c1045981bd9777432fad05a9e0c69daa4ed7e308bbaffe405/certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432", size = 134594, upload-time = "2026-06-17T10:31:07.894Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db", size = 133289, upload-time = "2026-06-17T10:31:06.348Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "eaquira"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = { editable = "." }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "httpx" },
|
||||||
|
{ name = "pycryptodome" },
|
||||||
|
{ name = "pytz" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [
|
||||||
|
{ name = "httpx", specifier = ">=0.28.1" },
|
||||||
|
{ name = "pycryptodome", specifier = ">=3.23.0" },
|
||||||
|
{ name = "pytz", specifier = ">=2026.2" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "h11"
|
||||||
|
version = "0.16.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpcore"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "certifi" },
|
||||||
|
{ name = "h11" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpx"
|
||||||
|
version = "0.28.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "anyio" },
|
||||||
|
{ name = "certifi" },
|
||||||
|
{ name = "httpcore" },
|
||||||
|
{ name = "idna" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "3.18"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pycryptodome"
|
||||||
|
version = "3.23.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276, upload-time = "2025-05-17T17:21:45.242Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627, upload-time = "2025-05-17T17:20:47.139Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362, upload-time = "2025-05-17T17:20:50.392Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625, upload-time = "2025-05-17T17:20:52.866Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954, upload-time = "2025-05-17T17:20:55.027Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534, upload-time = "2025-05-17T17:20:57.279Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853, upload-time = "2025-05-17T17:20:59.322Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465, upload-time = "2025-05-17T17:21:03.83Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414, upload-time = "2025-05-17T17:21:06.72Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484, upload-time = "2025-05-17T17:21:08.535Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636, upload-time = "2025-05-17T17:21:10.393Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytz"
|
||||||
|
version = "2026.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/ff/46/dd499ec9038423421951e4fad73051febaa13d2df82b4064f87af8b8c0c3/pytz-2026.2.tar.gz", hash = "sha256:0e60b47b29f21574376f218fe21abc009894a2321ea16c6754f3cad6eb7cdd6a", size = 320861, upload-time = "2026-05-04T01:35:29.667Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ec/dd/96da98f892250475bdf2328112d7468abdd4acc7b902b6af23f4ed958ea0/pytz-2026.2-py2.py3-none-any.whl", hash = "sha256:04156e608bee23d3792fd45c94ae47fae1036688e75032eea2e3bf0323d1f126", size = 510141, upload-time = "2026-05-04T01:35:27.408Z" },
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user