修复网络IO堵塞导致图片丢失问题(fix #152)

This commit is contained in:
MingxuanGame 2022-03-30 13:07:12 +08:00
parent b80464a8ca
commit 4e326368a2
No known key found for this signature in database
GPG Key ID: 90C7EFA11DC3C2FF
21 changed files with 158 additions and 95 deletions

View File

@ -1,42 +1,44 @@
import asyncio,os,sys import base64
import base64,re
import traceback import traceback
from aiocqhttp.exceptions import ActionFailed from aiocqhttp.exceptions import ActionFailed
from aiohttp import ClientConnectorError
from nonebot import get_bot, MessageSegment
from hoshino import Service from hoshino import Service
from hoshino.typing import CQEvent, HoshinoBot from hoshino.typing import CQEvent, HoshinoBot
from nonebot import get_bot, logger, MessageSegment
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
from mihoyo_libs.get_data import *
from mihoyo_libs.get_image import * from mihoyo_libs.get_image import *
from mihoyo_libs.get_mihoyo_bbs_data import * from mihoyo_libs.get_mihoyo_bbs_data import *
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
sv = Service('genshinuid') sv = Service('genshinuid')
hoshino_bot = get_bot() hoshino_bot = get_bot()
FILE_PATH = os.path.join(os.path.join(os.path.dirname(__file__), 'mihoyo_libs'),'mihoyo_bbs') FILE_PATH = os.path.join(os.path.join(os.path.dirname(__file__), 'mihoyo_libs'), 'mihoyo_bbs')
INDEX_PATH = os.path.join(FILE_PATH, 'index') INDEX_PATH = os.path.join(FILE_PATH, 'index')
Texture_PATH = os.path.join(FILE_PATH, 'texture2d') Texture_PATH = os.path.join(FILE_PATH, 'texture2d')
@sv.on_rex('[\u4e00-\u9fa5]+(用什么|能用啥|怎么养)') @sv.on_rex('[\u4e00-\u9fa5]+(用什么|能用啥|怎么养)')
async def send_char_adv(bot: HoshinoBot, ev: CQEvent): async def send_char_adv(bot: HoshinoBot, ev: CQEvent):
try: try:
name = str(ev.message).strip().replace(" ","")[:-3] name = str(ev.message).strip().replace(" ", "")[:-3]
im = await char_adv(name) im = await char_adv(name)
await bot.send(ev, im) await bot.send(ev, im)
except Exception as e: except Exception as e:
logger.exception("获取建议失败。") logger.exception("获取建议失败。")
@sv.on_rex('[\u4e00-\u9fa5]+(能给谁|给谁用|要给谁|谁能用)') @sv.on_rex('[\u4e00-\u9fa5]+(能给谁|给谁用|要给谁|谁能用)')
async def send_weapon_adv(bot: HoshinoBot, ev: CQEvent): async def send_weapon_adv(bot: HoshinoBot, ev: CQEvent):
try: try:
name = str(ev.message).strip().replace(" ","")[:-3] name = str(ev.message).strip().replace(" ", "")[:-3]
im = await weapon_adv(name) im = await weapon_adv(name)
await bot.send(ev, im) await bot.send(ev, im)
except Exception as e: except Exception as e:
logger.exception("获取建议失败。") logger.exception("获取建议失败。")
@sv.on_prefix('语音') @sv.on_prefix('语音')
async def send_audio(bot: HoshinoBot, ev: CQEvent): async def send_audio(bot: HoshinoBot, ev: CQEvent):
try: try:
@ -158,7 +160,7 @@ async def send_talents(bot: HoshinoBot, ev: CQEvent):
num = re.findall(r"[0-9]+", message) num = re.findall(r"[0-9]+", message)
if len(num) == 1: if len(num) == 1:
im = await char_wiki(name, "talents", num[0]) im = await char_wiki(name, "talents", num[0])
if isinstance(im,list): if isinstance(im, list):
await hoshino_bot.send_group_forward_msg(group_id=ev.group_id, messages=im) await hoshino_bot.send_group_forward_msg(group_id=ev.group_id, messages=im)
return return
else: else:
@ -240,6 +242,7 @@ async def clean_cache():
async def draw_event(): async def draw_event():
await draw_event_pic() await draw_event_pic()
@sv.on_fullmatch('开始获取米游币') @sv.on_fullmatch('开始获取米游币')
async def send_mihoyo_coin(bot: HoshinoBot, ev: CQEvent): async def send_mihoyo_coin(bot: HoshinoBot, ev: CQEvent):
await bot.send(ev, "开始操作……", at_sender=True) await bot.send(ev, "开始操作……", at_sender=True)
@ -260,6 +263,7 @@ async def send_mihoyo_coin(bot: HoshinoBot, ev: CQEvent):
await bot.send(ev, "机器人发送消息失败:{}".format(e.info['wording'])) await bot.send(ev, "机器人发送消息失败:{}".format(e.info['wording']))
logger.exception("发送签到信息失败") logger.exception("发送签到信息失败")
@sv.on_fullmatch('全部重签') @sv.on_fullmatch('全部重签')
async def _(bot: HoshinoBot, ev: CQEvent): async def _(bot: HoshinoBot, ev: CQEvent):
try: try:
@ -273,6 +277,7 @@ async def _(bot: HoshinoBot, ev: CQEvent):
traceback.print_exc() traceback.print_exc()
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e)) await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
@sv.on_fullmatch('全部重获取') @sv.on_fullmatch('全部重获取')
async def bbscoin_resign(bot: HoshinoBot, ev: CQEvent): async def bbscoin_resign(bot: HoshinoBot, ev: CQEvent):
try: try:
@ -286,6 +291,7 @@ async def bbscoin_resign(bot: HoshinoBot, ev: CQEvent):
traceback.print_exc() traceback.print_exc()
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e)) await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
# 每隔半小时检测树脂是否超过设定值 # 每隔半小时检测树脂是否超过设定值
@sv.scheduled_job('cron', minute="*/30") @sv.scheduled_job('cron', minute="*/30")
async def push(): async def push():
@ -366,11 +372,13 @@ async def daily_sign():
conn.close() conn.close()
return return
# 每日零点五十进行米游币获取 # 每日零点五十进行米游币获取
@sv.scheduled_job('cron', hour='0', minute="50") @sv.scheduled_job('cron', hour='0', minute="50")
async def sign_at_night(): async def sign_at_night():
await daily_mihoyo_bbs_sign() await daily_mihoyo_bbs_sign()
async def daily_mihoyo_bbs_sign(): async def daily_mihoyo_bbs_sign():
conn = sqlite3.connect('ID_DATA.db') conn = sqlite3.connect('ID_DATA.db')
c = conn.cursor() c = conn.cursor()
@ -382,15 +390,16 @@ async def daily_mihoyo_bbs_sign():
logger.info("正在执行{}".format(row[0])) logger.info("正在执行{}".format(row[0]))
if row[8]: if row[8]:
await asyncio.sleep(5 + random.randint(1, 3)) await asyncio.sleep(5 + random.randint(1, 3))
im = await mihoyo_coin(str(row[2]),str(row[8])) im = await mihoyo_coin(str(row[2]), str(row[8]))
logger.info(im) logger.info(im)
try: try:
await hoshino_bot.call_api(api='send_private_msg', await hoshino_bot.call_api(api='send_private_msg',
user_id=row[2], message=im) user_id=row[2], message=im)
except Exception: except Exception:
logger.exception(f"{im} Error") logger.exception(f"{im} Error")
logger.info("已结束。") logger.info("已结束。")
# 私聊事件 # 私聊事件
@hoshino_bot.on_message('private') @hoshino_bot.on_message('private')
async def setting(ctx): async def setting(ctx):
@ -441,19 +450,19 @@ async def setting(ctx):
uid = await select_db(userid, mode="uid") uid = await select_db(userid, mode="uid")
im = await open_push(int(uid[0]), userid, "off", "StatusC") im = await open_push(int(uid[0]), userid, "off", "StatusC")
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid, await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid,
message=im, at_sender=True) message=im, at_sender=True)
except Exception: except Exception:
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid, await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid,
message="未绑定uid信息", at_sender=True) message="未绑定uid信息", at_sender=True)
elif "gs关闭自动米游币" in message: elif "gs关闭自动米游币" in message:
try: try:
uid = await select_db(userid, mode="uid") uid = await select_db(userid, mode="uid")
im = await open_push(int(uid[0]), userid, "on", "StatusC") im = await open_push(int(uid[0]), userid, "on", "StatusC")
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid, await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid,
message=im, at_sender=True) message=im, at_sender=True)
except Exception: except Exception:
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid, await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid,
message="未绑定uid信息", at_sender=True) message="未绑定uid信息", at_sender=True)
elif 'gs开启自动签到' in message: elif 'gs开启自动签到' in message:
try: try:
uid = await select_db(userid, mode="uid") uid = await select_db(userid, mode="uid")
@ -481,6 +490,7 @@ async def setting(ctx):
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message="未找到uid绑定记录。") await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message="未找到uid绑定记录。")
logger.exception("关闭自动签到失败") logger.exception("关闭自动签到失败")
# 群聊开启 自动签到 和 推送树脂提醒 功能 # 群聊开启 自动签到 和 推送树脂提醒 功能
@sv.on_prefix('gs开启') @sv.on_prefix('gs开启')
async def open_switch_func(bot: HoshinoBot, ev: CQEvent): async def open_switch_func(bot: HoshinoBot, ev: CQEvent):
@ -589,10 +599,10 @@ async def close_switch_func(bot: HoshinoBot, ev: CQEvent):
else: else:
return return
except ActionFailed as e: except ActionFailed as e:
await bot.send("机器人发送消息失败:{}".format(e)) await bot.send(ev, "机器人发送消息失败:{}".format(e))
logger.exception("发送设置成功信息失败") logger.exception("发送设置成功信息失败")
except Exception as e: except Exception as e:
await bot.send("发生错误 {},请检查后台输出。".format(e)) await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
logger.exception("设置简洁签到报告失败") logger.exception("设置简洁签到报告失败")
except Exception as e: except Exception as e:
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e)) await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
@ -670,7 +680,8 @@ async def send_daily_data(bot: HoshinoBot, ev: CQEvent):
await bot.send(ev, "机器人发送消息失败:{}".format(e)) await bot.send(ev, "机器人发送消息失败:{}".format(e))
logger.exception("发送当前状态信息失败") logger.exception("发送当前状态信息失败")
#图片版信息
# 图片版信息
@sv.on_fullmatch('当前信息') @sv.on_fullmatch('当前信息')
async def send_genshin_info(bot: HoshinoBot, ev: CQEvent): async def send_genshin_info(bot: HoshinoBot, ev: CQEvent):
try: try:
@ -678,7 +689,7 @@ async def send_genshin_info(bot: HoshinoBot, ev: CQEvent):
uid = await select_db(ev.sender['user_id'], mode="uid") uid = await select_db(ev.sender['user_id'], mode="uid")
uid = uid[0] uid = uid[0]
image = re.search(r"\[CQ:image,file=(.*),url=(.*)]", message) image = re.search(r"\[CQ:image,file=(.*),url=(.*)]", message)
im = await draw_info_pic(uid,image) im = await draw_info_pic(uid, image)
try: try:
await bot.send(ev, MessageSegment.image(im), at_sender=True) await bot.send(ev, MessageSegment.image(im), at_sender=True)
except ActionFailed as e: except ActionFailed as e:
@ -894,6 +905,9 @@ async def get_info(bot, ev):
except TypeError: except TypeError:
await bot.send(ev, "获取失败可能是Cookies失效或者未打开米游社角色详情开关。") await bot.send(ev, "获取失败可能是Cookies失效或者未打开米游社角色详情开关。")
logger.exception("数据获取失败Cookie失效/不公开信息)") logger.exception("数据获取失败Cookie失效/不公开信息)")
except ClientConnectorError:
await bot.send(ev, "获取失败:连接超时")
logger.exception("连接超时")
except Exception as e: except Exception as e:
await bot.send(ev, "获取失败,有可能是数据状态有问题,\n{}\n请检查后台输出。".format(e)) await bot.send(ev, "获取失败,有可能是数据状态有问题,\n{}\n请检查后台输出。".format(e))
logger.exception("数据获取失败(数据状态问题)") logger.exception("数据获取失败(数据状态问题)")

