mirror of
https://github.com/KimigaiiWuyi/GenshinUID.git
synced 2025-05-07 12:43:26 +08:00
✨ 新增gsrc
This commit is contained in:
parent
f66336a293
commit
74a20a54db
14
GenshinUID/genshinuid_topup/__init__.py
Normal file
14
GenshinUID/genshinuid_topup/__init__.py
Normal file
@ -0,0 +1,14 @@
|
||||
from gsuid_core.sv import SV
|
||||
from gsuid_core.bot import Bot
|
||||
from gsuid_core.models import Event
|
||||
|
||||
from .gs_topup import topup_
|
||||
|
||||
|
||||
@SV('原神充值').on_fullmatch(('gsrc', '原神充值'))
|
||||
async def send_qrcode_login(bot: Bot, ev: Event):
|
||||
await bot.logger.info('开始执行[原神充值]')
|
||||
goods_id = int(ev.text) if ev.text.isdigit() else None
|
||||
if goods_id is None:
|
||||
return await bot.send('请输入正确的商品编号(1~6), 例如原神充值6!')
|
||||
await topup_(bot, ev.bot_id, ev.user_id, ev.group_id, ev.text)
|
93
GenshinUID/genshinuid_topup/gs_topup.py
Normal file
93
GenshinUID/genshinuid_topup/gs_topup.py
Normal file
@ -0,0 +1,93 @@
|
||||
import io
|
||||
import base64
|
||||
import asyncio
|
||||
import traceback
|
||||
|
||||
import qrcode
|
||||
from gsuid_core.bot import Bot
|
||||
from nonebot.log import logger
|
||||
from qrcode import ERROR_CORRECT_L
|
||||
from gsuid_core.segment import MessageSegment
|
||||
|
||||
from ..utils.mys_api import mys_api
|
||||
from ..utils.database import get_sqla
|
||||
from ..utils.error_reply import get_error
|
||||
from ..gsuid_utils.api.mys.models import MysOrder
|
||||
|
||||
disnote = '''免责声明:
|
||||
该充值接口由米游社提供,不对充值结果负责。
|
||||
请在充值前仔细阅读米哈游的充值条款。
|
||||
'''
|
||||
|
||||
|
||||
def get_qrcode_base64(url: str):
|
||||
qr = qrcode.QRCode(
|
||||
version=1,
|
||||
error_correction=ERROR_CORRECT_L,
|
||||
box_size=10,
|
||||
border=4,
|
||||
)
|
||||
qr.add_data(url)
|
||||
qr.make(fit=True)
|
||||
img = qr.make_image(fill_color='black', back_color='white')
|
||||
img_byte = io.BytesIO()
|
||||
img.save(img_byte, format='PNG') # type:ignore
|
||||
img_byte = img_byte.getvalue()
|
||||
return base64.b64encode(img_byte).decode()
|
||||
|
||||
|
||||
async def refresh(order: MysOrder, uid: str) -> str:
|
||||
times = 0
|
||||
while True:
|
||||
await asyncio.sleep(5)
|
||||
order_status = await mys_api.check_order(order, uid)
|
||||
if isinstance(order_status, int):
|
||||
return get_error(order_status)
|
||||
if order_status['status'] != 900:
|
||||
pass
|
||||
else:
|
||||
return '支付成功'
|
||||
times += 1
|
||||
if times > 60:
|
||||
return '支付超时'
|
||||
|
||||
|
||||
async def topup_(
|
||||
bot: Bot, bot_id: str, user_id: str, group_id: str, goods_id: int
|
||||
):
|
||||
sqla = get_sqla(bot_id)
|
||||
uid = await sqla.get_bind_uid(user_id)
|
||||
if uid is None:
|
||||
return await bot.send('未绑定米游社账号')
|
||||
fetchgoods_data = await mys_api.get_fetchgoods()
|
||||
if isinstance(fetchgoods_data, int):
|
||||
return await bot.send(get_error(fetchgoods_data))
|
||||
if goods_id < len(fetchgoods_data):
|
||||
goods_data = fetchgoods_data[goods_id]
|
||||
else:
|
||||
return await bot.send('商品不存在,最大为' + str(len(fetchgoods_data) - 1))
|
||||
order = await mys_api.topup(uid, goods_data)
|
||||
if isinstance(order, int):
|
||||
logger.warning(f'[充值] {group_id} {user_id} 出错!')
|
||||
return await bot.send(get_error(order))
|
||||
try:
|
||||
im = []
|
||||
b64_data = get_qrcode_base64(order['encode_order'])
|
||||
qrc = MessageSegment.image(b64_data)
|
||||
im.append(MessageSegment.text(f'充值uid:{uid}'))
|
||||
im.append(
|
||||
MessageSegment.text(
|
||||
f'商品名称:{goods_data["goods_name"]}×{goods_data["goods_unit"]}'
|
||||
if int(goods_data['goods_unit']) > 0
|
||||
else goods_data['goods_name']
|
||||
),
|
||||
)
|
||||
im.append(MessageSegment.text(f'商品价格:{int(order["amount"])/100}'))
|
||||
im.append(MessageSegment.text(f'订单号:{order["order_no"]}'))
|
||||
im.append(MessageSegment.text(disnote))
|
||||
im.append(MessageSegment.text(qrc))
|
||||
return await bot.send(MessageSegment.node(im))
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
logger.warning(f'[充值] {group_id} 图片发送失败')
|
||||
return await bot.send(await refresh(order, uid))
|
@ -116,4 +116,10 @@ bbs_Detailurl = BBS_URL + '/post/api/getPostFull?post_id={}'
|
||||
bbs_Shareurl = BBS_URL + '/apihub/api/getShareConf?entity_id={}&entity_type=1'
|
||||
bbs_Likeurl = f'{BBS_URL}/apihub/sapi/upvotePost'
|
||||
|
||||
# 原神充值中心
|
||||
fetchGoodsurl = f"{HK4_SDK_URL}/hk4e_cn/mdk/shopwindow/shopwindow/fetchGoods"
|
||||
CreateOrderurl = f"{HK4_SDK_URL}/hk4e_cn/mdk/atropos/api/createOrder"
|
||||
CheckOrderurl = f"{HK4_SDK_URL}/hk4e_cn/mdk/atropos/api/checkOrder"
|
||||
PriceTierurl = f"{HK4_SDK_URL}/hk4e_cn/mdk/shopwindow/shopwindow/listPriceTier"
|
||||
|
||||
_API = locals()
|
||||
|
@ -591,3 +591,58 @@ class MysGameSwitch(TypedDict):
|
||||
switch_id: int
|
||||
is_public: bool
|
||||
switch_name: str
|
||||
|
||||
|
||||
class MysGoods(TypedDict):
|
||||
goods_id: str
|
||||
goods_name: str
|
||||
goods_name_i18n_key: str
|
||||
goods_desc: str
|
||||
goods_desc_i18n_key: str
|
||||
goods_type: Literal['Normal', 'Special']
|
||||
goods_unit: str
|
||||
goods_icon: str
|
||||
currency: Literal['CNY']
|
||||
price: str
|
||||
symbol: Literal['¥']
|
||||
tier_id: Literal['Tier_1']
|
||||
bonus_desc: MysGoodsBonus
|
||||
once_bonus_desc: MysGoodsBonus
|
||||
available: bool
|
||||
tips_desc: str
|
||||
tips_i18n_key: str
|
||||
battle_pass_limit: str
|
||||
|
||||
|
||||
class MysGoodsBonus(TypedDict):
|
||||
bonus_desc: str
|
||||
bonus_desc_i18n_key: str
|
||||
bonus_unit: int
|
||||
bonus_goods_id: str
|
||||
bonus_icon: str
|
||||
|
||||
|
||||
class MysOrderCheck(TypedDict):
|
||||
status: int # 900为成功
|
||||
amount: str
|
||||
goods_title: str
|
||||
goods_num: str
|
||||
order_no: str
|
||||
pay_plat: Literal['alipay']
|
||||
|
||||
|
||||
class MysOrder(TypedDict):
|
||||
goods_id: str
|
||||
order_no: str
|
||||
currency: Literal['CNY']
|
||||
amount: str
|
||||
redirect_url: str
|
||||
foreign_serial: str
|
||||
encode_order: str
|
||||
account: str # mysid
|
||||
create_time: str
|
||||
ext_info: str
|
||||
balance: str
|
||||
method: str
|
||||
action: str
|
||||
session_cookie: str
|
||||
|
@ -19,6 +19,7 @@ from .tools import (
|
||||
random_text,
|
||||
get_ds_token,
|
||||
generate_os_ds,
|
||||
gen_payment_sign,
|
||||
get_web_ds_token,
|
||||
generate_passport_ds,
|
||||
)
|
||||
@ -28,6 +29,8 @@ from .models import (
|
||||
MysSign,
|
||||
RegTime,
|
||||
GachaLog,
|
||||
MysGoods,
|
||||
MysOrder,
|
||||
SignInfo,
|
||||
SignList,
|
||||
AbyssData,
|
||||
@ -38,6 +41,7 @@ from .models import (
|
||||
CalculateInfo,
|
||||
DailyNoteData,
|
||||
GameTokenInfo,
|
||||
MysOrderCheck,
|
||||
CharDetailData,
|
||||
CookieTokenInfo,
|
||||
LoginTicketInfo,
|
||||
@ -642,6 +646,90 @@ class MysApi:
|
||||
else:
|
||||
return data
|
||||
|
||||
async def get_fetchgoods(self) -> Union[int, List[MysGoods]]:
|
||||
data = {
|
||||
'released_flag': True,
|
||||
'game': 'hk4e_cn',
|
||||
'region': 'cn_gf01',
|
||||
'uid': '1',
|
||||
'account': '1',
|
||||
}
|
||||
resp = await self._mys_request(
|
||||
url=_API['fetchGoodsurl'],
|
||||
method='POST',
|
||||
data=data,
|
||||
)
|
||||
if isinstance(resp, int):
|
||||
return resp
|
||||
return cast(List[MysGoods], resp['data']['goods_list'])
|
||||
|
||||
async def topup(self, uid: str, goods: MysGoods) -> Union[int, MysOrder]:
|
||||
device_id = str(uuid.uuid4())
|
||||
HEADER = copy.deepcopy(_HEADER)
|
||||
ck = await self.get_ck(uid, 'OWNER')
|
||||
if ck is None:
|
||||
return -51
|
||||
HEADER['Cookie'] = ck
|
||||
account = HEADER['Cookie'].split('account_id=')[1].split(';')[0]
|
||||
order = {
|
||||
'account': str(account),
|
||||
'region': 'cn_gf01',
|
||||
'uid': uid,
|
||||
'delivery_url': '',
|
||||
'device': device_id,
|
||||
'channel_id': 1,
|
||||
'client_ip': '',
|
||||
'client_type': 4,
|
||||
'game': 'hk4e_cn',
|
||||
'amount': goods['price'],
|
||||
# 'amount': 600,
|
||||
'goods_num': 1,
|
||||
'goods_id': goods['goods_id'],
|
||||
'goods_title': f'{goods["goods_name"]}×{str(goods["goods_unit"])}'
|
||||
if int(goods['goods_unit']) > 0
|
||||
else goods['goods_name'],
|
||||
'price_tier': goods['tier_id'],
|
||||
# 'price_tier': 'Tier_1',
|
||||
'currency': 'CNY',
|
||||
'pay_plat': 'alipay',
|
||||
}
|
||||
data = {'order': order, 'sign': gen_payment_sign(order)}
|
||||
HEADER['x-rpc-device_id'] = device_id
|
||||
HEADER['x-rpc-client_type'] = '4'
|
||||
resp = await self._mys_request(
|
||||
url=_API['CreateOrderurl'],
|
||||
method='POST',
|
||||
header=HEADER,
|
||||
data=data,
|
||||
)
|
||||
if isinstance(resp, int):
|
||||
return resp
|
||||
return cast(MysOrder, resp['data'])
|
||||
|
||||
async def check_order(
|
||||
self, order: MysOrder, uid: str
|
||||
) -> Union[int, MysOrderCheck]:
|
||||
HEADER = copy.deepcopy(_HEADER)
|
||||
ck = await self.get_ck(uid, 'OWNER')
|
||||
if ck is None:
|
||||
return -51
|
||||
HEADER['Cookie'] = ck
|
||||
data = {
|
||||
'order_no': order['order_no'],
|
||||
'game': 'hk4e_cn',
|
||||
'region': 'cn_gf01',
|
||||
'uid': uid,
|
||||
}
|
||||
resp = await self._mys_request(
|
||||
url=_API['CheckOrderurl'],
|
||||
method='GET',
|
||||
header=HEADER,
|
||||
params=data,
|
||||
)
|
||||
if isinstance(resp, int):
|
||||
return resp
|
||||
return cast(MysOrderCheck, resp['data'])
|
||||
|
||||
async def simple_mys_req(
|
||||
self,
|
||||
URL: str,
|
||||
@ -657,7 +745,6 @@ class MysApi:
|
||||
server_id = RECOGNIZE_SERVER.get(uid[0])
|
||||
is_os = False if int(uid[0]) < 6 else True
|
||||
ex_params = '&'.join([f'{k}={v}' for k, v in params.items()])
|
||||
print(ex_params)
|
||||
if is_os:
|
||||
_URL = _API[f'{URL}_OS']
|
||||
HEADER = copy.deepcopy(_HEADER_OS)
|
||||
|
@ -1,3 +1,4 @@
|
||||
import hmac
|
||||
import json
|
||||
import time
|
||||
import random
|
||||
@ -76,3 +77,17 @@ def generate_os_ds(salt: str = '') -> str:
|
||||
|
||||
def generate_passport_ds(q: str = '', b: Optional[Dict[str, Any]] = None):
|
||||
return _random_str_ds(_S['PD'], string.ascii_letters, True, q, b)
|
||||
|
||||
|
||||
def HMCASHA256(data: str, key: str):
|
||||
key_bytes = key.encode('utf-8')
|
||||
message = data.encode('utf-8')
|
||||
sign = hmac.new(key_bytes, message, digestmod=hashlib.sha256).digest()
|
||||
return sign.hex()
|
||||
|
||||
|
||||
def gen_payment_sign(data):
|
||||
data = dict(sorted(data.items(), key=lambda x: x[0]))
|
||||
value = ''.join([str(i) for i in data.values()])
|
||||
sign = HMCASHA256(value, '6bdc3982c25f3f3c38668a32d287d16b')
|
||||
return sign
|
||||
|
6
poetry.lock
generated
6
poetry.lock
generated
@ -1544,14 +1544,14 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "3.1.0"
|
||||
version = "3.1.1"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "platformdirs-3.1.0-py3-none-any.whl", hash = "sha256:13b08a53ed71021350c9e300d4ea8668438fb0046ab3937ac9a29913a1a1350a"},
|
||||
{file = "platformdirs-3.1.0.tar.gz", hash = "sha256:accc3665857288317f32c7bebb5a8e482ba717b474f3fc1d18ca7f9214be0cef"},
|
||||
{file = "platformdirs-3.1.1-py3-none-any.whl", hash = "sha256:e5986afb596e4bb5bde29a79ac9061aa955b94fca2399b7aaac4090860920dd8"},
|
||||
{file = "platformdirs-3.1.1.tar.gz", hash = "sha256:024996549ee88ec1a9aa99ff7f8fc819bb59e2c3477b410d90a16d32d6e707aa"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
Loading…
x
Reference in New Issue
Block a user