新增gs剧诗版本深渊

This commit is contained in:
KimigaiiWuyi 2024-11-20 08:27:32 +08:00
parent d09bd873a7
commit 86a4169f68
10 changed files with 391 additions and 1 deletions

View File

@ -4,6 +4,7 @@ from typing import List
from gsuid_core.sv import SV
from gsuid_core.bot import Bot
from gsuid_core.models import Event
from gsuid_core.logger import logger
from gsuid_core.message_models import Button
from gsuid_core.segment import MessageSegment
@ -16,9 +17,11 @@ from .get_new_abyss_data import get_review_data
from ..utils.resource.RESOURCE_PATH import REF_PATH
from .get_bbs_post_guide import get_material_way_post
from ..utils.map.name_covert import alias_to_char_name
from .draw_poetry_abyss_pic import draw_poetry_abyss_image
sv_char_guide = SV('查询角色攻略')
sv_abyss_review = SV('查询深渊阵容')
sv_poetry_abyss_review = SV('查询剧诗深渊阵容')
sv_bbs_post_guide = SV('查询BBS攻略')
@ -57,6 +60,13 @@ async def send_bluekun_pic(bot: Bot, ev: Event):
await bot.logger.warning('未找到{}参考面板图片'.format(name))
@sv_poetry_abyss_review.on_command(('剧诗版本深渊', '剧诗深渊阵容'))
async def send_poetry_abyss_review(bot: Bot, ev: Event):
im = await draw_poetry_abyss_image()
logger.info('[剧诗版本深渊] 获得深渊信息成功!')
await bot.send(im)
@sv_abyss_review.on_command(('版本深渊', '深渊阵容', '深渊怪物'))
async def send_abyss_review(bot: Bot, ev: Event):
floor = '12'
@ -88,7 +98,7 @@ async def send_abyss_review(bot: Bot, ev: Event):
d = Button(f'♾️版本深渊{adv_version}', f'深渊概览{adv_version}')
await bot.send_option(im, [c, d])
elif isinstance(im, List):
mes = [MessageSegment.text(str(msg)) for msg in im]
mes = [MessageSegment.text(str(msg)) for msg in im] # type: ignore
await bot.send(MessageSegment.node(mes))
elif isinstance(im, str):
await bot.send(im)

View File

