forchannot b7a6f2eec4
📝 更新4.6数据和新抽卡记录链接 (#505)
* 📝 更新4.6 metadata

*  适配新抽卡记录链接
2024-04-24 14:35:41 +08:00

258 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import asyncio
import datetime
import time
from pathlib import Path
from typing import Dict, Union, Tuple, Optional
from nonebot import on_notice
from nonebot.adapters.onebot.v11 import GroupUploadNoticeEvent, NoticeEvent
from nonebot.rule import Rule
from LittlePaimon.database import PlayerInfo, LastQuery
from LittlePaimon.utils import logger, __version__
from LittlePaimon.utils.requests import aiorequests
from LittlePaimon.utils.api import get_authkey_by_stoken
from LittlePaimon.utils.files import load_json, save_json
from LittlePaimon.utils.path import GACHA_LOG
from .draw import draw_gacha_log
from .models import GachaItem, GachaLogInfo, GACHA_TYPE_LIST
GACHA_LOG_API = 'https://public-operation-hk4e.mihoyo.com/gacha_info/api/getGachaLog'
HEADERS: Dict[str, str] = {
'x-rpc-app_version': '2.11.1',
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 ('
'KHTML, like Gecko) miHoYoBBS/2.11.1',
'x-rpc-client_type': '5',
'Referer': 'https://webstatic.mihoyo.com/',
'Origin': 'https://webstatic.mihoyo.com',
}
PARAMS: Dict[str, Union[str, int]] = {
'authkey_ver': '1',
'sign_type': '2',
'auth_appid': 'webview_gacha',
'init_type': '200',
'gacha_id': 'fecafa7b6560db5f3182222395d88aaa6aaac1bc',
'lang': 'zh-cn',
'device_type': 'mobile',
'plat_type': 'ios',
'game_biz': 'hk4e_cn',
'size': '20',
}
def load_history_info(user_id: str, uid: str) -> Tuple[GachaLogInfo, bool]:
"""
读取历史抽卡记录数据
:param user_id: 用户id
:param uid: 原神uid
:return: 抽卡记录数据
"""
file_path = GACHA_LOG / f'gacha_log-{user_id}-{uid}.json'
if file_path.exists():
old_gacha_info = load_json(file_path)
if "集录祈愿" not in old_gacha_info["item_list"]:
old_gacha_info["item_list"]["集录祈愿"] = []
return GachaLogInfo.parse_obj(old_gacha_info), True
else:
return GachaLogInfo(user_id=user_id,
uid=uid,
update_time=datetime.datetime.now()), False
def save_gacha_log_info(user_id: str, uid: str, info: GachaLogInfo):
"""
保存抽卡记录数据
:param user_id: 用户id
:param uid: 原神uid
:param info: 抽卡记录数据
"""
save_path = GACHA_LOG / f'gacha_log-{user_id}-{uid}.json'
save_path_bak = GACHA_LOG / f'gacha_log-{user_id}-{uid}.json.bak'
# 将旧数据备份一次
if save_path.exists():
if save_path_bak.exists():
save_path_bak.unlink()
save_path.rename(save_path.parent / f'{save_path.name}.bak')
# 写入新数据
with save_path.open('w', encoding='utf-8') as f:
f.write(info.json(ensure_ascii=False, indent=4))
def gacha_log_to_UIGF(user_id: str, uid: str) -> Tuple[bool, str, Optional[Path]]:
"""
将抽卡记录转换为UIGF格式
:param user_id: 用户id
:param uid: 原神uid
"""
data, state = load_history_info(user_id, uid)
if not state:
return False, f'UID{uid}还没有抽卡记录数据,可使用命令[更新抽卡记录]更新', None
logger.info('原神抽卡记录', '', {'用户': user_id, 'UID': uid}, '导出抽卡记录', True)
save_path = Path() / 'data' / 'LittlePaimon' / 'user_data' / 'gacha_log_data' / f'gacha_log_UIGF-{user_id}-{uid}.json'
uigf_dict = {
'info': {
'uid': uid,
'lang': 'zh-cn',
'export_time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'export_timestamp': int(time.time()),
'export_app': 'LittlePaimon',
'export_app_version': __version__,
'uigf_version': 'v2.2'
},
'list': []
}
for items in data.item_list.values():
for item in items:
uigf_dict['list'].append({
'gacha_type': item.gacha_type,
'item_id': '',
'count': '1',
'time': item.time.strftime('%Y-%m-%d %H:%M:%S'),
'name': item.name,
'item_type': item.item_type,
'rank_type': item.rank_type,
'id': item.id,
'uigf_gacha_type': item.gacha_type,
'uid': uid
})
save_json(uigf_dict, save_path)
return True, '导出成功', save_path
async def get_gacha_log_data(user_id: str, uid: str):
"""
使用authkey获取抽卡记录数据并合并旧数据
:param user_id: 用户id
:param uid: 原神uid
:return: 更新结果
"""
await LastQuery.update_last_query(user_id, uid)
new_num = 0
type_new_num = {
'角色祈愿': 0,
'武器祈愿': 0,
'常驻祈愿': 0,
'新手祈愿': 0,
'集录祈愿': 0
}
server_id = 'cn_qd01' if uid[0] == '5' else 'cn_gf01'
authkey, state, cookie_info = await get_authkey_by_stoken(user_id, uid)
if not state:
return authkey
gacha_log, _ = load_history_info(user_id, uid)
params = PARAMS.copy()
params['region'] = server_id
params['authkey'] = authkey
logger.info('原神抽卡记录', '', {'用户': user_id, 'UID': uid}, '开始更新抽卡记录', True)
for pool_id, pool_name in GACHA_TYPE_LIST.items():
params['gacha_type'] = pool_id
end_id = 0
for page in range(1, 999):
params['page'] = page
params['end_id'] = end_id
params['timestamp'] = str(int(time.time()))
data = await aiorequests.get(url=GACHA_LOG_API,
headers=HEADERS,
params=params)
data = data.json()
if 'data' not in data or 'list' not in data['data']:
logger.info('原神抽卡记录', '➤➤', {}, 'Stoken已失效更新失败', False)
cookie_info.stoken = None
await cookie_info.save()
return f'UID{uid}的Stoken已失效请重新绑定或刷新cookie后再更新抽卡记录'
data = data['data']['list']
if not data:
break
for item in data:
item_info = GachaItem.parse_obj(item)
if item_info not in gacha_log.item_list[pool_name]:
gacha_log.item_list[pool_name].append(item_info)
new_num += 1
type_new_num[pool_name] += 1
end_id = data[-1]['id']
await asyncio.sleep(1)
logger.info('原神抽卡记录', f'➤➤<m>{pool_name}</m>', {}, '获取完成', True)
for i in gacha_log.item_list.values():
i.sort(key=lambda x: (x.time, x.id))
gacha_log.update_time = datetime.datetime.now()
save_gacha_log_info(user_id, uid, gacha_log)
if new_num == 0:
return f'UID{uid}更新完成,本次没有新增数据,可使用命令[查看抽卡记录]查看'
msg = f'UID{uid}更新完成,本次共新增{new_num}条抽卡记录:\n'
for pool_name, num in type_new_num.items():
if num != 0:
msg += f'{pool_name}{num}\n'
msg += '\n可使用命令[查看抽卡记录]查看'
return msg
async def get_gacha_log_img(user_id: str, uid: str, nickname: str):
"""
绘制抽卡记录图片入口
:param user_id: 用户id
:param uid: 原神uid
:param nickname: 用户昵称
:return: 抽卡记录图片
"""
await LastQuery.update_last_query(user_id, uid)
data, state = load_history_info(user_id, uid)
if not state:
return f'UID{uid}还没有抽卡记录数据,可使用命令[更新抽卡记录]更新'
if player_info := await PlayerInfo.get_or_none(user_id=user_id, uid=uid):
return await draw_gacha_log(player_info.user_id, player_info.uid, player_info.nickname, player_info.signature,
data)
else:
return await draw_gacha_log(user_id, uid, nickname, None, data)
def create_import_command(user_id: int):
"""
创建抽卡记录导入命令
:param user_id: 用户id
"""
def file_rule(event: NoticeEvent):
if isinstance(event, GroupUploadNoticeEvent) or event.notice_type == 'offline_file':
return event.dict()['user_id'] == user_id
return False
import_cmd = on_notice(priority=12, rule=Rule(file_rule), expire_time=datetime.timedelta(minutes=5), temp=True)
import_cmd.plugin_name = 'Paimon_Gacha_Log'
@import_cmd.handle()
async def _(event: NoticeEvent):
event_data = event.dict()
file_name = event_data['file']['name']
if not file_name.endswith('.json'):
await import_cmd.finish('文件格式错误请上传json文件', at_sender=True)
file_url = event_data['file']['url']
try:
data = await aiorequests.get(url=file_url)
data = data.json()
new_num = 0
uid = data['info']['uid']
await import_cmd.send(f'开始导入UID{uid}的抽卡记录,请稍候...', at_sender=True)
logger.info('原神抽卡记录', '', {'用户': user_id, 'UID': uid}, '导入抽卡记录', True)
gacha_log, _ = load_history_info(str(event_data['user_id']), uid)
for item in data['list']:
pool_name = GACHA_TYPE_LIST[item['gacha_type']]
item_info = GachaItem.parse_obj(item)
if item_info not in gacha_log.item_list[pool_name]:
gacha_log.item_list[pool_name].append(item_info)
new_num += 1
for i in gacha_log.item_list.values():
i.sort(key=lambda x: (x.time, x.id))
gacha_log.update_time = datetime.datetime.now()
save_gacha_log_info(str(event_data['user_id']), uid, gacha_log)
if new_num == 0:
await import_cmd.send(f'UID{uid}抽卡记录导入完成,本次没有新增数据', at_sender=True)
else:
await import_cmd.send(f'UID{uid}抽卡记录导入完成,共新增{new_num}条抽卡记录', at_sender=True)
except Exception:
await import_cmd.finish('导入抽卡记录失败请确认文件是否符合UIGF统一祈愿可交换标准', at_sender=True)