From 85af38f0750d0abac11a52befb66e4d833108cb4 Mon Sep 17 00:00:00 2001 From: qwerdvd <2450899274@qq.com> Date: Sat, 29 Apr 2023 17:30:55 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=E5=AE=8C=E6=88=90=E4=B8=80=E5=8D=8A?= =?UTF-8?q?=20`sr=E6=AF=8F=E6=97=A5`=20=E5=B7=A5=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- StarRailUID/sruid_utils/api/mys/models.py | 12 +- .../starrailuid_resin/draw_resin_card.py | 274 +++++++++++++----- StarRailUID/utils/image/convert.py | 109 +++++++ StarRailUID/utils/image/texture2d/mask.png | Bin 0 -> 5831 bytes StarRailUID/utils/image/texture2d/ring.png | Bin 0 -> 7988 bytes StarRailUID/utils/mys_api.py | 17 +- 6 files changed, 331 insertions(+), 81 deletions(-) create mode 100644 StarRailUID/utils/image/convert.py create mode 100644 StarRailUID/utils/image/texture2d/mask.png create mode 100644 StarRailUID/utils/image/texture2d/ring.png diff --git a/StarRailUID/sruid_utils/api/mys/models.py b/StarRailUID/sruid_utils/api/mys/models.py index d96d0b0..bc9632e 100644 --- a/StarRailUID/sruid_utils/api/mys/models.py +++ b/StarRailUID/sruid_utils/api/mys/models.py @@ -1,5 +1,13 @@ from typing import Any, List, TypedDict + +class RoleBasicInfo(TypedDict): + avatar: str + nick_name: str + region: str + level: int + + ################ # 每月札记相关 # ################ @@ -52,7 +60,7 @@ class MonthlyAward(TypedDict): ################ # 实时便签 # ################ -class SingleExpedition(TypedDict): +class Expedition(TypedDict): avatars: List[str] # 头像Url status: str remaining_time: int @@ -65,7 +73,7 @@ class DailyNoteData(TypedDict): stamina_recover_time: int accepted_expedition_num: int total_expedition_num: int - expeditions: List[SingleExpedition] + expeditions: List[Expedition] ################ diff --git a/StarRailUID/starrailuid_resin/draw_resin_card.py b/StarRailUID/starrailuid_resin/draw_resin_card.py index 8f025da..d68178a 100644 --- a/StarRailUID/starrailuid_resin/draw_resin_card.py +++ b/StarRailUID/starrailuid_resin/draw_resin_card.py @@ -1,99 +1,217 @@ -# import json -# import asyncio -# from typing import List +import asyncio +from io import BytesIO +from typing import List from pathlib import Path -from PIL import Image +import aiohttp +from PIL import Image, ImageDraw +from gsuid_core.logger import logger -# from PIL import ImageDraw -# from gsuid_core.logger import logger -# from gsuid_core.utils.api.mys.models import Expedition - -# from ..utils.mys_api import mys_api -# from ..utils.api import get_sqla -# from ..utils.image.convert import convert_img -# from ..utils.image.image_tools import get_simple_bg -# from ..utils.map.name_covert import enName_to_avatarId -# from ..utils.resource.RESOURCE_PATH import PLAYER_PATH, CHAR_SIDE_PATH -# from ..utils.fonts.starrail_fonts import ( -# sr_font_20, -# sr_font_26, -# sr_font_32, -# sr_font_60, -# ) +from ..utils.api import get_sqla +from ..utils.mys_api import mys_api +from ..utils.image.convert import convert_img +from ..sruid_utils.api.mys.models import Expedition +from ..utils.fonts.starrail_fonts import ( + sr_font_20, + sr_font_24, + sr_font_36, + sr_font_50, +) TEXT_PATH = Path(__file__).parent / 'texture2D' note_bg = Image.open(TEXT_PATH / 'note_bg.png') note_travel_bg = Image.open(TEXT_PATH / 'note_travel_bg.png') -based_w = 500 -based_h = 900 +based_w = 700 +based_h = 1000 white_overlay = Image.new('RGBA', (based_w, based_h), (255, 251, 242, 225)) first_color = (29, 29, 29) second_color = (98, 98, 98) +white_color = (255, 255, 255) green_color = (15, 196, 35) orange_color = (237, 115, 61) red_color = (235, 61, 75) -# async def _draw_task_img( -# img: Image.Image, -# img_draw: ImageDraw.ImageDraw, -# index: int, -# char: Expedition, -# ): -# char_en_name = char['avatar_side_icon'].split('_')[-1].split('.')[0] -# avatar_id = await enName_to_avatarId(char_en_name) -# char_pic = ( -# Image.open(CHAR_SIDE_PATH / f'{avatar_id}.png') -# .convert('RGBA') -# .resize((80, 80), Image.Resampling.LANCZOS) # type: ignore -# ) -# img.paste(char_pic, (22 + index * 90, 770), char_pic) -# if char['status'] == 'Finished': -# status_mark = '待收取' -# status_color = red_color -# else: -# status_mark = '已派遣' -# status_color = green_color -# img_draw.text( -# (65 + index * 90, 870), -# status_mark, -# font=sr_font_20, -# fill=status_color, -# anchor='mm', -# ) +async def download_image(url: str) -> Image.Image: + async with aiohttp.ClientSession() as session: + async with session.get(url) as response: + img_data = await response.read() + img = Image.open(BytesIO(img_data)) + return img + + +async def _draw_task_img( + img: Image.Image, + img_draw: ImageDraw.ImageDraw, + index: int, + char: Expedition, +): + for i in range(2): + avatar_url = char['avatars'][i] + image = await download_image(avatar_url) + char_pic = image.convert('RGBA').resize( + (40, 40), Image.Resampling.LANCZOS + ) # type: ignore + img.paste(char_pic, (22 + index * 90, 40), char_pic) + if char['status'] == 'Finished': + status_mark = '待收取' + status_color = red_color + else: + status_mark = '已派遣' + status_color = green_color + img_draw.text( + (65 + index * 90, 870), + status_mark, + font=sr_font_20, + fill=status_color, + anchor='mm', + ) async def get_resin_img(bot_id: str, user_id: str): - pass - # try: - # sqla = get_sqla(bot_id) - # uid_list: List = await sqla.get_bind_uid_list(user_id) - # logger.info('[每日信息]UID: {}'.format(uid_list)) - # # 进行校验UID是否绑定CK - # useable_uid_list = [] - # for uid in uid_list: - # status = await sqla.get_user_cookie(uid) - # if status is not None: - # useable_uid_list.append(uid) - # logger.info('[每日信息]可用UID: {}'.format(useable_uid_list)) - # if len(useable_uid_list) == 0: - # return '请先绑定一个可用CK & UID再来查询哦~' - # # 开始绘图任务 - # task = [] - # img = Image.new( - # 'RGBA', (based_w * len(useable_uid_list), based_h), (0, 0, 0, 0) - # ) - # for uid_index, uid in enumerate(useable_uid_list): - # task.append(_draw_all_resin_img(img, uid, uid_index)) - # await asyncio.gather(*task) - # res = await convert_img(img) - # logger.info('[查询每日信息]绘图已完成,等待发送!') - # except TypeError: - # logger.exception('[查询每日信息]绘图失败!') - # res = '你绑定过的UID中可能存在过期CK~请重新绑定一下噢~' - # - # return res + try: + sqla = get_sqla(bot_id) + uid_list: List = await sqla.get_bind_sruid_list(user_id) + logger.info('[每日信息]UID: {}'.format(uid_list)) + # 进行校验UID是否绑定CK + useable_uid_list = [] + for uid in uid_list: + status = await sqla.get_user_cookie(uid) + if status is not None: + useable_uid_list.append(uid) + logger.info('[每日信息]可用UID: {}'.format(useable_uid_list)) + if len(useable_uid_list) == 0: + return '请先绑定一个可用CK & UID再来查询哦~' + # 开始绘图任务 + task = [] + img = Image.new( + 'RGBA', (based_w * len(useable_uid_list), based_h), (0, 0, 0, 0) + ) + for uid_index, uid in enumerate(useable_uid_list): + task.append(_draw_all_resin_img(img, uid, uid_index)) + await asyncio.gather(*task) + res = await convert_img(img) + logger.info('[查询每日信息]绘图已完成,等待发送!') + except TypeError: + logger.exception('[查询每日信息]绘图失败!') + res = '你绑定过的UID中可能存在过期CK~请重新绑定一下噢~' + + return res + + +async def _draw_all_resin_img(img: Image.Image, uid: str, index: int): + resin_img = await draw_resin_img(uid) + img.paste(resin_img, (500 * index, 0), resin_img) + + +async def seconds2hours(seconds: int) -> str: + m, s = divmod(int(seconds), 60) + h, m = divmod(m, 60) + return '%02d小时%02d分' % (h, m) + + +async def draw_resin_img(sr_uid: str) -> Image.Image: + # 获取数据 + daily_data = await mys_api.get_daily_data(sr_uid) + + # 获取背景图片各项参数 + img = note_bg + # img.paste(white_overlay, (0, 0), white_overlay) + + if isinstance(daily_data, int): + img_draw = ImageDraw.Draw(img) + # img.paste(warn_pic, (0, 0), warn_pic) + # 写UID + img_draw.text( + (250, 553), + f'UID{sr_uid}', + font=sr_font_36, + fill=first_color, + anchor='mm', + ) + img_draw.text( + (250, 518), + f'错误码 {daily_data}', + font=sr_font_36, + fill=red_color, + anchor='mm', + ) + return img + + # nickname and level + role_basic_info = await mys_api.get_role_basic_info(sr_uid) + nickname = role_basic_info['nickname'] + level = role_basic_info['level'] + + # 开拓力 + stamina = daily_data['current_stamina'] + max_stamina = daily_data['max_stamina'] + stamina_str = f'{stamina}/{max_stamina}' + stamina_percent = stamina / max_stamina + if stamina_percent > 0.8: + stamina_color = red_color + else: + stamina_color = second_color + stamina_recovery_time = await seconds2hours( + daily_data['stamina_recover_time'] + ) + + img_draw = ImageDraw.Draw(img) + + # # 派遣 + # task_task = [] + # for index, char in enumerate(daily_data['expeditions']): + # task_task.append(_draw_task_img(img, img_draw, index, char)) + # await asyncio.gather(*task_task) + + # 绘制树脂圆环 + ring_pic = Image.open(TEXT_PATH / 'ring.apng') + percent = ( + round(stamina_percent * 90) + if round(stamina_percent * 90) <= 90 + else 90 + ) + ring_pic.seek(percent) + img.paste(ring_pic, (0, 0), ring_pic) + + # 写树脂剩余时间 + img_draw.text( + (350, 415), + f'还剩{stamina_recovery_time}', + font=sr_font_24, + fill=stamina_color, + anchor='mm', + ) + # 写Nickname + img_draw.text( + (350, 153), nickname, font=sr_font_36, fill=white_color, anchor='mm' + ) + # 写开拓等级 + img_draw.text( + (350, 210), + f'开拓等级{level}', + font=sr_font_24, + fill=white_color, + anchor='mm', + ) + # 写UID + img_draw.text( + (350, 655), + f'UID{sr_uid}', + font=sr_font_24, + fill=first_color, + anchor='mm', + ) + # 写树脂 + img_draw.text( + (350, 478), + stamina_str, + font=sr_font_50, + fill=first_color, + anchor='mm', + ) + + return img diff --git a/StarRailUID/utils/image/convert.py b/StarRailUID/utils/image/convert.py new file mode 100644 index 0000000..c3e3c31 --- /dev/null +++ b/StarRailUID/utils/image/convert.py @@ -0,0 +1,109 @@ +from io import BytesIO +from pathlib import Path +from base64 import b64encode +from typing import Union, overload + +import aiofiles +from PIL import Image, ImageFont + + +@overload +async def convert_img(img: Image.Image, is_base64: bool = False) -> bytes: + ... + + +@overload +async def convert_img(img: Image.Image, is_base64: bool = True) -> str: + ... + + +@overload +async def convert_img(img: bytes, is_base64: bool = False) -> str: + ... + + +@overload +async def convert_img(img: Path, is_base64: bool = False) -> str: + ... + + +async def convert_img( + img: Union[Image.Image, str, Path, bytes], is_base64: bool = False +): + """ + :说明: + 将PIL.Image对象转换为bytes或者base64格式。 + :参数: + * img (Image): 图片。 + * is_base64 (bool): 是否转换为base64格式, 不填默认转为bytes。 + :返回: + * res: bytes对象或base64编码图片。 + """ + if isinstance(img, Image.Image): + img = img.convert('RGB') + result_buffer = BytesIO() + img.save(result_buffer, format='PNG', quality=80, subsampling=0) + res = result_buffer.getvalue() + if is_base64: + res = 'base64://' + b64encode(res).decode() + return res + elif isinstance(img, bytes): + pass + else: + async with aiofiles.open(img, 'rb') as fp: + img = await fp.read() + return f'base64://{b64encode(img).decode()}' + + +async def str_lenth(r: str, size: int, limit: int = 540) -> str: + result = '' + temp = 0 + for i in r: + if i == '\n': + temp = 0 + result += i + continue + + if temp >= limit: + result += '\n' + i + temp = 0 + else: + result += i + + if i.isdigit(): + temp += round(size / 10 * 6) + elif i == '/': + temp += round(size / 10 * 2.2) + elif i == '.': + temp += round(size / 10 * 3) + elif i == '%': + temp += round(size / 10 * 9.4) + else: + temp += size + return result + + +def get_str_size( + r: str, font: ImageFont.FreeTypeFont, limit: int = 540 +) -> str: + result = '' + line = '' + for i in r: + if i == '\n': + result += f'{line}\n' + line = '' + continue + + line += i + size, _ = font.getsize(line) + if size >= limit: + result += f'{line}\n' + line = '' + else: + result += line + return result + + +def get_height(content: str, size: int) -> int: + line_count = content.count('\n') + return (line_count + 1) * size diff --git a/StarRailUID/utils/image/texture2d/mask.png b/StarRailUID/utils/image/texture2d/mask.png new file mode 100644 index 0000000000000000000000000000000000000000..c2211002bb790a52f19fa3c33c8b491106342c80 GIT binary patch literal 5831 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 literal 0 HcmV?d00001 diff --git a/StarRailUID/utils/image/texture2d/ring.png b/StarRailUID/utils/image/texture2d/ring.png new file mode 100644 index 0000000000000000000000000000000000000000..328995cb67d55b95cb71135c640b8dcb1171d9a1 GIT binary patch literal 7988 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 NH&BMxNLL(V{|C{+e}Vu2 literal 0 HcmV?d00001 diff --git a/StarRailUID/utils/mys_api.py b/StarRailUID/utils/mys_api.py index dacbf0f..8a286ef 100644 --- a/StarRailUID/utils/mys_api.py +++ b/StarRailUID/utils/mys_api.py @@ -14,8 +14,12 @@ from gsuid_core.utils.api.mys.tools import ( from ..utils.api import get_sqla from ..sruid_utils.api.mys.api import _API -from ..sruid_utils.api.mys.models import MonthlyAward, DailyNoteData from ....GenshinUID.GenshinUID.genshinuid_config.gs_config import gsconfig +from ..sruid_utils.api.mys.models import ( + MonthlyAward, + DailyNoteData, + RoleBasicInfo, +) RECOGNIZE_SERVER = { '1': 'prod_gf_cn', @@ -225,6 +229,17 @@ class _MysApi(BaseMysApi): data = cast(MonthlyAward, data['data']) return data + async def get_role_basic_info( + self, sr_uid: str + ) -> Union[RoleBasicInfo, int]: + data = await self.simple_mys_req( + 'STAR_RAIL_ROLE_BASIC_INFO_URL', sr_uid + ) + print(data) + if isinstance(data, Dict): + data = cast(DailyNoteData, data['data']) + return data + async def _mys_req_get( self, url: str,