新增幻想真境剧诗

This commit is contained in:
KimigaiiWuyi 2024-07-02 03:19:32 +08:00
parent 9d815653ae
commit 48bdf7bd9f
16 changed files with 371 additions and 6 deletions

View File

@ -0,0 +1,31 @@
import re
from gsuid_core.sv import SV
from gsuid_core.bot import Bot
from gsuid_core.models import Event
from gsuid_core.utils.error_reply import UID_HINT
from ..utils.convert import get_uid
from .draw_poetry_abyss import draw_poetry_abyss_img
sv_poetry_abyss = SV('查询幻想真境剧诗')
@sv_poetry_abyss.on_command(
('查询幻想真境剧诗', '幻想真境剧诗', '新深渊', '查询新深渊', '真剧诗'),
block=True,
)
async def send_poetry_abyss_info(bot: Bot, ev: Event):
name = ''.join(re.findall('[\u4e00-\u9fa5]', ev.text))
if name:
return
await bot.logger.info('开始执行[幻想真境剧诗]')
uid, user_id = await get_uid(bot, ev, True)
if uid is None:
return await bot.send(UID_HINT)
await bot.logger.info('[幻想真境剧诗]uid: {}'.format(uid))
im = await draw_poetry_abyss_img(uid, ev)
await bot.send(im)

View File

