mirror of
https://github.com/KimigaiiWuyi/GenshinUID.git
synced 2025-05-30 04:00:31 +08:00
315 lines
10 KiB
Python
315 lines
10 KiB
Python
import time
|
|
import asyncio
|
|
from pathlib import Path
|
|
from typing import Union, Optional
|
|
|
|
from nonebot.log import logger
|
|
from PIL import Image, ImageDraw
|
|
|
|
from ..utils.get_cookies.get_cookies import GetCookies
|
|
from ..utils.download_resource.download_url import download_file
|
|
from ..utils.draw_image_tools.send_image_tool import convert_img
|
|
from ..utils.draw_image_tools.draw_image_tool import get_simple_bg
|
|
from ..utils.genshin_fonts.genshin_fonts import genshin_font_origin
|
|
|
|
TEXT_PATH = Path(__file__).parent / 'texture2D'
|
|
RESOURCE_PATH = Path(__file__).parents[1] / 'resource'
|
|
CHAR_PATH = RESOURCE_PATH / 'chars'
|
|
CHAR_STAND_PATH = RESOURCE_PATH / 'char_stand'
|
|
CHAR_SIDE_PATH = RESOURCE_PATH / 'char_side'
|
|
TALENT_PATH = RESOURCE_PATH / 'texture2d' / 'talent'
|
|
|
|
abyss_title_pic = Image.open(TEXT_PATH / 'abyss_title.png')
|
|
char_mask = Image.open(TEXT_PATH / 'char_mask.png')
|
|
char_frame = Image.open(TEXT_PATH / 'char_frame.png')
|
|
|
|
text_title_color = (29, 29, 29)
|
|
text_floor_color = (30, 31, 25)
|
|
|
|
genshin_font_70 = genshin_font_origin(70)
|
|
genshin_font_32 = genshin_font_origin(32)
|
|
genshin_font_27 = genshin_font_origin(27)
|
|
|
|
|
|
async def get_abyss_star_pic(star: int) -> Image.Image:
|
|
star_pic = Image.open(TEXT_PATH / f'star{star}.png')
|
|
return star_pic
|
|
|
|
|
|
async def get_rarity_pic(rarity: int) -> Image.Image:
|
|
rarity_pic = Image.open(TEXT_PATH / f'rarity{rarity}.png')
|
|
return rarity_pic
|
|
|
|
|
|
async def get_talent_pic(talent: int) -> Image.Image:
|
|
return Image.open(TALENT_PATH / f'talent_{talent}.png')
|
|
|
|
|
|
async def get_rank_data(data: dict, path: Path):
|
|
char_id = data[0]['avatar_id']
|
|
# 只下载侧视图
|
|
if path == CHAR_SIDE_PATH:
|
|
# 确认角色头像路径
|
|
char_side_path = CHAR_PATH / f'{char_id}.png'
|
|
# 不存在自动下载
|
|
if not char_side_path.exists():
|
|
await download_file(data[0]['avatar_icon'], 3, f'{char_id}.png')
|
|
char_pic = Image.open(path / f'{char_id}.png').convert('RGBA')
|
|
if path == CHAR_STAND_PATH:
|
|
char_pic = char_pic.resize((862, 528), Image.Resampling.BICUBIC)
|
|
elif path == CHAR_SIDE_PATH:
|
|
char_pic = char_pic.resize((60, 60), Image.Resampling.BICUBIC)
|
|
rank_value = str(data[0]['value'])
|
|
return char_pic, rank_value
|
|
|
|
|
|
async def _draw_abyss_card(
|
|
char: dict,
|
|
talent_num: str,
|
|
floor_pic: Image.Image,
|
|
index_char: int,
|
|
index_part: int,
|
|
):
|
|
char_card = Image.new('RGBA', (150, 190), (0, 0, 0, 0))
|
|
# 根据稀有度获取背景
|
|
char_bg = await get_rarity_pic(char['rarity'])
|
|
# 确认角色头像路径
|
|
char_pic_path = CHAR_PATH / f'{char["id"]}.png'
|
|
# 不存在自动下载
|
|
if not char_pic_path.exists():
|
|
await download_file(char['icon'], 1, f'{char["id"]}.png')
|
|
char_pic = (
|
|
Image.open(char_pic_path)
|
|
.convert('RGBA')
|
|
.resize((150, 150), Image.Resampling.LANCZOS) # type: ignore
|
|
)
|
|
char_img = Image.new('RGBA', (150, 190), (0, 0, 0, 0))
|
|
char_img.paste(char_pic, (0, 3), char_pic)
|
|
char_bg = Image.alpha_composite(char_bg, char_img)
|
|
char_card.paste(char_bg, (0, 0), char_mask)
|
|
char_card = Image.alpha_composite(char_card, char_frame)
|
|
talent_pic = await get_talent_pic(int(talent_num))
|
|
char_card.paste(talent_pic, (83, 156), talent_pic)
|
|
char_card_draw = ImageDraw.Draw(char_card)
|
|
char_card_draw.text(
|
|
(9, 172),
|
|
f'Lv.{char["level"]}',
|
|
font=genshin_font_27,
|
|
fill=text_floor_color,
|
|
anchor='lm',
|
|
)
|
|
floor_pic.paste(
|
|
char_card,
|
|
(0 + 155 * index_char, 50 + index_part * 195),
|
|
char_card,
|
|
)
|
|
|
|
|
|
async def _draw_floor_card(
|
|
level_star: int,
|
|
floor_pic: Image.Image,
|
|
bg_img: Image.Image,
|
|
time_str: str,
|
|
index_floor: int,
|
|
):
|
|
star_pic = await get_abyss_star_pic(level_star)
|
|
floor_pic.paste(star_pic, (420, -5), star_pic)
|
|
floor_pic_draw = ImageDraw.Draw(floor_pic)
|
|
floor_pic_draw.text(
|
|
(31, 25),
|
|
time_str,
|
|
font=genshin_font_27,
|
|
fill=text_floor_color,
|
|
anchor='lm',
|
|
)
|
|
bg_img.paste(floor_pic, (5, 415 + index_floor * 440), floor_pic)
|
|
|
|
|
|
async def draw_abyss_img(
|
|
uid: str,
|
|
floor: Optional[int] = None,
|
|
schedule_type: str = '1',
|
|
) -> Union[bytes, str]:
|
|
|
|
# 获取Cookies
|
|
data_def = GetCookies()
|
|
retcode = await data_def.get_useable_cookies(uid)
|
|
if retcode:
|
|
return retcode
|
|
raw_data = data_def.raw_data
|
|
raw_abyss_data = await data_def.get_spiral_abyss_data(schedule_type)
|
|
|
|
# 获取数据
|
|
if raw_abyss_data:
|
|
raw_abyss_data = raw_abyss_data['data']
|
|
else:
|
|
return '没有获取到深渊数据'
|
|
if raw_data:
|
|
char_data = raw_data['data']['avatars']
|
|
else:
|
|
return '没有获取到角色数据'
|
|
char_temp = {}
|
|
|
|
# 获取查询者数据
|
|
is_unfull = False
|
|
if floor:
|
|
floor = floor - 9
|
|
if floor < 0:
|
|
return '楼层不能小于9层!'
|
|
if len(raw_abyss_data['floors']) >= floor + 1:
|
|
floors_data = raw_abyss_data['floors'][floor]
|
|
else:
|
|
return '你还没有挑战该层!'
|
|
else:
|
|
if len(raw_abyss_data['floors']) == 0:
|
|
return '你还没有挑战本期深渊!\n可以使用[上期深渊]命令查询上期~'
|
|
floors_data = raw_abyss_data['floors'][-1]
|
|
levels_num = len(floors_data['levels'])
|
|
if floors_data['levels'][0]['battles']:
|
|
floors_title = str(floors_data['index']) + '层'
|
|
else:
|
|
floors_title = '统计'
|
|
is_unfull = True
|
|
|
|
# 获取背景图片各项参数
|
|
based_w = 625
|
|
based_h = 415 if is_unfull else 415 + levels_num * 440
|
|
white_overlay = Image.new('RGBA', (based_w, based_h), (255, 255, 255, 188))
|
|
|
|
bg_img = await get_simple_bg(based_w, based_h)
|
|
bg_img.paste(white_overlay, (0, 0), white_overlay)
|
|
|
|
abyss_title = Image.new('RGBA', (625, 415), (0, 0, 0, 0))
|
|
|
|
damage_rank = raw_abyss_data['damage_rank']
|
|
defeat_rank = raw_abyss_data['defeat_rank']
|
|
take_damage_rank = raw_abyss_data['take_damage_rank']
|
|
normal_skill_rank = raw_abyss_data['normal_skill_rank']
|
|
energy_skill_rank = raw_abyss_data['energy_skill_rank']
|
|
|
|
dmg_pic, dmg_val = await get_rank_data(damage_rank, CHAR_STAND_PATH)
|
|
defeat_pic, defeat_val = await get_rank_data(defeat_rank, CHAR_SIDE_PATH)
|
|
(
|
|
take_damage_pic,
|
|
take_damage_val,
|
|
) = await get_rank_data(take_damage_rank, CHAR_SIDE_PATH)
|
|
(
|
|
normal_skill_pic,
|
|
normal_skill_val,
|
|
) = await get_rank_data(normal_skill_rank, CHAR_SIDE_PATH)
|
|
(
|
|
energy_skill_pic,
|
|
energy_skill_val,
|
|
) = await get_rank_data(energy_skill_rank, CHAR_SIDE_PATH)
|
|
|
|
abyss_title.paste(dmg_pic, (13, -42), dmg_pic)
|
|
abyss_title = Image.alpha_composite(abyss_title, abyss_title_pic)
|
|
abyss_title.paste(defeat_pic, (5, 171), defeat_pic)
|
|
abyss_title.paste(take_damage_pic, (5, 171 + 54), take_damage_pic)
|
|
abyss_title.paste(normal_skill_pic, (5, 171 + 54 * 2), normal_skill_pic)
|
|
abyss_title.paste(energy_skill_pic, (5, 171 + 54 * 3), energy_skill_pic)
|
|
|
|
abyss_title_draw = ImageDraw.Draw(abyss_title)
|
|
abyss_title_draw.text(
|
|
(41, 95),
|
|
f'深渊{floors_title}',
|
|
font=genshin_font_70,
|
|
fill=text_title_color,
|
|
anchor='lm',
|
|
)
|
|
abyss_title_draw.text(
|
|
(41, 139),
|
|
f'UID{uid}',
|
|
font=genshin_font_27,
|
|
fill=text_title_color,
|
|
anchor='lm',
|
|
)
|
|
abyss_title_draw.text(
|
|
(610, 282),
|
|
dmg_val,
|
|
font=genshin_font_32,
|
|
fill=text_title_color,
|
|
anchor='rm',
|
|
)
|
|
abyss_title_draw.text(
|
|
(610, 357),
|
|
str(raw_abyss_data['total_battle_times']),
|
|
font=genshin_font_32,
|
|
fill=text_title_color,
|
|
anchor='rm',
|
|
)
|
|
abyss_title_draw.text(
|
|
(64, 217),
|
|
defeat_val,
|
|
font=genshin_font_27,
|
|
fill=text_title_color,
|
|
anchor='lm',
|
|
)
|
|
abyss_title_draw.text(
|
|
(64, 217 + 54),
|
|
take_damage_val,
|
|
font=genshin_font_27,
|
|
fill=text_title_color,
|
|
anchor='lm',
|
|
)
|
|
abyss_title_draw.text(
|
|
(64, 217 + 54 * 2),
|
|
normal_skill_val,
|
|
font=genshin_font_27,
|
|
fill=text_title_color,
|
|
anchor='lm',
|
|
)
|
|
abyss_title_draw.text(
|
|
(64, 217 + 54 * 3),
|
|
energy_skill_val,
|
|
font=genshin_font_27,
|
|
fill=text_title_color,
|
|
anchor='lm',
|
|
)
|
|
|
|
bg_img.paste(abyss_title, (0, 0), abyss_title)
|
|
if is_unfull:
|
|
pass
|
|
else:
|
|
task = []
|
|
for index_floor, level in enumerate(floors_data['levels']):
|
|
floor_pic = Image.new('RGBA', (615, 440), (0, 0, 0, 0))
|
|
level_star = level['star']
|
|
timestamp = int(level['battles'][0]['timestamp'])
|
|
time_array = time.localtime(timestamp)
|
|
time_str = time.strftime('%Y-%m-%d %H:%M:%S', time_array)
|
|
for index_part, battle in enumerate(level['battles']):
|
|
for index_char, char in enumerate(battle['avatars']):
|
|
# 获取命座
|
|
if char["id"] in char_temp:
|
|
talent_num = char_temp[char["id"]]
|
|
else:
|
|
for i in char_data:
|
|
if i["id"] == char["id"]:
|
|
talent_num = str(
|
|
i["actived_constellation_num"]
|
|
)
|
|
char_temp[char["id"]] = talent_num
|
|
break
|
|
task.append(
|
|
_draw_abyss_card(
|
|
char,
|
|
talent_num, # type: ignore
|
|
floor_pic,
|
|
index_char,
|
|
index_part,
|
|
)
|
|
)
|
|
await asyncio.gather(*task)
|
|
task.clear()
|
|
task.append(
|
|
_draw_floor_card(
|
|
level_star, floor_pic, bg_img, time_str, index_floor
|
|
)
|
|
)
|
|
await asyncio.gather(*task)
|
|
|
|
res = await convert_img(bg_img)
|
|
logger.info('[查询深渊信息]绘图已完成,等待发送!')
|
|
return res
|