baiqwerdvd a88e96e513
update
2024-09-18 15:51:52 +08:00

424 lines
14 KiB
Python

import asyncio
import datetime
import json
from pathlib import Path
from typing import List, Tuple, Union
from PIL import Image, ImageDraw
from gsuid_core.logger import logger
from gsuid_core.utils.image.convert import convert_img
from gsuid_core.utils.image.image_tools import (
draw_pic_with_ring,
get_color_bg,
get_qq_avatar,
)
from ..utils.fonts.starrail_fonts import (
sr_font_20,
sr_font_24,
sr_font_28,
sr_font_38,
sr_font_40,
)
from ..utils.name_covert import name_to_avatar_id, name_to_weapon_id
from ..utils.resource.RESOURCE_PATH import (
CHAR_ICON_PATH,
PLAYER_PATH,
WEAPON_PATH,
)
TEXT_PATH = Path(__file__).parent / "texture2d"
EMO_PATH = Path(__file__).parent / "texture2d" / "emo"
# up_tag = Image.open(TEXT_PATH / 'up.png')
Abg3_img = Image.open(TEXT_PATH / "Abg3.png")
bg1_img = Image.open(TEXT_PATH / "bg1.png")
first_color = (29, 29, 29)
brown_color = (41, 25, 0)
red_color = (255, 66, 66)
green_color = (74, 189, 119)
white_color = (213, 213, 213)
whole_white_color = (255, 255, 255)
CHANGE_MAP = {
"始发跃迁": "begin",
"群星跃迁": "normal",
"角色跃迁": "char",
"光锥跃迁": "weapon",
}
HOMO_TAG = ["非到极致", "运气不好", "平稳保底", "小欧一把", "欧狗在此"]
NORMAL_LIST = [
"彦卿",
"白露",
"姬子",
"瓦尔特",
"布洛妮娅",
"克拉拉",
"杰帕德",
"银河铁道之夜",
"以世界之名",
"但战斗还未结束",
"制胜的瞬间",
"无可取代的东西",
"时节不居",
"如泥酣眠",
]
UP_LIST = {
"刻晴": [(2021, 2, 17, 18, 0, 0), (2021, 3, 2, 15, 59, 59)],
"提纳里": [(2022, 8, 24, 11, 0, 0), (2022, 9, 9, 17, 59, 59)],
"迪希雅": [(2023, 3, 1, 11, 0, 0), (2023, 3, 21, 17, 59, 59)],
}
async def _draw_card(
img: Image.Image,
xy_point: Tuple[int, int],
card_type: str,
name: str,
gacha_num: int,
is_up: bool,
):
card_img = Image.open(TEXT_PATH / "char_bg.png")
card_img_draw = ImageDraw.Draw(card_img)
point = (47, 31)
text_point = (100, 165)
if card_type == "角色":
_id = await name_to_avatar_id(name)
item_pic = (
Image.open(CHAR_ICON_PATH / f"{_id}.png").convert("RGBA").resize((105, 105))
)
else:
name = await name_to_weapon_id(name)
# _id = await weapon_id_to_en_name(name)
item_pic = (
Image.open(WEAPON_PATH / f"{name}.png").convert("RGBA").resize((124, 124))
)
point = (37, 24)
card_img.paste(item_pic, point, item_pic)
if gacha_num >= 81:
text_color = red_color
elif gacha_num <= 55:
text_color = green_color
else:
text_color = brown_color
card_img_draw.text(text_point, f"{gacha_num}", text_color, sr_font_24, "mm")
if is_up:
logger.info(f"up: {name}")
# card_img.paste(up_tag, (47, -2), up_tag)
img.paste(card_img, xy_point, card_img)
async def random_emo_pic(level: int) -> Image.Image:
emo_fold = EMO_PATH / f"3000{level}.png"
return Image.open(emo_fold)
async def get_level_from_list(ast: int, lst: List) -> int:
if ast == 0:
return 3
for num_index, num in enumerate(lst):
if ast <= num:
level = num_index + 1
break
else:
level = 6
return level
def check_up(name: str, _time: str) -> bool:
for char in UP_LIST:
if char == name:
time = UP_LIST[char]
s_time = datetime.datetime(*time[0])
e_time = datetime.datetime(*time[1])
gacha_time = datetime.datetime.strptime(_time, "%Y-%m-%d %H:%M:%S")
if gacha_time < s_time or gacha_time > e_time:
return False
return True
return False
async def draw_gachalogs_img(uid: str, user_id: str) -> Union[bytes, str]:
path = PLAYER_PATH / str(uid) / "gacha_logs.json"
if not path.exists():
return "你还没有跃迁数据噢~\n请使用命令`sr导入抽卡链接`更新跃迁数据~"
with Path.open(path, encoding="UTF-8") as f:
gacha_data = json.load(f)
# 数据初始化
total_data = {}
for i in ["群星跃迁", "始发跃迁", "角色跃迁", "光锥跃迁"]:
total_data[i] = {
"total": 0, # 五星总数
"avg": 0, # 抽卡平均数
"avg_up": 0, # up平均数
"remain": 0, # 已xx抽未出金
"r_num": [], # 不包含首位的抽卡数量
"e_num": [], # 包含首位的up抽卡数量
"up_list": [], # 抽到的UP列表(不包含首位)
"normal_list": [], # 抽到的五星列表(不包含首位)
"list": [], # 抽到的五星列表
"time_range": "", # 抽卡时间
"all_time": 0, # 抽卡总计秒数
"type": "一般型", # 抽卡类型: 随缘型, 氪金型, 规划型, 仓鼠型, 佛系型
"short_gacha_data": {"time": 0, "num": 0},
"long_gacha_data": {"time": 0, "num": 0},
}
# 拿到数据列表
data_list = gacha_data["data"][i]
# 初始化开关
is_not_first = True
# 开始初始化抽卡数
num = 1
# 从后面开始循环
temp_time = datetime.datetime(2023, 4, 26, 8, 0, 0)
for index, data in enumerate(data_list[::-1]):
# 计算抽卡时间跨度
if index == 0:
total_data[i]["time_range"] = data["time"]
if index == len(data_list) - 1:
total_data[i]["all_time"] = (
datetime.datetime.strptime(data["time"], "%Y-%m-%d %H:%M:%S")
- datetime.datetime.strptime(
total_data[i]["time_range"], "%Y-%m-%d %H:%M:%S"
)
).total_seconds()
total_data[i]["time_range"] += "~" + data["time"]
# 计算时间间隔
if index != 0:
now_time = datetime.datetime.strptime(data["time"], "%Y-%m-%d %H:%M:%S")
dis = (now_time - temp_time).total_seconds()
temp_time = now_time
if dis <= 5000:
total_data[i]["short_gacha_data"]["num"] += 1
total_data[i]["short_gacha_data"]["time"] += dis
elif dis >= 86400:
total_data[i]["long_gacha_data"]["num"] += 1
total_data[i]["long_gacha_data"]["time"] += dis
else:
temp_time = datetime.datetime.strptime(
data["time"], "%Y-%m-%d %H:%M:%S"
)
# 如果这是个五星
if data["rank_type"] == "5":
# 抽到这个五星花了多少抽
data["gacha_num"] = num
# 判断是否是UP
if data["name"] in NORMAL_LIST:
data["is_up"] = False
elif data["name"] in UP_LIST:
data["is_up"] = check_up(data["name"], data["time"])
else:
data["is_up"] = True
# 往里加东西
if is_not_first:
total_data[i]["r_num"].append(num)
total_data[i]["normal_list"].append(data)
if data["is_up"]:
total_data[i]["up_list"].append(data)
# 把这个数据扔到抽到的五星列表内
total_data[i]["list"].append(data)
# 判断经过了第一个
if total_data[i]["list"]:
is_not_first = True
num = 1
# 五星总数增加1
total_data[i]["total"] += 1
else:
num += 1
# 计算已多少抽
total_data[i]["remain"] = num - 1
# 计算平均抽卡数
if len(total_data[i]["normal_list"]) == 0:
total_data[i]["avg"] = 0
else:
total_data[i]["avg"] = float(
"{:.2f}".format(
sum(total_data[i]["r_num"]) / len(total_data[i]["r_num"])
)
)
# 计算平均up数量
if len(total_data[i]["up_list"]) == 0:
total_data[i]["avg_up"] = 0
else:
total_data[i]["avg_up"] = float(
"{:.2f}".format(
sum(total_data[i]["r_num"]) / len(total_data[i]["up_list"])
)
)
# 计算抽卡类型
# 如果抽卡总数小于40
if gacha_data[f"{CHANGE_MAP[i]}_gacha_num"] <= 40:
total_data[i]["type"] = "佛系型"
# 如果长时抽卡总数占据了总抽卡数的70%
elif (
total_data[i]["long_gacha_data"]["num"]
/ gacha_data[f"{CHANGE_MAP[i]}_gacha_num"]
>= 0.7
):
total_data[i]["type"] = "随缘型"
# 如果短时抽卡总数占据了总抽卡数的70%
elif (
total_data[i]["short_gacha_data"]["num"]
/ gacha_data[f"{CHANGE_MAP[i]}_gacha_num"]
>= 0.7
):
total_data[i]["type"] = "规划型"
# 如果抽卡数量远远大于标称抽卡数量
elif (
total_data[i]["all_time"] / 30000
<= gacha_data[f"{CHANGE_MAP[i]}_gacha_num"]
):
# 如果长时抽卡数量大于短时抽卡数量
if (
total_data[i]["long_gacha_data"]["num"]
>= total_data[i]["short_gacha_data"]["num"]
):
total_data[i]["type"] = "规划型"
else:
total_data[i]["type"] = "氪金型"
# 如果抽卡数量远远小于标称抽卡数量
elif (
total_data[i]["all_time"] / 32000
>= gacha_data[f"{CHANGE_MAP[i]}_gacha_num"] * 2
):
total_data[i]["type"] = "仓鼠型"
# 常量偏移数据
single_y = 170
# 计算图片尺寸
normal_y = (1 + ((total_data["群星跃迁"]["total"] - 1) // 5)) * single_y
begin_y = (1 + ((total_data["始发跃迁"]["total"] - 1) // 5)) * single_y
char_y = (1 + ((total_data["角色跃迁"]["total"] - 1) // 5)) * single_y
weapon_y = (1 + ((total_data["光锥跃迁"]["total"] - 1) // 5)) * single_y
# 获取背景图片各项参数
_id = str(user_id)
if _id.startswith("http"):
char_pic = await get_qq_avatar(avatar_url=_id)
else:
char_pic = await get_qq_avatar(qid=user_id)
char_pic = await draw_pic_with_ring(char_pic, 206, None, False)
# 获取背景图片各项参数
img = Abg3_img.copy()
img = await get_color_bg(800, 1600 + 400 + normal_y + char_y + weapon_y + begin_y)
gacha_title = bg1_img.copy()
gacha_title.paste(char_pic, (297, 81), char_pic)
img.paste(gacha_title, (0, 0), gacha_title)
img_draw = ImageDraw.Draw(img)
img_draw.text((400, 345), f"UID {uid}", white_color, sr_font_28, "mm")
# 处理title
# {'total': 0, 'avg': 0, 'remain': 0, 'list': []}
type_list = ["角色跃迁", "光锥跃迁", "群星跃迁", "始发跃迁"]
y_extend = 0
level = 3
for index, i in enumerate(type_list):
title = Image.open(TEXT_PATH / "bg2.png")
if i == "群星跃迁":
level = await get_level_from_list(
total_data[i]["avg"], [54, 61, 67, 73, 80]
)
elif i == "始发跃迁":
level = await get_level_from_list(
total_data[i]["avg"], [10, 20, 30, 40, 50]
)
elif i == "光锥跃迁":
level = await get_level_from_list(
total_data[i]["avg_up"], [62, 75, 88, 99, 111]
)
else:
level = await get_level_from_list(
total_data[i]["avg_up"], [74, 87, 99, 105, 120]
)
emo_pic = await random_emo_pic(level)
emo_pic = emo_pic.resize((195, 195))
title.paste(emo_pic, (500, 123), emo_pic)
title_draw = ImageDraw.Draw(title)
# 卡池
title_draw.text((110, 73), i, whole_white_color, sr_font_38, "lm")
# 抽卡时间
if total_data[i]["time_range"]:
time_range = total_data[i]["time_range"]
else:
time_range = "暂未抽过卡!"
title_draw.text((78, 340), time_range, brown_color, sr_font_20, "lm")
# 平均抽卡数量
title_draw.text(
(143, 215),
str(total_data[i]["avg"]),
first_color,
sr_font_40,
"mm",
)
# 平均up
title_draw.text(
(280, 215),
str(total_data[i]["avg_up"]),
first_color,
sr_font_40,
"mm",
)
# 抽卡总数
title_draw.text(
(413, 215),
str(gacha_data[f"{CHANGE_MAP[i]}_gacha_num"]),
first_color,
sr_font_40,
"mm",
)
# 已抽数
title_draw.text(
(333, 75),
str(total_data[i]["remain"]),
red_color,
sr_font_28,
"mm",
)
y_extend += (
(1 + ((total_data[type_list[index - 1]]["total"] - 1) // 5)) * single_y
if index != 0
else 0
)
y = 350 + index * 400 + y_extend
img.paste(title, (0, y), title)
tasks = []
for item_index, item in enumerate(total_data[i]["list"]):
item_x = (item_index % 5) * 138 + 25
item_y = (item_index // 5) * single_y + y + 355
xy_point = (item_x, item_y)
tasks.append(
_draw_card(
img,
xy_point,
item["item_type"],
item["name"],
item["gacha_num"],
item["is_up"],
)
)
await asyncio.gather(*tasks)
tasks.clear()
# 发送图片
res = await convert_img(img)
logger.info("[查询抽卡]绘图已完成,等待发送!")
# res = 123
return res