mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-05 03:39:59 +08:00
update 0.0.7.0
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
from nonebot import on_command
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
|
||||
from services.log import logger
|
||||
from .data_source import query_role_data
|
||||
from ..models import Genshin
|
||||
from utils.utils import get_message_text, is_number
|
||||
|
||||
|
||||
__zx_plugin_name__ = "原神玩家查询"
|
||||
__plugin_usage__ = """
|
||||
usage:
|
||||
通过uid查询原神玩家信息
|
||||
指令:
|
||||
原神玩家查询/ys ?[uid]
|
||||
示例:原神玩家查询 92342233
|
||||
""".strip()
|
||||
__plugin_des__ = "请问你们有几个肝?"
|
||||
__plugin_cmd__ = ["原神玩家查询/ys"]
|
||||
__plugin_type__ = ("原神相关",)
|
||||
__plugin_version__ = 0.1
|
||||
__plugin_author__ = "HibiKier"
|
||||
__plugin_settings__ = {
|
||||
"level": 5,
|
||||
"default_status": True,
|
||||
"limit_superuser": False,
|
||||
"cmd": ["原神玩家查询"],
|
||||
}
|
||||
|
||||
|
||||
query_role_info_matcher = on_command("原神玩家查询", aliases={"原神玩家查找", "ys"}, priority=5, block=True)
|
||||
|
||||
|
||||
@query_role_info_matcher.handle()
|
||||
async def _(bot: Bot, event: MessageEvent, state: T_State):
|
||||
msg = get_message_text(event.json())
|
||||
if msg:
|
||||
if not is_number(msg):
|
||||
await query_role_info_matcher.finish("查询uid必须为数字!")
|
||||
msg = int(msg)
|
||||
if not msg:
|
||||
uid = await Genshin.get_user_uid(event.user_id)
|
||||
else:
|
||||
uid = msg
|
||||
if not uid: # or not await Genshin.get_user_cookie(uid):
|
||||
await query_role_info_matcher.finish("请先绑定uid和cookie!")
|
||||
nickname = event.sender.card if event.sender.card else event.sender.nickname
|
||||
mys_id = await Genshin.get_user_mys_id(uid)
|
||||
data = await query_role_data(event.user_id, uid, mys_id, nickname)
|
||||
if data:
|
||||
await query_role_info_matcher.send(data)
|
||||
logger.info(
|
||||
f"(USER {event.user_id}, "
|
||||
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 使用原神玩家查询 uid:{uid}"
|
||||
)
|
||||
else:
|
||||
await query_role_info_matcher.send("查询失败..")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
from typing import Optional, List, Dict, Union
|
||||
from .draw_image import init_image, get_genshin_image
|
||||
from nonebot.adapters.cqhttp import MessageSegment
|
||||
from ..utils import get_ds, element_mastery
|
||||
from services.log import logger
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from configs.config import Config
|
||||
from ..models import Genshin
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ModuleNotFoundError:
|
||||
import json
|
||||
|
||||
|
||||
async def query_role_data(
|
||||
user_id: int, uid: int, mys_id: Optional[str] = None, nickname: Optional[str] = None
|
||||
) -> Optional[Union[MessageSegment, str]]:
|
||||
uid = str(uid)
|
||||
if uid[0] == "1" or uid[0] == "2":
|
||||
server_id = "cn_gf01"
|
||||
elif uid[0] == "5":
|
||||
server_id = "cn_qd01"
|
||||
else:
|
||||
return None
|
||||
return await get_image(user_id, uid, server_id, mys_id, nickname)
|
||||
|
||||
|
||||
async def get_image(
|
||||
user_id: int,
|
||||
uid: str,
|
||||
server_id: str,
|
||||
mys_id: Optional[str] = None,
|
||||
nickname: Optional[str] = None,
|
||||
) -> Optional[Union[MessageSegment, str]]:
|
||||
"""
|
||||
生成图片
|
||||
:param user_id:用户qq
|
||||
:param uid: 用户uid
|
||||
:param server_id: 服务器
|
||||
:param mys_id: 米游社id
|
||||
:param nickname: QQ昵称
|
||||
:return:
|
||||
"""
|
||||
data, code = await get_info(uid, server_id)
|
||||
if code != 200:
|
||||
return data
|
||||
if data:
|
||||
char_data_list, role_data, world_data_dict, home_data_list = parsed_data(data)
|
||||
mys_data = await get_mys_data(uid, mys_id)
|
||||
if mys_data:
|
||||
nickname = None
|
||||
if char_data_list:
|
||||
char_detailed_data = await get_character(
|
||||
uid, [x["id"] for x in char_data_list], server_id
|
||||
)
|
||||
_x = {}
|
||||
if char_detailed_data:
|
||||
for char in char_detailed_data["avatars"]:
|
||||
_x[char["name"]] = {
|
||||
"weapon": char["weapon"]["name"],
|
||||
"weapon_image": char["weapon"]["icon"],
|
||||
"level": char["weapon"]["level"],
|
||||
"affix_level": char["weapon"]["affix_level"],
|
||||
}
|
||||
|
||||
await init_image(char_data_list, _x)
|
||||
return await get_genshin_image(
|
||||
user_id,
|
||||
uid,
|
||||
char_data_list,
|
||||
role_data,
|
||||
world_data_dict,
|
||||
home_data_list,
|
||||
_x,
|
||||
mys_data,
|
||||
nickname,
|
||||
)
|
||||
return "未找到用户数据..."
|
||||
|
||||
|
||||
# Github-@lulu666lulu https://github.com/Azure99/GenshinPlayerQuery/issues/20
|
||||
"""
|
||||
{body:"",query:{"action_ticket": undefined, "game_biz": "hk4e_cn”}}
|
||||
对应 https://api-takumi.mihoyo.com/binding/api/getUserGameRolesByCookie?game_biz=hk4e_cn //查询米哈游账号下绑定的游戏(game_biz可留空)
|
||||
{body:"",query:{"uid": 12345(被查询账号米哈游uid)}}
|
||||
对应 https://api-takumi.mihoyo.com/game_record/app/card/wapi/getGameRecordCard?uid=
|
||||
{body:"",query:{'role_id': '查询账号的uid(游戏里的)' ,'server': '游戏服务器'}}
|
||||
对应 https://api-takumi.mihoyo.com/game_record/app/genshin/api/index?server= server信息 &role_id= 游戏uid
|
||||
{body:"",query:{'role_id': '查询账号的uid(游戏里的)' , 'schedule_type': 1(我这边只看到出现过1和2), 'server': 'cn_gf01'}}
|
||||
对应 https://api-takumi.mihoyo.com/game_record/app/genshin/api/spiralAbyss?schedule_type=1&server= server信息 &role_id= 游戏uid
|
||||
{body:"",query:{game_id: 2(目前我知道有崩坏3是1原神是2)}}
|
||||
对应 https://api-takumi.mihoyo.com/game_record/app/card/wapi/getAnnouncement?game_id= 这个是公告api
|
||||
b=body q=query
|
||||
其中b只在post的时候有内容,q只在get的时候有内容
|
||||
"""
|
||||
|
||||
|
||||
async def get_info(uid_: str, server_id: str) -> "Optional[Union[dict, str]], int":
|
||||
try:
|
||||
req = await AsyncHttpx.get(
|
||||
url=f"https://api-takumi.mihoyo.com/game_record/app/genshin/api/index?server={server_id}&role_id={uid_}",
|
||||
headers={
|
||||
"Accept": "application/json, text/plain, */*",
|
||||
"DS": get_ds(f"role_id={uid_}&server={server_id}"),
|
||||
"Origin": "https://webstatic.mihoyo.com",
|
||||
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
|
||||
"User-Agent": "Mozilla/5.0 (Linux; Android 9; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/39.0.0.0 Mobile Safari/537.36 miHoYoBBS/2.2.0",
|
||||
"x-rpc-client_type": Config.get_config("genshin", "client_type"),
|
||||
"Referer": "https://webstatic.mihoyo.com/app/community-game-records/index.html?v=6",
|
||||
"Accept-Encoding": "gzip, deflate",
|
||||
"Accept-Language": "zh-CN,en-US;q=0.8",
|
||||
"X-Requested-With": "com.mihoyo.hyperion",
|
||||
"Cookie": await Genshin.get_user_cookie(int(uid_))
|
||||
},
|
||||
)
|
||||
data = req.json()
|
||||
if data["message"] == "OK":
|
||||
return data["data"], 200
|
||||
return data["message"], 999
|
||||
except Exception as e:
|
||||
logger.error(f"访问失败,请重试! {type(e)}: {e}")
|
||||
return None, -1
|
||||
|
||||
|
||||
async def get_character(
|
||||
uid: str, character_ids: List[str], server_id="cn_gf01"
|
||||
) -> Optional[dict]:
|
||||
try:
|
||||
req = await AsyncHttpx.post(
|
||||
url="https://api-takumi.mihoyo.com/game_record/app/genshin/api/character",
|
||||
headers={
|
||||
"Accept": "application/json, text/plain, */*",
|
||||
"DS": get_ds(
|
||||
"",
|
||||
{
|
||||
"character_ids": character_ids,
|
||||
"role_id": uid,
|
||||
"server": server_id,
|
||||
},
|
||||
),
|
||||
"Origin": "https://webstatic.mihoyo.com",
|
||||
"Cookie": await Genshin.get_user_cookie(int(uid)),
|
||||
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
|
||||
"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/",
|
||||
"Accept-Encoding": "gzip, deflate",
|
||||
"Accept-Language": "zh-CN,en-US;q=0.8",
|
||||
"X-Requested-With": "com.mihoyo.hyperion",
|
||||
},
|
||||
json={"character_ids": character_ids, "role_id": uid, "server": server_id},
|
||||
)
|
||||
data = req.json()
|
||||
if data["message"] == "OK":
|
||||
return data["data"]
|
||||
except Exception as e:
|
||||
logger.error(f"访问失败,请重试! {type(e)}: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def parsed_data(
|
||||
data: dict,
|
||||
) -> "Optional[List[Dict[str, str]]], Dict[str, str], Optional[List[Dict[str, str]]], Optional[List[Dict[str, str]]]":
|
||||
"""
|
||||
解析数据
|
||||
:param data: 数据
|
||||
"""
|
||||
char_data_list = []
|
||||
for char in data["avatars"]:
|
||||
_x = {
|
||||
"id": char["id"],
|
||||
"image": char["image"],
|
||||
"name": char["name"],
|
||||
"element": element_mastery[char["element"].lower()],
|
||||
"fetter": char["fetter"],
|
||||
"level": char["level"],
|
||||
"rarity": char["rarity"],
|
||||
"actived_constellation_num": char["actived_constellation_num"],
|
||||
}
|
||||
char_data_list.append(_x)
|
||||
role_data = {
|
||||
"active_day_number": data["stats"]["active_day_number"], # 活跃天数
|
||||
"achievement_number": data["stats"]["achievement_number"], # 达成成就数量
|
||||
"win_rate": data["stats"]["win_rate"],
|
||||
"anemoculus_number": data["stats"]["anemoculus_number"], # 风神瞳已收集
|
||||
"geoculus_number": data["stats"]["geoculus_number"], # 岩神瞳已收集
|
||||
"avatar_number": data["stats"]["avatar_number"], # 获得角色数量
|
||||
"way_point_number": data["stats"]["way_point_number"], # 传送点已解锁
|
||||
"domain_number": data["stats"]["domain_number"], # 秘境解锁数量
|
||||
"spiral_abyss": data["stats"]["spiral_abyss"], # 深渊当期进度
|
||||
"precious_chest_number": data["stats"]["precious_chest_number"], # 珍贵宝箱
|
||||
"luxurious_chest_number": data["stats"]["luxurious_chest_number"], # 华丽宝箱
|
||||
"exquisite_chest_number": data["stats"]["exquisite_chest_number"], # 精致宝箱
|
||||
"magic_chest_number": data["stats"]["magic_chest_number"], # 奇馈宝箱
|
||||
"common_chest_number": data["stats"]["common_chest_number"], # 普通宝箱
|
||||
"electroculus_number": data["stats"]["electroculus_number"], # 雷神瞳已收集
|
||||
}
|
||||
world_data_dict = {}
|
||||
for world in data["world_explorations"]:
|
||||
_x = {
|
||||
"level": world["level"], # 声望等级
|
||||
"exploration_percentage": world["exploration_percentage"], # 探索进度
|
||||
"image": world["icon"],
|
||||
"name": world["name"],
|
||||
"offerings": world["offerings"],
|
||||
}
|
||||
world_data_dict[world["name"]] = _x
|
||||
home_data_list = []
|
||||
for home in data["homes"]:
|
||||
_x = {
|
||||
"level": home["level"], # 最大信任等级
|
||||
"visit_num": home["visit_num"], # 最高历史访客数
|
||||
"comfort_num": home["comfort_num"], # 最高洞天仙力
|
||||
"item_num": home["item_num"], # 已获得摆件数量
|
||||
"name": home["name"],
|
||||
"icon": home["icon"],
|
||||
"comfort_level_name": home["comfort_level_name"],
|
||||
"comfort_level_icon": home["comfort_level_icon"],
|
||||
}
|
||||
home_data_list.append(_x)
|
||||
return char_data_list, role_data, world_data_dict, home_data_list
|
||||
|
||||
|
||||
async def get_mys_data(uid: str, mys_id: Optional[str]) -> Optional[List[Dict]]:
|
||||
"""
|
||||
获取用户米游社数据
|
||||
:param uid: 原神uid
|
||||
:param mys_id: 米游社id
|
||||
"""
|
||||
if mys_id:
|
||||
try:
|
||||
req = await AsyncHttpx.get(
|
||||
url=f"https://api-takumi.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid={mys_id}",
|
||||
headers={
|
||||
"DS": get_ds(f"uid={mys_id}"),
|
||||
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
|
||||
"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/",
|
||||
"Cookie": await Genshin.get_user_cookie(int(uid))
|
||||
},
|
||||
)
|
||||
data = req.json()
|
||||
if data["message"] == "OK":
|
||||
return data["data"]["list"]
|
||||
except Exception as e:
|
||||
logger.error(f"访问失败,请重试! {type(e)}: {e}")
|
||||
return None
|
||||
@@ -0,0 +1,530 @@
|
||||
from configs.path_config import IMAGE_PATH
|
||||
from pathlib import Path
|
||||
from utils.image_utils import BuildImage
|
||||
from typing import List, Dict, Optional
|
||||
from utils.message_builder import image
|
||||
from nonebot.adapters.cqhttp import MessageSegment
|
||||
from utils.http_utils import AsyncHttpx
|
||||
from utils.utils import get_user_avatar
|
||||
from io import BytesIO
|
||||
import random
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
|
||||
image_path = Path(IMAGE_PATH) / "genshin" / "genshin_card"
|
||||
|
||||
|
||||
async def get_genshin_image(
|
||||
user_id: int,
|
||||
uid: str,
|
||||
char_data_list: List[Dict],
|
||||
role_data: Dict,
|
||||
world_data_dict: Dict,
|
||||
home_data_list: List[Dict],
|
||||
char_detailed_dict: dict = None,
|
||||
mys_data: Optional[List[Dict]] = None,
|
||||
nickname: Optional[str] = None,
|
||||
) -> MessageSegment:
|
||||
"""
|
||||
生成图片数据
|
||||
:param user_id:用户qq
|
||||
:param uid: 原神uid
|
||||
:param char_data_list: 角色列表
|
||||
:param role_data: 玩家数据
|
||||
:param world_data_dict: 国家数据字典
|
||||
:param home_data_list: 家园列表
|
||||
:param char_detailed_dict: 角色武器字典
|
||||
:param mys_data: 用户米游社数据
|
||||
:param nickname: 用户昵称
|
||||
"""
|
||||
user_ava = BytesIO(await get_user_avatar(user_id))
|
||||
return await asyncio.get_event_loop().run_in_executor(
|
||||
None,
|
||||
_get_genshin_image,
|
||||
uid,
|
||||
char_data_list,
|
||||
role_data,
|
||||
world_data_dict,
|
||||
home_data_list,
|
||||
char_detailed_dict,
|
||||
mys_data,
|
||||
nickname,
|
||||
user_ava,
|
||||
)
|
||||
|
||||
|
||||
def _get_genshin_image(
|
||||
uid: str,
|
||||
char_data_list: List[Dict],
|
||||
role_data: Dict,
|
||||
world_data_dict: Dict,
|
||||
home_data_list: List[Dict],
|
||||
char_detailed_dict: dict = None,
|
||||
mys_data: Optional[Dict] = None,
|
||||
nickname: Optional[str] = None,
|
||||
user_ava: Optional[BytesIO] = None,
|
||||
) -> MessageSegment:
|
||||
"""
|
||||
生成图片数据
|
||||
:param uid: 原神uid
|
||||
:param char_data_list: 角色列表
|
||||
:param role_data: 玩家数据
|
||||
:param world_data_dict: 国家数据字典
|
||||
:param home_data_list: 家园列表
|
||||
:param char_detailed_dict: 角色武器字典
|
||||
:param mys_data: 用户米游社数据
|
||||
:param nickname: 用户昵称
|
||||
:param user_ava:用户头像
|
||||
"""
|
||||
x = 450 if char_detailed_dict else 330
|
||||
char_height = (
|
||||
len(char_data_list) / 7
|
||||
if len(char_data_list) % 7 == 0
|
||||
else len(char_data_list) / 7 + 1
|
||||
)
|
||||
foot = BuildImage(1700, 87, background=image_path / "head.png")
|
||||
head = BuildImage(1700, 87, background=image_path / "head.png")
|
||||
head.rotate(180)
|
||||
middle = BuildImage(
|
||||
1700, int(1600 + 200 + x * char_height), background=image_path / "middle.png"
|
||||
)
|
||||
A = BuildImage(middle.w, middle.h + foot.h + head.h)
|
||||
A.paste(head, (-5, 0), True)
|
||||
A.paste(middle, (0, head.h), True)
|
||||
A.paste(foot, (0, head.h + middle.h), True)
|
||||
A.crop((0, 0, A.w - 5, A.h))
|
||||
user_image = get_user_data_image(uid, role_data, mys_data, nickname, user_ava)
|
||||
home_image = get_home_data_image(home_data_list)
|
||||
country_image = get_country_data_image(world_data_dict)
|
||||
char_image, _h = get_char_data_image(char_data_list, char_detailed_dict)
|
||||
top_bk = BuildImage(user_image.w, user_image.h + home_image.h + 100, color="#F9F6F2")
|
||||
top_bk.paste(user_image, alpha=True)
|
||||
top_bk.paste(home_image, (0, user_image.h + 50), alpha=True)
|
||||
top_bk.paste(country_image, (home_image.w + 100, user_image.h + 50), alpha=True)
|
||||
bar = BuildImage(1600, 200, font_size=50, color="#F9F6F2", font="HYWenHei-85W.ttf")
|
||||
bar.text((50, 10), "角色背包", (104, 103, 101))
|
||||
bar.line((50, 90, 1550, 90), (227, 219, 209), width=10)
|
||||
if A.h - top_bk.h - bar.h - _h > 200:
|
||||
_h = A.h - top_bk.h - bar.h - _h - 200
|
||||
A.crop((0, 0, A.w, A.h - _h))
|
||||
A.paste(foot, (0, A.h - 87))
|
||||
A.paste(top_bk, (0, 100), center_type="by_width")
|
||||
A.paste(bar, (50, top_bk.h + 80))
|
||||
A.paste(char_image, (0, top_bk.h + bar.h + 10), center_type="by_width")
|
||||
rand = random.randint(1, 10000)
|
||||
A.save(Path(IMAGE_PATH) / "temp" / f"genshin_user_card_{rand}.png")
|
||||
return image(f"genshin_user_card_{rand}.png", "temp")
|
||||
|
||||
|
||||
def get_user_data_image(
|
||||
uid: str,
|
||||
role_data: Dict,
|
||||
mys_data: Optional[Dict] = None,
|
||||
nickname: Optional[str] = None,
|
||||
user_ava: Optional[BytesIO] = None,
|
||||
) -> BuildImage:
|
||||
"""
|
||||
画出玩家基本数据
|
||||
:param uid: 原神uid
|
||||
:param role_data: 玩家数据
|
||||
:param mys_data: 玩家米游社数据
|
||||
:param nickname: 用户昵称
|
||||
:param user_ava:用户头像
|
||||
"""
|
||||
if mys_data:
|
||||
nickname = [x["nickname"] for x in mys_data if x["game_id"] == 2][0]
|
||||
region = BuildImage(1440, 450, color="#E3DBD1", font="HYWenHei-85W.ttf")
|
||||
region.circle_corner(30)
|
||||
uname_img = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=nickname,
|
||||
font_size=40,
|
||||
color=(255, 255, 255, 0),
|
||||
font="HYWenHei-85W.ttf",
|
||||
)
|
||||
uid_img = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"UID: {uid}",
|
||||
font_size=25,
|
||||
color=(255, 255, 255, 0),
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_color=(21, 167, 89),
|
||||
)
|
||||
ava_bk = BuildImage(270, 270, background=image_path / "cover.png")
|
||||
# 用户头像
|
||||
if user_ava:
|
||||
ava_img = BuildImage(200, 200, background=user_ava)
|
||||
ava_img.circle()
|
||||
ava_bk.paste(ava_img, alpha=True, center_type="center")
|
||||
else:
|
||||
ava_img = BuildImage(
|
||||
245,
|
||||
245,
|
||||
background=image_path
|
||||
/ "chars_ava"
|
||||
/ random.choice(os.listdir(image_path / "chars_ava")),
|
||||
)
|
||||
ava_bk.paste(ava_img, (12, 16), alpha=True)
|
||||
region.paste(uname_img, (int(170 + uid_img.w / 2 - uname_img.w / 2), 305), True)
|
||||
region.paste(uid_img, (170, 355), True)
|
||||
region.paste(ava_bk, (int(550 / 2 - ava_bk.w / 2), 40), True)
|
||||
data_img = BuildImage(
|
||||
800, 400, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
||||
)
|
||||
_height = 0
|
||||
keys = [
|
||||
["活跃天数", "成就达成", "获得角色", "深境螺旋"],
|
||||
["华丽宝箱", "珍贵宝箱", "精致宝箱", "普通宝箱"],
|
||||
["奇馈宝箱", "风神瞳", "岩神瞳", "雷神瞳"],
|
||||
]
|
||||
values = [
|
||||
[
|
||||
role_data["active_day_number"],
|
||||
role_data["achievement_number"],
|
||||
role_data["avatar_number"],
|
||||
role_data["spiral_abyss"],
|
||||
],
|
||||
[
|
||||
role_data["luxurious_chest_number"],
|
||||
role_data["precious_chest_number"],
|
||||
role_data["exquisite_chest_number"],
|
||||
role_data["common_chest_number"],
|
||||
],
|
||||
[
|
||||
role_data["magic_chest_number"],
|
||||
role_data["anemoculus_number"],
|
||||
role_data["geoculus_number"],
|
||||
role_data["electroculus_number"],
|
||||
],
|
||||
]
|
||||
for key, value in zip(keys, values):
|
||||
_tmp_data_img = BuildImage(
|
||||
800, 200, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
||||
)
|
||||
_width = 10
|
||||
for k, v in zip(key, value):
|
||||
t_ = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=k,
|
||||
color=(255, 255, 255, 0),
|
||||
font_color=(138, 143, 143),
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=30,
|
||||
)
|
||||
tmp_ = BuildImage(
|
||||
t_.w, t_.h + 70, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
||||
)
|
||||
tmp_.text((0, 0), str(v), center_type="by_width")
|
||||
tmp_.paste(t_, (0, 50), True, "by_width")
|
||||
_tmp_data_img.paste(tmp_, (_width if len(key) > 3 else _width + 15, 0))
|
||||
_width += 200
|
||||
data_img.paste(_tmp_data_img, (0, _height))
|
||||
_height += _tmp_data_img.h - 70
|
||||
region.paste(data_img, (510, 50))
|
||||
return region
|
||||
|
||||
|
||||
def get_home_data_image(home_data_list: List[Dict]) -> BuildImage:
|
||||
"""
|
||||
画出家园数据
|
||||
:param home_data_list: 家园列表
|
||||
"""
|
||||
region = BuildImage(
|
||||
550, 1050, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
||||
)
|
||||
try:
|
||||
region.text(
|
||||
(0, 30), f'尘歌壶 Lv.{home_data_list[0]["level"]}', center_type="by_width"
|
||||
)
|
||||
region.text(
|
||||
(0, 980), f'仙力: {home_data_list[0]["comfort_num"]}', center_type="by_width"
|
||||
)
|
||||
except (IndexError, KeyError):
|
||||
region.text((0, 30), f"尘歌壶 Lv.0", center_type="by_width")
|
||||
region.text((0, 980), f"仙力: 0", center_type="by_width")
|
||||
region.circle_corner(30)
|
||||
height = 100
|
||||
homes = os.listdir(image_path / "homes")
|
||||
homes.remove("lock.png")
|
||||
homes.sort()
|
||||
unlock_home = [x["name"] for x in home_data_list]
|
||||
for i, file in enumerate(homes):
|
||||
home_img = image_path / "homes" / file
|
||||
x = BuildImage(500, 250, background=home_img)
|
||||
if file.split(".")[0] not in unlock_home:
|
||||
black_img = BuildImage(500, 250, color="black")
|
||||
lock_img = BuildImage(0, 0, background=image_path / "homes" / "lock.png")
|
||||
black_img.circle_corner(50)
|
||||
black_img.transparent(1)
|
||||
black_img.paste(lock_img, alpha=True, center_type="center")
|
||||
x.paste(black_img, alpha=True)
|
||||
else:
|
||||
black_img = BuildImage(
|
||||
500, 150, color="black", font="HYWenHei-85W.ttf", font_size=40
|
||||
)
|
||||
black_img.text((55, 55), file.split(".")[0], fill=(226, 211, 146))
|
||||
black_img.transparent(1)
|
||||
text_img = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text="洞天等级",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_color=(203, 200, 184),
|
||||
font_size=35,
|
||||
color=(255, 255, 255, 0),
|
||||
)
|
||||
level_img = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f'{home_data_list[0]["comfort_level_name"]}',
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_color=(211, 213, 207),
|
||||
font_size=30,
|
||||
color=(255, 255, 255, 0),
|
||||
)
|
||||
black_img.paste(text_img, (270, 25), True)
|
||||
black_img.paste(level_img, (278, 85), True)
|
||||
x.paste(black_img, alpha=True, center_type="center")
|
||||
x.circle_corner(50)
|
||||
region.paste(x, (0, height), True, "by_width")
|
||||
height += 300
|
||||
return region
|
||||
|
||||
|
||||
def get_country_data_image(world_data_dict: Dict) -> BuildImage:
|
||||
"""
|
||||
画出国家探索供奉等图像
|
||||
:param world_data_dict: 国家数据字典
|
||||
"""
|
||||
region = BuildImage(790, 1050, color="#F9F6F2")
|
||||
height = 0
|
||||
for country in ["蒙德", "龙脊雪山", "璃月", "稻妻"]:
|
||||
x = BuildImage(790, 250, color="#3A4467")
|
||||
logo = BuildImage(180, 180, background=image_path / "logo" / f"{country}.png")
|
||||
tmp_bk = BuildImage(770, 230, color="#606779")
|
||||
tmp_bk.circle_corner(10)
|
||||
content_bk = BuildImage(
|
||||
755, 215, color="#3A4467", font_size=40, font="HYWenHei-85W.ttf"
|
||||
)
|
||||
content_bk.paste(logo, (50, 0), True, "by_height")
|
||||
if country in ["蒙德", "璃月"]:
|
||||
content_bk.text((300, 40), "探索", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 40),
|
||||
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
content_bk.text((300, 120), "声望", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 120),
|
||||
f"Lv.{world_data_dict[country]['level']}",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
elif country in ["龙脊雪山"]:
|
||||
content_bk.text((300, 40), "探索", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 40),
|
||||
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
content_bk.text((300, 120), "供奉", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 120),
|
||||
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
elif country in ["稻妻"]:
|
||||
content_bk.text((300, 20), "探索", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 20),
|
||||
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
content_bk.text((300, 85), "声望", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 85),
|
||||
f"Lv.{world_data_dict[country]['level']}",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
content_bk.text((300, 150), "神樱", fill=(239, 211, 114))
|
||||
content_bk.text(
|
||||
(450, 150),
|
||||
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
|
||||
fill=(255, 255, 255),
|
||||
)
|
||||
x.paste(tmp_bk, alpha=True, center_type="center")
|
||||
x.paste(content_bk, alpha=True, center_type="center")
|
||||
x.circle_corner(20)
|
||||
region.paste(x, (0, height), center_type="by_width")
|
||||
height += 267
|
||||
return region
|
||||
|
||||
|
||||
def get_char_data_image(
|
||||
char_data_list: List[Dict], char_detailed_dict: dict
|
||||
) -> "BuildImage, int":
|
||||
"""
|
||||
画出角色列表
|
||||
:param char_data_list: 角色列表
|
||||
:param char_detailed_dict: 角色武器
|
||||
"""
|
||||
x = 420 if char_detailed_dict else 350
|
||||
_h = x * int(
|
||||
len(char_data_list) / 7
|
||||
if len(char_data_list) % 7 == 0
|
||||
else len(char_data_list) / 7 + 1
|
||||
)
|
||||
region = BuildImage(
|
||||
1600,
|
||||
_h,
|
||||
color="#F9F6F2",
|
||||
)
|
||||
width = 120
|
||||
height = 0
|
||||
idx = 0
|
||||
for char in char_data_list:
|
||||
if width + 230 > 1550:
|
||||
width = 120
|
||||
height += x
|
||||
idx += 1
|
||||
char_img = image_path / "chars" / f'{char["name"]}.png'
|
||||
char_bk = BuildImage(
|
||||
270,
|
||||
500 if char_detailed_dict else 400,
|
||||
background=image_path / "element.png",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=35,
|
||||
)
|
||||
char_img = BuildImage(0, 0, background=char_img)
|
||||
actived_constellation_num = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"命之座: {char['actived_constellation_num']}层",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=25,
|
||||
color=(255, 255, 255, 0),
|
||||
)
|
||||
level = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"Lv.{char['level']}",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=30,
|
||||
color=(255, 255, 255, 0),
|
||||
font_color=(21, 167, 89),
|
||||
)
|
||||
love_log = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text="♥",
|
||||
font="HWZhongSong.ttf",
|
||||
font_size=40,
|
||||
color=(255, 255, 255, 0),
|
||||
font_color=(232, 31, 168),
|
||||
)
|
||||
fetter = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f'{char["fetter"]}',
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=30,
|
||||
color=(255, 255, 255, 0),
|
||||
font_color=(232, 31, 168),
|
||||
)
|
||||
if char_detailed_dict.get(char["name"]):
|
||||
weapon = BuildImage(
|
||||
100,
|
||||
100,
|
||||
background=image_path
|
||||
/ "weapons"
|
||||
/ f'{char_detailed_dict[char["name"]]["weapon"]}.png',
|
||||
)
|
||||
weapon_name = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"{char_detailed_dict[char['name']]['weapon']}",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=25,
|
||||
color=(255, 255, 255, 0),
|
||||
)
|
||||
weapon_affix_level = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"精炼: {char_detailed_dict[char['name']]['affix_level']}",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=20,
|
||||
color=(255, 255, 255, 0),
|
||||
)
|
||||
weapon_level = BuildImage(
|
||||
0,
|
||||
0,
|
||||
plain_text=f"Lv.{char_detailed_dict[char['name']]['level']}",
|
||||
font="HYWenHei-85W.ttf",
|
||||
font_size=25,
|
||||
color=(255, 255, 255, 0),
|
||||
font_color=(21, 167, 89),
|
||||
)
|
||||
char_bk.paste(weapon, (20, 380), True)
|
||||
char_bk.paste(
|
||||
weapon_name,
|
||||
(100 + int((char_bk.w - 22 - weapon.w - weapon_name.w) / 2 - 10), 390),
|
||||
True,
|
||||
)
|
||||
char_bk.paste(
|
||||
weapon_affix_level,
|
||||
(
|
||||
(
|
||||
100
|
||||
+ int(
|
||||
(char_bk.w - 10 - weapon.w - weapon_affix_level.w) / 2 - 10
|
||||
),
|
||||
420,
|
||||
)
|
||||
),
|
||||
True,
|
||||
)
|
||||
char_bk.paste(
|
||||
weapon_level,
|
||||
(
|
||||
(
|
||||
100
|
||||
+ int((char_bk.w - 10 - weapon.w - weapon_level.w) / 2 - 10),
|
||||
450,
|
||||
)
|
||||
),
|
||||
True,
|
||||
)
|
||||
char_bk.paste(char_img, (0, 5), alpha=True, center_type="by_width")
|
||||
char_bk.text((0, 270), char["name"], center_type="by_width")
|
||||
char_bk.paste(actived_constellation_num, (0, 310), True, "by_width")
|
||||
char_bk.paste(level, (60, 340), True)
|
||||
char_bk.paste(love_log, (155, 330), True)
|
||||
char_bk.paste(fetter, (180, 340), True)
|
||||
char_bk.resize(0.8)
|
||||
region.paste(char_bk, (width, height), True)
|
||||
width += 230
|
||||
return region, _h
|
||||
|
||||
|
||||
async def init_image(char_data_list: List[Dict], char_detailed_dict: dict):
|
||||
"""
|
||||
下载头像
|
||||
:param char_data_list: 角色列表
|
||||
:param char_detailed_dict: 角色武器
|
||||
"""
|
||||
for char in char_data_list:
|
||||
file = image_path / "chars" / f'{char["name"]}.png'
|
||||
file.parent.mkdir(parents=True, exist_ok=True)
|
||||
if not file.exists():
|
||||
await AsyncHttpx.download_file(char["image"], file)
|
||||
for char in char_detailed_dict.keys():
|
||||
file = image_path / "weapons" / f'{char_detailed_dict[char]["weapon"]}.png'
|
||||
file.parent.mkdir(parents=True, exist_ok=True)
|
||||
if not file.exists():
|
||||
await AsyncHttpx.download_file(
|
||||
char_detailed_dict[char]["weapon_image"], file
|
||||
)
|
||||
Reference in New Issue
Block a user