Files
HeXi/hexi/plugins/nonebot_plugin_bf_bot/data.py
T
sansenhoshiandClaude b61d09f09f 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>
2026-09-01 13:13:40 +08:00

285 lines
11 KiB
Python

import httpx
import re
from typing import Any, Dict, Optional
from .get_bf6_data import *
from .tracker_data import *
async def get_data_bf3(player, player_id, user_id, platform):
url = f"https://api.gametools.network/bf3/all/?format_values=true&playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false&lang=en-us"
url = f"https://api.gametools.network/bf3/all/?format_values=true&name={player}&platform={platform}&skip_battlelog=false&lang=en-us"
async with httpx.AsyncClient(timeout=10.0) as client:
# 创建两个并发任务
task_id = asyncio.create_task(client.get(url_by_id))
task_name = asyncio.create_task(client.get(url_by_name))
# 等待第一个完成的任务
done, pending = await asyncio.wait(
[task_id, task_name],
return_when=asyncio.FIRST_COMPLETED
)
# 取消未完成的任务
for task in pending:
task.cancel()
# 检查已完成的任务是否成功且无 errors
for task in done:
try:
response = await task
if response.status_code == 200:
data = response.json()
if 'errors' not in data:
logger.info(f"成功获取数据({'ID' if task is task_id else 'Name'}方式)")
return data
except (httpx.RequestError, ValueError) as e:
logger.warning(f"请求或解析失败: {e}")
if pending:
pass
# 如果所有尝试都失败,返回错误
return {"errors": ["未找到玩家"]}
async def get_data_bf4(player, player_id, user_id, platform):
url_by_id = f"https://api.gametools.network/bf4/all/?format_values=true&playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false&lang=en-us"
url_by_name = f"https://api.gametools.network/bf4/all/?format_values=true&name={player}&platform={platform}&skip_battlelog=false&lang=en-us"
async with httpx.AsyncClient(timeout=10.0) as client:
# 创建两个并发任务
task_id = asyncio.create_task(client.get(url_by_id))
task_name = asyncio.create_task(client.get(url_by_name))
# 等待第一个完成的任务
done, pending = await asyncio.wait(
[task_id, task_name],
return_when=asyncio.FIRST_COMPLETED
)
# 取消未完成的任务
for task in pending:
task.cancel()
# 检查已完成的任务是否成功且无 errors
for task in done:
try:
response = await task
if response.status_code == 200:
data = response.json()
if 'errors' not in data:
logger.info(f"成功获取数据({'ID' if task is task_id else 'Name'}方式)")
return data
except (httpx.RequestError, ValueError) as e:
logger.warning(f"请求或解析失败: {e}")
if pending:
pass
# 如果所有尝试都失败,返回错误
return {"errors": ["未找到玩家"]}
async def get_data_bf1(player, player_id, user_id, platform):
url_by_id = f"https://api.gametools.network/bf1/all/?format_values=true&playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false&lang=en-us"
url_by_name = f"https://api.gametools.network/bf1/all/?format_values=true&name={player}&platform={platform}&skip_battlelog=false&lang=en-us"
async with httpx.AsyncClient(timeout=10.0) as client:
# 创建两个并发任务
task_id = asyncio.create_task(client.get(url_by_id))
task_name = asyncio.create_task(client.get(url_by_name))
# 等待第一个完成的任务
done, pending = await asyncio.wait(
[task_id, task_name],
return_when=asyncio.FIRST_COMPLETED
)
# 取消未完成的任务
for task in pending:
task.cancel()
# 检查已完成的任务是否成功且无 errors
for task in done:
try:
response = await task
if response.status_code == 200:
data = response.json()
if 'errors' not in data:
logger.info(f"成功获取数据({'ID' if task is task_id else 'Name'}方式)")
return data
except (httpx.RequestError, ValueError) as e:
logger.warning(f"请求或解析失败: {e}")
if pending:
pass
# 如果所有尝试都失败,返回错误
return {"errors": ["未找到玩家"]}
async def get_data_bfv(player, player_id, user_id, platform):
url_by_id = f"https://api.gametools.network/bfv/all/?format_values=true&playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false&lang=en-us"
url_by_name = f"https://api.gametools.network/bfv/all/?format_values=true&name={player}&platform={platform}&skip_battlelog=false&lang=en-us"
async with httpx.AsyncClient(timeout=10.0) as client:
# 创建两个并发任务
task_id = asyncio.create_task(client.get(url_by_id))
task_name = asyncio.create_task(client.get(url_by_name))
# 等待第一个完成的任务
done, pending = await asyncio.wait(
[task_id, task_name],
return_when=asyncio.FIRST_COMPLETED
)
# 取消未完成的任务
for task in pending:
task.cancel()
# 检查已完成的任务是否成功且无 errors
for task in done:
try:
response = await task
if response.status_code == 200:
data = response.json()
if 'errors' not in data:
logger.info(f"成功获取数据({'ID' if task is task_id else 'Name'}方式)")
return data
except (httpx.RequestError, ValueError) as e:
logger.warning(f"请求或解析失败: {e}")
if pending:
pass
# 如果所有尝试都失败,返回错误
return {"errors": ["未找到玩家"]}
async def get_data_bf6(player_name, player_id, user_id, platform):
# 构造两个 URL
url_by_id = f"https://api.gametools.network/bf6/all/?format_values=true&playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false&lang=en-us"
url_by_name = f"https://api.gametools.network/bf6/all/?format_values=true&name={player_name}&platform={platform}&skip_battlelog=false&lang=en-us"
async with httpx.AsyncClient(timeout=10.0) as client:
# 创建两个并发任务
task_id = asyncio.create_task(client.get(url_by_id))
task_name = asyncio.create_task(client.get(url_by_name))
# 等待第一个完成的任务
done, pending = await asyncio.wait(
[task_id, task_name],
return_when=asyncio.FIRST_COMPLETED
)
# 取消未完成的任务
for task in pending:
task.cancel()
# 检查已完成的任务是否成功且无 errors
for task in done:
try:
response = await task
if response.status_code == 200:
data = response.json()
if 'errors' not in data:
logger.info(f"成功获取数据({'ID' if task is task_id else 'Name'}方式)")
return data
except (httpx.RequestError, ValueError) as e:
logger.warning(f"请求或解析失败: {e}")
if pending:
pass
# 如果所有尝试都失败,返回错误
return {"errors": ["未找到玩家"]}
async def get_player_info_by_name(user_name, platform):
user_info_url = f"https://api.gametools.network/bfglobal/player/?name={user_name}&platform={platform}&skip_battlelog=false"
payload = {}
headers = {
'accept': 'application/json'
}
logger.info(f"查询用户请求url:{user_info_url}")
response = requests.request("GET", user_info_url, headers=headers, data=payload)
user_info_json = json.loads(response.text)
return user_info_json
async def get_player_info_by_ea_id(player_id, user_id, platform):
url = f"https://api.gametools.network/bfglobal/player/?playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false"
payload = {}
headers = {
'accept': 'application/json'
}
response = requests.request("GET", url, headers=headers, data=payload)
user_info_json = json.loads(response.text)
return user_info_json
def normalize_name(name: str) -> str:
"""统一用户名格式(大小写 + 空格)"""
return (name or "").strip().lower()
def extract_rank(status: str) -> int:
"""从 status 中提取 Rank 数值"""
if not status:
return 0
match = re.search(r'Rank\s+(\d+)', status)
return int(match.group(1)) if match else 0
async def get_bf6_rank(player,player_id, user_id, platform):
url_by_name = f"https://api.gametools.network/bf6/profile/?name={player}&playerid=1234&nucleus_id=1234&platform=ea&skip_battlelog=true&lang=en-us"
url_by_id = f"https://api.gametools.network/bf6/profile/?name={player}&playerid=1234&nucleus_id=1234&platform=ea&skip_battlelog=true&lang=en-us"
payload = {}
headers = {
'accept': 'application/json'
}
response = requests.request("GET", url, headers=headers, data=payload)
result: Dict[str, Any] = response.json().get("playerProfiles")
logger.info(f"Tracker用户信息:{result}")
if not result or "errors" in result:
logger.warning(f"查询失败或返回错误: {player}")
return 0
data = result.get("data") or []
if not data:
logger.info(f"未搜索到用户: {player}")
return 0
norm_player = normalize_name(player)
# 评分函数(核心策略)
def score(r: Dict[str, Any]) -> int:
if not r or not r.get("status"):
return -1
name = normalize_name(r.get("platformUserHandle"))
platform = r.get("platformSlug")
s = 0
# 用户名匹配权重(最高优先级)
if name == norm_player:
s += 100
elif norm_player in name:
s += 50
# 平台权重(次优先级)
if platform == "origin":
s += 20
return s
# 选出最优 candidate
target: Optional[Dict[str, Any]] = max(data, key=score, default=None)
if not target or score(target) <= 0:
logger.info(f"未匹配到有效用户: {player}")
return 0
# 提取信息
name = target.get("platformUserHandle")
uid = target.get("titleUserId")
status = target.get("status", "")
rank = extract_rank(status)
user_info = {
"name": name,
"uid": uid,
"rank": rank,
"platform": target.get("platformSlug"),
}
logger.info(f"最终匹配用户: {user_info}")
return rank