Add HeXi bot codebase: custom plugins, web frontends, tests
- hexi core: message handling, rate limiting, cooldown, plugin manager - Custom plugins: BF stats, daily check-in, quotes, persona cards, etc. - Community plugins vendored under hexi/plugins with local fixes - Web admin frontends (learning-chat, persona-admin), unified hexi/web - Tests for rate_limit/cooldown/memes/persona; poetry.lock Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,271 @@
|
||||
from nonebot import logger
|
||||
import json
|
||||
|
||||
# from bf6_data import *
|
||||
import requests
|
||||
from curl_cffi import AsyncSession, CurlError
|
||||
from nonebot import logger
|
||||
|
||||
from .bf6_data import *
|
||||
|
||||
url_search = "https://api.tracker.gg/api/v2/bf6/standard/search?platform={platform}&query={name}&autocomplete=true"
|
||||
url_overview = "https://api.tracker.gg/api/v2/bf6/standard/profile/ign/{param}"
|
||||
|
||||
|
||||
async def format_data(response, search_type):
|
||||
status = ""
|
||||
|
||||
platform_info = response['data']['platformInfo']
|
||||
segments = response['data']['segments']
|
||||
|
||||
overview = ""
|
||||
weapons = []
|
||||
vehicles = []
|
||||
gamemodes = []
|
||||
gadgets = []
|
||||
kits = []
|
||||
maps = []
|
||||
|
||||
for segment in segments:
|
||||
if segment['type'] == 'overview':
|
||||
overview = segment
|
||||
elif segment['type'] == 'weapon':
|
||||
weapons.append(segment)
|
||||
elif segment['type'] == 'vehicle':
|
||||
vehicles.append(segment)
|
||||
elif segment['type'] == 'gamemode':
|
||||
gamemodes.append(segment)
|
||||
elif segment['type'] == 'gadget':
|
||||
gadgets.append(segment)
|
||||
elif segment['type'] == 'kit':
|
||||
kits.append(segment)
|
||||
elif segment['type'] == 'level':
|
||||
maps.append(segment)
|
||||
if search_type == 0:
|
||||
status = await get_overview(platform_info, overview, weapons, vehicles, gamemodes, gadgets, kits, maps)
|
||||
if search_type == 1:
|
||||
status = await get_weapons(platform_info, overview, weapons, vehicles, gamemodes, gadgets, kits, maps)
|
||||
|
||||
return status
|
||||
|
||||
|
||||
async def get_user_id_2_data(title_id, search_type):
|
||||
url = url_overview.format(param=title_id)
|
||||
info = await search_user_with_fallback(url)
|
||||
info = await format_data(info, search_type)
|
||||
return info
|
||||
|
||||
|
||||
# 调用此方法获取格式化后的数据(调用此方法即可)
|
||||
async def get_info(player, search_type):
|
||||
# 先使用橘子搜索
|
||||
url = url_search.format(platform="orign", name=player)
|
||||
result = await search_user_with_fallback(url)
|
||||
# 无结果再使用steam搜索
|
||||
if "errors" in result:
|
||||
url = url_search.format(platform="steam", name=player)
|
||||
result = await search_user_with_fallback(url)
|
||||
title_id_list = []
|
||||
logger.info(f"查询结果: \n{json.dumps(result, ensure_ascii=False, indent=2)}")
|
||||
if "status" in result or "errors" in result:
|
||||
return 3, '查询异常'
|
||||
for res in result['data']:
|
||||
if res['status'] is not None:
|
||||
name = res['platformUserHandle']
|
||||
uid = res['titleUserId']
|
||||
status = res['status'].strip().split('•', 1)[0].replace("Rank", "")
|
||||
user = {
|
||||
'name': name,
|
||||
'rank': status,
|
||||
'uid': uid,
|
||||
}
|
||||
title_id_list.append(user)
|
||||
if len(title_id_list) > 1:
|
||||
user_list = sorted(title_id_list, key=lambda k: int(k['rank']), reverse=True)
|
||||
msg = '\n'.join(f'用户名:{info["name"]}-等级:{info["rank"]}-UID:{info["uid"]}' for info in user_list)
|
||||
logger.info(f"检测到多个同名用户\n{msg}")
|
||||
return 0, title_id_list
|
||||
elif len(title_id_list) == 1:
|
||||
logger.info(f"单用户{title_id_list}")
|
||||
info = await get_user_id_2_data(title_id_list[0]['uid'], search_type)
|
||||
logger.info(f"查询结果: {json.dumps(info, ensure_ascii=False, indent=2)}")
|
||||
return 1, info
|
||||
else:
|
||||
logger.info(f"未查询到用户")
|
||||
return 2, '未查询到用户'
|
||||
|
||||
|
||||
async def get_overview(platform_info, overview, weapons, vehicles, gamemodes, gadgets, kits, maps):
|
||||
top_kill_weapon = sorted(weapons, key=lambda k: k['stats']['kills']['value'], reverse=True)[0]
|
||||
best_weapon = {
|
||||
"名称": top_kill_weapon['metadata']['name'],
|
||||
"击杀": top_kill_weapon['stats']['kills']['value'],
|
||||
"KPM": top_kill_weapon['stats']['killsPerMinute']['value'],
|
||||
"时长": top_kill_weapon['stats']['timePlayed']['displayValue'],
|
||||
"爆头率": top_kill_weapon['stats']['headshotPercentage']['displayValue'],
|
||||
"命中率": top_kill_weapon['stats']['shotsAccuracy']['displayValue']
|
||||
}
|
||||
top_kill_vehicle = sorted(vehicles, key=lambda k: k['stats']['kills']['value'], reverse=True)[0]
|
||||
best_vehicle = {
|
||||
"名称": top_kill_vehicle['metadata']['name'],
|
||||
"击杀": top_kill_vehicle['stats']['kills']['value'],
|
||||
"KPM": top_kill_vehicle['stats']['killsPerMinute']['value'],
|
||||
"时长": top_kill_vehicle['stats']['timePlayed']['displayValue'],
|
||||
"碾压": top_kill_vehicle['stats']['roadKills']['value'],
|
||||
"摧毁": top_kill_vehicle['stats']['destroyedWith']['value'],
|
||||
|
||||
}
|
||||
shot_count = overview['stats']['shotsFired']['value']
|
||||
hit_count = overview['stats']['shotsHit']['value']
|
||||
logger.info(f"开火数:{shot_count}")
|
||||
logger.info(f"命中数:{hit_count}")
|
||||
acc = round((hit_count / shot_count) * 100, 2)
|
||||
logger.info(f"命中率:{acc}%")
|
||||
player_info = {
|
||||
'玩家名称': platform_info['platformUserHandle'],
|
||||
'游玩平台': platform_info['platformSlug'],
|
||||
'游戏等级': overview['stats']['careerPlayerRank']['displayValue'],
|
||||
'游玩时长': overview['stats']['timePlayed']['displayValue'],
|
||||
'游玩场次': overview['stats']['matchesPlayed']['displayValue'],
|
||||
'对局胜率': overview['stats']['wlPercentage']['displayValue'],
|
||||
'对局得分': overview['stats']['score']['displayValue'],
|
||||
'玩家K/D': overview['stats']['kdRatio']['value'],
|
||||
'玩家KPM': overview['stats']['killsPerMinute']['value'],
|
||||
'玩家SPM': overview['stats']['scorePerMinute']['value'],
|
||||
'真人击杀': overview['stats']['playerKills']['displayValue'],
|
||||
'击杀总计': overview['stats']['kills']['displayValue'],
|
||||
'目标占领': overview['stats']['objectivesCaptured']['value'],
|
||||
'游戏助攻': overview['stats']['assists']['displayValue'],
|
||||
'救援数量': overview['stats']['revives']['displayValue'],
|
||||
'最高连杀': overview['stats']['multiKills']['value'],
|
||||
'命中率': f"{acc}%",
|
||||
'爆头率': overview['stats']['headshotPercentage']['displayValue'],
|
||||
'最佳武器': best_weapon,
|
||||
'最佳载具': best_vehicle,
|
||||
}
|
||||
return player_info
|
||||
|
||||
|
||||
async def get_weapons(platform_info, overview, weapons, vehicles, gamemodes, gadgets, kits, maps):
|
||||
top_kill_weapon = sorted(weapons, key=lambda k: k['stats']['kills']['value'], reverse=True)[0]
|
||||
best_weapon = {
|
||||
"名称": top_kill_weapon['metadata']['name'],
|
||||
"击杀": top_kill_weapon['stats']['kills']['value'],
|
||||
"KPM": top_kill_weapon['stats']['killsPerMinute']['value'],
|
||||
"时长": top_kill_weapon['stats']['timePlayed']['displayValue'],
|
||||
"爆头率": top_kill_weapon['stats']['headshotPercentage']['displayValue'],
|
||||
"命中率": top_kill_weapon['stats']['shotsAccuracy']['displayValue']
|
||||
}
|
||||
top_kill_vehicle = sorted(vehicles, key=lambda k: k['stats']['kills']['value'], reverse=True)[0]
|
||||
best_vehicle = {
|
||||
"名称": top_kill_vehicle['metadata']['name'],
|
||||
"击杀": top_kill_vehicle['stats']['kills']['value'],
|
||||
"KPM": top_kill_vehicle['stats']['killsPerMinute']['value'],
|
||||
"时长": top_kill_vehicle['stats']['timePlayed']['displayValue'],
|
||||
"碾压": top_kill_vehicle['stats']['roadKills']['value'],
|
||||
"摧毁": top_kill_vehicle['stats']['destroyedWith']['value'],
|
||||
|
||||
}
|
||||
shot_count = overview['stats']['shotsFired']['value']
|
||||
hit_count = overview['stats']['shotsHit']['value']
|
||||
logger.info(f"开火数:{shot_count}")
|
||||
logger.info(f"命中数:{hit_count}")
|
||||
acc = round((hit_count / shot_count) * 100, 2)
|
||||
logger.info(f"命中率:{acc}%")
|
||||
player_info = {
|
||||
'玩家名称': platform_info['platformUserHandle'],
|
||||
'游玩平台': platform_info['platformSlug'],
|
||||
'游戏等级': overview['stats']['careerPlayerRank']['displayValue'],
|
||||
'游玩时长': overview['stats']['timePlayed']['displayValue'],
|
||||
'游玩场次': overview['stats']['matchesPlayed']['displayValue'],
|
||||
'对局胜率': overview['stats']['wlPercentage']['displayValue'],
|
||||
'对局得分': overview['stats']['score']['displayValue'],
|
||||
'玩家K/D': overview['stats']['kdRatio']['value'],
|
||||
'玩家KPM': overview['stats']['killsPerMinute']['value'],
|
||||
'玩家SPM': overview['stats']['scorePerMinute']['value'],
|
||||
'真人击杀': overview['stats']['playerKills']['displayValue'],
|
||||
'击杀总计': overview['stats']['kills']['displayValue'],
|
||||
'目标占领': overview['stats']['objectivesCaptured']['value'],
|
||||
'游戏助攻': overview['stats']['assists']['displayValue'],
|
||||
'救援数量': overview['stats']['revives']['displayValue'],
|
||||
'最高连杀': overview['stats']['multiKills']['value'],
|
||||
'命中率': f"{acc}%",
|
||||
'爆头率': overview['stats']['headshotPercentage']['displayValue'],
|
||||
'最佳武器': best_weapon,
|
||||
'最佳载具': best_vehicle,
|
||||
}
|
||||
return player_info
|
||||
|
||||
|
||||
async def get_vehicles(platform_info, overview, weapons, vehicles, gamemodes, gadgets, kits, maps):
|
||||
top_kill_weapon = sorted(weapons, key=lambda k: k['stats']['kills']['value'], reverse=True)[0]
|
||||
best_weapon = {
|
||||
"名称": top_kill_weapon['metadata']['name'],
|
||||
"击杀": top_kill_weapon['stats']['kills']['value'],
|
||||
"KPM": top_kill_weapon['stats']['killsPerMinute']['value'],
|
||||
"时长": top_kill_weapon['stats']['timePlayed']['displayValue'],
|
||||
"爆头率": top_kill_weapon['stats']['headshotPercentage']['displayValue'],
|
||||
"命中率": top_kill_weapon['stats']['shotsAccuracy']['displayValue']
|
||||
}
|
||||
top_kill_vehicle = sorted(vehicles, key=lambda k: k['stats']['kills']['value'], reverse=True)[0]
|
||||
best_vehicle = {
|
||||
"名称": top_kill_vehicle['metadata']['name'],
|
||||
"击杀": top_kill_vehicle['stats']['kills']['value'],
|
||||
"KPM": top_kill_vehicle['stats']['killsPerMinute']['value'],
|
||||
"时长": top_kill_vehicle['stats']['timePlayed']['displayValue'],
|
||||
"碾压": top_kill_vehicle['stats']['roadKills']['value'],
|
||||
"摧毁": top_kill_vehicle['stats']['destroyedWith']['value'],
|
||||
|
||||
}
|
||||
shot_count = overview['stats']['shotsFired']['value']
|
||||
hit_count = overview['stats']['shotsHit']['value']
|
||||
logger.info(f"开火数:{shot_count}")
|
||||
logger.info(f"命中数:{hit_count}")
|
||||
acc = round((hit_count / shot_count) * 100, 2)
|
||||
logger.info(f"命中率:{acc}%")
|
||||
player_info = {
|
||||
'玩家名称': platform_info['platformUserHandle'],
|
||||
'游玩平台': platform_info['platformSlug'],
|
||||
'游戏等级': overview['stats']['careerPlayerRank']['displayValue'],
|
||||
'游玩时长': overview['stats']['timePlayed']['displayValue'],
|
||||
'游玩场次': overview['stats']['matchesPlayed']['displayValue'],
|
||||
'对局胜率': overview['stats']['wlPercentage']['displayValue'],
|
||||
'对局得分': overview['stats']['score']['displayValue'],
|
||||
'玩家K/D': overview['stats']['kdRatio']['value'],
|
||||
'玩家KPM': overview['stats']['killsPerMinute']['value'],
|
||||
'玩家SPM': overview['stats']['scorePerMinute']['value'],
|
||||
'真人击杀': overview['stats']['playerKills']['displayValue'],
|
||||
'击杀总计': overview['stats']['kills']['displayValue'],
|
||||
'目标占领': overview['stats']['objectivesCaptured']['value'],
|
||||
'游戏助攻': overview['stats']['assists']['displayValue'],
|
||||
'救援数量': overview['stats']['revives']['displayValue'],
|
||||
'最高连杀': overview['stats']['multiKills']['value'],
|
||||
'命中率': f"{acc}%",
|
||||
'爆头率': overview['stats']['headshotPercentage']['displayValue'],
|
||||
'最佳武器': best_weapon,
|
||||
'最佳载具': best_vehicle,
|
||||
}
|
||||
return player_info
|
||||
|
||||
|
||||
async def get_bf6_data(player_id, user_id, platform):
|
||||
|
||||
url = "https://api.gametools.network/bf6/multiple/?raw=false&format_values=true"
|
||||
|
||||
payload = json.dumps([
|
||||
{
|
||||
"player_id": player_id,
|
||||
"user_id": user_id,
|
||||
"platform": platform
|
||||
}
|
||||
])
|
||||
headers = {
|
||||
'accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
player_stat_json = json.loads(response.text)
|
||||
|
||||
return player_stat_json
|
||||
Reference in New Issue
Block a user