@ -0,0 +1,222 @@
import re
from pathlib import Path
from datetime import datetime
from PIL import Image, ImageDraw
from gsuid_core.utils.error_reply import get_error
from gsuid_core.utils.image.convert import convert_img
from ..utils.image.image_tools import add_footer
from ..utils.api.hakush.request import hakush_api
from ..utils.map.name_covert import avatar_id_to_name
from ..utils.resource.RESOURCE_PATH import CHAR_CARD_PATH, MONSTER_ICON_PATH
from ..utils.fonts.genshin_fonts import (
gs_font_20,
gs_font_22,
gs_font_26,
gs_font_28,
gs_font_30,
gs_font_38,
)
TEXT_PATH = Path(__file__).parent / 'texture2d2'
def remove_angle_brackets(text: str) -> str:
cleaned_text = re.sub(r'<.*?>', '', text)
return cleaned_text
def is_current_time_in_range(start_time: str, end_time: str) -> bool:
start_datetime = datetime.strptime(start_time, "%Y-%m-%d %H:%M:%S")
end_datetime = datetime.strptime(end_time, "%Y-%m-%d %H:%M:%S")
current_datetime = datetime.now()
return start_datetime <= current_datetime <= end_datetime
async def draw_poetry_abyss_image():
data = await hakush_api.get_hakush_rolecombats()
if isinstance(data, int):
return get_error(data)
poetry_id = 0
for _id in data:
item = data[_id]
begin = item['begin']
end = item['end']
if is_current_time_in_range(begin, end):
poetry_id = _id
break
else:
return '没有找到当前的活动!'
pdata = await hakush_api.get_hakush_rolecombat(poetry_id)
if isinstance(pdata, int):
return get_error(pdata)
w, h = 1000, 1270 + 50
monster_list = list(pdata['DifficultyConfig'].values())[-1]
monster_room = monster_list['Room']
for room_id in monster_room:
monster = monster_room[room_id]
if 'Title' in monster:
h += 301
else:
h += 145
time = f"{pdata['BeginTime']} ~ {pdata['EndTime']}"
img = Image.new('RGBA', (w, h), (22, 18, 20, 255))
title = Image.open(TEXT_PATH / 'title.png')
title_draw = ImageDraw.Draw(title)
title_draw.text(
(500, 473),
f'剧诗ID{poetry_id} 详细信息',
(255, 255, 255),
font=gs_font_38,
anchor='mm',
)
img.paste(title, (0, 0), title)
avatar_bg = Image.open(TEXT_PATH / 'avatar_bg.png')
avatar_draw = ImageDraw.Draw(avatar_bg)
avatar_draw.text(
(500, 184),
time,
(139, 137, 133),
font=gs_font_22,
anchor='mm',
)
avatar_draw.text(
(500, 474),
pdata['AvatarConfig']['BuffAvatarList'][0]['Desc'][16:-9],
(139, 137, 133),
font=gs_font_26,
anchor='mm',
)
for cindex, char in enumerate(pdata['AvatarConfig']['BuffAvatarList']):
char_id = str(char['Id'])
char_img = Image.open(CHAR_CARD_PATH / f'{char_id}.png')
char_img = char_img.resize((102, 124))
char_name = await avatar_id_to_name(char_id)
char_draw = ImageDraw.Draw(char_img)
char_draw.text(
(51, 111),
char_name,
(10, 10, 10),
font=gs_font_20,
anchor='mm',
)
avatar_bg.paste(char_img, (121 + cindex * 130, 302), char_img)
for iindex, char_id in enumerate(
pdata['AvatarConfig']['InviteAvatarList']
):
char_id = str(char_id)
char_img = Image.open(CHAR_CARD_PATH / f'{char_id}.png')
char_img = char_img.resize((102, 124))
char_name = await avatar_id_to_name(char_id)
char_draw = ImageDraw.Draw(char_img)
char_draw.text(
(51, 111),
char_name,
(10, 10, 10),
font=gs_font_20,
anchor='mm',
)
avatar_bg.paste(char_img, (252 + iindex * 130, 576), char_img)
img.paste(avatar_bg, (0, 482), avatar_bg)
point = 1270
for room_id in monster_room:
monster = monster_room[room_id]
if 'Title' in monster:
monster_bg = Image.open(TEXT_PATH / 'long_monster_bg.png')
monster_draw = ImageDraw.Draw(monster_bg)
desc = remove_angle_brackets(monster['Desc'])
desc = desc[:26] + '...'
monster_draw.text(
(245, 69),
f'{monster["Title"]}',
'black',
font=gs_font_30,
anchor='lm',
)
for mindex, m in enumerate(monster['MonsterPreviewList']):
monster_icon = m['Icon']
monster_img = await hakush_api.get_hakush_ui(
monster_icon, MONSTER_ICON_PATH
)
monster_img = monster_img.resize((90, 90))
monster_name = m['Name']
if '·' in monster_name:
monster_name = monster_name.split('·')[-1]
monster_name = monster_name[:6]
monster_hp = int(m['Hp'])
mimg = Image.new(
'RGBA',
(250, 90),
(219, 209, 203),
)
ming_draw = ImageDraw.Draw(mimg)
mimg.paste(monster_img, (0, 0), monster_img)
ming_draw.text(
(100, 30),
f'{monster_name}',
(36, 36, 36),
font=gs_font_22,
anchor='lm',
)
ming_draw.text(
(100, 57),
f'HP {monster_hp}',
(90, 90, 90),
font=gs_font_22,
anchor='lm',
)
monster_bg.paste(mimg, (126 + mindex * 257, 158), mimg)
else:
monster_bg = Image.open(TEXT_PATH / 'short_monster_bg.png')
monster_draw = ImageDraw.Draw(monster_bg)
desc = f'怪物等级 Lv{monster["MonsterLevel"]}'
monster_draw.text(
(131, 69),
f'{room_id}',
'black',
font=gs_font_30,
anchor='lm',
)
monster_draw.text(
(131, 114),
desc,
(99, 99, 99),
font=gs_font_28,
anchor='lm',
)
if 'Title' not in monster:
point -= 12
img.paste(monster_bg, (0, point), monster_bg)
if 'Title' not in monster:
point += 145
else:
point += 301
img = add_footer(img, 1000)
res = await convert_img(img)
return res

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 KiB

View File

@ -507,6 +507,14 @@
"need_sk": false,
"need_admin": false
},
{
"name": "剧诗版本深渊",
"desc": "获取当前版本剧诗深渊阵容",
"eg": "剧诗版本深渊",
"need_ck": false,
"need_sk": false,
"need_admin": false
},
{
"name": "查成就",
"desc": "查询这个成就的攻略",

View File

@ -0,0 +1,5 @@
HAKUSH_D_API = 'https://api.hakush.in/gi/data'
HAKUSH_U_API = 'https://api.hakush.in/gi/UI'
HAKUSH_ROLECOMBATS_API = f'{HAKUSH_D_API}/rolecombat.json'
HAKUSH_ROLECOMBAT_API = f'{HAKUSH_D_API}/zh/rolecombat/' + '{}.json'

View File

@ -0,0 +1,58 @@
from typing import Dict, List, TypedDict
class RoleCombatEvent(TypedDict):
begin: str
end: str
element: List[int]
invite: List[int]
buff: List[int]
live_begin: str
live_end: str
class BuffAvatar(TypedDict):
Id: int
Desc: str
class MonsterPreview(TypedDict):
Id: int
Hp: float
Name: str
Icon: str
class RoomConfig(TypedDict):
MonsterLevel: int
Title: str
Desc: str
MonsterPreviewList: List[MonsterPreview]
class DifficultyLevel(TypedDict):
CanInvitePool: int
BossMaxRoomNumber: int
MinimumAvatarLevel: int
Room: Dict[str, RoomConfig]
CanInvitePoolAdd: int
class AvatarConfig(TypedDict):
ElementList: List[int]
InviteAvatarList: List[int]
BuffAvatarList: List[BuffAvatar]
class ShopItem(TypedDict):
Id: int
Name: str
Desc: str
class RoleCombatData(TypedDict):
BeginTime: str
EndTime: str
AvatarConfig: AvatarConfig
DifficultyConfig: Dict[str, DifficultyLevel]
ShopConfig: List[ShopItem]

View File

@ -0,0 +1,87 @@
import io
import json
from pathlib import Path
from typing import Any, Dict, Union, Literal, Optional, cast
from PIL import Image
from httpx import AsyncClient
from gsuid_core.logger import logger
from .models import RoleCombatData, RoleCombatEvent
from .api import HAKUSH_U_API, HAKUSH_ROLECOMBAT_API, HAKUSH_ROLECOMBATS_API
class _HakushAPI:
ssl_verify = True
_HEADER = {'User-Agent': 'GenshinUID & GsCore'}
async def get_hakush_rolecombats(
self,
) -> Union[Dict[str, RoleCombatEvent], int]:
data = await self._hakush_request(HAKUSH_ROLECOMBATS_API)
if isinstance(data, Dict):
return cast(Dict[str, RoleCombatEvent], data)
else:
return -500
async def get_hakush_rolecombat(
self, id: str
) -> Union[RoleCombatData, int]:
data = await self._hakush_request(HAKUSH_ROLECOMBAT_API.format(id))
if isinstance(data, Dict):
return cast(RoleCombatData, data)
else:
return -500
async def get_hakush_ui(
self, ui_name: str, save_path: Path
) -> Image.Image:
png_file_path = save_path / f'{ui_name}.png'
if png_file_path.exists():
return Image.open(png_file_path)
url = f'{HAKUSH_U_API}/{ui_name}.webp'
data = await self._hakush_request(url)
if isinstance(data, bytes):
webp_stream = io.BytesIO(data)
with Image.open(webp_stream) as img:
img.save(str(png_file_path), 'PNG')
return img
else:
return Image.new('RGBA', (256, 256))
async def _hakush_request(
self,
url: str,
method: Literal['GET', 'POST'] = 'GET',
header: Dict[str, Any] = _HEADER,
params: Optional[Dict[str, Any]] = None,
_json: Optional[Dict[str, Any]] = None,
) -> Union[Dict, int, bytes]:
async with AsyncClient(timeout=None) as client:
logger.debug(f'[HAKUSH] 正在请求{url}')
resp = await client.request(
method,
url,
headers=header,
params=params,
json=_json,
)
try:
raw_data = await resp.json()
except: # noqa
try:
raw_data = json.loads(resp.text)
except: # noqa
try:
raw_data = resp.content
except: # noqa
raw_data = {
'retcode': -999,
'data': resp.text,
}
if not isinstance(raw_data, bytes):
logger.debug(raw_data)
return raw_data
hakush_api = _HakushAPI()