@ -0,0 +1,212 @@
from pathlib import Path
from datetime import datetime
from typing import List, Union
from PIL import Image, ImageDraw
from gsuid_core.models import Event
from gsuid_core.utils.error_reply import get_error
from gsuid_core.utils.image.image_tools import get_avatar_with_ring
from ..utils.mys_api import mys_api
from ..utils.colors import first_color
from ..utils.image.convert import convert_img
from ..utils.image.image_tools import add_footer
from ..utils.resource.download_url import download_file
from ..utils.resource.RESOURCE_PATH import ICON_PATH, CHAR_CARD_PATH
from ..utils.resource.generate_char_card import create_single_char_card
from ..utils.fonts.genshin_fonts import (
gs_font_20,
gs_font_28,
gs_font_36,
gs_font_40,
gs_font_50,
)
TEXT_PATH = Path(__file__).parent / 'texture2d'
DIFFICULTY_MAP = {
1: '简单模式',
2: '普通模式',
3: '困难模式',
}
def timestamp_to_str(timestamp: float):
dt = datetime.fromtimestamp(timestamp)
return dt.strftime('%Y.%m.%d %H:%M:%S')
async def draw_buff(
data: List,
startb: int,
stage: Image.Image,
stage_draw: ImageDraw.ImageDraw,
_type: str,
):
if _type == '神秘收获':
y = 206
else:
y = 253
for index_choice, choice in enumerate(data):
name = f'{choice["name"]}.png'
path = ICON_PATH / name
if not path.exists():
await download_file(choice['icon'], 8, name)
icon = Image.open(path).resize((45, 45)).convert('RGBA')
buff = Image.open(TEXT_PATH / 'buff.png')
buff.paste(icon, (-3, -4), icon)
stage.paste(buff, (startb + index_choice * 44, y), buff)
if not data:
stage_draw.text(
(startb, y + 21), f'暂无{_type}', (68, 59, 45), gs_font_20, 'lm'
)
async def draw_poetry_abyss_img(uid: str, ev: Event) -> Union[str, bytes]:
data = await mys_api.get_poetry_abyss_data(uid)
if isinstance(data, int):
return get_error(data)
if not data['is_unlock'] or not data['data']:
return '[幻想真境剧诗] 你还没有解锁该模式!'
data = data['data'][0]
round_data = data['detail']['rounds_data']
stat_data = data['stat']
start_time = timestamp_to_str(float(data['schedule']['start_time']))
end_time = timestamp_to_str(float(data['schedule']['end_time']))
w, h = 1000, 1040 + 50 + (len(round_data) // 2) * 330
img = Image.new('RGBA', (w, h), (22, 18, 20))
title = Image.open(TEXT_PATH / 'title.png').convert('RGBA')
status = Image.open(TEXT_PATH / 'status.png').convert('RGBA')
title_draw = ImageDraw.Draw(title)
status_draw = ImageDraw.Draw(status)
avatar = await get_avatar_with_ring(ev, 278)
title.paste(avatar, (361, 115), avatar)
title_draw.text((500, 473), f'UID {uid}', 'white', gs_font_36, 'mm')
difficulty = DIFFICULTY_MAP.get(stat_data['difficulty_id'], '困难模式')
max_round_id = stat_data['max_round_id']
is_gold = (
True
if stat_data['difficulty_id'] == 3 and max_round_id == 8
else False
)
time = f'{start_time} ~ {end_time}'
avatar_bonus = stat_data['avatar_bonus_num']
rent_cnt = stat_data['rent_cnt']
coin_num = stat_data['coin_num']
if is_gold:
status_icon = Image.open(TEXT_PATH / 'yes.png')
else:
status_icon = Image.open(TEXT_PATH / 'no.png')
status_icon = status_icon.convert('RGBA')
status.paste(status_icon, (560, 111), status_icon)
status_draw.text((462, 132), difficulty, (236, 233, 229), gs_font_36, 'mm')
status_draw.text((500, 189), time, (139, 137, 133), gs_font_20, 'mm')
status_draw.text(
(220, 398), f'{max_round_id}', (68, 59, 45), gs_font_50, 'mm'
)
status_draw.text(
(416, 398), f'{avatar_bonus}', (68, 59, 45), gs_font_50, 'mm'
)
status_draw.text((604, 398), f'{rent_cnt}', (68, 59, 45), gs_font_50, 'mm')
status_draw.text((793, 398), f'{coin_num}', (68, 59, 45), gs_font_50, 'mm')
flower_yes = Image.open(TEXT_PATH / 'flower_yes.png').convert('RGBA')
flower_no = Image.open(TEXT_PATH / 'flower_no.png').convert('RGBA')
medals = stat_data['get_medal_round_list']
while len(medals) < 8:
medals.append(0)
for index, medal in enumerate(medals):
flower = flower_yes if medal else flower_no
status.paste(flower, (449 + 42 * index, 270), flower)
img.paste(title, (0, 0), title)
img.paste(status, (0, 474), status)
for i, r in enumerate(round_data):
is_get_medal = r['is_get_medal']
round_id = r['round_id']
_medal = flower_yes if is_get_medal else flower_no
if i % 2 == 0:
stage = Image.open(TEXT_PATH / 'stage.png')
stage_draw = ImageDraw.Draw(stage)
stage_draw.text(
(160, 54), f'{round_id}', (68, 59, 45), gs_font_28, 'lm'
)
stage.paste(_medal, (97, 32), _medal)
startx = 92
startb = 116
else:
stage_draw.text(
(830, 54), f'{round_id}', (68, 59, 45), gs_font_28, 'rm'
)
stage.paste(_medal, (866, 32), _medal)
startx = 520
startb = 552
for index_char, char in enumerate(r['avatars']):
char_id = char['avatar_id']
char_type = char['avatar_type']
char_pic_path = CHAR_CARD_PATH / f'{char_id}.png'
# 不存在自动下载
if not char_pic_path.exists():
await create_single_char_card(char_id)
char_card = Image.open(char_pic_path).convert('RGBA')
char_card_draw = ImageDraw.Draw(char_card)
char_card_draw.text(
(128, 280),
f'Lv.{char["level"]}',
font=gs_font_40,
fill=first_color,
anchor='mm',
)
char_card = char_card.resize((89, 108), Image.Resampling.LANCZOS)
stage.paste(
char_card,
(startx + 97 * index_char, 88),
char_card,
)
if char_type != 1:
char_tag = Image.open(TEXT_PATH / f'{char_type}.png')
stage.paste(
char_tag,
(startx + 16 + 97 * index_char, 75),
char_tag,
)
await draw_buff(
r['choice_cards'],
startb,
stage,
stage_draw,
'神秘收获',
)
await draw_buff(
r['buffs'],
startb,
stage,
stage_draw,
'奇妙助益',
)
if i % 2 == 1:
img.paste(stage, (0, 1040 + 330 * (i // 2)), stage)
img = add_footer(img, 1000)
res = await convert_img(img)
return res

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 776 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1,2 +1,3 @@
base_url = 'https://api-takumi-record.mihoyo.com/' base_url = 'https://api-takumi-record.mihoyo.com'
widget_url = f'{base_url}game_record/genshin/aapi/widget/v2' widget_url = f'{base_url}/game_record/genshin/aapi/widget/v2'
new_abyss_url = f'{base_url}/game_record/app/genshin/api/role_combat'

View File

@ -73,3 +73,97 @@ class FakeResin(WidgetResin):
transformer: Transformer transformer: Transformer
daily_task: DayilyTask daily_task: DayilyTask
archon_quest_progress: ArchonProgress archon_quest_progress: ArchonProgress
class PoetryAbyssLinks(TypedDict):
lineup_link: str
lineup_link_pc: str
strategy_link: str
lineup_publish_link: str
lineup_publish_link_pc: str
class PoetryAbyssAvatar(TypedDict):
avatar_id: int
avatar_type: int
name: str
element: str
image: str
level: int
rarity: int
class PoetryAbyssChoiceCard(TypedDict):
icon: str
name: str
desc: str
is_enhanced: bool
id: int
class PoetryAbyssBuff(TypedDict):
icon: str
name: str
desc: str
is_enhanced: bool
id: int
class PoetryAbyssDateTime(TypedDict):
year: int
month: int
day: int
hour: int
minute: int
second: int
class PoetryAbyssSchedule(TypedDict):
start_time: int
end_time: int
schedule_type: int
schedule_id: int
start_date_time: PoetryAbyssDateTime
end_date_time: PoetryAbyssDateTime
class PoetryAbyssDetailStat(TypedDict):
difficulty_id: int
max_round_id: int
heraldry: int
get_medal_round_list: List[int]
medal_num: int
coin_num: int
avatar_bonus_num: int
rent_cnt: int
class RoundData(TypedDict):
avatars: List[PoetryAbyssAvatar]
choice_cards: List[PoetryAbyssChoiceCard]
buffs: List[PoetryAbyssBuff]
is_get_medal: bool
round_id: int
finish_time: int
finish_date_time: PoetryAbyssDateTime
detail_stat: PoetryAbyssDetailStat
class PoetryAbyssDetail(TypedDict):
rounds_data: List[RoundData]
detail_stat: PoetryAbyssDetailStat
backup_avatars: List[PoetryAbyssAvatar]
class PoetryAbyssData(TypedDict):
detail: PoetryAbyssDetail
stat: PoetryAbyssDetailStat
schedule: PoetryAbyssSchedule
has_data: bool
has_detail_data: bool
class PoetryAbyssDatas(TypedDict):
data: List[PoetryAbyssData]
is_unlock: bool
links: PoetryAbyssLinks

View File

@ -2,10 +2,10 @@ from copy import deepcopy
from typing import Dict, Union, cast from typing import Dict, Union, cast
from gsuid_core.utils.api.mys_api import _MysApi from gsuid_core.utils.api.mys_api import _MysApi
from gsuid_core.utils.api.mys.tools import get_web_ds_token from gsuid_core.utils.api.mys.tools import get_ds_token, get_web_ds_token
from .api import widget_url from .api import widget_url, new_abyss_url
from .models import WidgetResin from .models import WidgetResin, PoetryAbyssDatas
class GsMysAPI(_MysApi): class GsMysAPI(_MysApi):
@ -28,3 +28,30 @@ class GsMysAPI(_MysApi):
if isinstance(data, Dict): if isinstance(data, Dict):
data = cast(WidgetResin, data['data']) data = cast(WidgetResin, data['data'])
return data return data
async def get_poetry_abyss_data(
self, uid: str
) -> Union[PoetryAbyssDatas, int]:
server_id = self.RECOGNIZE_SERVER.get(uid[0])
HEADER = deepcopy(self._HEADER)
ck = await self.get_ck(uid)
if ck is None:
return -51
HEADER['Cookie'] = ck
params = {
'server': server_id,
'role_id': uid,
'need_detail': True,
}
HEADER['DS'] = get_ds_token(
'&'.join([f'{k}={v}' for k, v in params.items()])
)
data = await self._mys_request(
new_abyss_url,
'GET',
HEADER,
params,
)
if isinstance(data, Dict):
data = cast(PoetryAbyssDatas, data['data'])
return data

View File

@ -1,2 +1,2 @@
GenshinUID_version = '4.7.1' GenshinUID_version = '4.7.2'
Genshin_version = '4.7.0' Genshin_version = '4.7.0'