View File

@ -10,6 +10,7 @@ import time
from shutil import copyfile from shutil import copyfile
import requests import requests
from aiohttp import ClientSession
from httpx import AsyncClient from httpx import AsyncClient
from nonebot import logger from nonebot import logger
@ -726,28 +727,29 @@ def get_character(uid, character_ids, ck, server_id="cn_gf01"):
logger.info(e.with_traceback) logger.info(e.with_traceback)
async def get_calculate_info(uid, char_id, ck, server_id="cn_gf01"): async def get_calculate_info(client: ClientSession, uid, char_id, ck, name, server_id="cn_gf01"):
if uid[0] == '5': if uid[0] == '5':
server_id = "cn_qd01" server_id = "cn_qd01"
url = "https://api-takumi.mihoyo.com/event/e20200928calculate/v1/sync/avatar/detail" url = "https://api-takumi.mihoyo.com/event/e20200928calculate/v1/sync/avatar/detail"
async with AsyncClient() as client: req = await client.get(
req = await client.get( url=url,
url=url, headers={
headers={ 'DS': get_ds_token("uid={}&avatar_id={}&region={}".format(uid, char_id, server_id)),
'DS' : get_ds_token("uid={}&avatar_id={}&region={}".format(uid, char_id, server_id)), 'x-rpc-app_version': mhyVersion,
'x-rpc-app_version': mhyVersion, 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 ('
'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',
'KHTML, like Gecko) miHoYoBBS/2.11.1', 'x-rpc-client_type': '5',
'x-rpc-client_type': '5', 'Referer': 'https://webstatic.mihoyo.com/',
'Referer' : 'https://webstatic.mihoyo.com/', "Cookie": ck},
"Cookie" : ck}, params={
params={ "avatar_id": char_id,
"avatar_id": char_id, "uid": uid,
"uid" : uid, "region": server_id
"region" : server_id }
} )
) data = await req.json()
data = json.loads(req.text) data.update({"name": name})
logger.debug(name + "=" + str(char_id) + "===" + str(data)) # DEBUG
return data return data

View File

@ -14,8 +14,9 @@ from wordcloud import WordCloud
from .get_data import * from .get_data import *
STATUS = []
FILE_PATH = os.path.dirname(__file__) FILE_PATH = os.path.dirname(__file__)
FILE2_PATH = os.path.join(FILE_PATH, 'mihoyo_libs/mihoyo_bbs') FILE2_PATH = os.path.join(FILE_PATH, 'mihoyo_bbs')
CHAR_PATH = os.path.join(FILE2_PATH, 'chars') CHAR_PATH = os.path.join(FILE2_PATH, 'chars')
CHAR_DONE_PATH = os.path.join(FILE2_PATH, 'char_done') CHAR_DONE_PATH = os.path.join(FILE2_PATH, 'char_done')
CHAR_IMG_PATH = os.path.join(FILE2_PATH, 'char_img') CHAR_IMG_PATH = os.path.join(FILE2_PATH, 'char_img')
@ -27,7 +28,7 @@ WEAPON_PATH = os.path.join(FILE2_PATH, 'weapon')
BG_PATH = os.path.join(FILE2_PATH, 'bg') BG_PATH = os.path.join(FILE2_PATH, 'bg')
class customize_image: class CustomizeImage:
def __init__(self, image: Match, based_w: int, based_h: int) -> None: def __init__(self, image: Match, based_w: int, based_h: int) -> None:
self.bg_img = self.get_image(image, based_w, based_h) self.bg_img = self.get_image(image, based_w, based_h)
@ -131,9 +132,9 @@ class customize_image:
green_color = color[1] green_color = color[1]
blue_color = color[2] blue_color = color[2]
highlight_color = {"red" : red_color - 127 if red_color > 127 else 127, highlight_color = {"red": red_color - 127 if red_color > 127 else 127,
"green": green_color - 127 if green_color > 127 else 127, "green": green_color - 127 if green_color > 127 else 127,
"blue" : blue_color - 127 if blue_color > 127 else 127} "blue": blue_color - 127 if blue_color > 127 else 127}
max_color = max(highlight_color.values()) max_color = max(highlight_color.values())
@ -192,7 +193,7 @@ def get_rel_pic(url: str):
f.write(get(url).content) f.write(get(url).content)
class get_cookies: class GetCookies:
def __init__(self) -> None: def __init__(self) -> None:
self.useable_cookies: Optional[str] = None self.useable_cookies: Optional[str] = None
self.uid: Optional[str] = None self.uid: Optional[str] = None
@ -545,7 +546,7 @@ async def draw_word_cloud(uid: str, image: Optional[Match] = None, mode: int = 2
async def draw_abyss0_pic(uid, nickname, image=None, mode=2, date="1"): async def draw_abyss0_pic(uid, nickname, image=None, mode=2, date="1"):
# 获取Cookies # 获取Cookies
data_def = get_cookies() data_def = GetCookies()
retcode = await data_def.get_useable_cookies(uid, mode, date) retcode = await data_def.get_useable_cookies(uid, mode, date)
if not retcode: if not retcode:
return retcode return retcode
@ -565,7 +566,7 @@ async def draw_abyss0_pic(uid, nickname, image=None, mode=2, date="1"):
# 获取背景图片各项参数 # 获取背景图片各项参数
based_w = 900 based_w = 900
based_h = 660 + levels_num * 315 based_h = 660 + levels_num * 315
image_def = customize_image(image, based_w, based_h) image_def = CustomizeImage(image, based_w, based_h)
bg_img = image_def.bg_img bg_img = image_def.bg_img
bg_color = image_def.bg_color bg_color = image_def.bg_color
text_color = image_def.text_color text_color = image_def.text_color
@ -794,13 +795,13 @@ async def draw_abyss0_pic(uid, nickname, image=None, mode=2, date="1"):
abyss2.paste(abyss_star1, (730, 155), abyss_star1) abyss2.paste(abyss_star1, (730, 155), abyss_star1)
abyss2_text_draw = ImageDraw.Draw(abyss2) abyss2_text_draw = ImageDraw.Draw(abyss2)
abyss2_text_draw.text((87, 30), f"{j + 1}", text_color, genshin_font(21)) abyss2_text_draw.text((87, 30), f"{j + 1}", text_color, genshin_font(21))
timeStamp1 = int(floors_data['levels'][j]['battles'][0]['timestamp']) timestamp1 = int(floors_data['levels'][j]['battles'][0]['timestamp'])
timeStamp2 = int(floors_data['levels'][j]['battles'][1]['timestamp']) timestamp2 = int(floors_data['levels'][j]['battles'][1]['timestamp'])
timeArray1 = time.localtime(timeStamp1) time_array1 = time.localtime(timestamp1)
timeArray2 = time.localtime(timeStamp2) time_array2 = time.localtime(timestamp2)
otherStyleTime1 = time.strftime("%Y--%m--%d %H:%M:%S", timeArray1) other_style_time1 = time.strftime("%Y--%m--%d %H:%M:%S", time_array1)
otherStyleTime2 = time.strftime("%Y--%m--%d %H:%M:%S", timeArray2) other_style_time2 = time.strftime("%Y--%m--%d %H:%M:%S", time_array2)
abyss2_text_draw.text((167, 33), f"{otherStyleTime1}/{otherStyleTime2}", text_color, genshin_font(19)) abyss2_text_draw.text((167, 33), f"{other_style_time1}/{other_style_time2}", text_color, genshin_font(19))
bg_img.paste(abyss2, (0, 605 + j * 315), abyss2) bg_img.paste(abyss2, (0, 605 + j * 315), abyss2)
bg_img.paste(abyss3, (0, len(floors_data["levels"]) * 315 + 610), abyss3) bg_img.paste(abyss3, (0, len(floors_data["levels"]) * 315 + 610), abyss3)
@ -826,7 +827,7 @@ async def draw_abyss0_pic(uid, nickname, image=None, mode=2, date="1"):
async def draw_abyss_pic(uid: str, nickname: str, floor_num: int, image: Optional[Match] = None, mode: int = 2, async def draw_abyss_pic(uid: str, nickname: str, floor_num: int, image: Optional[Match] = None, mode: int = 2,
date: str = "1"): date: str = "1"):
# 获取Cookies # 获取Cookies
data_def = get_cookies() data_def = GetCookies()
retcode = await data_def.get_useable_cookies(uid, mode, date) retcode = await data_def.get_useable_cookies(uid, mode, date)
if not retcode: if not retcode:
return retcode return retcode
@ -848,7 +849,7 @@ async def draw_abyss_pic(uid: str, nickname: str, floor_num: int, image: Optiona
# 获取背景图片各项参数 # 获取背景图片各项参数
based_w = 900 based_w = 900
based_h = 440 + levels_num * 340 based_h = 440 + levels_num * 340
image_def = customize_image(image, based_w, based_h) image_def = CustomizeImage(image, based_w, based_h)
bg_img = image_def.bg_img bg_img = image_def.bg_img
bg_color = image_def.bg_color bg_color = image_def.bg_color
text_color = image_def.text_color text_color = image_def.text_color
@ -952,13 +953,13 @@ async def draw_abyss_pic(uid: str, nickname: str, floor_num: int, image: Optiona
abyss2.paste(abyss_star1, (730, 155), abyss_star1) abyss2.paste(abyss_star1, (730, 155), abyss_star1)
abyss2_text_draw = ImageDraw.Draw(abyss2) abyss2_text_draw = ImageDraw.Draw(abyss2)
abyss2_text_draw.text((87, 30), f"{j + 1}", text_color, genshin_font(21)) abyss2_text_draw.text((87, 30), f"{j + 1}", text_color, genshin_font(21))
timeStamp1 = int(based_data['levels'][j]['battles'][0]['timestamp']) timestamp1 = int(based_data['levels'][j]['battles'][0]['timestamp'])
timeStamp2 = int(based_data['levels'][j]['battles'][1]['timestamp']) timestamp2 = int(based_data['levels'][j]['battles'][1]['timestamp'])
timeArray1 = time.localtime(timeStamp1) time_array1 = time.localtime(timestamp1)
timeArray2 = time.localtime(timeStamp2) time_array2 = time.localtime(timestamp2)
otherStyleTime1 = time.strftime("%Y--%m--%d %H:%M:%S", timeArray1) other_style_time1 = time.strftime("%Y--%m--%d %H:%M:%S", time_array1)
otherStyleTime2 = time.strftime("%Y--%m--%d %H:%M:%S", timeArray2) other_style_time2 = time.strftime("%Y--%m--%d %H:%M:%S", time_array2)
abyss2_text_draw.text((167, 33), f"{otherStyleTime1}/{otherStyleTime2}", text_color, genshin_font(19)) abyss2_text_draw.text((167, 33), f"{other_style_time1}/{other_style_time2}", text_color, genshin_font(19))
bg_img.paste(abyss2, (0, 350 + j * 340), abyss2) bg_img.paste(abyss2, (0, 350 + j * 340), abyss2)
bg_img.paste(abyss3, (0, len(based_data['levels']) * 340 + 400), abyss3) bg_img.paste(abyss3, (0, len(based_data['levels']) * 340 + 400), abyss3)
@ -979,9 +980,20 @@ async def draw_abyss_pic(uid: str, nickname: str, floor_num: int, image: Optiona
return resultmes return resultmes
async def get_all_calculate_info(client: ClientSession, uid: str, char_id: list[str], ck: str, name: list):
tasks = []
for id_, name_ in zip(char_id, name):
tasks.append(get_calculate_info(client, uid, id_, ck, name_))
data = []
repos = await asyncio.wait(tasks)
for i in repos[0]:
data.append(i.result())
return data
async def draw_char_pic(img: Image, char_data: dict, index: int, bg_color: tuple[int, int, int], async def draw_char_pic(img: Image, char_data: dict, index: int, bg_color: tuple[int, int, int],
text_color: tuple[int, int, int], bg_detail_color: tuple[int, int, int], text_color: tuple[int, int, int], bg_detail_color: tuple[int, int, int],
char_high_color: tuple[int, int, int], uid, use_cookies): char_high_color: tuple[int, int, int], char_talent_data: dict):
char_mingzuo = 0 char_mingzuo = 0
for k in char_data['constellations']: for k in char_data['constellations']:
if k['is_actived']: if k['is_actived']:
@ -1006,8 +1018,7 @@ async def draw_char_pic(img: Image, char_data: dict, index: int, bg_color: tuple
char_3.putalpha(alpha) char_3.putalpha(alpha)
""" """
char_1_mask = Image.open(os.path.join(TEXT_PATH, "char_1_mask.png")) char_1_mask = Image.open(os.path.join(TEXT_PATH, "char_1_mask.png"))
STATUS.append(char_data['name'])
char_talent_data = await get_calculate_info(uid, str(char_data["id"]), use_cookies)
if not os.path.exists(os.path.join(WEAPON_PATH, str(char_data['weapon']['icon'].split('/')[-1]))): if not os.path.exists(os.path.join(WEAPON_PATH, str(char_data['weapon']['icon'].split('/')[-1]))):
get_weapon_pic(char_data['weapon']['icon']) get_weapon_pic(char_data['weapon']['icon'])
if not os.path.exists(os.path.join(CHAR_PATH, str(char_data['id']) + ".png")): if not os.path.exists(os.path.join(CHAR_PATH, str(char_data['id']) + ".png")):
@ -1055,13 +1066,14 @@ async def draw_char_pic(img: Image, char_data: dict, index: int, bg_color: tuple
anchor="mm") anchor="mm")
char_crop = (75 + 190 * (index % 4), 800 + 100 * (index // 4)) char_crop = (75 + 190 * (index % 4), 800 + 100 * (index // 4))
STATUS.remove(char_data['name'])
img.paste(char_0, char_crop, char_0) img.paste(char_0, char_crop, char_0)
async def draw_pic(uid: str, nickname: str, image: Optional[Match] = None, mode: int = 2, async def draw_pic(uid: str, nickname: str, image: Optional[Match] = None, mode: int = 2,
role_level: Optional[int] = None): role_level: Optional[int] = None):
# 获取Cookies # 获取Cookies
data_def = get_cookies() data_def = GetCookies()
retcode = await data_def.get_useable_cookies(uid, mode) retcode = await data_def.get_useable_cookies(uid, mode)
if not retcode: if not retcode:
return retcode return retcode
@ -1089,7 +1101,7 @@ async def draw_pic(uid: str, nickname: str, image: Optional[Match] = None, mode:
# 获取背景图片各项参数 # 获取背景图片各项参数
based_w = 900 based_w = 900
based_h = 870 + char_hang * 100 if char_num > 8 else 890 + char_hang * 110 based_h = 870 + char_hang * 100 if char_num > 8 else 890 + char_hang * 110
image_def = customize_image(image, based_w, based_h) image_def = CustomizeImage(image, based_w, based_h)
bg_img = image_def.bg_img bg_img = image_def.bg_img
bg_color = image_def.bg_color bg_color = image_def.bg_color
text_color = image_def.text_color text_color = image_def.text_color
@ -1154,34 +1166,46 @@ async def draw_pic(uid: str, nickname: str, image: Optional[Match] = None, mode:
text_draw.text((258, 625.4), str(raw_data['stats']['way_point_number']), text_color, genshin_font(24)) text_draw.text((258, 625.4), str(raw_data['stats']['way_point_number']), text_color, genshin_font(24))
text_draw.text((258, 675.4), str(raw_data['stats']['domain_number']), text_color, genshin_font(24)) text_draw.text((258, 675.4), str(raw_data['stats']['domain_number']), text_color, genshin_font(24))
# 蒙德 mondstadt = liyue = dragonspine = inazuma = offering = dict()
text_draw.text((490, 370), str(raw_data['world_explorations'][4]['exploration_percentage'] / 10) + '%', text_color, for i in raw_data['world_explorations']:
if i["name"] == "蒙德":
mondstadt = i
elif i["name"] == "璃月":
liyue = i
elif i["name"] == "龙脊雪山":
dragonspine = i
elif i["name"] == "稻妻":
inazuma = i
elif i["name"] == "渊下宫":
offering = i
text_draw.text((490, 370), str(mondstadt['exploration_percentage'] / 10) + '%', text_color,
genshin_font(22)) genshin_font(22))
text_draw.text((490, 400), 'lv.' + str(raw_data['world_explorations'][4]['level']), text_color, genshin_font(22)) text_draw.text((490, 400), 'lv.' + str(mondstadt['level']), text_color, genshin_font(22))
text_draw.text((513, 430), str(raw_data['stats']['anemoculus_number']), text_color, genshin_font(22)) text_draw.text((513, 430), str(raw_data['stats']['anemoculus_number']), text_color, genshin_font(22))
# 璃月 # 璃月
text_draw.text((490, 490), str(raw_data['world_explorations'][3]['exploration_percentage'] / 10) + '%', text_color, text_draw.text((490, 490), str(liyue['exploration_percentage'] / 10) + '%', text_color,
genshin_font(22)) genshin_font(22))
text_draw.text((490, 520), 'lv.' + str(raw_data['world_explorations'][3]['level']), text_color, genshin_font(22)) text_draw.text((490, 520), 'lv.' + str(liyue['level']), text_color, genshin_font(22))
text_draw.text((513, 550), str(raw_data['stats']['geoculus_number']), text_color, genshin_font(22)) text_draw.text((513, 550), str(raw_data['stats']['geoculus_number']), text_color, genshin_font(22))
# 雪山 # 雪山
text_draw.text((745, 373.5), str(raw_data['world_explorations'][2]['exploration_percentage'] / 10) + '%', text_draw.text((745, 373.5), str(dragonspine['exploration_percentage'] / 10) + '%',
text_color, text_color,
genshin_font(22)) genshin_font(22))
text_draw.text((745, 407.1), 'lv.' + str(raw_data['world_explorations'][2]['level']), text_color, genshin_font(22)) text_draw.text((745, 407.1), 'lv.' + str(dragonspine['level']), text_color, genshin_font(22))
# 稻妻 # 稻妻
text_draw.text((490, 608), str(raw_data['world_explorations'][1]['exploration_percentage'] / 10) + '%', text_color, text_draw.text((490, 608), str(inazuma['exploration_percentage'] / 10) + '%', text_color,
genshin_font(22)) genshin_font(22))
text_draw.text((490, 635), 'lv.' + str(raw_data['world_explorations'][1]['level']), text_color, genshin_font(22)) text_draw.text((490, 635), 'lv.' + str(inazuma['level']), text_color, genshin_font(22))
text_draw.text((490, 662), 'lv.' + str(raw_data['world_explorations'][1]['offerings'][0]['level']), text_color, text_draw.text((490, 662), 'lv.' + str(inazuma['offerings'][0]['level']), text_color,
genshin_font(22)) genshin_font(22))
text_draw.text((513, 689), str(raw_data['stats']['electroculus_number']), text_color, genshin_font(22)) text_draw.text((513, 689), str(raw_data['stats']['electroculus_number']), text_color, genshin_font(22))
# 渊下宫 # 渊下宫
text_draw.text((745, 480), str(raw_data['world_explorations'][0]['exploration_percentage'] / 10) + '%', text_color, text_draw.text((745, 480), str(offering['exploration_percentage'] / 10) + '%', text_color,
genshin_font(22)) genshin_font(22))
# 家园 # 家园
@ -1231,10 +1255,30 @@ async def draw_pic(uid: str, nickname: str, image: Optional[Match] = None, mode:
char_datas.sort(key=lambda x: (-x['rarity'], -x['level'], -x['fetter'])) char_datas.sort(key=lambda x: (-x['rarity'], -x['level'], -x['fetter']))
if char_num > 8: if char_num > 8:
char_names = []
client = ClientSession()
for i in char_datas:
char_names.append(i['name'])
talent_data = await get_all_calculate_info(client, uid, char_ids,
use_cookies, char_names)
await client.close()
tasks = [] tasks = []
for index, i in enumerate(char_datas): for index, i in enumerate(char_datas):
tasks.append(draw_char_pic(bg_img, i, index, char_color, text_color, bg_detail_color, char_high_color, uid, for j in talent_data:
use_cookies)) if j["name"] == i['name']:
tasks.append(
draw_char_pic(
bg_img,
i,
index,
char_color,
text_color,
bg_detail_color,
char_high_color,
j
)
)
await asyncio.wait(tasks) await asyncio.wait(tasks)
""" """
char_mingzuo = 0 char_mingzuo = 0
@ -1428,7 +1472,7 @@ async def draw_info_pic(uid: str, image: Optional[Match] = None) -> str:
return "%02d:%02d:%02d" % (h, m, s) return "%02d:%02d:%02d" % (h, m, s)
# 获取Cookies # 获取Cookies
data_def = get_cookies() data_def = GetCookies()
retcode = await data_def.get_useable_cookies(uid) retcode = await data_def.get_useable_cookies(uid)
if not retcode: if not retcode:
return retcode return retcode
@ -1443,7 +1487,7 @@ async def draw_info_pic(uid: str, image: Optional[Match] = None) -> str:
# 获取背景图片各项参数 # 获取背景图片各项参数
based_w = 900 based_w = 900
based_h = 1380 based_h = 1380
image_def = customize_image(image, based_w, based_h) image_def = CustomizeImage(image, based_w, based_h)
bg_img = image_def.bg_img bg_img = image_def.bg_img
bg_color = image_def.bg_color bg_color = image_def.bg_color
text_color = image_def.text_color text_color = image_def.text_color
@ -1492,7 +1536,8 @@ async def draw_info_pic(uid: str, image: Optional[Match] = None) -> str:
# 本日原石/摩拉 # 本日原石/摩拉
text_draw.text((675, 148), text_draw.text((675, 148),
f"{award_data['data']['day_data']['current_primogems']}/{award_data['data']['day_data']['last_primogems']}", f"{award_data['data']['day_data']['current_primogems']}/"
f"{award_data['data']['day_data']['last_primogems']}",
text_color, genshin_font(28), anchor="lm") text_color, genshin_font(28), anchor="lm")
text_draw.text((675, 212), text_draw.text((675, 212),
f"{award_data['data']['day_data']['current_mora']}\n{award_data['data']['day_data']['last_mora']}", f"{award_data['data']['day_data']['current_mora']}\n{award_data['data']['day_data']['last_mora']}",
@ -1523,7 +1568,8 @@ async def draw_info_pic(uid: str, image: Optional[Match] = None) -> str:
text_draw.text((390, 503), f"{daily_data['finished_task_num']}/{daily_data['total_task_num']}", text_color, text_draw.text((390, 503), f"{daily_data['finished_task_num']}/{daily_data['total_task_num']}", text_color,
genshin_font(26), anchor="lm") genshin_font(26), anchor="lm")
text_draw.text((390, 597), text_draw.text((390, 597),
f"{str(daily_data['resin_discount_num_limit'] - daily_data['remain_resin_discount_num'])}/{daily_data['resin_discount_num_limit']}", f"{str(daily_data['resin_discount_num_limit'] - daily_data['remain_resin_discount_num'])}/"
f"{daily_data['resin_discount_num_limit']}",
text_color, genshin_font(26), anchor="lm") text_color, genshin_font(26), anchor="lm")
# 树脂恢复时间计算 # 树脂恢复时间计算
@ -1532,13 +1578,13 @@ async def draw_info_pic(uid: str, image: Optional[Match] = None) -> str:
else: else:
resin_recovery_time = seconds2hours( resin_recovery_time = seconds2hours(
daily_data['resin_recovery_time']) daily_data['resin_recovery_time'])
next_resin_rec_time = seconds2hours( next_resin_rec_time = seconds2hours(
8 * 60 - ((daily_data['max_resin'] - daily_data['current_resin']) * 8 * 60 - int( 8 * 60 - ((daily_data['max_resin'] - daily_data['current_resin']) * 8 * 60 - int(
daily_data['resin_recovery_time']))) daily_data['resin_recovery_time'])))
text_draw.text((268, 305), f" {next_resin_rec_time}", text_color, genshin_font(18), anchor="lm") text_draw.text((268, 305), f" {next_resin_rec_time}", text_color, genshin_font(18), anchor="lm")
text_draw.text((170, 331), f"预计 后全部恢复", text_color, genshin_font(18), anchor="lm") text_draw.text((170, 331), f"预计 后全部恢复", text_color, genshin_font(18), anchor="lm")
text_draw.text((208, 331), f"{resin_recovery_time}", highlight_color, genshin_font(18), anchor="lm") text_draw.text((208, 331), f"{resin_recovery_time}", highlight_color, genshin_font(18), anchor="lm")
# 洞天宝钱时间计算 # 洞天宝钱时间计算
coin_rec_time = seconds2hours(int(daily_data["home_coin_recovery_time"])) coin_rec_time = seconds2hours(int(daily_data["home_coin_recovery_time"]))
@ -1576,10 +1622,11 @@ async def draw_info_pic(uid: str, image: Optional[Match] = None) -> str:
if not os.path.exists( if not os.path.exists(
os.path.join(CHAR_IMG_PATH, f"UI_AvatarIcon_{i['avatar_side_icon'].split('_')[-1][:-4]}@2x.png")): os.path.join(CHAR_IMG_PATH, f"UI_AvatarIcon_{i['avatar_side_icon'].split('_')[-1][:-4]}@2x.png")):
get_char_img_pic( get_char_img_pic(
f"https://upload-bbs.mihoyo.com/game_record/genshin/character_image/UI_AvatarIcon_{i['avatar_side_icon'].split('_')[-1][:-4]}@2x.png") f"https://upload-bbs.mihoyo.com/game_record/genshin/character_image"
# char_stand_img = os.path.join(CHAR_IMG_PATH, f"UI_AvatarIcon_{i['avatar_side_icon'].split('_')[-1][:-4]}@2x.png") f"/UI_AvatarIcon_{i['avatar_side_icon'].split('_')[-1][:-4]}@2x.png")
# char_stand = Image.open(char_stand_img) # char_stand_img = os.path.join(CHAR_IMG_PATH, f"UI_AvatarIcon_{i['avatar_side_icon'].split('_')[-1][
# char_stand_mask = Image.open(os.path.join(TEXT_PATH, "stand_mask.png")) # :-4]}@2x.png") char_stand = Image.open(char_stand_img) char_stand_mask = Image.open(os.path.join(TEXT_PATH,
# "stand_mask.png"))
# charpic_temp = Image.new("RGBA", (900, 130)) # charpic_temp = Image.new("RGBA", (900, 130))
# charpic_temp.paste(char_stand, (395, -99), char_stand_mask) # charpic_temp.paste(char_stand, (395, -99), char_stand_mask)
@ -1702,4 +1749,4 @@ async def draw_event_pic() -> None:
base_img = base_img.convert('RGB') base_img = base_img.convert('RGB')
base_img.save(os.path.join(FILE2_PATH, 'event.jpg'), format='JPEG', subsampling=0, quality=90) base_img.save(os.path.join(FILE2_PATH, 'event.jpg'), format='JPEG', subsampling=0, quality=90)
return return

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 795 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 714 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 788 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB