small fix

This commit is contained in:
baiqwerdvd 2024-09-06 02:30:44 +08:00
parent 1dfab6c55b
commit 5e57113f2d
No known key found for this signature in database
GPG Key ID: 7717E46E1797411A
62 changed files with 2937 additions and 3306 deletions

View File

@ -16,11 +16,11 @@ async def get_character_data(
avatar_id: str, avatar_id: str,
) -> Union[HakushHsrCharacter, None]: ) -> Union[HakushHsrCharacter, None]:
async with AsyncClient( async with AsyncClient(
base_url='https://api.hakush.in/hsr/data', base_url="https://api.hakush.in/hsr/data",
headers=_HEADER, headers=_HEADER,
timeout=30, timeout=30,
) as client: ) as client:
req = await client.get(f'/cn/character/{avatar_id}.json') req = await client.get(f"/cn/character/{avatar_id}.json")
if req.status_code == 200: if req.status_code == 200:
return convert(req.json(), type=HakushHsrCharacter) return convert(req.json(), type=HakushHsrCharacter)
return None return None
@ -30,39 +30,35 @@ async def get_lightcone_data(
lightcone_id: str, lightcone_id: str,
) -> Union[HakushHsrLightcone, None]: ) -> Union[HakushHsrLightcone, None]:
async with AsyncClient( async with AsyncClient(
base_url='https://api.hakush.in/hsr/data', base_url="https://api.hakush.in/hsr/data",
headers=_HEADER, headers=_HEADER,
timeout=30, timeout=30,
) as client: ) as client:
req = await client.get(f'/cn/lightcone/{lightcone_id}.json') req = await client.get(f"/cn/lightcone/{lightcone_id}.json")
if req.status_code == 200: if req.status_code == 200:
return convert(req.json(), type=HakushHsrLightcone) return convert(req.json(), type=HakushHsrLightcone)
return None return None
async def get_character_index() -> ( async def get_character_index() -> Union[Dict[str, HakushHsrCharacterIndex], None]:
Union[Dict[str, HakushHsrCharacterIndex], None]
):
async with AsyncClient( async with AsyncClient(
base_url='https://api.hakush.in/hsr/data', base_url="https://api.hakush.in/hsr/data",
headers=_HEADER, headers=_HEADER,
timeout=30, timeout=30,
) as client: ) as client:
req = await client.get('/character.json') req = await client.get("/character.json")
if req.status_code == 200: if req.status_code == 200:
return convert(req.json(), type=Dict[str, HakushHsrCharacterIndex]) return convert(req.json(), type=Dict[str, HakushHsrCharacterIndex])
return None return None
async def get_lightcone_index() -> ( async def get_lightcone_index() -> Union[Dict[str, HakushHsrLightconeIndex], None]:
Union[Dict[str, HakushHsrLightconeIndex], None]
):
async with AsyncClient( async with AsyncClient(
base_url='https://api.hakush.in/hsr/data', base_url="https://api.hakush.in/hsr/data",
headers=_HEADER, headers=_HEADER,
timeout=30, timeout=30,
) as client: ) as client:
req = await client.get('/character.json') req = await client.get("/character.json")
if req.status_code == 200: if req.status_code == 200:
return convert(req.json(), type=Dict[str, HakushHsrLightconeIndex]) return convert(req.json(), type=Dict[str, HakushHsrLightconeIndex])
return None return None

View File

@ -3,4 +3,4 @@
from .models import MihomoData as MihomoData from .models import MihomoData as MihomoData
from .requests import get_char_card_info as requests from .requests import get_char_card_info as requests
__all__ = ['requests', 'MihomoData'] __all__ = ["requests", "MihomoData"]

View File

@ -12,13 +12,13 @@ from ....utils.resource.RESOURCE_PATH import PLAYER_PATH
async def get_char_card_info(uid: str) -> MihomoData: async def get_char_card_info(uid: str) -> MihomoData:
async with AsyncClient( async with AsyncClient(
base_url='http://api.mihomo.me', base_url="http://api.mihomo.me",
headers=_HEADER, headers=_HEADER,
timeout=30, timeout=30,
) as client: ) as client:
req = await client.get(f'/sr_info/{uid}') req = await client.get(f"/sr_info/{uid}")
path = PLAYER_PATH / str(uid) path = PLAYER_PATH / str(uid)
path.mkdir(parents=True, exist_ok=True) path.mkdir(parents=True, exist_ok=True)
with Path.open(path / f'{uid!s}.json', 'w') as file: with Path.open(path / f"{uid!s}.json", "w") as file:
file.write(req.text) file.write(req.text)
return convert(req.json(), type=MihomoData) return convert(req.json(), type=MihomoData)

View File

@ -1,75 +1,65 @@
# flake8: noqa # flake8: noqa
OLD_URL = 'https://api-takumi.mihoyo.com' OLD_URL = "https://api-takumi.mihoyo.com"
OS_OLD_URL = 'https://api-os-takumi.mihoyo.com' OS_OLD_URL = "https://api-os-takumi.mihoyo.com"
NEW_URL = 'https://api-takumi-record.mihoyo.com' NEW_URL = "https://api-takumi-record.mihoyo.com"
OS_URL = 'https://sg-public-api.hoyolab.com' OS_URL = "https://sg-public-api.hoyolab.com"
OS_INFO_URL = 'https://bbs-api-os.hoyolab.com' OS_INFO_URL = "https://bbs-api-os.hoyolab.com"
STAR_RAIL_SIGN_INFO_URL = f'{OLD_URL}/event/luna/info' STAR_RAIL_SIGN_INFO_URL = f"{OLD_URL}/event/luna/info"
STAR_RAIL_SIGN_INFO_URL_OS = f'{OS_URL}/event/luna/os/info' STAR_RAIL_SIGN_INFO_URL_OS = f"{OS_URL}/event/luna/os/info"
STAR_RAIL_SIGN_LIST_URL = f'{OLD_URL}/event/luna/home' STAR_RAIL_SIGN_LIST_URL = f"{OLD_URL}/event/luna/home"
STAR_RAIL_SIGN_LIST_URL_OS = f'{OS_URL}/event/luna/os/home' STAR_RAIL_SIGN_LIST_URL_OS = f"{OS_URL}/event/luna/os/home"
STAR_RAIL_SIGN_EXTRA_INFO_URL = f'{OLD_URL}/event/luna/extra_info' STAR_RAIL_SIGN_EXTRA_INFO_URL = f"{OLD_URL}/event/luna/extra_info"
STAR_RAIL_SIGN_EXTRA_REWARD_URL = f'{OLD_URL}/event/luna/extra_reward' STAR_RAIL_SIGN_EXTRA_REWARD_URL = f"{OLD_URL}/event/luna/extra_reward"
STAR_RAIL_SIGN_URL = f'{OLD_URL}/event/luna/sign' STAR_RAIL_SIGN_URL = f"{OLD_URL}/event/luna/sign"
STAR_RAIL_SIGN_URL_OS = f'{OS_URL}/event/luna/os/sign' STAR_RAIL_SIGN_URL_OS = f"{OS_URL}/event/luna/os/sign"
STAR_RAIL_MONTH_INFO_URL = ( STAR_RAIL_MONTH_INFO_URL = f"{OLD_URL}/event/srledger/month_info" # 开拓阅历接口
f'{OLD_URL}/event/srledger/month_info' # 开拓阅历接口
)
STAR_RAIL_MONTH_DETAIL_URL = ( STAR_RAIL_MONTH_DETAIL_URL = (
f'{OLD_URL}/event/srledger/month_detail' # 开拓阅历详情接口 f"{OLD_URL}/event/srledger/month_detail" # 开拓阅历详情接口
) )
STAR_RAIL_NOTE_URL = ( STAR_RAIL_NOTE_URL = f"{NEW_URL}/game_record/app/hkrpg/api/note" # 实时便签接口
f'{NEW_URL}/game_record/app/hkrpg/api/note' # 实时便签接口 STAR_RAIL_NOTE_URL_OS = f"{OS_INFO_URL}/game_record/hkrpg/api/note" # OS实时便签接口
) STAR_RAIL_INDEX_URL = f"{NEW_URL}/game_record/app/hkrpg/api/index" # 角色橱窗接口
STAR_RAIL_NOTE_URL_OS = ( STAR_RAIL_INDEX_URL_OS = f"{OS_INFO_URL}/game_record/hkrpg/api/index" # OS角色橱窗接口
f'{OS_INFO_URL}/game_record/hkrpg/api/note' # OS实时便签接口
)
STAR_RAIL_INDEX_URL = (
f'{NEW_URL}/game_record/app/hkrpg/api/index' # 角色橱窗接口
)
STAR_RAIL_INDEX_URL_OS = (
f'{OS_INFO_URL}/game_record/hkrpg/api/index' # OS角色橱窗接口
)
STAR_RAIL_AVATAR_BASIC_URL = ( STAR_RAIL_AVATAR_BASIC_URL = (
f'{NEW_URL}/game_record/app/hkrpg/api/avatar/basic' # 全部角色接口 f"{NEW_URL}/game_record/app/hkrpg/api/avatar/basic" # 全部角色接口
) )
STAR_RAIL_ROLE_BASIC_INFO_URL = ( STAR_RAIL_ROLE_BASIC_INFO_URL = (
f'{NEW_URL}/game_record/app/hkrpg/api/role/basicInfo' # 角色基础信息接口 f"{NEW_URL}/game_record/app/hkrpg/api/role/basicInfo" # 角色基础信息接口
) )
STAR_RAIL_ROLE_BASIC_INFO_URL_OS = f'{OS_INFO_URL}/game_record/hkrpg/api/index' STAR_RAIL_ROLE_BASIC_INFO_URL_OS = f"{OS_INFO_URL}/game_record/hkrpg/api/index"
STAR_RAIL_AVATAR_INFO_URL = ( STAR_RAIL_AVATAR_INFO_URL = (
f'{NEW_URL}/game_record/app/hkrpg/api/avatar/info' # 角色详细信息接口 f"{NEW_URL}/game_record/app/hkrpg/api/avatar/info" # 角色详细信息接口
) )
STAR_RAIL_AVATAR_INFO_URL_OS = ( STAR_RAIL_AVATAR_INFO_URL_OS = (
f'{OS_INFO_URL}/game_record/hkrpg/api/avatar/info' # OS角色详细信息接口 f"{OS_INFO_URL}/game_record/hkrpg/api/avatar/info" # OS角色详细信息接口
) )
STAR_RAIL_AVATAR_LIST_URL = f'{OLD_URL}/event/rpgcalc/avatar/list' STAR_RAIL_AVATAR_LIST_URL = f"{OLD_URL}/event/rpgcalc/avatar/list"
STAR_RAIL_AVATAR_DETAIL_URL = f'{OLD_URL}/event/rpgcalc/avatar/detail' STAR_RAIL_AVATAR_DETAIL_URL = f"{OLD_URL}/event/rpgcalc/avatar/detail"
CHALLENGE_INFO_URL = f'{NEW_URL}/game_record/app/hkrpg/api/challenge' # 忘却之庭 CHALLENGE_INFO_URL = f"{NEW_URL}/game_record/app/hkrpg/api/challenge" # 忘却之庭
CHALLENGE_INFO_URL_OS = f'{OS_INFO_URL}/game_record/hkrpg/api/challenge' # OS忘却之庭 CHALLENGE_INFO_URL_OS = f"{OS_INFO_URL}/game_record/hkrpg/api/challenge" # OS忘却之庭
CHALLENGE_STORY_INFO_URL = f'{NEW_URL}/game_record/app/hkrpg/api/challenge_story' # 虚构叙事 CHALLENGE_STORY_INFO_URL = (
CHALLENGE_BOSS_INFO_URL = f'{NEW_URL}/game_record/app/hkrpg/api/challenge_boss' # 末日幻影 f"{NEW_URL}/game_record/app/hkrpg/api/challenge_story" # 虚构叙事
ROGUE_INFO_URL = (
f'{NEW_URL}/game_record/app/hkrpg/api/rogue' # 角色模拟宇宙信息接口
) )
CHALLENGE_BOSS_INFO_URL = (
f"{NEW_URL}/game_record/app/hkrpg/api/challenge_boss" # 末日幻影
)
ROGUE_INFO_URL = f"{NEW_URL}/game_record/app/hkrpg/api/rogue" # 角色模拟宇宙信息接口
ROGUE_LOCUST_INFO_URL = ( ROGUE_LOCUST_INFO_URL = (
f'{NEW_URL}/game_record/app/hkrpg/api/rogue_locust' # 角色寰宇蝗灾信息接口 f"{NEW_URL}/game_record/app/hkrpg/api/rogue_locust" # 角色寰宇蝗灾信息接口
) )
STAR_RAIL_GACHA_LOG_URL = f'{OLD_URL}/common/gacha_record/api/getGachaLog' STAR_RAIL_GACHA_LOG_URL = f"{OLD_URL}/common/gacha_record/api/getGachaLog"
STAR_RAIL_GACHA_LOG_URL_OS = ( STAR_RAIL_GACHA_LOG_URL_OS = f"{OS_OLD_URL}/common/gacha_record/api/getGachaLog"
f'{OS_OLD_URL}/common/gacha_record/api/getGachaLog'
)
GET_FP_URL = 'https://public-data-api.mihoyo.com/device-fp/api/getFp' GET_FP_URL = "https://public-data-api.mihoyo.com/device-fp/api/getFp"
GET_FP_URL_OS = 'https://sg-public-data-api.hoyoverse.com/device-fp/api/getFp' GET_FP_URL_OS = "https://sg-public-data-api.hoyoverse.com/device-fp/api/getFp"
# CREATE_QRCODE = f'{OLD_URL}/event/bbs_sign_reward/gen_auth_code' # CREATE_QRCODE = f'{OLD_URL}/event/bbs_sign_reward/gen_auth_code'
STAR_RAIL_WIDGRT_URL = f'{NEW_URL}/game_record/app/hkrpg/aapi/widget' STAR_RAIL_WIDGRT_URL = f"{NEW_URL}/game_record/app/hkrpg/aapi/widget"
_API = locals() _API = locals()

View File

@ -1,3 +1,3 @@
from gsuid_core.version import __version__ from gsuid_core.version import __version__
_HEADER = {'User-Agent': f'StarRailUID/{__version__}'} _HEADER = {"User-Agent": f"StarRailUID/{__version__}"}

View File

@ -1,45 +1,43 @@
import re import re
from gsuid_core.sv import SV from .draw_abyss_card import draw_abyss_img
from ..utils.sr_prefix import PREFIX
from gsuid_core.bot import Bot from gsuid_core.bot import Bot
from gsuid_core.models import Event from gsuid_core.models import Event
from gsuid_core.sv import SV
from gsuid_core.utils.database.api import get_uid
from gsuid_core.utils.database.models import GsBind
from gsuid_core.utils.error_reply import UID_HINT from gsuid_core.utils.error_reply import UID_HINT
from ..utils.convert import get_uid sv_srabyss = SV("sr查询深渊")
from ..utils.sr_prefix import PREFIX
from .draw_abyss_card import draw_abyss_img
sv_srabyss = SV('sr查询深渊')
@sv_srabyss.on_command( @sv_srabyss.on_command(
( (
f'{PREFIX}查询深渊', f"{PREFIX}查询深渊",
f'{PREFIX}查询上期深渊', f"{PREFIX}查询上期深渊",
f'{PREFIX}上期深渊', f"{PREFIX}上期深渊",
f'{PREFIX}深渊', f"{PREFIX}深渊",
), ),
block=True, block=True,
) )
async def send_srabyss_info(bot: Bot, ev: Event): async def send_srabyss_info(bot: Bot, ev: Event):
name = ''.join(re.findall('[\u4e00-\u9fa5]', ev.text)) name = "".join(re.findall("[\u4e00-\u9fa5]", ev.text))
if name: if name:
return None return None
await bot.logger.info('开始执行[sr查询深渊信息]') await bot.logger.info("开始执行[sr查询深渊信息]")
get_uid_ = await get_uid(bot, ev, True) uid, user_id = await get_uid(bot, ev, GsBind, "sr", True)
if get_uid_ is None:
return await bot.send(UID_HINT)
uid, user_id = get_uid_
if uid is None: if uid is None:
return await bot.send(UID_HINT) return await bot.send(UID_HINT)
await bot.logger.info(f'[sr查询深渊信息]uid: {uid}') await bot.logger.info(f"[sr查询深渊信息]uid: {uid}")
if '上期' in ev.command: if "上期" in ev.command:
schedule_type = '2' schedule_type = "2"
else: else:
schedule_type = '1' schedule_type = "1"
await bot.logger.info(f'[sr查询深渊信息]深渊期数: {schedule_type}') await bot.logger.info(f"[sr查询深渊信息]深渊期数: {schedule_type}")
im = await draw_abyss_img(user_id, uid, ev.sender, schedule_type) im = await draw_abyss_img(user_id, uid, ev.sender, schedule_type)
await bot.send(im) await bot.send(im)

View File

@ -1,17 +1,7 @@
from pathlib import Path from pathlib import Path
from typing import Union, Optional from typing import Any, Dict, Union
from PIL import Image, ImageDraw
from gsuid_core.logger import logger
from gsuid_core.utils.error_reply import get_error
from gsuid_core.utils.image.image_tools import (
get_qq_avatar,
draw_pic_with_ring,
)
from .utils import get_icon from .utils import get_icon
from ..utils.mys_api import mys_api
from ..utils.image.convert import convert_img
from ..sruid_utils.api.mys.models import AbyssAvatar from ..sruid_utils.api.mys.models import AbyssAvatar
from ..utils.fonts.starrail_fonts import ( from ..utils.fonts.starrail_fonts import (
sr_font_22, sr_font_22,
@ -20,39 +10,41 @@ from ..utils.fonts.starrail_fonts import (
sr_font_34, sr_font_34,
sr_font_42, sr_font_42,
) )
from ..utils.mys_api import mys_api
TEXT_PATH = Path(__file__).parent / 'texture2D' from PIL import Image, ImageDraw
from gsuid_core.logger import logger
from gsuid_core.utils.error_reply import get_error
from gsuid_core.utils.image.convert import convert_img
from gsuid_core.utils.image.image_tools import (
draw_pic_with_ring,
get_qq_avatar,
)
TEXT_PATH = Path(__file__).parent / "texture2D"
white_color = (255, 255, 255) white_color = (255, 255, 255)
gray_color = (175, 175, 175) gray_color = (175, 175, 175)
img_bg = Image.open(TEXT_PATH / 'bg.jpg') img_bg = Image.open(TEXT_PATH / "bg.jpg")
level_cover = Image.open(TEXT_PATH / 'level_cover.png').convert('RGBA') level_cover = Image.open(TEXT_PATH / "level_cover.png").convert("RGBA")
char_bg_4 = Image.open(TEXT_PATH / 'char4_bg.png').convert('RGBA') char_bg_4 = Image.open(TEXT_PATH / "char4_bg.png").convert("RGBA")
char_bg_5 = Image.open(TEXT_PATH / 'char5_bg.png').convert('RGBA') char_bg_5 = Image.open(TEXT_PATH / "char5_bg.png").convert("RGBA")
rank_bg = Image.open(TEXT_PATH / 'rank_bg.png').convert('RGBA') rank_bg = Image.open(TEXT_PATH / "rank_bg.png").convert("RGBA")
star_yes = Image.open(TEXT_PATH / 'star.png').convert('RGBA') star_yes = Image.open(TEXT_PATH / "star.png").convert("RGBA")
star_gray = Image.open(TEXT_PATH / 'star_gray.png').convert('RGBA') star_gray = Image.open(TEXT_PATH / "star_gray.png").convert("RGBA")
elements = { elements = {
'ice': Image.open(TEXT_PATH / 'IconNatureColorIce.png').convert('RGBA'), "ice": Image.open(TEXT_PATH / "IconNatureColorIce.png").convert("RGBA"),
'fire': Image.open(TEXT_PATH / 'IconNatureColorFire.png').convert('RGBA'), "fire": Image.open(TEXT_PATH / "IconNatureColorFire.png").convert("RGBA"),
'imaginary': Image.open( "imaginary": Image.open(TEXT_PATH / "IconNatureColorImaginary.png").convert("RGBA"),
TEXT_PATH / 'IconNatureColorImaginary.png' "quantum": Image.open(TEXT_PATH / "IconNatureColorQuantum.png").convert("RGBA"),
).convert('RGBA'), "lightning": Image.open(TEXT_PATH / "IconNatureColorThunder.png").convert("RGBA"),
'quantum': Image.open(TEXT_PATH / 'IconNatureColorQuantum.png').convert( "wind": Image.open(TEXT_PATH / "IconNatureColorWind.png").convert("RGBA"),
'RGBA' "physical": Image.open(TEXT_PATH / "IconNaturePhysical.png").convert("RGBA"),
),
'lightning': Image.open(TEXT_PATH / 'IconNatureColorThunder.png').convert(
'RGBA'
),
'wind': Image.open(TEXT_PATH / 'IconNatureColorWind.png').convert('RGBA'),
'physical': Image.open(TEXT_PATH / 'IconNaturePhysical.png').convert(
'RGBA'
),
} }
async def get_abyss_star_pic(star: int) -> Image.Image: async def get_abyss_star_pic(star: int) -> Image.Image:
return Image.open(TEXT_PATH / f'star{star}.png') return Image.open(TEXT_PATH / f"star{star}.png")
async def _draw_abyss_card( async def _draw_abyss_card(
@ -72,17 +64,17 @@ async def _draw_abyss_card(
char_bg.paste(rank_bg, (150, 16), mask=rank_bg) char_bg.paste(rank_bg, (150, 16), mask=rank_bg)
char_card_draw.text( char_card_draw.text(
(162, 31), (162, 31),
f'{char.rank}', f"{char.rank}",
font=sr_font_22, font=sr_font_22,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
char_card_draw.text( char_card_draw.text(
(100, 165), (100, 165),
f'等级 {char.level}', f"等级 {char.level}",
font=sr_font_22, font=sr_font_22,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
floor_pic.paste( floor_pic.paste(
char_bg, char_bg,
@ -92,16 +84,16 @@ async def _draw_abyss_card(
async def _draw_floor_card( async def _draw_floor_card(
level_star: int, level_star: Union[int, str],
floor_pic: Image.Image, floor_pic: Image.Image,
img: Image.Image, img: Image.Image,
index_floor: int, index_floor: int,
floor_name: str, floor_name: str,
round_num: int, round_num: Union[int, None],
): ):
for index_num in [0, 1, 2]: for index_num in [0, 1, 2]:
star_num = index_num + 1 star_num = index_num + 1
if star_num <= level_star: if star_num <= int(level_star):
star_pic = star_yes.copy() star_pic = star_yes.copy()
else: else:
star_pic = star_gray.copy() star_pic = star_gray.copy()
@ -112,14 +104,14 @@ async def _draw_floor_card(
floor_name, floor_name,
font=sr_font_42, font=sr_font_42,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
floor_pic_draw.text( floor_pic_draw.text(
(802, 60), (802, 60),
f'使用轮: {round_num}', f"使用轮: {round_num}",
font=sr_font_28, font=sr_font_28,
fill=gray_color, fill=gray_color,
anchor='rm', anchor="rm",
) )
img.paste(floor_pic, (0, 657 + index_floor * 570), floor_pic) img.paste(floor_pic, (0, 657 + index_floor * 570), floor_pic)
@ -127,8 +119,8 @@ async def _draw_floor_card(
async def draw_abyss_img( async def draw_abyss_img(
qid: Union[str, int], qid: Union[str, int],
uid: str, uid: str,
sender: Union[str, str], sender: Dict[str, Any],
schedule_type: str = '1', schedule_type: str = "1",
) -> Union[bytes, str]: ) -> Union[bytes, str]:
raw_abyss_data = await mys_api.get_abyss_info(uid, schedule_type) raw_abyss_data = await mys_api.get_abyss_info(uid, schedule_type)
@ -136,10 +128,12 @@ async def draw_abyss_img(
return get_error(raw_abyss_data) return get_error(raw_abyss_data)
# 获取查询者数据 # 获取查询者数据
if raw_abyss_data.max_floor == '': if raw_abyss_data.max_floor == "":
return '你还没有挑战本期深渊!\n可以使用[sr上期深渊]命令查询上期~' return "你还没有挑战本期深渊!\n可以使用[sr上期深渊]命令查询上期~"
# 过滤掉 is_fast快速通关 为 True 的项 # 过滤掉 is_fast (快速通关) 为 True 的项
floor_detail = [detail for detail in raw_abyss_data.all_floor_detail if not detail.is_fast] floor_detail = [
detail for detail in raw_abyss_data.all_floor_detail if not detail.is_fast
]
floor_num = len(floor_detail) floor_num = len(floor_detail)
# 获取背景图片各项参数 # 获取背景图片各项参数
@ -147,15 +141,15 @@ async def draw_abyss_img(
based_h = 657 + 570 * floor_num based_h = 657 + 570 * floor_num
img = img_bg.copy() img = img_bg.copy()
img = img.crop((0, 0, based_w, based_h)) img = img.crop((0, 0, based_w, based_h))
abyss_title = Image.open(TEXT_PATH / 'head.png') abyss_title = Image.open(TEXT_PATH / "head.png")
img.paste(abyss_title, (0, 0), abyss_title) img.paste(abyss_title, (0, 0), abyss_title)
# 获取头像 # 获取头像
_id = str(qid) _id = str(qid)
if _id.startswith('http'): if _id.startswith("http"):
char_pic = await get_qq_avatar(avatar_url=_id) char_pic = await get_qq_avatar(avatar_url=_id)
elif sender.get('avatar') is not None: elif sender.get("avatar") is not None:
char_pic = await get_qq_avatar(avatar_url=sender['avatar']) char_pic = await get_qq_avatar(avatar_url=sender["avatar"])
else: else:
char_pic = await get_qq_avatar(qid=qid) char_pic = await get_qq_avatar(qid=qid)
char_pic = await draw_pic_with_ring(char_pic, 250, None, False) char_pic = await draw_pic_with_ring(char_pic, 250, None, False)
@ -164,42 +158,42 @@ async def draw_abyss_img(
# 绘制抬头 # 绘制抬头
img_draw = ImageDraw.Draw(img) img_draw = ImageDraw.Draw(img)
img_draw.text((450, 442), f'UID {uid}', white_color, sr_font_28, 'mm') img_draw.text((450, 442), f"UID {uid}", white_color, sr_font_28, "mm")
# 总体数据 # 总体数据
abyss_data = Image.open(TEXT_PATH / 'data.png') abyss_data = Image.open(TEXT_PATH / "data.png")
img.paste(abyss_data, (0, 500), abyss_data) img.paste(abyss_data, (0, 500), abyss_data)
# 最深抵达 # 最深抵达
img_draw.text( img_draw.text(
(220, 565), (220, 565),
f'{raw_abyss_data.max_floor}', f"{raw_abyss_data.max_floor}",
white_color, white_color,
sr_font_34, sr_font_34,
'lm', "lm",
) )
# 挑战次数 # 挑战次数
img_draw.text( img_draw.text(
(220, 612), (220, 612),
f'{raw_abyss_data.battle_num}', f"{raw_abyss_data.battle_num}",
white_color, white_color,
sr_font_34, sr_font_34,
'lm', "lm",
) )
star_num_pic = Image.open(TEXT_PATH / 'star.png') star_num_pic = Image.open(TEXT_PATH / "star.png")
img.paste(star_num_pic, (615, 557), star_num_pic) img.paste(star_num_pic, (615, 557), star_num_pic)
img_draw.text( img_draw.text(
(695, 590), (695, 590),
f'{raw_abyss_data.star_num}/36', f"{raw_abyss_data.star_num}/36",
white_color, white_color,
sr_font_42, sr_font_42,
'lm', "lm",
) )
for index_floor, level in enumerate(raw_abyss_data.all_floor_detail): for index_floor, level in enumerate(raw_abyss_data.all_floor_detail):
floor_pic = Image.open(TEXT_PATH / 'floor_bg.png') floor_pic = Image.open(TEXT_PATH / "floor_bg.png")
level_star = level.star_num level_star = level.star_num
floor_name = level.name floor_name = level.name
round_num = level.round_num round_num = level.round_num
@ -211,23 +205,24 @@ async def draw_abyss_img(
time_array = node_1.challenge_time time_array = node_1.challenge_time
else: else:
time_array = node_2.challenge_time time_array = node_2.challenge_time
time_str = f'{time_array.year}-{time_array.month}' assert time_array is not None
time_str = f'{time_str}-{time_array.day}' time_str = f"{time_array.year}-{time_array.month}"
time_str = f'{time_str} {time_array.hour}:{time_array.minute}:00' time_str = f"{time_str}-{time_array.day}"
time_str = f"{time_str} {time_array.hour}:{time_array.minute}:00"
floor_pic_draw = ImageDraw.Draw(floor_pic) floor_pic_draw = ImageDraw.Draw(floor_pic)
floor_pic_draw.text( floor_pic_draw.text(
(112, 120 + index_part * 219), (112, 120 + index_part * 219),
f'节点{node_num}', f"节点{node_num}",
white_color, white_color,
sr_font_30, sr_font_30,
'lm', "lm",
) )
floor_pic_draw.text( floor_pic_draw.text(
(201, 120 + index_part * 219), (201, 120 + index_part * 219),
f'{time_str}', f"{time_str}",
gray_color, gray_color,
sr_font_22, sr_font_22,
'lm', "lm",
) )
if node_num == 1: if node_num == 1:
avatars_array = node_1 avatars_array = node_1
@ -251,5 +246,5 @@ async def draw_abyss_img(
) )
res = await convert_img(img) res = await convert_img(img)
logger.info('[查询深渊信息]绘图已完成,等待发送!') logger.info("[查询深渊信息]绘图已完成,等待发送!")
return res return res

View File

@ -6,14 +6,14 @@ from PIL import Image
from aiohttp import ClientSession from aiohttp import ClientSession
from gsuid_core.data_store import get_res_path from gsuid_core.data_store import get_res_path
T = TypeVar('T') T = TypeVar("T")
ROLEINFO_PATH = get_res_path() / 'StarRailUID' / 'roleinfo' ROLEINFO_PATH = get_res_path() / "StarRailUID" / "roleinfo"
ROLEINFO_PATH.mkdir(parents=True, exist_ok=True) ROLEINFO_PATH.mkdir(parents=True, exist_ok=True)
async def get_icon(url: str) -> Image.Image: async def get_icon(url: str) -> Image.Image:
name = url.split('/')[-1] name = url.split("/")[-1]
path = ROLEINFO_PATH / name path = ROLEINFO_PATH / name
if (path).exists(): if (path).exists():
content = path.read_bytes() content = path.read_bytes()
@ -21,6 +21,6 @@ async def get_icon(url: str) -> Image.Image:
async with ClientSession() as client: async with ClientSession() as client:
async with client.get(url) as resp: async with client.get(url) as resp:
content = await resp.read() content = await resp.read()
with Path.open(path, 'wb') as f: with Path.open(path, "wb") as f:
f.write(content) f.write(content)
return Image.open(BytesIO(content)).convert('RGBA') return Image.open(BytesIO(content)).convert("RGBA")

View File

@ -1,45 +1,43 @@
import re import re
from gsuid_core.sv import SV from .draw_abyss_card import draw_abyss_img
from ..utils.sr_prefix import PREFIX
from gsuid_core.bot import Bot from gsuid_core.bot import Bot
from gsuid_core.models import Event from gsuid_core.models import Event
from gsuid_core.sv import SV
from gsuid_core.utils.database.api import get_uid
from gsuid_core.utils.database.models import GsBind
from gsuid_core.utils.error_reply import UID_HINT from gsuid_core.utils.error_reply import UID_HINT
from ..utils.convert import get_uid sv_abyss_boss = SV("sr查询末日幻影")
from ..utils.sr_prefix import PREFIX
from .draw_abyss_card import draw_abyss_img
sv_abyss_boss = SV('sr查询末日幻影')
@sv_abyss_boss.on_command( @sv_abyss_boss.on_command(
( (
f'{PREFIX}查询末日幻影', f"{PREFIX}查询末日幻影",
f'{PREFIX}查询上期末日幻影', f"{PREFIX}查询上期末日幻影",
f'{PREFIX}上期末日', f"{PREFIX}上期末日",
f'{PREFIX}末日', f"{PREFIX}末日",
), ),
block=True, block=True,
) )
async def send_srabyss_info(bot: Bot, ev: Event): async def send_srabyss_info(bot: Bot, ev: Event):
name = ''.join(re.findall('[\u4e00-\u9fa5]', ev.text)) name = "".join(re.findall("[\u4e00-\u9fa5]", ev.text))
if name: if name:
return None return None
await bot.logger.info('开始执行[sr查询末日幻影信息]') await bot.logger.info("开始执行[sr查询末日幻影信息]")
get_uid_ = await get_uid(bot, ev, True) uid, user_id = await get_uid(bot, ev, GsBind, "sr", True)
if get_uid_ is None:
return await bot.send(UID_HINT)
uid, user_id = get_uid_
if uid is None: if uid is None:
return await bot.send(UID_HINT) return await bot.send(UID_HINT)
await bot.logger.info(f'[sr查询末日幻影信息]uid: {uid}') await bot.logger.info(f"[sr查询末日幻影信息]uid: {uid}")
if '上期' in ev.command: if "上期" in ev.command:
schedule_type = '2' schedule_type = "2"
else: else:
schedule_type = '1' schedule_type = "1"
await bot.logger.info(f'[sr查询末日幻影信息]末日幻影期数: {schedule_type}') await bot.logger.info(f"[sr查询末日幻影信息]末日幻影期数: {schedule_type}")
im = await draw_abyss_img(user_id, uid, ev.sender, schedule_type) im = await draw_abyss_img(user_id, uid, ev.sender, schedule_type)
await bot.send(im) await bot.send(im)

View File

@ -1,17 +1,7 @@
from pathlib import Path from pathlib import Path
from typing import Union, Optional from typing import Any, Dict, Union
from PIL import Image, ImageDraw
from gsuid_core.logger import logger
from gsuid_core.utils.error_reply import get_error
from gsuid_core.utils.image.image_tools import (
get_qq_avatar,
draw_pic_with_ring,
)
from .utils import get_icon from .utils import get_icon
from ..utils.mys_api import mys_api
from ..utils.image.convert import convert_img
from ..sruid_utils.api.mys.models import AbyssAvatar from ..sruid_utils.api.mys.models import AbyssAvatar
from ..utils.fonts.starrail_fonts import ( from ..utils.fonts.starrail_fonts import (
sr_font_22, sr_font_22,
@ -20,39 +10,41 @@ from ..utils.fonts.starrail_fonts import (
sr_font_34, sr_font_34,
sr_font_42, sr_font_42,
) )
from ..utils.mys_api import mys_api
TEXT_PATH = Path(__file__).parent / 'texture2D' from PIL import Image, ImageDraw
from gsuid_core.logger import logger
from gsuid_core.utils.error_reply import get_error
from gsuid_core.utils.image.convert import convert_img
from gsuid_core.utils.image.image_tools import (
draw_pic_with_ring,
get_qq_avatar,
)
TEXT_PATH = Path(__file__).parent / "texture2D"
white_color = (255, 255, 255) white_color = (255, 255, 255)
gray_color = (175, 175, 175) gray_color = (175, 175, 175)
img_bg = Image.open(TEXT_PATH / 'bg.jpg') img_bg = Image.open(TEXT_PATH / "bg.jpg")
level_cover = Image.open(TEXT_PATH / 'level_cover.png').convert('RGBA') level_cover = Image.open(TEXT_PATH / "level_cover.png").convert("RGBA")
char_bg_4 = Image.open(TEXT_PATH / 'char4_bg.png').convert('RGBA') char_bg_4 = Image.open(TEXT_PATH / "char4_bg.png").convert("RGBA")
char_bg_5 = Image.open(TEXT_PATH / 'char5_bg.png').convert('RGBA') char_bg_5 = Image.open(TEXT_PATH / "char5_bg.png").convert("RGBA")
rank_bg = Image.open(TEXT_PATH / 'rank_bg.png').convert('RGBA') rank_bg = Image.open(TEXT_PATH / "rank_bg.png").convert("RGBA")
star_yes = Image.open(TEXT_PATH / 'star.png').convert('RGBA') star_yes = Image.open(TEXT_PATH / "star.png").convert("RGBA")
star_gray = Image.open(TEXT_PATH / 'star_gray.png').convert('RGBA') star_gray = Image.open(TEXT_PATH / "star_gray.png").convert("RGBA")
elements = { elements = {
'ice': Image.open(TEXT_PATH / 'IconNatureColorIce.png').convert('RGBA'), "ice": Image.open(TEXT_PATH / "IconNatureColorIce.png").convert("RGBA"),
'fire': Image.open(TEXT_PATH / 'IconNatureColorFire.png').convert('RGBA'), "fire": Image.open(TEXT_PATH / "IconNatureColorFire.png").convert("RGBA"),
'imaginary': Image.open( "imaginary": Image.open(TEXT_PATH / "IconNatureColorImaginary.png").convert("RGBA"),
TEXT_PATH / 'IconNatureColorImaginary.png' "quantum": Image.open(TEXT_PATH / "IconNatureColorQuantum.png").convert("RGBA"),
).convert('RGBA'), "lightning": Image.open(TEXT_PATH / "IconNatureColorThunder.png").convert("RGBA"),
'quantum': Image.open(TEXT_PATH / 'IconNatureColorQuantum.png').convert( "wind": Image.open(TEXT_PATH / "IconNatureColorWind.png").convert("RGBA"),
'RGBA' "physical": Image.open(TEXT_PATH / "IconNaturePhysical.png").convert("RGBA"),
),
'lightning': Image.open(TEXT_PATH / 'IconNatureColorThunder.png').convert(
'RGBA'
),
'wind': Image.open(TEXT_PATH / 'IconNatureColorWind.png').convert('RGBA'),
'physical': Image.open(TEXT_PATH / 'IconNaturePhysical.png').convert(
'RGBA'
),
} }
async def get_abyss_star_pic(star: int) -> Image.Image: async def get_abyss_star_pic(star: int) -> Image.Image:
return Image.open(TEXT_PATH / f'star{star}.png') return Image.open(TEXT_PATH / f"star{star}.png")
async def _draw_abyss_card( async def _draw_abyss_card(
@ -75,17 +67,17 @@ async def _draw_abyss_card(
char_bg.paste(rank_bg, (150, 16), mask=rank_bg) char_bg.paste(rank_bg, (150, 16), mask=rank_bg)
char_card_draw.text( char_card_draw.text(
(162, 31), (162, 31),
f'{char.rank}', f"{char.rank}",
font=sr_font_22, font=sr_font_22,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
char_card_draw.text( char_card_draw.text(
(100, 165), (100, 165),
f'等级 {char.level}', f"等级 {char.level}",
font=sr_font_22, font=sr_font_22,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
floor_pic.paste( floor_pic.paste(
char_bg, char_bg,
@ -114,7 +106,7 @@ async def _draw_floor_card(
floor_name, floor_name,
font=sr_font_42, font=sr_font_42,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
img.paste(floor_pic, (0, 657 + index_floor * 570), floor_pic) img.paste(floor_pic, (0, 657 + index_floor * 570), floor_pic)
@ -122,18 +114,20 @@ async def _draw_floor_card(
async def draw_abyss_img( async def draw_abyss_img(
qid: Union[str, int], qid: Union[str, int],
uid: str, uid: str,
sender: Union[str, str], sender: Dict[str, Any],
schedule_type: str = '1', schedule_type: str = "1",
) -> Union[bytes, str]: ) -> Union[bytes, str]:
raw_abyss_data = await mys_api.get_abyss_boss_info(uid, schedule_type) raw_abyss_data = await mys_api.get_abyss_boss_info(uid, schedule_type)
if isinstance(raw_abyss_data, int): if isinstance(raw_abyss_data, int):
return get_error(raw_abyss_data) return get_error(raw_abyss_data)
# 获取查询者数据 # 获取查询者数据
if raw_abyss_data.max_floor == '': if raw_abyss_data.max_floor == "":
return '你还没有挑战本期末日幻影!\n可以使用[sr上期末日幻影]命令查询上期~' return "你还没有挑战本期末日幻影!\n可以使用[sr上期末日幻影]命令查询上期~"
# 过滤掉 is_fast快速通关 为 True 的项 # 过滤掉 is_fast (快速通关) 为 True 的项
floor_detail = [detail for detail in raw_abyss_data.all_floor_detail if not detail.is_fast] floor_detail = [
detail for detail in raw_abyss_data.all_floor_detail if not detail.is_fast
]
floor_num = len(floor_detail) floor_num = len(floor_detail)
# 获取背景图片各项参数 # 获取背景图片各项参数
@ -141,15 +135,15 @@ async def draw_abyss_img(
based_h = 657 + 570 * floor_num based_h = 657 + 570 * floor_num
img = img_bg.copy() img = img_bg.copy()
img = img.crop((0, 0, based_w, based_h)) img = img.crop((0, 0, based_w, based_h))
abyss_title = Image.open(TEXT_PATH / 'head.png') abyss_title = Image.open(TEXT_PATH / "head.png")
img.paste(abyss_title, (0, 0), abyss_title) img.paste(abyss_title, (0, 0), abyss_title)
# 获取头像 # 获取头像
_id = str(qid) _id = str(qid)
if _id.startswith('http'): if _id.startswith("http"):
char_pic = await get_qq_avatar(avatar_url=_id) char_pic = await get_qq_avatar(avatar_url=_id)
elif sender.get('avatar') is not None: elif sender.get("avatar") is not None:
char_pic = await get_qq_avatar(avatar_url=sender['avatar']) char_pic = await get_qq_avatar(avatar_url=sender["avatar"])
else: else:
char_pic = await get_qq_avatar(qid=qid) char_pic = await get_qq_avatar(qid=qid)
char_pic = await draw_pic_with_ring(char_pic, 250, None, False) char_pic = await draw_pic_with_ring(char_pic, 250, None, False)
@ -158,42 +152,42 @@ async def draw_abyss_img(
# 绘制抬头 # 绘制抬头
img_draw = ImageDraw.Draw(img) img_draw = ImageDraw.Draw(img)
img_draw.text((450, 442), f'UID {uid}', white_color, sr_font_28, 'mm') img_draw.text((450, 442), f"UID {uid}", white_color, sr_font_28, "mm")
# 总体数据 # 总体数据
abyss_data = Image.open(TEXT_PATH / 'data.png') abyss_data = Image.open(TEXT_PATH / "data.png")
img.paste(abyss_data, (0, 500), abyss_data) img.paste(abyss_data, (0, 500), abyss_data)
# 最深抵达 # 最深抵达
img_draw.text( img_draw.text(
(220, 565), (220, 565),
f'{raw_abyss_data.max_floor}', f"{raw_abyss_data.max_floor}",
white_color, white_color,
sr_font_34, sr_font_34,
'lm', "lm",
) )
# 挑战次数 # 挑战次数
img_draw.text( img_draw.text(
(220, 612), (220, 612),
f'{raw_abyss_data.battle_num}', f"{raw_abyss_data.battle_num}",
white_color, white_color,
sr_font_34, sr_font_34,
'lm', "lm",
) )
star_num_pic = Image.open(TEXT_PATH / 'star.png') star_num_pic = Image.open(TEXT_PATH / "star.png")
img.paste(star_num_pic, (615, 557), star_num_pic) img.paste(star_num_pic, (615, 557), star_num_pic)
img_draw.text( img_draw.text(
(695, 590), (695, 590),
f'{raw_abyss_data.star_num}/12', f"{raw_abyss_data.star_num}/12",
white_color, white_color,
sr_font_42, sr_font_42,
'lm', "lm",
) )
for index_floor, level in enumerate(floor_detail): for index_floor, level in enumerate(floor_detail):
floor_pic = Image.open(TEXT_PATH / 'floor_bg.png') floor_pic = Image.open(TEXT_PATH / "floor_bg.png")
level_star = int(level.star_num) level_star = int(level.star_num)
floor_name = level.name floor_name = level.name
node_1 = level.node_1 node_1 = level.node_1
@ -204,23 +198,24 @@ async def draw_abyss_img(
time_array = node_1.challenge_time time_array = node_1.challenge_time
else: else:
time_array = node_2.challenge_time time_array = node_2.challenge_time
time_str = f'{time_array.year}-{time_array.month}' assert time_array is not None
time_str = f'{time_str}-{time_array.day}' time_str = f"{time_array.year}-{time_array.month}"
time_str = f'{time_str} {time_array.hour}:{time_array.minute}:00' time_str = f"{time_str}-{time_array.day}"
time_str = f"{time_str} {time_array.hour}:{time_array.minute}:00"
floor_pic_draw = ImageDraw.Draw(floor_pic) floor_pic_draw = ImageDraw.Draw(floor_pic)
floor_pic_draw.text( floor_pic_draw.text(
(112, 120 + index_part * 219), (112, 120 + index_part * 219),
f'节点{node_num}', f"节点{node_num}",
white_color, white_color,
sr_font_30, sr_font_30,
'lm', "lm",
) )
floor_pic_draw.text( floor_pic_draw.text(
(201, 120 + index_part * 219), (201, 120 + index_part * 219),
f'{time_str}', f"{time_str}",
gray_color, gray_color,
sr_font_22, sr_font_22,
'lm', "lm",
) )
if node_num == 1: if node_num == 1:
avatars_array = node_1 avatars_array = node_1
@ -240,9 +235,8 @@ async def draw_abyss_img(
img, img,
index_floor, index_floor,
floor_name, floor_name,
) )
res = await convert_img(img) res = await convert_img(img)
logger.info('[查询末日幻影信息]绘图已完成,等待发送!') logger.info("[查询末日幻影信息]绘图已完成,等待发送!")
return res return res

View File

@ -6,14 +6,14 @@ from PIL import Image
from aiohttp import ClientSession from aiohttp import ClientSession
from gsuid_core.data_store import get_res_path from gsuid_core.data_store import get_res_path
T = TypeVar('T') T = TypeVar("T")
ROLEINFO_PATH = get_res_path() / 'StarRailUID' / 'roleinfo' ROLEINFO_PATH = get_res_path() / "StarRailUID" / "roleinfo"
ROLEINFO_PATH.mkdir(parents=True, exist_ok=True) ROLEINFO_PATH.mkdir(parents=True, exist_ok=True)
async def get_icon(url: str) -> Image.Image: async def get_icon(url: str) -> Image.Image:
name = url.split('/')[-1] name = url.split("/")[-1]
path = ROLEINFO_PATH / name path = ROLEINFO_PATH / name
if (path).exists(): if (path).exists():
content = path.read_bytes() content = path.read_bytes()
@ -21,6 +21,6 @@ async def get_icon(url: str) -> Image.Image:
async with ClientSession() as client: async with ClientSession() as client:
async with client.get(url) as resp: async with client.get(url) as resp:
content = await resp.read() content = await resp.read()
with Path.open(path, 'wb') as f: with Path.open(path, "wb") as f:
f.write(content) f.write(content)
return Image.open(BytesIO(content)).convert('RGBA') return Image.open(BytesIO(content)).convert("RGBA")

View File

@ -1,47 +1,45 @@
import re import re
from gsuid_core.sv import SV from .draw_abyss_card import draw_abyss_img
from ..utils.sr_prefix import PREFIX
from gsuid_core.bot import Bot from gsuid_core.bot import Bot
from gsuid_core.models import Event from gsuid_core.models import Event
from gsuid_core.sv import SV
from gsuid_core.utils.database.api import get_uid
from gsuid_core.utils.database.models import GsBind
from gsuid_core.utils.error_reply import UID_HINT from gsuid_core.utils.error_reply import UID_HINT
from ..utils.convert import get_uid sv_abyss_story = SV("sr查询虚构叙事")
from ..utils.sr_prefix import PREFIX
from .draw_abyss_card import draw_abyss_img
sv_abyss_story = SV('sr查询虚构叙事')
@sv_abyss_story.on_command( @sv_abyss_story.on_command(
( (
f'{PREFIX}查询虚构叙事', f"{PREFIX}查询虚构叙事",
f'{PREFIX}xg', f"{PREFIX}xg",
f'{PREFIX}查询上期虚构叙事', f"{PREFIX}查询上期虚构叙事",
f'{PREFIX}sqxg', f"{PREFIX}sqxg",
f'{PREFIX}上期虚构', f"{PREFIX}上期虚构",
f'{PREFIX}虚构', f"{PREFIX}虚构",
), ),
block=True, block=True,
) )
async def send_srabyss_info(bot: Bot, ev: Event): async def send_srabyss_info(bot: Bot, ev: Event):
name = ''.join(re.findall('[\u4e00-\u9fa5]', ev.text)) name = "".join(re.findall("[\u4e00-\u9fa5]", ev.text))
if name: if name:
return None return None
await bot.logger.info('开始执行[sr查询虚构叙事信息]') await bot.logger.info("开始执行[sr查询虚构叙事信息]")
get_uid_ = await get_uid(bot, ev, True) uid, user_id = await get_uid(bot, ev, GsBind, "sr", True)
if get_uid_ is None:
return await bot.send(UID_HINT)
uid, user_id = get_uid_
if uid is None: if uid is None:
return await bot.send(UID_HINT) return await bot.send(UID_HINT)
await bot.logger.info(f'[sr查询虚构叙事信息]uid: {uid}') await bot.logger.info(f"[sr查询虚构叙事信息]uid: {uid}")
if 'sq' in ev.command or '上期' in ev.command: if "sq" in ev.command or "上期" in ev.command:
schedule_type = '2' schedule_type = "2"
else: else:
schedule_type = '1' schedule_type = "1"
await bot.logger.info(f'[sr查询虚构叙事信息]虚构叙事期数: {schedule_type}') await bot.logger.info(f"[sr查询虚构叙事信息]虚构叙事期数: {schedule_type}")
im = await draw_abyss_img(user_id, uid, ev.sender, schedule_type) im = await draw_abyss_img(user_id, uid, ev.sender, schedule_type)
await bot.send(im) await bot.send(im)

View File

@ -1,17 +1,7 @@
from pathlib import Path from pathlib import Path
from typing import Union, Optional from typing import Any, Dict, Union
from PIL import Image, ImageDraw
from gsuid_core.logger import logger
from gsuid_core.utils.error_reply import get_error
from gsuid_core.utils.image.image_tools import (
get_qq_avatar,
draw_pic_with_ring,
)
from .utils import get_icon from .utils import get_icon
from ..utils.mys_api import mys_api
from ..utils.image.convert import convert_img
from ..sruid_utils.api.mys.models import AbyssAvatar from ..sruid_utils.api.mys.models import AbyssAvatar
from ..utils.fonts.starrail_fonts import ( from ..utils.fonts.starrail_fonts import (
sr_font_22, sr_font_22,
@ -20,39 +10,41 @@ from ..utils.fonts.starrail_fonts import (
sr_font_34, sr_font_34,
sr_font_42, sr_font_42,
) )
from ..utils.mys_api import mys_api
TEXT_PATH = Path(__file__).parent / 'texture2D' from PIL import Image, ImageDraw
from gsuid_core.logger import logger
from gsuid_core.utils.error_reply import get_error
from gsuid_core.utils.image.convert import convert_img
from gsuid_core.utils.image.image_tools import (
draw_pic_with_ring,
get_qq_avatar,
)
TEXT_PATH = Path(__file__).parent / "texture2D"
white_color = (255, 255, 255) white_color = (255, 255, 255)
gray_color = (175, 175, 175) gray_color = (175, 175, 175)
img_bg = Image.open(TEXT_PATH / 'bg.jpg') img_bg = Image.open(TEXT_PATH / "bg.jpg")
level_cover = Image.open(TEXT_PATH / 'level_cover.png').convert('RGBA') level_cover = Image.open(TEXT_PATH / "level_cover.png").convert("RGBA")
char_bg_4 = Image.open(TEXT_PATH / 'char4_bg.png').convert('RGBA') char_bg_4 = Image.open(TEXT_PATH / "char4_bg.png").convert("RGBA")
char_bg_5 = Image.open(TEXT_PATH / 'char5_bg.png').convert('RGBA') char_bg_5 = Image.open(TEXT_PATH / "char5_bg.png").convert("RGBA")
rank_bg = Image.open(TEXT_PATH / 'rank_bg.png').convert('RGBA') rank_bg = Image.open(TEXT_PATH / "rank_bg.png").convert("RGBA")
star_yes = Image.open(TEXT_PATH / 'star.png').convert('RGBA') star_yes = Image.open(TEXT_PATH / "star.png").convert("RGBA")
star_gray = Image.open(TEXT_PATH / 'star_gray.png').convert('RGBA') star_gray = Image.open(TEXT_PATH / "star_gray.png").convert("RGBA")
elements = { elements = {
'ice': Image.open(TEXT_PATH / 'IconNatureColorIce.png').convert('RGBA'), "ice": Image.open(TEXT_PATH / "IconNatureColorIce.png").convert("RGBA"),
'fire': Image.open(TEXT_PATH / 'IconNatureColorFire.png').convert('RGBA'), "fire": Image.open(TEXT_PATH / "IconNatureColorFire.png").convert("RGBA"),
'imaginary': Image.open( "imaginary": Image.open(TEXT_PATH / "IconNatureColorImaginary.png").convert("RGBA"),
TEXT_PATH / 'IconNatureColorImaginary.png' "quantum": Image.open(TEXT_PATH / "IconNatureColorQuantum.png").convert("RGBA"),
).convert('RGBA'), "lightning": Image.open(TEXT_PATH / "IconNatureColorThunder.png").convert("RGBA"),
'quantum': Image.open(TEXT_PATH / 'IconNatureColorQuantum.png').convert( "wind": Image.open(TEXT_PATH / "IconNatureColorWind.png").convert("RGBA"),
'RGBA' "physical": Image.open(TEXT_PATH / "IconNaturePhysical.png").convert("RGBA"),
),
'lightning': Image.open(TEXT_PATH / 'IconNatureColorThunder.png').convert(
'RGBA'
),
'wind': Image.open(TEXT_PATH / 'IconNatureColorWind.png').convert('RGBA'),
'physical': Image.open(TEXT_PATH / 'IconNaturePhysical.png').convert(
'RGBA'
),
} }
async def get_abyss_star_pic(star: int) -> Image.Image: async def get_abyss_star_pic(star: int) -> Image.Image:
return Image.open(TEXT_PATH / f'star{star}.png') return Image.open(TEXT_PATH / f"star{star}.png")
async def _draw_abyss_card( async def _draw_abyss_card(
@ -76,10 +68,10 @@ async def _draw_abyss_card(
char_bg.paste(rank_bg, (150, 16), mask=rank_bg) char_bg.paste(rank_bg, (150, 16), mask=rank_bg)
char_card_draw.text( char_card_draw.text(
(162, 31), (162, 31),
f'{char.rank}', f"{char.rank}",
font=sr_font_22, font=sr_font_22,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
# 不存在自动下载 # 不存在自动下载
# if not char_pic_path.exists(): # if not char_pic_path.exists():
@ -89,10 +81,10 @@ async def _draw_abyss_card(
# char_card.paste(talent_pic, (137, 260), talent_pic) # char_card.paste(talent_pic, (137, 260), talent_pic)
char_card_draw.text( char_card_draw.text(
(100, 165), (100, 165),
f'等级 {char.level}', f"等级 {char.level}",
font=sr_font_22, font=sr_font_22,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
floor_pic.paste( floor_pic.paste(
char_bg, char_bg,
@ -102,16 +94,16 @@ async def _draw_abyss_card(
async def _draw_floor_card( async def _draw_floor_card(
level_star: int, level_star: Union[int, str],
floor_pic: Image.Image, floor_pic: Image.Image,
img: Image.Image, img: Image.Image,
index_floor: int, index_floor: int,
floor_name: str, floor_name: str,
round_num: int, round_num: Union[int, None],
): ):
for index_num in [0, 1, 2]: for index_num in [0, 1, 2]:
star_num = index_num + 1 star_num = index_num + 1
if star_num <= level_star: if star_num <= int(level_star):
star_pic = star_yes.copy() star_pic = star_yes.copy()
else: else:
star_pic = star_gray.copy() star_pic = star_gray.copy()
@ -122,14 +114,14 @@ async def _draw_floor_card(
floor_name, floor_name,
font=sr_font_42, font=sr_font_42,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
floor_pic_draw.text( floor_pic_draw.text(
(802, 60), (802, 60),
f'使用轮: {round_num}', f"使用轮: {round_num}",
font=sr_font_28, font=sr_font_28,
fill=gray_color, fill=gray_color,
anchor='rm', anchor="rm",
) )
img.paste(floor_pic, (0, 657 + index_floor * 570), floor_pic) img.paste(floor_pic, (0, 657 + index_floor * 570), floor_pic)
@ -137,18 +129,20 @@ async def _draw_floor_card(
async def draw_abyss_img( async def draw_abyss_img(
qid: Union[str, int], qid: Union[str, int],
uid: str, uid: str,
sender: Union[str, str], sender: Dict[str, Any],
schedule_type: str = '1', schedule_type: str = "1",
) -> Union[bytes, str]: ) -> Union[bytes, str]:
raw_abyss_data = await mys_api.get_abyss_story_info(uid, schedule_type) raw_abyss_data = await mys_api.get_abyss_story_info(uid, schedule_type)
if isinstance(raw_abyss_data, int): if isinstance(raw_abyss_data, int):
return get_error(raw_abyss_data) return get_error(raw_abyss_data)
# 获取查询者数据 # 获取查询者数据
if raw_abyss_data.max_floor == '': if raw_abyss_data.max_floor == "":
return '你还没有挑战本期虚构叙事!\n可以使用[sr上期虚构叙事]命令查询上期~' return "你还没有挑战本期虚构叙事!\n可以使用[sr上期虚构叙事]命令查询上期~"
# 过滤掉 is_fast快速通关 为 True 的项 # 过滤掉 is_fast (快速通关) 为 True 的项
floor_detail = [detail for detail in raw_abyss_data.all_floor_detail if not detail.is_fast] floor_detail = [
detail for detail in raw_abyss_data.all_floor_detail if not detail.is_fast
]
floor_num = len(floor_detail) floor_num = len(floor_detail)
# 获取背景图片各项参数 # 获取背景图片各项参数
@ -156,15 +150,15 @@ async def draw_abyss_img(
based_h = 657 + 570 * floor_num based_h = 657 + 570 * floor_num
img = img_bg.copy() img = img_bg.copy()
img = img.crop((0, 0, based_w, based_h)) img = img.crop((0, 0, based_w, based_h))
abyss_title = Image.open(TEXT_PATH / 'head.png') abyss_title = Image.open(TEXT_PATH / "head.png")
img.paste(abyss_title, (0, 0), abyss_title) img.paste(abyss_title, (0, 0), abyss_title)
# 获取头像 # 获取头像
_id = str(qid) _id = str(qid)
if _id.startswith('http'): if _id.startswith("http"):
char_pic = await get_qq_avatar(avatar_url=_id) char_pic = await get_qq_avatar(avatar_url=_id)
elif sender.get('avatar') is not None: elif sender.get("avatar") is not None:
char_pic = await get_qq_avatar(avatar_url=sender['avatar']) char_pic = await get_qq_avatar(avatar_url=sender["avatar"])
else: else:
char_pic = await get_qq_avatar(qid=qid) char_pic = await get_qq_avatar(qid=qid)
char_pic = await draw_pic_with_ring(char_pic, 250, None, False) char_pic = await draw_pic_with_ring(char_pic, 250, None, False)
@ -173,42 +167,42 @@ async def draw_abyss_img(
# 绘制抬头 # 绘制抬头
img_draw = ImageDraw.Draw(img) img_draw = ImageDraw.Draw(img)
img_draw.text((450, 442), f'UID {uid}', white_color, sr_font_28, 'mm') img_draw.text((450, 442), f"UID {uid}", white_color, sr_font_28, "mm")
# 总体数据 # 总体数据
abyss_data = Image.open(TEXT_PATH / 'data.png') abyss_data = Image.open(TEXT_PATH / "data.png")
img.paste(abyss_data, (0, 500), abyss_data) img.paste(abyss_data, (0, 500), abyss_data)
# 最深抵达 # 最深抵达
img_draw.text( img_draw.text(
(220, 565), (220, 565),
f'{raw_abyss_data.max_floor}', f"{raw_abyss_data.max_floor}",
white_color, white_color,
sr_font_34, sr_font_34,
'lm', "lm",
) )
# 挑战次数 # 挑战次数
img_draw.text( img_draw.text(
(220, 612), (220, 612),
f'{raw_abyss_data.battle_num}', f"{raw_abyss_data.battle_num}",
white_color, white_color,
sr_font_34, sr_font_34,
'lm', "lm",
) )
star_num_pic = Image.open(TEXT_PATH / 'star.png') star_num_pic = Image.open(TEXT_PATH / "star.png")
img.paste(star_num_pic, (615, 557), star_num_pic) img.paste(star_num_pic, (615, 557), star_num_pic)
img_draw.text( img_draw.text(
(695, 590), (695, 590),
f'{raw_abyss_data.star_num}/12', f"{raw_abyss_data.star_num}/12",
white_color, white_color,
sr_font_42, sr_font_42,
'lm', "lm",
) )
for index_floor, level in enumerate(raw_abyss_data.all_floor_detail): for index_floor, level in enumerate(raw_abyss_data.all_floor_detail):
floor_pic = Image.open(TEXT_PATH / 'floor_bg.png') floor_pic = Image.open(TEXT_PATH / "floor_bg.png")
level_star = level.star_num level_star = level.star_num
floor_name = level.name floor_name = level.name
round_num = level.round_num round_num = level.round_num
@ -220,23 +214,24 @@ async def draw_abyss_img(
time_array = node_1.challenge_time time_array = node_1.challenge_time
else: else:
time_array = node_2.challenge_time time_array = node_2.challenge_time
time_str = f'{time_array.year}-{time_array.month}' assert time_array is not None
time_str = f'{time_str}-{time_array.day}' time_str = f"{time_array.year}-{time_array.month}"
time_str = f'{time_str} {time_array.hour}:{time_array.minute}:00' time_str = f"{time_str}-{time_array.day}"
time_str = f"{time_str} {time_array.hour}:{time_array.minute}:00"
floor_pic_draw = ImageDraw.Draw(floor_pic) floor_pic_draw = ImageDraw.Draw(floor_pic)
floor_pic_draw.text( floor_pic_draw.text(
(112, 120 + index_part * 219), (112, 120 + index_part * 219),
f'节点{node_num}', f"节点{node_num}",
white_color, white_color,
sr_font_30, sr_font_30,
'lm', "lm",
) )
floor_pic_draw.text( floor_pic_draw.text(
(201, 120 + index_part * 219), (201, 120 + index_part * 219),
f'{time_str}', f"{time_str}",
gray_color, gray_color,
sr_font_22, sr_font_22,
'lm', "lm",
) )
if node_num == 1: if node_num == 1:
avatars_array = node_1 avatars_array = node_1
@ -261,5 +256,5 @@ async def draw_abyss_img(
) )
res = await convert_img(img) res = await convert_img(img)
logger.info('[查询虚构叙事信息]绘图已完成,等待发送!') logger.info("[查询虚构叙事信息]绘图已完成,等待发送!")
return res return res

View File

@ -6,14 +6,14 @@ from PIL import Image
from aiohttp import ClientSession from aiohttp import ClientSession
from gsuid_core.data_store import get_res_path from gsuid_core.data_store import get_res_path
T = TypeVar('T') T = TypeVar("T")
ROLEINFO_PATH = get_res_path() / 'StarRailUID' / 'roleinfo' ROLEINFO_PATH = get_res_path() / "StarRailUID" / "roleinfo"
ROLEINFO_PATH.mkdir(parents=True, exist_ok=True) ROLEINFO_PATH.mkdir(parents=True, exist_ok=True)
async def get_icon(url: str) -> Image.Image: async def get_icon(url: str) -> Image.Image:
name = url.split('/')[-1] name = url.split("/")[-1]
path = ROLEINFO_PATH / name path = ROLEINFO_PATH / name
if (path).exists(): if (path).exists():
content = path.read_bytes() content = path.read_bytes()
@ -21,6 +21,6 @@ async def get_icon(url: str) -> Image.Image:
async with ClientSession() as client: async with ClientSession() as client:
async with client.get(url) as resp: async with client.get(url) as resp:
content = await resp.read() content = await resp.read()
with Path.open(path, 'wb') as f: with Path.open(path, "wb") as f:
f.write(content) f.write(content)
return Image.open(BytesIO(content)).convert('RGBA') return Image.open(BytesIO(content)).convert("RGBA")

View File

@ -1,6 +1,5 @@
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from ..utils.convert import get_uid
from ..utils.error_reply import UID_HINT from ..utils.error_reply import UID_HINT
from ..utils.map.name_covert import ( from ..utils.map.name_covert import (
alias_to_char_name, alias_to_char_name,
@ -10,26 +9,29 @@ from ..utils.mys_api import mys_api
from ..utils.sr_prefix import PREFIX from ..utils.sr_prefix import PREFIX
from gsuid_core.sv import SV from gsuid_core.sv import SV
from gsuid_core.utils.database.api import get_uid
from gsuid_core.utils.database.models import GsBind
from gsuid_core.utils.error_reply import get_error from gsuid_core.utils.error_reply import get_error
if TYPE_CHECKING: if TYPE_CHECKING:
from gsuid_core.bot import Bot from gsuid_core.bot import Bot
from gsuid_core.models import Event from gsuid_core.models import Event
sv_char_calc = SV('sr养成计算') sv_char_calc = SV("sr养成计算")
@sv_char_calc.on_command(f'{PREFIX}养成计算', block=True) @sv_char_calc.on_command(f"{PREFIX}养成计算", block=True)
async def send_char_calc_info(bot: 'Bot', ev: 'Event'): async def send_char_calc_info(bot: "Bot", ev: "Event"):
name = ev.text.strip() name = ev.text.strip()
char_id = await name_to_avatar_id(name) char_id = await name_to_avatar_id(name)
if char_id == '': if char_id == "":
result_fake_name = await alias_to_char_name(name) result_fake_name = await alias_to_char_name(name)
if result_fake_name is None: if result_fake_name is None:
return '请输入正确的角色名' return "请输入正确的角色名"
fake_name = result_fake_name fake_name = result_fake_name
char_id = await name_to_avatar_id(fake_name) char_id = await name_to_avatar_id(fake_name)
uid = await get_uid(bot, ev, only_uid=True)
uid = await get_uid(bot, ev, GsBind, "sr")
if uid is None: if uid is None:
return await bot.send(UID_HINT) return await bot.send(UID_HINT)
@ -39,8 +41,6 @@ async def send_char_calc_info(bot: 'Bot', ev: 'Event'):
avatar_skills = avatar_detail.skills + avatar_detail.skills_other avatar_skills = avatar_detail.skills + avatar_detail.skills_other
skill_list = [] skill_list = []
for skill in avatar_skills: for skill in avatar_skills:
skill_list.append( skill_list.append(f"{skill.point_id}({skill.cur_level}/{skill.max_level})")
f'{skill.point_id}({skill.cur_level}/{skill.max_level})'
)
return None return None

View File

@ -1,28 +1,29 @@
import re
from pathlib import Path from pathlib import Path
import re
from typing import Tuple, cast from typing import Tuple, cast
from .get_char_img import draw_char_info_img
from .to_card import api_to_card
from ..utils.error_reply import UID_HINT
from ..utils.resource.RESOURCE_PATH import TEMP_PATH
from ..utils.sr_prefix import PREFIX
from PIL import Image from PIL import Image
from gsuid_core.sv import SV
from gsuid_core.bot import Bot from gsuid_core.bot import Bot
from gsuid_core.models import Event
from gsuid_core.message_models import Button from gsuid_core.message_models import Button
from gsuid_core.models import Event
from gsuid_core.sv import SV
from gsuid_core.utils.database.api import get_uid
from gsuid_core.utils.database.models import GsBind
from gsuid_core.utils.image.convert import convert_img
from starrail_damage_cal.map.SR_MAP_PATH import avatarId2Name from starrail_damage_cal.map.SR_MAP_PATH import avatarId2Name
from .to_card import api_to_card sv_char_info_config = SV("sr面板设置", pm=2)
from ..utils.convert import get_uid sv_get_char_info = SV("sr面板查询", priority=10)
from ..utils.sr_prefix import PREFIX sv_get_sr_original_pic = SV("sr查看面板原图", priority=5)
from ..utils.error_reply import UID_HINT
from .get_char_img import draw_char_info_img
from ..utils.image.convert import convert_img
from ..utils.resource.RESOURCE_PATH import TEMP_PATH
sv_char_info_config = SV('sr面板设置', pm=2)
sv_get_char_info = SV('sr面板查询', priority=10)
sv_get_sr_original_pic = SV('sr查看面板原图', priority=5)
@sv_get_char_info.on_prefix(f'{PREFIX}查询') @sv_get_char_info.on_prefix(f"{PREFIX}查询")
async def send_char_info(bot: Bot, ev: Event): async def send_char_info(bot: Bot, ev: Event):
name = ev.text.strip() name = ev.text.strip()
im = await _get_char_info(bot, ev, ev.text) im = await _get_char_info(bot, ev, ev.text)
@ -36,12 +37,12 @@ async def send_char_info(bot: Bot, ev: Event):
await bot.send_option( await bot.send_option(
img, img,
[ [
Button('🔄更换武器', f'sr查询{name}', action=2), Button("🔄更换武器", f"sr查询{name}", action=2),
Button('⏫提高命座', f'sr查询六魂{name}', action=2), Button("⏫提高命座", f"sr查询六魂{name}", action=2),
], ],
) )
if im[1]: if im[1]:
with Path.open(TEMP_PATH / f'{ev.msg_id}.jpg', 'wb') as f: with Path.open(TEMP_PATH / f"{ev.msg_id}.jpg", "wb") as f:
f.write(cast(bytes, im[1])) f.write(cast(bytes, im[1]))
elif isinstance(im, Image.Image): elif isinstance(im, Image.Image):
await bot.send(await convert_img(im)) await bot.send(await convert_img(im))
@ -50,14 +51,14 @@ async def send_char_info(bot: Bot, ev: Event):
await bot.send_option( await bot.send_option(
im, im,
[ [
Button('🔄更换武器', f'sr查询{name}', action=2), Button("🔄更换武器", f"sr查询{name}", action=2),
Button('⏫提高命座', f'sr查询六魂{name}', action=2), Button("⏫提高命座", f"sr查询六魂{name}", action=2),
], ],
) )
elif im is None: elif im is None:
return return
else: else:
await bot.send('发生未知错误') await bot.send("发生未知错误")
async def _get_char_info(bot: Bot, ev: Event, text: str): async def _get_char_info(bot: Bot, ev: Event, text: str):
@ -66,33 +67,33 @@ async def _get_char_info(bot: Bot, ev: Event, text: str):
if not msg: if not msg:
return None return None
# 获取角色名 # 获取角色名
await bot.logger.info('开始执行[查询角色面板]') await bot.logger.info("开始执行[查询角色面板]")
# 获取uid # 获取uid
if '' in msg or '' in msg or '' in msg: if "" in msg or "" in msg or "" in msg:
uid = await get_uid(bot, ev, False, True) uid = await get_uid(bot, ev, GsBind, "sr", False)
else: else:
uid = await get_uid(bot, ev) uid = await get_uid(bot, ev, GsBind, "sr")
msg = ' '.join(re.findall('[\u4e00-\u9fa5]+', text)) msg = " ".join(re.findall("[\u4e00-\u9fa5]+", text))
if uid is None: if uid is None:
return await bot.send(UID_HINT) return await bot.send(UID_HINT)
await bot.logger.info(f'[查询角色面板]uid: {uid}') await bot.logger.info(f"[查询角色面板]uid: {uid}")
return await draw_char_info_img(msg, uid) return await draw_char_info_img(msg, uid)
@sv_get_char_info.on_command(f'{PREFIX}强制刷新') @sv_get_char_info.on_command(f"{PREFIX}强制刷新")
async def send_card_info(bot: Bot, ev: Event): async def send_card_info(bot: Bot, ev: Event):
uid = await get_uid(bot, ev) uid = await get_uid(bot, ev, GsBind, "sr")
if uid is None: if uid is None:
return await bot.send(UID_HINT) return await bot.send(UID_HINT)
await bot.logger.info(f'[sr强制刷新]uid: {uid}') await bot.logger.info(f"[sr强制刷新]uid: {uid}")
im = await api_to_card(uid) im = await api_to_card(uid)
await bot.logger.info(f'UID{uid}获取角色数据成功!') await bot.logger.info(f"UID{uid}获取角色数据成功!")
if isinstance(im, Tuple): if isinstance(im, Tuple):
buttons = [ buttons = [
Button( Button(
f'✅查询{avatarId2Name[str(avatarid)]}', f"✅查询{avatarId2Name[str(avatarid)]}",
f'sr查询{avatarId2Name[str(avatarid)]}', f"sr查询{avatarId2Name[str(avatarid)]}",
) )
for avatarid in im[1] for avatarid in im[1]
] ]

File diff suppressed because it is too large Load Diff

View File

@ -1,67 +1,67 @@
import re
import json import json
from pathlib import Path from pathlib import Path
from typing import Dict, Tuple, Union, Optional import re
from typing import Dict, Optional, Tuple, Union
from .draw_char_img import draw_char_img
from ..utils.error_reply import CHAR_HINT
from ..utils.map.SR_MAP_PATH import (
AvatarRankSkillUp,
EquipmentID2Name,
EquipmentID2Rarity,
Property2Name,
avatarId2DamageType,
avatarId2EnName,
avatarId2Name,
avatarId2Rarity,
characterSkillTree,
rankId2Name,
skillId2AttackType,
skillId2Effect,
skillId2Name,
)
from ..utils.map.name_covert import (
alias_to_char_name,
alias_to_weapon_name,
name_to_avatar_id,
name_to_weapon_id,
)
from ..utils.resource.RESOURCE_PATH import PLAYER_PATH
from gsuid_core.logger import logger from gsuid_core.logger import logger
from starrail_damage_cal.to_data import api_to_dict
from starrail_damage_cal.excel.model import ( from starrail_damage_cal.excel.model import (
AvatarPromotionConfig, AvatarPromotionConfig,
EquipmentPromotionConfig, EquipmentPromotionConfig,
) )
from starrail_damage_cal.to_data import api_to_dict
from .draw_char_img import draw_char_img
from ..utils.error_reply import CHAR_HINT
from ..utils.resource.RESOURCE_PATH import PLAYER_PATH
from ..utils.map.name_covert import (
name_to_avatar_id,
name_to_weapon_id,
alias_to_char_name,
alias_to_weapon_name,
)
from ..utils.map.SR_MAP_PATH import (
Property2Name,
EquipmentID2Name,
AvatarRankSkillUp,
EquipmentID2Rarity,
rankId2Name,
skillId2Name,
avatarId2Name,
skillId2Effect,
avatarId2EnName,
avatarId2Rarity,
characterSkillTree,
skillId2AttackType,
avatarId2DamageType,
)
WEAPON_TO_INT = { WEAPON_TO_INT = {
'': 1, "": 1,
'': 2, "": 2,
'': 3, "": 3,
'': 4, "": 4,
'': 5, "": 5,
'': 5, "": 5,
} }
CHAR_TO_INT = { CHAR_TO_INT = {
'': 0, "": 0,
'': 1, "": 1,
'': 2, "": 2,
'': 3, "": 3,
'': 4, "": 4,
'': 5, "": 5,
'': 6, "": 6,
'': 6, "": 6,
} }
PieceName_ilst = { PieceName_ilst = {
0: ['', ''], 0: ["", ""],
1: [''], 1: [""],
2: ['', '', ''], 2: ["", "", ""],
3: ['', ''], 3: ["", ""],
4: [''], 4: [""],
5: ['', ''], 5: ["", ""],
} }
@ -77,11 +77,11 @@ async def draw_char_info_img(raw_mes: str, sr_uid: str):
char = await get_char(*_args) char = await get_char(*_args)
if isinstance(char, str): if isinstance(char, str):
logger.info('[sr查询角色] 绘图失败, 替换的武器不正确!') logger.info("[sr查询角色] 绘图失败, 替换的武器不正确!")
return char return char
im = await draw_char_img(char, sr_uid, raw_mes) im = await draw_char_img(char, sr_uid, raw_mes)
logger.info('[查询角色] 绘图完成,等待发送...') logger.info("[查询角色] 绘图完成,等待发送...")
return im return im
@ -92,24 +92,24 @@ async def get_char_args(
# 六命希儿带于夜色中换1000xxxx4青雀遗器换1000xxxx6希儿头换银狼手 # 六命希儿带于夜色中换1000xxxx4青雀遗器换1000xxxx6希儿头换银狼手
# 六命希儿带于夜色中换1000xxxx6希儿头 # 六命希儿带于夜色中换1000xxxx6希儿头
# 希儿换银狼手 # 希儿换银狼手
fake_name = '' fake_name = ""
talent_num = None talent_num = None
char_data = {} char_data = {}
weapon, weapon_affix = None, None weapon, weapon_affix = None, None
msg = msg.replace('', '').replace('', '').replace('圣遗物', '遗器') msg = msg.replace("", "").replace("", "").replace("圣遗物", "遗器")
# 希儿带于夜色中换1000xxxx6希儿头 # 希儿带于夜色中换1000xxxx6希儿头
msg_list = msg.split('') msg_list = msg.split("")
for index, part in enumerate(msg_list): for index, part in enumerate(msg_list):
changeuid = await get_part_uid(part, uid) changeuid = await get_part_uid(part, uid)
if changeuid is None: if changeuid is None:
return 'UID不正确噢~' return "UID不正确噢~"
# 判断主体 # 判断主体
if index == 0: if index == 0:
fake_name, talent_num = await get_fake_char_str(part) fake_name, talent_num = await get_fake_char_str(part)
# 判断是否开启fake_char # 判断是否开启fake_char
if '遗器' in msg: if "遗器" in msg:
char_data = await get_char_data(uid, fake_name) char_data = await get_char_data(uid, fake_name)
if isinstance(char_data, str): if isinstance(char_data, str):
char_data = await make_new_charinfo(uid, fake_name) char_data = await make_new_charinfo(uid, fake_name)
@ -119,29 +119,25 @@ async def get_char_args(
return char_data return char_data
continue continue
if '遗器' in part: if "遗器" in part:
char_data = await get_fake_char_data( char_data = await get_fake_char_data(
char_data, char_data,
part.replace('遗器', '').replace(changeuid, ''), part.replace("遗器", "").replace(changeuid, ""),
changeuid, changeuid,
) )
if isinstance(char_data, str): if isinstance(char_data, str):
return char_data return char_data
else: else:
for i, s in enumerate( for i, s in enumerate(["头部", "手部", "躯干", "腿部", "位面球", "连结绳"]):
['头部', '手部', '躯干', '腿部', '位面球', '连结绳'] if "赤沙" in part:
):
if '赤沙' in part:
continue continue
if part[-1] in PieceName_ilst[i]: if part[-1] in PieceName_ilst[i]:
if isinstance(char_data, str): if isinstance(char_data, str):
return char_data return char_data
char_data = await change_equip( char_data = await change_equip(changeuid, char_data, part, s, i)
changeuid, char_data, part, s, i
)
if not char_data: if not char_data:
change_name = part.replace(part[-1], '') change_name = part.replace(part[-1], "")
return f'要替换的{change_name}{s}遗器不存在噢~' return f"要替换的{change_name}{s}遗器不存在噢~"
break break
else: else:
weapon, weapon_affix = await get_fake_weapon_str(part) weapon, weapon_affix = await get_fake_weapon_str(part)
@ -149,24 +145,22 @@ async def get_char_args(
return char_data, weapon, weapon_affix, talent_num return char_data, weapon, weapon_affix, talent_num
async def change_equip( async def change_equip(uid: str, char_data: Dict, part: str, s: str, i: int) -> Dict:
uid: str, char_data: Dict, part: str, s: str, i: int char_name = part.replace(part[-1], "").replace(uid, "")
) -> Dict:
char_name = part.replace(part[-1], '').replace(uid, '')
fake_data = await get_char_data(uid, char_name) fake_data = await get_char_data(uid, char_name)
if isinstance(fake_data, str): if isinstance(fake_data, str):
return {} return {}
relicmap = i + 1 relicmap = i + 1
for equip in fake_data['RelicInfo']: for equip in fake_data["RelicInfo"]:
if str(str(equip['relicId'])[-1]) == str(relicmap): if str(str(equip["relicId"])[-1]) == str(relicmap):
char_data['RelicInfo'][i] = equip char_data["RelicInfo"][i] = equip
break break
return char_data return char_data
async def get_part_uid(part: str, uid: str): async def get_part_uid(part: str, uid: str):
sr_uid = uid sr_uid = uid
uid_data = re.findall(r'\d{9}', part) uid_data = re.findall(r"\d{9}", part)
if uid_data: if uid_data:
sr_uid: Optional[str] = uid_data[0] sr_uid: Optional[str] = uid_data[0]
return sr_uid return sr_uid
@ -178,9 +172,7 @@ async def get_fake_char_str(char_name: str) -> Tuple[str, Optional[int]]:
""" """
talent_num = None talent_num = None
if ('' in char_name or '' in char_name) and char_name[ if ("" in char_name or "" in char_name) and char_name[0] in CHAR_TO_INT:
0
] in CHAR_TO_INT:
talent_num = CHAR_TO_INT[char_name[0]] talent_num = CHAR_TO_INT[char_name[0]]
char_name = char_name[2:] char_name = char_name[2:]
return char_name, talent_num return char_name, talent_num
@ -188,7 +180,7 @@ async def get_fake_char_str(char_name: str) -> Tuple[str, Optional[int]]:
async def get_fake_weapon_str(msg: str) -> Tuple[str, Optional[int]]: async def get_fake_weapon_str(msg: str) -> Tuple[str, Optional[int]]:
weapon_affix = 1 weapon_affix = 1
if '' in msg and msg[1] in WEAPON_TO_INT: if "" in msg and msg[1] in WEAPON_TO_INT:
weapon_affix = WEAPON_TO_INT[msg[1]] weapon_affix = WEAPON_TO_INT[msg[1]]
weapon = msg[2:] weapon = msg[2:]
else: else:
@ -203,7 +195,7 @@ async def get_fake_char_data(
if isinstance(original_data, str): if isinstance(original_data, str):
return original_data return original_data
if isinstance(original_data, Dict): if isinstance(original_data, Dict):
char_data['RelicInfo'] = original_data['RelicInfo'] char_data["RelicInfo"] = original_data["RelicInfo"]
return char_data return char_data
@ -212,16 +204,16 @@ async def get_char_data(
uid: str, char_name: str, enable_self: bool = True uid: str, char_name: str, enable_self: bool = True
) -> Union[Dict, str]: ) -> Union[Dict, str]:
player_path = PLAYER_PATH / str(uid) player_path = PLAYER_PATH / str(uid)
SELF_PATH = player_path / 'SELF' SELF_PATH = player_path / "SELF"
if '开拓者' in str(char_name): if "开拓者" in str(char_name):
char_name = '开拓者' char_name = "开拓者"
char_id = await name_to_avatar_id(char_name) char_id = await name_to_avatar_id(char_name)
if char_id == '': if char_id == "":
char_name = await alias_to_char_name(char_name) char_name = await alias_to_char_name(char_name)
if char_name is False: if char_name is False:
return '请输入正确的角色名' return "请输入正确的角色名"
char_path = player_path / f'{char_name}.json' char_path = player_path / f"{char_name}.json"
char_self_path = SELF_PATH / f'{char_name}.json' char_self_path = SELF_PATH / f"{char_name}.json"
path = Path() path = Path()
if char_path.exists(): if char_path.exists():
path = char_path path = char_path
@ -243,7 +235,7 @@ async def get_char_data(
else: else:
return CHAR_HINT.format(char_name, char_name) return CHAR_HINT.format(char_name, char_name)
with Path.open(path, encoding='utf8') as fp: with Path.open(path, encoding="utf8") as fp:
return json.load(fp) return json.load(fp)
@ -252,39 +244,29 @@ async def make_new_charinfo(
fake_name: str, fake_name: str,
): ):
char_data = {} char_data = {}
char_data['uid'] = uid char_data["uid"] = uid
char_data['nickName'] = 'test' char_data["nickName"] = "test"
char_id = await name_to_avatar_id(fake_name) char_id = await name_to_avatar_id(fake_name)
if char_id == '': if char_id == "":
fake_name = await alias_to_char_name(fake_name) fake_name = await alias_to_char_name(fake_name)
if fake_name is False: if fake_name is False:
return '请输入正确的角色名' return "请输入正确的角色名"
char_id = await name_to_avatar_id(fake_name) char_id = await name_to_avatar_id(fake_name)
char_data['avatarId'] = int(char_id) char_data["avatarId"] = int(char_id)
char_data['avatarName'] = fake_name char_data["avatarName"] = fake_name
char_data['avatarElement'] = avatarId2DamageType[ char_data["avatarElement"] = avatarId2DamageType[str(char_data["avatarId"])]
str(char_data['avatarId']) char_data["avatarRarity"] = str(avatarId2Rarity[str(char_data["avatarId"])])
] char_data["avatarPromotion"] = 6
char_data['avatarRarity'] = str( char_data["avatarLevel"] = 80
avatarId2Rarity[str(char_data['avatarId'])] char_data["avatarSkill"] = await get_skill_list(char_data["avatarId"])
) char_data["avatarExtraAbility"] = await get_extra_list(char_data["avatarId"])
char_data['avatarPromotion'] = 6 char_data["avatarAttributeBonus"] = await get_attribute_list(char_data["avatarId"])
char_data['avatarLevel'] = 80 char_data["RelicInfo"] = []
char_data['avatarSkill'] = await get_skill_list(char_data['avatarId']) char_data["avatarEnName"] = avatarId2EnName[str(char_data["avatarId"])]
char_data['avatarExtraAbility'] = await get_extra_list( char_data["rank"] = 0
char_data['avatarId'] char_data["rankList"] = []
) char_data["baseAttributes"] = await get_baseAttributes(char_data["avatarId"])
char_data['avatarAttributeBonus'] = await get_attribute_list( char_data["equipmentInfo"] = {}
char_data['avatarId']
)
char_data['RelicInfo'] = []
char_data['avatarEnName'] = avatarId2EnName[str(char_data['avatarId'])]
char_data['rank'] = 0
char_data['rankList'] = []
char_data['baseAttributes'] = await get_baseAttributes(
char_data['avatarId']
)
char_data['equipmentInfo'] = {}
return char_data return char_data
@ -293,35 +275,40 @@ async def get_baseAttributes(
): ):
# 处理基础属性 # 处理基础属性
base_attributes = {} base_attributes = {}
avatar_promotion_base = AvatarPromotionConfig.Avatar[str(char_id)]['6']
avatar_promotion_base = None
for avatar in AvatarPromotionConfig:
if avatar.AvatarID == str(char_id):
avatar_promotion_base = avatar
break
if not avatar_promotion_base:
msg = f"AvatarPromotionConfig not found: {char_id}"
raise ValueError(msg)
# 攻击力 # 攻击力
base_attributes['attack'] = ( base_attributes["attack"] = (
avatar_promotion_base.AttackBase.Value avatar_promotion_base.AttackBase.Value
+ avatar_promotion_base.AttackAdd.Value * (80 - 1) + avatar_promotion_base.AttackAdd.Value * (80 - 1)
) )
# 防御力 # 防御力
base_attributes['defence'] = ( base_attributes["defence"] = (
avatar_promotion_base.DefenceBase.Value avatar_promotion_base.DefenceBase.Value
+ avatar_promotion_base.DefenceAdd.Value * (80 - 1) + avatar_promotion_base.DefenceAdd.Value * (80 - 1)
) )
# 血量 # 血量
base_attributes['hp'] = ( base_attributes["hp"] = (
avatar_promotion_base.HPBase.Value avatar_promotion_base.HPBase.Value
+ avatar_promotion_base.HPAdd.Value * (80 - 1) + avatar_promotion_base.HPAdd.Value * (80 - 1)
) )
# 速度 # 速度
base_attributes['speed'] = avatar_promotion_base.SpeedBase.Value base_attributes["speed"] = avatar_promotion_base.SpeedBase.Value
# 暴击率 # 暴击率
base_attributes['CriticalChanceBase'] = ( base_attributes["CriticalChanceBase"] = avatar_promotion_base.CriticalChance.Value
avatar_promotion_base.CriticalChance.Value
)
# 暴击伤害 # 暴击伤害
base_attributes['CriticalDamageBase'] = ( base_attributes["CriticalDamageBase"] = avatar_promotion_base.CriticalDamage.Value
avatar_promotion_base.CriticalDamage.Value
)
# 嘲讽 # 嘲讽
base_attributes['BaseAggro'] = avatar_promotion_base.BaseAggro.Value base_attributes["BaseAggro"] = avatar_promotion_base.BaseAggro.Value
return base_attributes return base_attributes
@ -331,21 +318,19 @@ async def get_attribute_list(
attribute_list = [] attribute_list = []
for attributeid in [201, 202, 203, 204, 205, 206, 207, 208, 209, 210]: for attributeid in [201, 202, 203, 204, 205, 206, 207, 208, 209, 210]:
attribute_bonus_temp = {} attribute_bonus_temp = {}
attribute_bonus_temp['attributeBonusId'] = char_id * 1000 + attributeid attribute_bonus_temp["attributeBonusId"] = char_id * 1000 + attributeid
attribute_bonus_temp['attributeBonusLevel'] = 1 attribute_bonus_temp["attributeBonusLevel"] = 1
status_add = characterSkillTree[str(char_id)][ status_add = characterSkillTree[str(char_id)][
str(attribute_bonus_temp['attributeBonusId']) str(attribute_bonus_temp["attributeBonusId"])
]['levels'][0]['properties'] ]["levels"][0]["properties"]
attribute_bonus_temp['statusAdd'] = {} attribute_bonus_temp["statusAdd"] = {}
if status_add: if status_add:
for property_ in status_add: for property_ in status_add:
attribute_bonus_temp['statusAdd']['property'] = property_[ attribute_bonus_temp["statusAdd"]["property"] = property_["type"]
'type' attribute_bonus_temp["statusAdd"]["name"] = Property2Name[
property_["type"]
] ]
attribute_bonus_temp['statusAdd']['name'] = Property2Name[ attribute_bonus_temp["statusAdd"]["value"] = property_["value"]
property_['type']
]
attribute_bonus_temp['statusAdd']['value'] = property_['value']
attribute_list.append(attribute_bonus_temp) attribute_list.append(attribute_bonus_temp)
return attribute_list return attribute_list
@ -356,8 +341,8 @@ async def get_extra_list(
extra_list = [] extra_list = []
for extraid in [101, 102, 103]: for extraid in [101, 102, 103]:
extra_temp = {} extra_temp = {}
extra_temp['extraAbilityId'] = char_id * 1000 + extraid extra_temp["extraAbilityId"] = char_id * 1000 + extraid
extra_temp['extraAbilityLevel'] = 1 extra_temp["extraAbilityLevel"] = 1
extra_list.append(extra_temp) extra_list.append(extra_temp)
return extra_list return extra_list
@ -368,18 +353,16 @@ async def get_skill_list(
Skilllist = [] Skilllist = []
for skillid in [1, 2, 3, 4, 7]: for skillid in [1, 2, 3, 4, 7]:
skill_temp = {} skill_temp = {}
skill_temp['skillId'] = char_id * 100 + skillid skill_temp["skillId"] = char_id * 100 + skillid
skill_temp['skillName'] = skillId2Name[str(skill_temp['skillId'])] skill_temp["skillName"] = skillId2Name[str(skill_temp["skillId"])]
skill_temp['skillEffect'] = skillId2Effect[str(skill_temp['skillId'])] skill_temp["skillEffect"] = skillId2Effect[str(skill_temp["skillId"])]
skill_temp['skillAttackType'] = skillId2AttackType[ skill_temp["skillAttackType"] = skillId2AttackType[str(skill_temp["skillId"])]
str(skill_temp['skillId'])
]
skilllevel = 10 skilllevel = 10
if skillid == 1: if skillid == 1:
skilllevel = 6 skilllevel = 6
if skillid == 7: if skillid == 7:
skilllevel = 1 skilllevel = 1
skill_temp['skillLevel'] = skilllevel skill_temp["skillLevel"] = skilllevel
Skilllist.append(skill_temp) Skilllist.append(skill_temp)
return Skilllist return Skilllist
@ -391,9 +374,9 @@ async def get_rank_list(
rank_temp = [] rank_temp = []
for index in range(talent_num): for index in range(talent_num):
rankTemp = {} rankTemp = {}
rank_id = int(str(char_id) + '0' + str(index + 1)) rank_id = int(str(char_id) + "0" + str(index + 1))
rankTemp['rankId'] = rank_id rankTemp["rankId"] = rank_id
rankTemp['rankName'] = rankId2Name[str(rank_id)] rankTemp["rankName"] = rankId2Name[str(rank_id)]
rank_temp.append(rankTemp) rank_temp.append(rankTemp)
return rank_temp return rank_temp
@ -407,82 +390,82 @@ async def get_char(
if isinstance(talent_num, int): if isinstance(talent_num, int):
# 处理命座 # 处理命座
rank_temp = [] rank_temp = []
char_data['rank'] = talent_num char_data["rank"] = talent_num
for index in range(talent_num): for index in range(talent_num):
rankTemp = {} rankTemp = {}
rank_id = int(str(char_data['avatarId']) + '0' + str(index + 1)) rank_id = int(str(char_data["avatarId"]) + "0" + str(index + 1))
rankTemp['rankId'] = rank_id rankTemp["rankId"] = rank_id
rankTemp['rankName'] = rankId2Name[str(rank_id)] rankTemp["rankName"] = rankId2Name[str(rank_id)]
rank_temp.append(rankTemp) rank_temp.append(rankTemp)
char_data['rankList'] = rank_temp char_data["rankList"] = rank_temp
# 处理命座中的 level_up_skills # 处理命座中的 level_up_skills
if char_data.get('rankList'): if char_data.get("rankList"):
for rank_item in char_data['rankList']: for rank_item in char_data["rankList"]:
rank_id = rank_item['rankId'] rank_id = rank_item["rankId"]
level_up_skill = AvatarRankSkillUp[str(rank_id)] level_up_skill = AvatarRankSkillUp[str(rank_id)]
if level_up_skill: if level_up_skill:
for item in level_up_skill: for item in level_up_skill:
skill_id = item['id'] skill_id = item["id"]
skill_up_num = item['num'] skill_up_num = item["num"]
# 查找skill_id在不在avatarSkill中 # 查找skill_id在不在avatarSkill中
for index, skill_item in enumerate( for index, skill_item in enumerate(char_data["avatarSkill"]):
char_data['avatarSkill'] if str(skill_id) == str(skill_item["skillId"]):
):
if str(skill_id) == str(skill_item['skillId']):
if skill_id[-1] == 1: if skill_id[-1] == 1:
skilllevel_max = 7 skilllevel_max = 7
else: else:
skilllevel_max = 12 skilllevel_max = 12
skilllevel = min( skilllevel = min(
skilllevel_max, skilllevel_max,
char_data['avatarSkill'][index][ char_data["avatarSkill"][index]["skillLevel"]
'skillLevel'
]
+ skill_up_num, + skill_up_num,
) )
char_data['avatarSkill'][index][ char_data["avatarSkill"][index]["skillLevel"] = (
'skillLevel' skilllevel
] = skilllevel )
break break
if isinstance(weapon, str): if isinstance(weapon, str):
# 处理武器 # 处理武器
equipmentid = await name_to_weapon_id(weapon) equipmentid = await name_to_weapon_id(weapon)
if equipmentid == '': if equipmentid == "":
weapon = await alias_to_weapon_name(weapon) weapon = await alias_to_weapon_name(weapon)
equipmentid = await name_to_weapon_id(weapon) equipmentid = await name_to_weapon_id(weapon)
equipment_info = {} equipment_info = {}
equipment_info['equipmentID'] = int(equipmentid) equipment_info["equipmentID"] = int(equipmentid)
equipment_info['equipmentName'] = EquipmentID2Name[str(equipmentid)] equipment_info["equipmentName"] = EquipmentID2Name[str(equipmentid)]
equipment_info['equipmentLevel'] = 80 equipment_info["equipmentLevel"] = 80
equipment_info['equipmentPromotion'] = 6 equipment_info["equipmentPromotion"] = 6
equipment_info['equipmentRank'] = weapon_affix equipment_info["equipmentRank"] = weapon_affix
equipment_info['equipmentRarity'] = EquipmentID2Rarity[ equipment_info["equipmentRarity"] = EquipmentID2Rarity[str(equipmentid)]
str(equipmentid)
]
equipment_base_attributes = {} equipment_base_attributes = {}
equipment_promotion_base = EquipmentPromotionConfig.Equipment[
str(equipmentid) equipment_promotion_base = None
]['6'] for equipment in EquipmentPromotionConfig:
if equipment.EquipmentID == str(equipmentid):
equipment_promotion_base = equipment
break
if not equipment_promotion_base:
msg = f"EquipmentPromotionConfig not found: {equipmentid}"
raise ValueError(msg)
# 生命值 # 生命值
equipment_base_attributes['hp'] = ( equipment_base_attributes["hp"] = (
equipment_promotion_base.BaseHP.Value equipment_promotion_base.BaseHP.Value
+ equipment_promotion_base.BaseHPAdd.Value * (80 - 1) + equipment_promotion_base.BaseHPAdd.Value * (80 - 1)
) )
# 攻击力 # 攻击力
equipment_base_attributes['attack'] = ( equipment_base_attributes["attack"] = (
equipment_promotion_base.BaseAttack.Value equipment_promotion_base.BaseAttack.Value
+ equipment_promotion_base.BaseAttackAdd.Value * (80 - 1) + equipment_promotion_base.BaseAttackAdd.Value * (80 - 1)
) )
# 防御力 # 防御力
equipment_base_attributes['defence'] = ( equipment_base_attributes["defence"] = (
equipment_promotion_base.BaseDefence.Value equipment_promotion_base.BaseDefence.Value
+ equipment_promotion_base.BaseDefenceAdd.Value * (80 - 1) + equipment_promotion_base.BaseDefenceAdd.Value * (80 - 1)
) )
equipment_info['baseAttributes'] = equipment_base_attributes equipment_info["baseAttributes"] = equipment_base_attributes
char_data['equipmentInfo'] = equipment_info char_data["equipmentInfo"] = equipment_info
return char_data return char_data

View File

@ -19,12 +19,12 @@ second_color = (67, 61, 56)
white_color = (247, 247, 247) white_color = (247, 247, 247)
gray_color = (175, 175, 175) gray_color = (175, 175, 175)
TEXT_PATH = Path(__file__).parent / 'texture2D' TEXT_PATH = Path(__file__).parent / "texture2D"
char_mask = Image.open(TEXT_PATH / 'ring_mask.png') char_mask = Image.open(TEXT_PATH / "ring_mask.png")
char_bg_mask = Image.open(TEXT_PATH / 'char_bg_mask.png') char_bg_mask = Image.open(TEXT_PATH / "char_bg_mask.png")
tag = Image.open(TEXT_PATH / 'tag.png') tag = Image.open(TEXT_PATH / "tag.png")
footbar = Image.open(TEXT_PATH / 'footbar.png') footbar = Image.open(TEXT_PATH / "footbar.png")
pic_500 = Image.open(TEXT_PATH / '500.png') pic_500 = Image.open(TEXT_PATH / "500.png")
async def api_to_card(uid: str) -> Union[Tuple[bytes, List[str]], bytes]: async def api_to_card(uid: str) -> Union[Tuple[bytes, List[str]], bytes]:
@ -52,19 +52,17 @@ async def draw_enka_card(uid: str, char_list: List, showfrom: int = 0):
avatarName = avatarId2Name[str(char)] avatarName = avatarId2Name[str(char)]
char_data_list.append( char_data_list.append(
{ {
'avatarName': avatarName, "avatarName": avatarName,
'avatarId': str(char), "avatarId": str(char),
} }
) )
if showfrom == 0: if showfrom == 0:
line1 = f'展柜内有 {len(char_data_list)} 个角色!' line1 = f"展柜内有 {len(char_data_list)} 个角色!"
elif char_data_list is None: elif char_data_list is None:
return await convert_img(Image.new('RGBA', (0, 1), (255, 255, 255))) return await convert_img(Image.new("RGBA", (0, 1), (255, 255, 255)))
else: else:
line1 = f'UID {uid} 刷新成功' line1 = f"UID {uid} 刷新成功"
line2 = ( line2 = f'可以使用 sr查询{char_data_list[0]["avatarName"]} 查询详情角色面板'
f'可以使用 sr查询{char_data_list[0]["avatarName"]} 查询详情角色面板'
)
char_num = len(char_data_list) char_num = len(char_data_list)
if char_num <= 4: if char_num <= 4:
based_w, based_h = 1380, 926 based_w, based_h = 1380, 926
@ -73,19 +71,19 @@ async def draw_enka_card(uid: str, char_list: List, showfrom: int = 0):
show_type = 0 show_type = 0
based_w, based_h = 1380, 310 + (((char_num - 1) // 4) + 1) * 320 based_w, based_h = 1380, 310 + (((char_num - 1) // 4) + 1) * 320
img = Image.open(TEXT_PATH / 'shin.jpg') img = Image.open(TEXT_PATH / "shin.jpg")
img = crop_center_img(img, based_w, based_h) img = crop_center_img(img, based_w, based_h)
img.paste(tag, (0, 0), tag) img.paste(tag, (0, 0), tag)
img_draw = ImageDraw.Draw(img, 'RGBA') img_draw = ImageDraw.Draw(img, "RGBA")
# 写底层文字 # 写底层文字
img_draw.text( img_draw.text(
(690, based_h - 26), (690, based_h - 26),
'--Created by qwerdvd-Designed By Wuyi-Thank for mihomo.me--', "--Created by qwerdvd-Designed By Wuyi-Thank for mihomo.me--",
(22, 22, 22), (22, 22, 22),
fw_font_28, fw_font_28,
'mm', "mm",
) )
img_draw.text( img_draw.text(
@ -93,14 +91,14 @@ async def draw_enka_card(uid: str, char_list: List, showfrom: int = 0):
line1, line1,
white_color, white_color,
sr_font_58, sr_font_58,
'lm', "lm",
) )
img_draw.text( img_draw.text(
(225, 175), (225, 175),
line2, line2,
gray_color, gray_color,
sr_font_24, sr_font_24,
'lm', "lm",
) )
tasks = [] tasks = []
for index, char_data in enumerate(char_data_list): for index, char_data in enumerate(char_data_list):
@ -113,17 +111,17 @@ async def draw_enka_card(uid: str, char_list: List, showfrom: int = 0):
async def draw_mihomo_char(index: int, img: Image.Image, char_data: Dict): async def draw_mihomo_char(index: int, img: Image.Image, char_data: Dict):
char_id = char_data['avatarId'] char_id = char_data["avatarId"]
char_name = char_data['avatarName'] char_name = char_data["avatarName"]
char_star = await avatar_id_to_char_star(str(char_id)) char_star = await avatar_id_to_char_star(str(char_id))
char_card = Image.open(TEXT_PATH / f'char{char_star}_bg.png') char_card = Image.open(TEXT_PATH / f"char{char_star}_bg.png")
char_temp = Image.new('RGBA', (300, 650)) char_temp = Image.new("RGBA", (300, 650))
char_img = ( char_img = (
Image.open(str(CHAR_PREVIEW_PATH / f'{char_id}.png')) Image.open(str(CHAR_PREVIEW_PATH / f"{char_id}.png"))
.convert('RGBA') .convert("RGBA")
.resize((449, 615)) .resize((449, 615))
) )
if char_name == '希儿': if char_name == "希儿":
char_img = char_img.resize((449, 650)) char_img = char_img.resize((449, 650))
char_img = char_img.crop((135, 0, 379, 457)) char_img = char_img.crop((135, 0, 379, 457))
char_temp.paste(char_img, (32, 98), char_img) char_temp.paste(char_img, (32, 98), char_img)
@ -132,40 +130,40 @@ async def draw_mihomo_char(index: int, img: Image.Image, char_data: Dict):
char_temp.paste(char_img, (32, 38), char_img) char_temp.paste(char_img, (32, 38), char_img)
char_card.paste(char_temp, (0, 0), char_bg_mask) char_card.paste(char_temp, (0, 0), char_bg_mask)
img_draw = ImageDraw.Draw(char_card, 'RGBA') img_draw = ImageDraw.Draw(char_card, "RGBA")
img_draw.text( img_draw.text(
(150, 585), (150, 585),
char_name, char_name,
white_color, white_color,
sr_font_30, sr_font_30,
'mm', "mm",
) )
x = 42 + index * 325 x = 42 + index * 325
img.paste(char_card, (x, 199), char_card) img.paste(char_card, (x, 199), char_card)
async def draw_enka_char(index: int, img: Image.Image, char_data: Dict): async def draw_enka_char(index: int, img: Image.Image, char_data: Dict):
char_id = char_data['avatarId'] char_id = char_data["avatarId"]
char_star = await avatar_id_to_char_star(str(char_id)) char_star = await avatar_id_to_char_star(str(char_id))
char_card = Image.open(TEXT_PATH / f'ring_{char_star}.png') char_card = Image.open(TEXT_PATH / f"ring_{char_star}.png")
_path = CHAR_PREVIEW_PATH / f'{char_id}.png' _path = CHAR_PREVIEW_PATH / f"{char_id}.png"
char_img = Image.open(_path).convert('RGBA') char_img = Image.open(_path).convert("RGBA")
char_img = char_img.resize( char_img = char_img.resize(
(int(char_img.size[0] * 0.76), int(char_img.size[1] * 0.76)) (int(char_img.size[0] * 0.76), int(char_img.size[1] * 0.76))
) )
char_temp = Image.new('RGBA', (300, 400)) char_temp = Image.new("RGBA", (300, 400))
card_temp = Image.new('RGBA', (300, 400)) card_temp = Image.new("RGBA", (300, 400))
char_temp.paste(char_img, (19, 57), char_img) char_temp.paste(char_img, (19, 57), char_img)
card_temp.paste(char_temp, (0, 0), char_mask) card_temp.paste(char_temp, (0, 0), char_mask)
char_draw = ImageDraw.Draw(card_temp) char_draw = ImageDraw.Draw(card_temp)
char_draw.text( char_draw.text(
(144, 285), (144, 285),
char_data['avatarName'], char_data["avatarName"],
'white', "white",
sr_font_30, sr_font_30,
'mm', "mm",
) )
img.paste( img.paste(

View File

@ -7,18 +7,16 @@ from gsuid_core.models import Event
from gsuid_core.sv import SV from gsuid_core.sv import SV
from gsuid_core.utils.database.models import GsBind from gsuid_core.utils.database.models import GsBind
PREFIX = srconfig.get_config('StarRailPrefix').data PREFIX = srconfig.get_config("StarRailPrefix").data
sv_self_config = SV('星穹铁道配置') sv_self_config = SV("星穹铁道配置")
@sv_self_config.on_prefix((f'{PREFIX}开启', f'{PREFIX}关闭')) @sv_self_config.on_prefix((f"{PREFIX}开启", f"{PREFIX}关闭"))
async def open_switch_func(bot: Bot, ev: Event): async def open_switch_func(bot: Bot, ev: Event):
uid = await GsBind.get_uid_by_game(ev.user_id, ev.bot_id, 'sr') uid = await GsBind.get_uid_by_game(ev.user_id, ev.bot_id, "sr")
if uid is None: if uid is None:
return await bot.send('[星穹铁道] 你还没有绑定UID哦!') return await bot.send("[星穹铁道] 你还没有绑定UID哦!")
logger.info( logger.info(f"[{ev.user_id}] [UID{uid}]尝试[{ev.command[2:]}]了[{ev.text}]功能")
f'[{ev.user_id}] [UID{uid}]尝试[{ev.command[2:]}]了[{ev.text}]功能'
)
await bot.send(await set_config_func(uid, ev)) await bot.send(await set_config_func(uid, ev))
return None return None

View File

@ -4,47 +4,43 @@ from gsuid_core.utils.plugins_config.models import (
GSC, GSC,
GsStrConfig, GsStrConfig,
GsBoolConfig, GsBoolConfig,
GsListStrConfig, GsIntConfig, GsListStrConfig,
GsIntConfig,
) )
CONIFG_DEFAULT: Dict[str, GSC] = { CONIFG_DEFAULT: Dict[str, GSC] = {
'SignTime': GsListStrConfig( "SignTime": GsListStrConfig(
'每晚签到时间设置', '每晚米游社签到时间设置(时,分)', ['0', '38'] "每晚签到时间设置", "每晚米游社签到时间设置(时,分)", ["0", "38"]
), ),
'PrivateSignReport': GsBoolConfig( "PrivateSignReport": GsBoolConfig(
'签到私聊报告', "签到私聊报告",
'关闭后将不再给任何人推送当天签到任务完成情况', "关闭后将不再给任何人推送当天签到任务完成情况",
False, False,
), ),
'SchedSignin': GsBoolConfig( "SchedSignin": GsBoolConfig(
'定时签到', "定时签到",
'开启后每晚00:30将开始自动签到任务', "开启后每晚00:30将开始自动签到任务",
True, True,
), ),
'SchedStaminaPush': GsBoolConfig( "SchedStaminaPush": GsBoolConfig(
'定时检查开拓力', "定时检查开拓力",
'开启后每隔半小时检查一次开拓力', "开启后每隔半小时检查一次开拓力",
True, True,
), ),
'push_max_value': GsIntConfig( "push_max_value": GsIntConfig("提醒阈值", "发送提醒的阈值", 200, 240),
'提醒阈值', "CrazyNotice": GsBoolConfig(
'发送提醒的阈值', "催命模式",
200, "开启后当达到推送阈值将会一直推送",
240
),
'CrazyNotice': GsBoolConfig(
'催命模式',
'开启后当达到推送阈值将会一直推送',
False, False,
), ),
'StarRailPrefix': GsStrConfig( "StarRailPrefix": GsStrConfig(
'插件命令前缀(确认无冲突再修改)', "插件命令前缀(确认无冲突再修改)",
'用于本插件的前缀设定', "用于本插件的前缀设定",
'sr', "sr",
), ),
'WidgetResin': GsBoolConfig( "WidgetResin": GsBoolConfig(
'体力使用组件API', "体力使用组件API",
'开启后mr功能将转为调用组件API, 可能缺失数据、数据不准', "开启后mr功能将转为调用组件API, 可能缺失数据、数据不准",
True, True,
), ),
} }

View File

@ -8,26 +8,26 @@ async def set_config_func(
uid: str, uid: str,
ev: Event, ev: Event,
): ):
if '开启' in ev.command: if "开启" in ev.command:
if ev.user_type == 'direct': if ev.user_type == "direct":
value = 'on' value = "on"
elif ev.group_id: elif ev.group_id:
value = ev.group_id value = ev.group_id
else: else:
value = 'on' value = "on"
else: else:
value = 'off' value = "off"
text = await set_database_value( text = await set_database_value(
GsUser, GsUser,
'sr', "sr",
'sr开启', "sr开启",
ev.text.strip(), ev.text.strip(),
uid, uid,
ev.bot_id, ev.bot_id,
value, value,
) )
if text is None: if text is None:
return '[星穹铁道] 未找到配置项' return "[星穹铁道] 未找到配置项"
logger.success(f'[UID{uid}]成功将配置[SR自动签到]设置为[{value}]!') logger.success(f"[UID{uid}]成功将配置[SR自动签到]设置为[{value}]!")
return text return text

View File

@ -4,7 +4,7 @@ from .config_default import CONIFG_DEFAULT
from ..utils.resource.RESOURCE_PATH import CONFIG_PATH from ..utils.resource.RESOURCE_PATH import CONFIG_PATH
srconfig = StringConfig( srconfig = StringConfig(
'StarRailUID', "StarRailUID",
CONFIG_PATH, CONFIG_PATH,
CONIFG_DEFAULT, CONIFG_DEFAULT,
) )

View File

@ -1,24 +1,22 @@
from gsuid_core.sv import SV from .draw_gachalogs import draw_gachalogs_img
from .get_gachalogs import save_gachalogs
from ..utils.error_reply import UID_HINT
from ..utils.sr_prefix import PREFIX
from gsuid_core.bot import Bot from gsuid_core.bot import Bot
from gsuid_core.models import Event from gsuid_core.models import Event
from gsuid_core.sv import SV
from gsuid_core.utils.database.api import get_uid
from gsuid_core.utils.database.models import GsBind
from ..utils.convert import get_uid sv_gacha_log = SV("sr抽卡记录")
from ..utils.sr_prefix import PREFIX sv_get_gachalog_by_link = SV("sr导入抽卡链接", area="DIRECT")
from ..utils.error_reply import UID_HINT
from .get_gachalogs import save_gachalogs
from .draw_gachalogs import draw_gachalogs_img
sv_gacha_log = SV('sr抽卡记录')
sv_get_gachalog_by_link = SV('sr导入抽卡链接', area='DIRECT')
@sv_gacha_log.on_fullmatch(f'{PREFIX}抽卡记录') @sv_gacha_log.on_fullmatch(f"{PREFIX}抽卡记录")
async def send_gacha_log_card_info(bot: Bot, ev: Event): async def send_gacha_log_card_info(bot: Bot, ev: Event):
await bot.logger.info('开始执行[sr抽卡记录]') await bot.logger.info("开始执行[sr抽卡记录]")
get_uid_ = await get_uid(bot, ev, True, False) uid, user_id = await get_uid(bot, ev, GsBind, "sr", True)
if get_uid_ is None:
return await bot.send(UID_HINT)
uid, user_id = get_uid_
if uid is None: if uid is None:
return await bot.send(UID_HINT) return await bot.send(UID_HINT)
im = await draw_gachalogs_img(uid, user_id) im = await draw_gachalogs_img(uid, user_id)
@ -26,21 +24,19 @@ async def send_gacha_log_card_info(bot: Bot, ev: Event):
return None return None
@sv_get_gachalog_by_link.on_command(f'{PREFIX}导入抽卡链接') @sv_get_gachalog_by_link.on_command(f"{PREFIX}导入抽卡链接")
async def get_gachalog_by_link(bot: Bot, ev: Event): async def get_gachalog_by_link(bot: Bot, ev: Event):
await bot.logger.info('开始执行[sr导入抽卡链接]') await bot.logger.info("开始执行[sr导入抽卡链接]")
uid = await get_uid(bot, ev, only_uid=True) uid = await get_uid(bot, ev, GsBind, "sr")
if uid is None: if uid is None:
return await bot.send(UID_HINT) return await bot.send(UID_HINT)
gacha_url = ev.text.strip() gacha_url = ev.text.strip()
if not gacha_url or not isinstance(gacha_url, str): if not gacha_url or not isinstance(gacha_url, str):
return await bot.send('请给出正确的抽卡记录链接') return await bot.send("请给出正确的抽卡记录链接")
is_force = False is_force = False
if ev.command.startswith('强制'): if ev.command.startswith("强制"):
await bot.logger.info('[WARNING]本次为强制刷新') await bot.logger.info("[WARNING]本次为强制刷新")
is_force = True is_force = True
await bot.send( await bot.send(f"UID{uid}开始执行[刷新抽卡记录],需要一定时间...请勿重复触发!")
f'UID{uid}开始执行[刷新抽卡记录],需要一定时间...请勿重复触发!'
)
im = await save_gachalogs(uid, gacha_url, None, is_force) im = await save_gachalogs(uid, gacha_url, None, is_force)
return await bot.send(im) return await bot.send(im)

View File

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

View File

@ -12,29 +12,27 @@ from ..utils.resource.RESOURCE_PATH import PLAYER_PATH
from ..sruid_utils.api.mys.models import SingleGachaLog from ..sruid_utils.api.mys.models import SingleGachaLog
gacha_type_meta_data = { gacha_type_meta_data = {
'群星跃迁': ['1'], "群星跃迁": ["1"],
'始发跃迁': ['2'], "始发跃迁": ["2"],
'角色跃迁': ['11'], "角色跃迁": ["11"],
'光锥跃迁': ['12'], "光锥跃迁": ["12"],
} }
async def get_new_gachalog_by_link( async def get_new_gachalog_by_link(
uid: str, gacha_url: str, full_data: Dict, is_force: bool uid: str, gacha_url: str, full_data: Dict, is_force: bool
): ):
full_data = msgspec.convert( full_data = msgspec.convert(full_data, type=Dict[str, List[SingleGachaLog]])
full_data, type=Dict[str, List[SingleGachaLog]]
)
temp = [] temp = []
for gacha_name in gacha_type_meta_data: for gacha_name in gacha_type_meta_data:
for gacha_type in gacha_type_meta_data[gacha_name]: for gacha_type in gacha_type_meta_data[gacha_name]:
end_id = '0' end_id = "0"
for page in range(1, 999): for page in range(1, 999):
url = parse.urlparse(gacha_url) url = parse.urlparse(gacha_url)
url_parse = parse.parse_qs(url.query) url_parse = parse.parse_qs(url.query)
if 'authkey' not in url_parse: if "authkey" not in url_parse:
return {} return {}
authkey = url_parse['authkey'][0] authkey = url_parse["authkey"][0]
data = await mys_api.get_gacha_log_by_link_in_authkey( data = await mys_api.get_gacha_log_by_link_in_authkey(
uid, authkey, gacha_type, page, end_id uid, authkey, gacha_type, page, end_id
) )
@ -74,13 +72,13 @@ async def save_gachalogs(
# 获取当前时间 # 获取当前时间
now = datetime.now() now = datetime.now()
current_time = now.strftime('%Y-%m-%d %H-%M-%S') current_time = now.strftime("%Y-%m-%d %H-%M-%S")
# 初始化最后保存的数据 # 初始化最后保存的数据
result = {} result = {}
# 抽卡记录json路径 # 抽卡记录json路径
gachalogs_path = path / 'gacha_logs.json' gachalogs_path = path / "gacha_logs.json"
# 如果有老的,准备合并, 先打开文件 # 如果有老的,准备合并, 先打开文件
gachalogs_history = {} gachalogs_history = {}
@ -91,19 +89,19 @@ async def save_gachalogs(
old_weapon_gacha_num, old_weapon_gacha_num,
) = (0, 0, 0, 0) ) = (0, 0, 0, 0)
if gachalogs_path.exists(): if gachalogs_path.exists():
with Path.open(gachalogs_path, encoding='UTF-8') as f: with Path.open(gachalogs_path, encoding="UTF-8") as f:
gachalogs_history: Dict = json.load(f) gachalogs_history: Dict = json.load(f)
gachalogs_history = gachalogs_history['data'] gachalogs_history = gachalogs_history["data"]
old_normal_gacha_num = len(gachalogs_history['群星跃迁']) old_normal_gacha_num = len(gachalogs_history["群星跃迁"])
old_begin_gacha_num = len(gachalogs_history['始发跃迁']) old_begin_gacha_num = len(gachalogs_history["始发跃迁"])
old_char_gacha_num = len(gachalogs_history['角色跃迁']) old_char_gacha_num = len(gachalogs_history["角色跃迁"])
old_weapon_gacha_num = len(gachalogs_history['光锥跃迁']) old_weapon_gacha_num = len(gachalogs_history["光锥跃迁"])
else: else:
gachalogs_history = { gachalogs_history = {
'群星跃迁': [], "群星跃迁": [],
'始发跃迁': [], "始发跃迁": [],
'角色跃迁': [], "角色跃迁": [],
'光锥跃迁': [], "光锥跃迁": [],
} }
# 获取新抽卡记录 # 获取新抽卡记录
@ -113,69 +111,66 @@ async def save_gachalogs(
) )
else: else:
new_data = { new_data = {
'始发跃迁': [], "始发跃迁": [],
'群星跃迁': [], "群星跃迁": [],
'角色跃迁': [], "角色跃迁": [],
'光锥跃迁': [], "光锥跃迁": [],
} }
if gachalogs_history: if gachalogs_history:
for i in ['始发跃迁', '群星跃迁', '角色跃迁', '光锥跃迁']: for i in ["始发跃迁", "群星跃迁", "角色跃迁", "光锥跃迁"]:
for item in raw_data[i]: for item in raw_data[i]:
if ( if item not in gachalogs_history[i] and item not in new_data[i]:
item not in gachalogs_history[i]
and item not in new_data[i]
):
new_data[i].append(item) new_data[i].append(item)
raw_data = new_data raw_data = new_data
for i in ['始发跃迁', '群星跃迁', '角色跃迁', '光锥跃迁']: for i in ["始发跃迁", "群星跃迁", "角色跃迁", "光锥跃迁"]:
raw_data[i].extend(gachalogs_history[i]) raw_data[i].extend(gachalogs_history[i])
if raw_data == {} or not raw_data: if raw_data == {} or not raw_data:
return '请给出正确的抽卡记录链接或链接已失效' return "请给出正确的抽卡记录链接或链接已失效"
temp_data = { temp_data = {
'始发跃迁': [], "始发跃迁": [],
'群星跃迁': [], "群星跃迁": [],
'角色跃迁': [], "角色跃迁": [],
'光锥跃迁': [], "光锥跃迁": [],
} }
for i in ['始发跃迁', '群星跃迁', '角色跃迁', '光锥跃迁']: for i in ["始发跃迁", "群星跃迁", "角色跃迁", "光锥跃迁"]:
for item in raw_data[i]: for item in raw_data[i]:
if item not in temp_data[i]: if item not in temp_data[i]:
temp_data[i].append(item) temp_data[i].append(item)
raw_data = temp_data raw_data = temp_data
result['uid'] = uid result["uid"] = uid
result['data_time'] = current_time result["data_time"] = current_time
result['normal_gacha_num'] = len(raw_data['群星跃迁']) result["normal_gacha_num"] = len(raw_data["群星跃迁"])
result['begin_gacha_num'] = len(raw_data['始发跃迁']) result["begin_gacha_num"] = len(raw_data["始发跃迁"])
result['char_gacha_num'] = len(raw_data['角色跃迁']) result["char_gacha_num"] = len(raw_data["角色跃迁"])
result['weapon_gacha_num'] = len(raw_data['光锥跃迁']) result["weapon_gacha_num"] = len(raw_data["光锥跃迁"])
for i in ['群星跃迁', '角色跃迁', '光锥跃迁']: for i in ["群星跃迁", "角色跃迁", "光锥跃迁"]:
if len(raw_data[i]) > 1: if len(raw_data[i]) > 1:
raw_data[i].sort(key=lambda x: (-int(x.id))) raw_data[i].sort(key=lambda x: (-int(x.id)))
result['data'] = raw_data result["data"] = raw_data
# 计算数据 # 计算数据
normal_add = result['normal_gacha_num'] - old_normal_gacha_num normal_add = result["normal_gacha_num"] - old_normal_gacha_num
begin_gacha_add = result['begin_gacha_num'] - old_begin_gacha_num begin_gacha_add = result["begin_gacha_num"] - old_begin_gacha_num
char_add = result['char_gacha_num'] - old_char_gacha_num char_add = result["char_gacha_num"] - old_char_gacha_num
weapon_add = result['weapon_gacha_num'] - old_weapon_gacha_num weapon_add = result["weapon_gacha_num"] - old_weapon_gacha_num
all_add = normal_add + char_add + weapon_add + begin_gacha_add all_add = normal_add + char_add + weapon_add + begin_gacha_add
# 保存文件 # 保存文件
result = msgspec.to_builtins(result) result = msgspec.to_builtins(result)
with Path.open(gachalogs_path, 'w', encoding='UTF-8') as file: with Path.open(gachalogs_path, "w", encoding="UTF-8") as file:
json.dump(result, file, indent=2, ensure_ascii=False) json.dump(result, file, indent=2, ensure_ascii=False)
# 回复文字 # 回复文字
if all_add == 0: if all_add == 0:
im = f'UID{uid}没有新增祈愿数据!' im = f"UID{uid}没有新增祈愿数据!"
else: else:
im = ( im = (
f'UID{uid}数据更新成功!' f"UID{uid}数据更新成功!"
f'本次更新{all_add}个数据\n' f"本次更新{all_add}个数据\n"
f'群星跃迁{normal_add}\n始发跃迁{begin_gacha_add}\n' f"群星跃迁{normal_add}\n始发跃迁{begin_gacha_add}\n"
f'角色跃迁{char_add}\n光锥跃迁{weapon_add}个!' f"角色跃迁{char_add}\n光锥跃迁{weapon_add}个!"
) )
return im return im

View File

@ -6,11 +6,11 @@ from gsuid_core.logger import logger
from .get_help import get_core_help from .get_help import get_core_help
from ..utils.sr_prefix import PREFIX from ..utils.sr_prefix import PREFIX
sv_sr_help = SV('sr帮助') sv_sr_help = SV("sr帮助")
@sv_sr_help.on_fullmatch(f'{PREFIX}帮助') @sv_sr_help.on_fullmatch(f"{PREFIX}帮助")
async def send_help_img(bot: Bot, ev: Event): async def send_help_img(bot: Bot, ev: Event):
logger.info('开始执行[sr帮助]') logger.info("开始执行[sr帮助]")
im = await get_core_help() im = await get_core_help()
await bot.send(im) await bot.send(im)

View File

@ -10,32 +10,30 @@ from gsuid_core.help.draw_plugin_help import get_help
from ..version import StarRail_version from ..version import StarRail_version
from ..utils.fonts.starrail_fonts import starrail_font_origin from ..utils.fonts.starrail_fonts import starrail_font_origin
TEXT_PATH = Path(__file__).parent / 'texture2d' TEXT_PATH = Path(__file__).parent / "texture2d"
HELP_DATA = Path(__file__).parent / 'Help.json' HELP_DATA = Path(__file__).parent / "Help.json"
async def get_help_data() -> Optional[Dict[str, PluginHelp]]: async def get_help_data() -> Optional[Dict[str, PluginHelp]]:
if HELP_DATA.exists(): if HELP_DATA.exists():
async with aiofiles.open(HELP_DATA, 'rb') as file: async with aiofiles.open(HELP_DATA, "rb") as file:
return msgjson.decode( return msgjson.decode(await file.read(), type=Dict[str, PluginHelp])
await file.read(), type=Dict[str, PluginHelp]
)
return None return None
async def get_core_help() -> Union[bytes, str]: async def get_core_help() -> Union[bytes, str]:
help_data = await get_help_data() help_data = await get_help_data()
if help_data is None: if help_data is None:
return '暂未找到帮助数据...' return "暂未找到帮助数据..."
return await get_help( return await get_help(
'StarRailUID', "StarRailUID",
f'版本号:{StarRail_version}', f"版本号:{StarRail_version}",
help_data, help_data,
Image.open(TEXT_PATH / 'bg.jpg'), Image.open(TEXT_PATH / "bg.jpg"),
Image.open(TEXT_PATH / 'ICON.png'), Image.open(TEXT_PATH / "ICON.png"),
Image.open(TEXT_PATH / 'badge.png'), Image.open(TEXT_PATH / "badge.png"),
Image.open(TEXT_PATH / 'banner.png'), Image.open(TEXT_PATH / "banner.png"),
Image.open(TEXT_PATH / 'button.png'), Image.open(TEXT_PATH / "button.png"),
starrail_font_origin, starrail_font_origin,
) )

View File

@ -1,21 +1,21 @@
from gsuid_core.sv import SV from .draw_note_card import draw_note_img
from .note_text import award
from ..utils.error_reply import UID_HINT
from ..utils.sr_prefix import PREFIX
from gsuid_core.bot import Bot from gsuid_core.bot import Bot
from gsuid_core.models import Event from gsuid_core.models import Event
from gsuid_core.sv import SV
from gsuid_core.utils.database.api import get_uid
from gsuid_core.utils.database.models import GsBind from gsuid_core.utils.database.models import GsBind
from .note_text import award sv_get_monthly_data = SV("sr查询月历")
from ..utils.convert import get_uid
from ..utils.sr_prefix import PREFIX
from ..utils.error_reply import UID_HINT
from .draw_note_card import draw_note_img
sv_get_monthly_data = SV('sr查询月历')
# 群聊内 每月统计 功能 # 群聊内 每月统计 功能
@sv_get_monthly_data.on_fullmatch(f'{PREFIX}每月统计') @sv_get_monthly_data.on_fullmatch(f"{PREFIX}每月统计")
async def send_monthly_data(bot: Bot, ev: Event): async def send_monthly_data(bot: Bot, ev: Event):
sr_uid = await GsBind.get_uid_by_game(ev.user_id, ev.bot_id, 'sr') sr_uid = await GsBind.get_uid_by_game(ev.user_id, ev.bot_id, "sr")
if sr_uid is None: if sr_uid is None:
return UID_HINT return UID_HINT
await bot.send(await award(sr_uid)) await bot.send(await award(sr_uid))
@ -24,14 +24,14 @@ async def send_monthly_data(bot: Bot, ev: Event):
@sv_get_monthly_data.on_fullmatch( @sv_get_monthly_data.on_fullmatch(
( (
f'{PREFIX}开拓月历', f"{PREFIX}开拓月历",
f'{PREFIX}zj', f"{PREFIX}zj",
f'{PREFIX}月历', f"{PREFIX}月历",
) )
) )
async def send_monthly_pic(bot: Bot, ev: Event): async def send_monthly_pic(bot: Bot, ev: Event):
await bot.logger.info('开始执行[sr开拓月历]') await bot.logger.info("开始执行[sr开拓月历]")
sr_uid = await get_uid(bot, ev) sr_uid = await get_uid(bot, ev, GsBind, "sr")
if sr_uid is None: if sr_uid is None:
return UID_HINT return UID_HINT
im = await draw_note_img(str(sr_uid)) im = await draw_note_img(str(sr_uid))

View File

@ -1,23 +1,23 @@
from datetime import datetime
import json import json
from pathlib import Path from pathlib import Path
from typing import Union from typing import Union
from datetime import datetime
from PIL import Image, ImageDraw from PIL import Image, ImageDraw
from msgspec import json as msgjson
from gsuid_core.logger import logger from gsuid_core.logger import logger
from gsuid_core.utils.image.convert import convert_img
from msgspec import json as msgjson
from ..utils.mys_api import mys_api
from ..utils.error_reply import get_error
from ..utils.image.convert import convert_img
from ..sruid_utils.api.mys.models import MonthlyAward from ..sruid_utils.api.mys.models import MonthlyAward
from ..utils.resource.RESOURCE_PATH import PLAYER_PATH from ..utils.error_reply import get_error
from ..utils.fonts.starrail_fonts import sr_font_20, sr_font_28, sr_font_34 from ..utils.fonts.starrail_fonts import sr_font_20, sr_font_28, sr_font_34
from ..utils.mys_api import mys_api
from ..utils.resource.RESOURCE_PATH import PLAYER_PATH
TEXT_PATH = Path(__file__).parent / 'texture2d' TEXT_PATH = Path(__file__).parent / "texture2d"
monthly_bg = Image.open(TEXT_PATH / 'monthly_bg.png') monthly_bg = Image.open(TEXT_PATH / "monthly_bg.png")
avatar_default = Image.open(TEXT_PATH / '200101.png') avatar_default = Image.open(TEXT_PATH / "200101.png")
first_color = (29, 29, 29) first_color = (29, 29, 29)
second_color = (67, 61, 56) second_color = (67, 61, 56)
@ -26,20 +26,20 @@ black_color = (54, 54, 54)
white_color = (213, 213, 213) white_color = (213, 213, 213)
COLOR_MAP = { COLOR_MAP = {
'每日活跃': (248, 227, 157), "每日活跃": (248, 227, 157),
'活动奖励': (99, 231, 176), "活动奖励": (99, 231, 176),
'冒险奖励': (114, 205, 251), "冒险奖励": (114, 205, 251),
'模拟宇宙奖励': (160, 149, 248), "模拟宇宙奖励": (160, 149, 248),
'忘却之庭奖励': (221, 119, 250), "忘却之庭奖励": (221, 119, 250),
'邮件奖励': (244, 110, 104), "邮件奖励": (244, 110, 104),
'其他': (255, 242, 200), "其他": (255, 242, 200),
'Daily Activity': (248, 227, 157), "Daily Activity": (248, 227, 157),
'Events': (99, 231, 176), "Events": (99, 231, 176),
'Adventure': (114, 205, 251), "Adventure": (114, 205, 251),
'moni': (160, 149, 248), "moni": (160, 149, 248),
'Spiral Abyss': (221, 119, 250), "Spiral Abyss": (221, 119, 250),
'Quests': (244, 110, 104), "Quests": (244, 110, 104),
'Other': (255, 242, 200), "Other": (255, 242, 200),
} }
@ -50,25 +50,25 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
# 获取当前时间 # 获取当前时间
now = datetime.now() now = datetime.now()
current_year_mon = now.strftime('%Y-%m') current_year_mon = now.strftime("%Y-%m")
add_month = '' add_month = ""
if int(now.month) < 10: if int(now.month) < 10:
add_month = '0' add_month = "0"
now_month = str(now.year) + str(add_month) + str(now.month) now_month = str(now.year) + str(add_month) + str(now.month)
# 获取数据 # 获取数据
data = await mys_api.get_award(sr_uid, now_month) data = await mys_api.get_sr_award(sr_uid, now_month)
if isinstance(data, int): if isinstance(data, int):
return get_error(data) return get_error(data)
# 保存数据 # 保存数据
with Path.open( with Path.open(
path / f'monthly_{current_year_mon}.json', 'w', encoding='utf-8' path / f"monthly_{current_year_mon}.json", "w", encoding="utf-8"
) as f: ) as f:
save_json_data = msgjson.format(msgjson.encode(data), indent=4) save_json_data = msgjson.format(msgjson.encode(data), indent=4)
save_data = json.dumps( save_data = json.dumps(
{ {
'data_time': now.strftime('%Y-%m-%d %H:%M:%S'), "data_time": now.strftime("%Y-%m-%d %H:%M:%S"),
'data': save_json_data.decode('utf-8'), "data": save_json_data.decode("utf-8"),
}, },
ensure_ascii=False, ensure_ascii=False,
) )
@ -80,33 +80,31 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
if last_month == 0: if last_month == 0:
last_month = 12 last_month = 12
last_year -= 1 last_year -= 1
last_year_mon = f'{last_year}-{last_month:02d}' last_year_mon = f"{last_year}-{last_month:02d}"
last_monthly_path = path / f'monthly_{last_year_mon}.json' last_monthly_path = path / f"monthly_{last_year_mon}.json"
if last_monthly_path.exists(): if last_monthly_path.exists():
with Path.open(last_monthly_path, encoding='utf-8') as f: with Path.open(last_monthly_path, encoding="utf-8") as f:
last_monthly_data = json.load(f) last_monthly_data = json.load(f)
last_monthly_data = msgjson.decode( last_monthly_data = msgjson.decode(
last_monthly_data['data'], type=MonthlyAward last_monthly_data["data"], type=MonthlyAward
) )
else: else:
add_month = '' add_month = ""
if int(last_month) < 10: if int(last_month) < 10:
add_month = '0' add_month = "0"
find_last_month = str(last_year) + str(add_month) + str(last_month) find_last_month = str(last_year) + str(add_month) + str(last_month)
last_monthly_data = await mys_api.get_award(sr_uid, find_last_month) last_monthly_data = await mys_api.get_sr_award(sr_uid, find_last_month)
if isinstance(last_monthly_data, int): if isinstance(last_monthly_data, int):
return get_error(last_monthly_data) return get_error(last_monthly_data)
# 保存上月数据 # 保存上月数据
with Path.open( with Path.open(
path / f'monthly_{last_year_mon}.json', 'w', encoding='utf-8' path / f"monthly_{last_year_mon}.json", "w", encoding="utf-8"
) as f: ) as f:
save_json_data = msgjson.format( save_json_data = msgjson.format(msgjson.encode(last_monthly_data), indent=4)
msgjson.encode(last_monthly_data), indent=4
)
save_data = json.dumps( save_data = json.dumps(
{ {
'data_time': now.strftime('%Y-%m-%d %H:%M:%S'), "data_time": now.strftime("%Y-%m-%d %H:%M:%S"),
'data': save_json_data.decode('utf-8'), "data": save_json_data.decode("utf-8"),
}, },
ensure_ascii=False, ensure_ascii=False,
) )
@ -141,7 +139,7 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
img = monthly_bg.copy() img = monthly_bg.copy()
avatar_img = avatar_default.copy() avatar_img = avatar_default.copy()
char_pic = avatar_img.convert('RGBA').resize( char_pic = avatar_img.convert("RGBA").resize(
(125, 125), (125, 125),
Image.Resampling.LANCZOS, # type: ignore Image.Resampling.LANCZOS, # type: ignore
) )
@ -149,17 +147,15 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
img_draw = ImageDraw.Draw(img) img_draw = ImageDraw.Draw(img)
# 写Nickname # 写Nickname
img_draw.text( img_draw.text((310, 184), nickname, font=sr_font_34, fill=first_color, anchor="lm")
(310, 184), nickname, font=sr_font_34, fill=first_color, anchor='lm'
)
# 写UID # 写UID
img_draw.text( img_draw.text(
(267, 219), (267, 219),
f'UID {sr_uid}', f"UID {sr_uid}",
font=sr_font_20, font=sr_font_20,
fill=second_color2, fill=second_color2,
anchor='lm', anchor="lm",
) )
# 写本日星琼 # 写本日星琼
@ -168,7 +164,7 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
day_hcoin_str, day_hcoin_str,
font=sr_font_28, font=sr_font_28,
fill=white_color, fill=white_color,
anchor='lm', anchor="lm",
) )
# 写本月星琼 # 写本月星琼
@ -177,7 +173,7 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
month_hcoin_str, month_hcoin_str,
font=sr_font_28, font=sr_font_28,
fill=white_color, fill=white_color,
anchor='lm', anchor="lm",
) )
# 写昨日星琼 # 写昨日星琼
@ -186,7 +182,7 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
lastday_hcoin_str, lastday_hcoin_str,
font=sr_font_28, font=sr_font_28,
fill=black_color, fill=black_color,
anchor='lm', anchor="lm",
) )
# 写上月星琼 # 写上月星琼
@ -195,7 +191,7 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
lastmonth_hcoin_str, lastmonth_hcoin_str,
font=sr_font_28, font=sr_font_28,
fill=black_color, fill=black_color,
anchor='lm', anchor="lm",
) )
# 写本日铁票 # 写本日铁票
@ -204,7 +200,7 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
day_rails_pass_str, day_rails_pass_str,
font=sr_font_28, font=sr_font_28,
fill=white_color, fill=white_color,
anchor='lm', anchor="lm",
) )
# 写本月铁票 # 写本月铁票
@ -213,7 +209,7 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
month_rails_pass_str, month_rails_pass_str,
font=sr_font_28, font=sr_font_28,
fill=white_color, fill=white_color,
anchor='lm', anchor="lm",
) )
# 写昨日铁票 # 写昨日铁票
@ -222,7 +218,7 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
lastday_rails_pass_str, lastday_rails_pass_str,
font=sr_font_28, font=sr_font_28,
fill=black_color, fill=black_color,
anchor='lm', anchor="lm",
) )
# 写上月铁票 # 写上月铁票
@ -231,16 +227,16 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
lastmonth_rails_pass_str, lastmonth_rails_pass_str,
font=sr_font_28, font=sr_font_28,
fill=black_color, fill=black_color,
anchor='lm', anchor="lm",
) )
xy = ((0, 0), (2100, 2100)) xy = ((0, 0), (2100, 2100))
temp = -90 temp = -90
if not data.month_data.group_by: if not data.month_data.group_by:
pie_image = Image.new('RGBA', (2100, 2100), color=(255, 255, 255, 0)) pie_image = Image.new("RGBA", (2100, 2100), color=(255, 255, 255, 0))
pie_image_draw = ImageDraw.Draw(pie_image) pie_image_draw = ImageDraw.Draw(pie_image)
pie_image_draw.ellipse(xy, fill=(128, 128, 128)) pie_image_draw.ellipse(xy, fill=(128, 128, 128))
else: else:
pie_image = Image.new('RGBA', (2100, 2100), color=(255, 255, 255, 0)) pie_image = Image.new("RGBA", (2100, 2100), color=(255, 255, 255, 0))
pie_image_draw = ImageDraw.Draw(pie_image) pie_image_draw = ImageDraw.Draw(pie_image)
for _index, i in enumerate(data.month_data.group_by): for _index, i in enumerate(data.month_data.group_by):
pie_image_draw.pieslice( pie_image_draw.pieslice(
@ -251,7 +247,7 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
) )
temp = temp + (i.percent / 100) * 360 temp = temp + (i.percent / 100) * 360
# 绘制蒙版圆形 # 绘制蒙版圆形
new_image = Image.new('RGBA', (2100, 2100), color=(255, 255, 255, 0)) new_image = Image.new("RGBA", (2100, 2100), color=(255, 255, 255, 0))
pie_image_draw.ellipse((150, 150, 1950, 1950), fill=(255, 255, 255, 0)) pie_image_draw.ellipse((150, 150, 1950, 1950), fill=(255, 255, 255, 0))
position = (1050, 1050) position = (1050, 1050)
@ -260,7 +256,7 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
img.paste(result_pie, (138, 618), result_pie) img.paste(result_pie, (138, 618), result_pie)
if last_monthly_data: if last_monthly_data:
pie_image = Image.new('RGBA', (2100, 2100), color=(255, 255, 255, 0)) pie_image = Image.new("RGBA", (2100, 2100), color=(255, 255, 255, 0))
pie_image_draw = ImageDraw.Draw(pie_image) pie_image_draw = ImageDraw.Draw(pie_image)
for _index, i in enumerate(last_monthly_data.month_data.group_by): for _index, i in enumerate(last_monthly_data.month_data.group_by):
pie_image_draw.pieslice( pie_image_draw.pieslice(
@ -271,12 +267,12 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
) )
temp = temp + (i.percent / 100) * 360 temp = temp + (i.percent / 100) * 360
else: else:
pie_image = Image.new('RGBA', (2100, 2100), color=(255, 255, 255, 0)) pie_image = Image.new("RGBA", (2100, 2100), color=(255, 255, 255, 0))
pie_image_draw = ImageDraw.Draw(pie_image) pie_image_draw = ImageDraw.Draw(pie_image)
pie_image_draw.ellipse(xy, fill=(128, 128, 128)) pie_image_draw.ellipse(xy, fill=(128, 128, 128))
# 绘制蒙版圆形 # 绘制蒙版圆形
new_image = Image.new('RGBA', (2100, 2100), color=(255, 255, 255, 0)) new_image = Image.new("RGBA", (2100, 2100), color=(255, 255, 255, 0))
pie_image_draw.ellipse((150, 150, 1950, 1950), fill=(255, 255, 255, 0)) pie_image_draw.ellipse((150, 150, 1950, 1950), fill=(255, 255, 255, 0))
position = (1050, 1050) position = (1050, 1050)
@ -285,13 +281,13 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
img.paste(result_pie, (138, 618 + 350), result_pie) img.paste(result_pie, (138, 618 + 350), result_pie)
img = await convert_img(img) img = await convert_img(img)
logger.info('[开拓月历] 图片绘制完成!等待发送...') logger.info("[开拓月历] 图片绘制完成!等待发送...")
return img return img
async def int_carry(i: int) -> str: async def int_carry(i: int) -> str:
if i >= 100000: if i >= 100000:
i_str = f'{i / 10000:.1f}W' i_str = f"{i / 10000:.1f}W"
else: else:
i_str = str(i) i_str = str(i)
return i_str return i_str

View File

@ -1,7 +1,7 @@
from datetime import datetime from datetime import datetime
from ..utils.mys_api import mys_api
from ..utils.error_reply import get_error from ..utils.error_reply import get_error
from ..utils.mys_api import mys_api
month_im = """============== month_im = """==============
SR_UID:{} SR_UID:{}
@ -24,7 +24,7 @@ SR_UID:{}
async def award(uid) -> str: async def award(uid) -> str:
# 获取当前的月份 # 获取当前的月份
data = await mys_api.get_award(uid, datetime.now().month) data = await mys_api.get_sr_award(uid, datetime.now().month)
if isinstance(data, int): if isinstance(data, int):
return get_error(data) return get_error(data)
day_hcoin = data.day_data.current_hcoin day_hcoin = data.day_data.current_hcoin
@ -38,17 +38,17 @@ async def award(uid) -> str:
month_rails_pass = data.month_data.current_rails_pass month_rails_pass = data.month_data.current_rails_pass
lastmonth_stone = data.month_data.last_hcoin lastmonth_stone = data.month_data.last_hcoin
lastmonth_rails_pass = data.month_data.last_rails_pass lastmonth_rails_pass = data.month_data.last_rails_pass
group_str = '' group_str = ""
for i in data.month_data.group_by: for i in data.month_data.group_by:
group_str = ( group_str = (
group_str group_str
+ i.action_name + i.action_name
+ ':' + ":"
+ str(i.num) + str(i.num)
+ '(' + "("
+ str(i.percent) + str(i.percent)
+ '%)' + "%)"
+ '\n' + "\n"
) )
return month_im.format( return month_im.format(

View File

@ -6,18 +6,16 @@ from gsuid_core.logger import logger
from ..utils.sr_prefix import PREFIX from ..utils.sr_prefix import PREFIX
from ..utils.resource.download_from_cos import check_use from ..utils.resource.download_from_cos import check_use
sv_sr_download_config = SV('sr下载资源', pm=1) sv_sr_download_config = SV("sr下载资源", pm=1)
@sv_sr_download_config.on_fullmatch(f'{PREFIX}下载全部资源') @sv_sr_download_config.on_fullmatch(f"{PREFIX}下载全部资源")
async def send_download_resource_msg(bot: Bot, ev: Event): async def send_download_resource_msg(bot: Bot, ev: Event):
await bot.send('sr正在开始下载~可能需要较久的时间!') await bot.send("sr正在开始下载~可能需要较久的时间!")
im = await check_use() im = await check_use()
await bot.send(im) await bot.send(im)
async def startup(): async def startup():
logger.info( logger.info("[sr资源文件下载] 正在检查与下载缺失的资源文件,可能需要较长时间,请稍等")
'[sr资源文件下载] 正在检查与下载缺失的资源文件,可能需要较长时间,请稍等' logger.info(f"[sr资源文件下载] {await check_use()}")
)
logger.info(f'[sr资源文件下载] {await check_use()}')

View File

@ -1,60 +1,58 @@
import re import re
from gsuid_core.sv import SV from .draw_rogue_card import draw_rogue_img, draw_rogue_locust_img
from ..utils.sr_prefix import PREFIX
from gsuid_core.bot import Bot from gsuid_core.bot import Bot
from gsuid_core.models import Event from gsuid_core.models import Event
from gsuid_core.sv import SV
from gsuid_core.utils.database.api import get_uid
from gsuid_core.utils.database.models import GsBind
from gsuid_core.utils.error_reply import UID_HINT from gsuid_core.utils.error_reply import UID_HINT
from ..utils.convert import get_uid sv_srabyss = SV("sr查询模拟宇宙")
from ..utils.sr_prefix import PREFIX sv_srabyss_locust = SV("sr查询寰宇蝗灾")
from .draw_rogue_card import draw_rogue_img, draw_rogue_locust_img
sv_srabyss = SV('sr查询模拟宇宙')
sv_srabyss_locust = SV('sr查询寰宇蝗灾')
@sv_srabyss.on_command( @sv_srabyss.on_command(
( (
f'{PREFIX}查询宇宙', f"{PREFIX}查询宇宙",
f'{PREFIX}yz', f"{PREFIX}yz",
f'{PREFIX}查询上期宇宙', f"{PREFIX}查询上期宇宙",
f'{PREFIX}sqyz', f"{PREFIX}sqyz",
f'{PREFIX}上期宇宙', f"{PREFIX}上期宇宙",
f'{PREFIX}宇宙', f"{PREFIX}宇宙",
f'{PREFIX}查询模拟宇宙', f"{PREFIX}查询模拟宇宙",
f'{PREFIX}上期模拟宇宙', f"{PREFIX}上期模拟宇宙",
f'{PREFIX}查询上期模拟宇宙', f"{PREFIX}查询上期模拟宇宙",
), ),
block=True, block=True,
) )
async def send_srabyss_info(bot: Bot, ev: Event): async def send_srabyss_info(bot: Bot, ev: Event):
name = ''.join(re.findall('[\u4e00-\u9fa5]', ev.text)) name = "".join(re.findall("[\u4e00-\u9fa5]", ev.text))
if name: if name:
return None return None
await bot.logger.info('开始执行[sr查询模拟宇宙信息]') await bot.logger.info("开始执行[sr查询模拟宇宙信息]")
get_uid_ = await get_uid(bot, ev, True) uid, user_id = await get_uid(bot, ev, GsBind, "sr", True)
if get_uid_ is None:
return await bot.send(UID_HINT)
uid, user_id = get_uid_
if uid is None: if uid is None:
return await bot.send(UID_HINT) return await bot.send(UID_HINT)
await bot.logger.info(f'[sr查询模拟宇宙信息]uid: {uid}') await bot.logger.info(f"[sr查询模拟宇宙信息]uid: {uid}")
if 'sq' in ev.command or '上期' in ev.command: if "sq" in ev.command or "上期" in ev.command:
schedule_type = '2' schedule_type = "2"
else: else:
schedule_type = '3' schedule_type = "3"
await bot.logger.info(f'[sr查询模拟宇宙信息]模拟宇宙期数: {schedule_type}') await bot.logger.info(f"[sr查询模拟宇宙信息]模拟宇宙期数: {schedule_type}")
if ev.text in ['', '', '', '', '', '']: if ev.text in ["", "", "", "", "", ""]:
floor = ( floor = (
ev.text.replace('', '1') ev.text.replace("", "1")
.replace('', '2') .replace("", "2")
.replace('', '3') .replace("", "3")
.replace('', '4') .replace("", "4")
.replace('', '5') .replace("", "5")
.replace('', '6') .replace("", "6")
) )
else: else:
floor = ev.text floor = ev.text
@ -62,7 +60,7 @@ async def send_srabyss_info(bot: Bot, ev: Event):
floor = int(floor) floor = int(floor)
else: else:
floor = None floor = None
await bot.logger.info(f'[sr查询模拟宇宙信息]模拟宇宙世界数: {floor}') await bot.logger.info(f"[sr查询模拟宇宙信息]模拟宇宙世界数: {floor}")
im = await draw_rogue_img(user_id, uid, ev.sender, floor, schedule_type) im = await draw_rogue_img(user_id, uid, ev.sender, floor, schedule_type)
await bot.send(im) await bot.send(im)
return None return None
@ -70,26 +68,23 @@ async def send_srabyss_info(bot: Bot, ev: Event):
@sv_srabyss_locust.on_command( @sv_srabyss_locust.on_command(
( (
f'{PREFIX}寰宇蝗灾', f"{PREFIX}寰宇蝗灾",
f'{PREFIX}hyhz', f"{PREFIX}hyhz",
f'{PREFIX}查询寰宇蝗灾', f"{PREFIX}查询寰宇蝗灾",
f'{PREFIX}sqhyhz', f"{PREFIX}sqhyhz",
), ),
block=True, block=True,
) )
async def send_srabyss_locust_info(bot: Bot, ev: Event): async def send_srabyss_locust_info(bot: Bot, ev: Event):
name = ''.join(re.findall('[\u4e00-\u9fa5]', ev.text)) name = "".join(re.findall("[\u4e00-\u9fa5]", ev.text))
if name: if name:
return None return None
await bot.logger.info('开始执行[sr查询寰宇蝗灾信息]') await bot.logger.info("开始执行[sr查询寰宇蝗灾信息]")
get_uid_ = await get_uid(bot, ev, True) uid, user_id = await get_uid(bot, ev, GsBind, "sr", True)
if get_uid_ is None:
return await bot.send(UID_HINT)
uid, user_id = get_uid_
if uid is None: if uid is None:
return await bot.send(UID_HINT) return await bot.send(UID_HINT)
await bot.logger.info(f'[sr查询寰宇蝗灾信息]uid: {uid}') await bot.logger.info(f"[sr查询寰宇蝗灾信息]uid: {uid}")
im = await draw_rogue_locust_img(user_id, uid, ev.sender) im = await draw_rogue_locust_img(user_id, uid, ev.sender)
await bot.send(im) await bot.send(im)
return None return None

View File

@ -1,95 +1,87 @@
import math import math
from pathlib import Path from pathlib import Path
from typing import List, Union, Optional from typing import Any, Dict, List, Optional, Union
from PIL import Image, ImageDraw
from gsuid_core.logger import logger
from gsuid_core.utils.error_reply import get_error
from gsuid_core.utils.image.image_tools import (
get_qq_avatar,
draw_pic_with_ring,
)
from .utils import get_icon from .utils import get_icon
from ..utils.mys_api import mys_api from ..sruid_utils.api.mys.models import (
from ..utils.image.convert import convert_img LocustBlocks,
RogueAvatar,
RogueBuffitems,
RogueMiracles,
)
from ..utils.fonts.starrail_fonts import ( from ..utils.fonts.starrail_fonts import (
sr_font_22, sr_font_22,
sr_font_28, sr_font_28,
sr_font_34, sr_font_34,
sr_font_42, sr_font_42,
) )
from ..sruid_utils.api.mys.models import ( from ..utils.mys_api import mys_api
RogueAvatar,
LocustBlocks, from PIL import Image, ImageDraw
RogueMiracles, from gsuid_core.logger import logger
RogueBuffitems, from gsuid_core.utils.error_reply import get_error
from gsuid_core.utils.image.convert import convert_img
from gsuid_core.utils.image.image_tools import (
draw_pic_with_ring,
get_qq_avatar,
) )
TEXT_PATH = Path(__file__).parent / 'texture2D' TEXT_PATH = Path(__file__).parent / "texture2D"
white_color = (255, 255, 255) white_color = (255, 255, 255)
gray_color = (175, 175, 175) gray_color = (175, 175, 175)
img_bg = Image.open(TEXT_PATH / 'bg.jpg') img_bg = Image.open(TEXT_PATH / "bg.jpg")
level_cover = Image.open(TEXT_PATH / 'level_cover.png').convert('RGBA') level_cover = Image.open(TEXT_PATH / "level_cover.png").convert("RGBA")
char_bg_4 = Image.open(TEXT_PATH / 'char4_bg.png').convert('RGBA') char_bg_4 = Image.open(TEXT_PATH / "char4_bg.png").convert("RGBA")
char_bg_5 = Image.open(TEXT_PATH / 'char5_bg.png').convert('RGBA') char_bg_5 = Image.open(TEXT_PATH / "char5_bg.png").convert("RGBA")
rank_bg = Image.open(TEXT_PATH / 'rank_bg.png').convert('RGBA') rank_bg = Image.open(TEXT_PATH / "rank_bg.png").convert("RGBA")
content_center = Image.open(TEXT_PATH / 'center.png').convert('RGBA') content_center = Image.open(TEXT_PATH / "center.png").convert("RGBA")
elements = { elements = {
'ice': Image.open(TEXT_PATH / 'IconNatureColorIce.png').convert('RGBA'), "ice": Image.open(TEXT_PATH / "IconNatureColorIce.png").convert("RGBA"),
'fire': Image.open(TEXT_PATH / 'IconNatureColorFire.png').convert('RGBA'), "fire": Image.open(TEXT_PATH / "IconNatureColorFire.png").convert("RGBA"),
'imaginary': Image.open( "imaginary": Image.open(TEXT_PATH / "IconNatureColorImaginary.png").convert("RGBA"),
TEXT_PATH / 'IconNatureColorImaginary.png' "quantum": Image.open(TEXT_PATH / "IconNatureColorQuantum.png").convert("RGBA"),
).convert('RGBA'), "lightning": Image.open(TEXT_PATH / "IconNatureColorThunder.png").convert("RGBA"),
'quantum': Image.open(TEXT_PATH / 'IconNatureColorQuantum.png').convert( "wind": Image.open(TEXT_PATH / "IconNatureColorWind.png").convert("RGBA"),
'RGBA' "physical": Image.open(TEXT_PATH / "IconNaturePhysical.png").convert("RGBA"),
),
'lightning': Image.open(TEXT_PATH / 'IconNatureColorThunder.png').convert(
'RGBA'
),
'wind': Image.open(TEXT_PATH / 'IconNatureColorWind.png').convert('RGBA'),
'physical': Image.open(TEXT_PATH / 'IconNaturePhysical.png').convert(
'RGBA'
),
} }
progresslist = { progresslist = {
1: '第一世界', 1: "第一世界",
2: '第二世界', 2: "第二世界",
3: '第三世界', 3: "第三世界",
4: '第四世界', 4: "第四世界",
5: '第五世界', 5: "第五世界",
6: '第六世界', 6: "第六世界",
7: '第七世界', 7: "第七世界",
8: '第八世界', 8: "第八世界",
} }
difficultylist = { difficultylist = {
1: 'I', 1: "I",
2: '', 2: "",
3: '', 3: "",
4: '', 4: "",
5: 'V', 5: "V",
6: '', 6: "",
7: '', 7: "",
8: '', 8: "",
} }
bufflist = { bufflist = {
120: '存护', 120: "存护",
121: '记忆', 121: "记忆",
122: '虚无', 122: "虚无",
123: '丰饶', 123: "丰饶",
124: '巡猎', 124: "巡猎",
125: '毁灭', 125: "毁灭",
126: '欢愉', 126: "欢愉",
127: '繁育', 127: "繁育",
} }
async def get_abyss_star_pic(star: int) -> Image.Image: async def get_abyss_star_pic(star: int) -> Image.Image:
return Image.open(TEXT_PATH / f'star{star}.png') return Image.open(TEXT_PATH / f"star{star}.png")
async def _draw_rogue_buff( async def _draw_rogue_buff(
@ -101,15 +93,15 @@ async def _draw_rogue_buff(
): ):
draw_height = 0 draw_height = 0
floor_pic_draw = ImageDraw.Draw(floor_pic) floor_pic_draw = ImageDraw.Draw(floor_pic)
buff_icon_img = Image.open(TEXT_PATH / f'{buff_icon}.png') buff_icon_img = Image.open(TEXT_PATH / f"{buff_icon}.png")
buff_icon_img = buff_icon_img.resize((40, 40)) buff_icon_img = buff_icon_img.resize((40, 40))
floor_pic.paste(buff_icon_img, (95, 400 + buff_height), buff_icon_img) floor_pic.paste(buff_icon_img, (95, 400 + buff_height), buff_icon_img)
floor_pic_draw.text( floor_pic_draw.text(
(140, 425 + buff_height), (140, 425 + buff_height),
f'{buff_name}:', f"{buff_name}:",
font=sr_font_28, font=sr_font_28,
fill=gray_color, fill=gray_color,
anchor='lm', anchor="lm",
) )
draw_height = draw_height + 40 draw_height = draw_height + 40
buff_num = len(buffs) buff_num = len(buffs)
@ -125,9 +117,7 @@ async def _draw_rogue_buff(
is_evoluted = 1 is_evoluted = 1
else: else:
is_evoluted = 0 is_evoluted = 0
buff_bg = Image.open( buff_bg = Image.open(TEXT_PATH / f"zhufu_{item.rank}_{is_evoluted}.png")
TEXT_PATH / f'zhufu_{item.rank}_{is_evoluted}.png'
)
buff_bg = buff_bg.resize((233, 35)) buff_bg = buff_bg.resize((233, 35))
z_left = 90 + 240 * zb_list[jishu][1] z_left = 90 + 240 * zb_list[jishu][1]
z_top = buff_height + 450 + 55 * zb_list[jishu][0] z_top = buff_height + 450 + 55 * zb_list[jishu][0]
@ -138,7 +128,7 @@ async def _draw_rogue_buff(
item.name, item.name,
font=sr_font_22, font=sr_font_22,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
return draw_height return draw_height
@ -159,7 +149,7 @@ async def _draw_rogue_blocks(
zb_list.append([m, n]) zb_list.append([m, n])
jishu = 0 jishu = 0
for block in blocks: for block in blocks:
block_icon = Image.open(TEXT_PATH / f'{block.name}.png') block_icon = Image.open(TEXT_PATH / f"{block.name}.png")
z_left_bg = 90 + 357 * zb_list[jishu][1] z_left_bg = 90 + 357 * zb_list[jishu][1]
z_top_bg = buff_height + 470 + 80 * zb_list[jishu][0] z_top_bg = buff_height + 470 + 80 * zb_list[jishu][0]
jishu = jishu + 1 jishu = jishu + 1
@ -168,10 +158,10 @@ async def _draw_rogue_blocks(
floor_pic.paste(block_icon, (z_left_icon, z_top_icon), mask=block_icon) floor_pic.paste(block_icon, (z_left_icon, z_top_icon), mask=block_icon)
floor_pic_draw.text( floor_pic_draw.text(
(z_left_bg + 80, z_top_bg + 35), (z_left_bg + 80, z_top_bg + 35),
f'{block.name} x{block.num}', f"{block.name} x{block.num}",
font=sr_font_22, font=sr_font_22,
fill=white_color, fill=white_color,
anchor='lm', anchor="lm",
) )
return draw_height return draw_height
@ -226,17 +216,17 @@ async def _draw_rogue_card(
char_bg.paste(rank_bg, (150, 16), mask=rank_bg) char_bg.paste(rank_bg, (150, 16), mask=rank_bg)
char_card_draw.text( char_card_draw.text(
(162, 31), (162, 31),
f'{char.rank}', f"{char.rank}",
font=sr_font_22, font=sr_font_22,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
char_card_draw.text( char_card_draw.text(
(100, 165), (100, 165),
f'等级 {char.level}', f"等级 {char.level}",
font=sr_font_22, font=sr_font_22,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
floor_pic.paste( floor_pic.paste(
char_bg, char_bg,
@ -248,17 +238,17 @@ async def _draw_rogue_card(
async def draw_rogue_img( async def draw_rogue_img(
qid: Union[str, int], qid: Union[str, int],
uid: str, uid: str,
sender: Union[str, str], sender: Dict[str, Any],
floor: Optional[int] = None, floor: Optional[int] = None,
schedule_type: str = '3', schedule_type: str = "3",
) -> Union[bytes, str]: ) -> Union[bytes, str]:
raw_rogue_data = await mys_api.get_rogue_info(uid, '3') raw_rogue_data = await mys_api.get_rogue_info(uid, "3")
if isinstance(raw_rogue_data, int): if isinstance(raw_rogue_data, int):
return get_error(raw_rogue_data) return get_error(raw_rogue_data)
# 计算背景图尺寸 # 计算背景图尺寸
if schedule_type == '3': if schedule_type == "3":
rogue_detail = raw_rogue_data.current_record.records rogue_detail = raw_rogue_data.current_record.records
else: else:
rogue_detail = raw_rogue_data.last_record.records rogue_detail = raw_rogue_data.last_record.records
@ -305,29 +295,29 @@ async def draw_rogue_img(
# 获取查询者数据 # 获取查询者数据
if floor: if floor:
if floor > 8: if floor > 8:
return '世界不能大于第八世界!' return "世界不能大于第八世界!"
if floor not in detail_list: if floor not in detail_list:
return '你还没有挑战该模拟宇宙!' return "你还没有挑战该模拟宇宙!"
elif schedule_type == '3': elif schedule_type == "3":
if raw_rogue_data.current_record.basic.finish_cnt == 0: if raw_rogue_data.current_record.basic.finish_cnt == 0:
return '你还没有挑战本期模拟宇宙!\n可以使用[sr上期模拟宇宙]命令查询上期~' return "你还没有挑战本期模拟宇宙!\n可以使用[sr上期模拟宇宙]命令查询上期~"
elif raw_rogue_data.last_record.basic.finish_cnt == 0: elif raw_rogue_data.last_record.basic.finish_cnt == 0:
return '你还没有挑战上期模拟宇宙!\n可以使用[sr模拟宇宙]命令查询本期~' return "你还没有挑战上期模拟宇宙!\n可以使用[sr模拟宇宙]命令查询本期~"
# 获取背景图片各项参数 # 获取背景图片各项参数
based_w = 900 based_w = 900
img = Image.new('RGB', (based_w, based_h), (10, 18, 49)) img = Image.new("RGB", (based_w, based_h), (10, 18, 49))
img.paste(img_bg, (0, 0)) img.paste(img_bg, (0, 0))
# img = img.crop((0, 0, based_w, based_h)) # img = img.crop((0, 0, based_w, based_h))
rogue_title = Image.open(TEXT_PATH / 'head.png') rogue_title = Image.open(TEXT_PATH / "head.png")
img.paste(rogue_title, (0, 0), rogue_title) img.paste(rogue_title, (0, 0), rogue_title)
# 获取头像 # 获取头像
_id = str(qid) _id = str(qid)
if _id.startswith('http'): if _id.startswith("http"):
char_pic = await get_qq_avatar(avatar_url=_id) char_pic = await get_qq_avatar(avatar_url=_id)
elif sender.get('avatar') is not None: elif sender.get("avatar") is not None:
char_pic = await get_qq_avatar(avatar_url=sender['avatar']) char_pic = await get_qq_avatar(avatar_url=sender["avatar"])
else: else:
char_pic = await get_qq_avatar(qid=qid) char_pic = await get_qq_avatar(qid=qid)
char_pic = await draw_pic_with_ring(char_pic, 250, None, False) char_pic = await draw_pic_with_ring(char_pic, 250, None, False)
@ -336,58 +326,58 @@ async def draw_rogue_img(
# 绘制抬头 # 绘制抬头
img_draw = ImageDraw.Draw(img) img_draw = ImageDraw.Draw(img)
img_draw.text((450, 442), f'UID {uid}', white_color, sr_font_28, 'mm') img_draw.text((450, 442), f"UID {uid}", white_color, sr_font_28, "mm")
# 总体数据 # 总体数据
rogue_data = Image.open(TEXT_PATH / 'data.png') rogue_data = Image.open(TEXT_PATH / "data.png")
img.paste(rogue_data, (0, 500), rogue_data) img.paste(rogue_data, (0, 500), rogue_data)
# 技能树激活 # 技能树激活
img_draw.text( img_draw.text(
(165, 569), (165, 569),
f'{raw_rogue_data.basic_info.unlocked_skill_points}', f"{raw_rogue_data.basic_info.unlocked_skill_points}",
white_color, white_color,
sr_font_42, sr_font_42,
'mm', "mm",
) )
img_draw.text( img_draw.text(
(165, 615), (165, 615),
'已激活技能树', "已激活技能树",
gray_color, gray_color,
sr_font_28, sr_font_28,
'mm', "mm",
) )
# 奇物解锁 # 奇物解锁
img_draw.text( img_draw.text(
(450, 569), (450, 569),
f'{raw_rogue_data.basic_info.unlocked_miracle_num}', f"{raw_rogue_data.basic_info.unlocked_miracle_num}",
white_color, white_color,
sr_font_42, sr_font_42,
'mm', "mm",
) )
img_draw.text( img_draw.text(
(450, 615), (450, 615),
'已解锁奇物', "已解锁奇物",
gray_color, gray_color,
sr_font_28, sr_font_28,
'mm', "mm",
) )
# 祝福解锁 # 祝福解锁
img_draw.text( img_draw.text(
(730, 569), (730, 569),
f'{raw_rogue_data.basic_info.unlocked_buff_num}', f"{raw_rogue_data.basic_info.unlocked_buff_num}",
white_color, white_color,
sr_font_42, sr_font_42,
'mm', "mm",
) )
img_draw.text( img_draw.text(
(730, 615), (730, 615),
'已解锁祝福', "已解锁祝福",
gray_color, gray_color,
sr_font_28, sr_font_28,
'mm', "mm",
) )
for index_floor, detail in enumerate(rogue_detail): for index_floor, detail in enumerate(rogue_detail):
@ -400,25 +390,19 @@ async def draw_rogue_img(
if detail_h_list[index_floor] is None: if detail_h_list[index_floor] is None:
continue continue
floor_pic = Image.open(TEXT_PATH / 'detail_bg.png').convert('RGBA') floor_pic = Image.open(TEXT_PATH / "detail_bg.png").convert("RGBA")
floor_pic = floor_pic.resize((900, detail_h_list[index_floor])) floor_pic = floor_pic.resize((900, detail_h_list[index_floor]))
floor_top_pic = Image.open(TEXT_PATH / 'floor_bg_top.png').convert( floor_top_pic = Image.open(TEXT_PATH / "floor_bg_top.png").convert("RGBA")
'RGBA'
)
floor_pic.paste(floor_top_pic, (0, 0), floor_top_pic) floor_pic.paste(floor_top_pic, (0, 0), floor_top_pic)
floor_center_pic = Image.open( floor_center_pic = Image.open(TEXT_PATH / "floor_bg_center.png").convert("RGBA")
TEXT_PATH / 'floor_bg_center.png'
).convert('RGBA')
floor_center_pic = floor_center_pic.resize( floor_center_pic = floor_center_pic.resize(
(900, detail_h_list[index_floor] - 170) (900, detail_h_list[index_floor] - 170)
) )
floor_pic.paste(floor_center_pic, (0, 100), floor_center_pic) floor_pic.paste(floor_center_pic, (0, 100), floor_center_pic)
floor_bot_pic = Image.open(TEXT_PATH / 'floor_bg_bot.png').convert( floor_bot_pic = Image.open(TEXT_PATH / "floor_bg_bot.png").convert("RGBA")
'RGBA'
)
floor_pic.paste( floor_pic.paste(
floor_bot_pic, (0, detail_h_list[index_floor] - 70), floor_bot_pic floor_bot_pic, (0, detail_h_list[index_floor] - 70), floor_bot_pic
) )
@ -427,30 +411,30 @@ async def draw_rogue_img(
difficulty_name = difficultylist[detail.difficulty] difficulty_name = difficultylist[detail.difficulty]
time_array = detail.finish_time time_array = detail.finish_time
time_str = f'{time_array.year}-{time_array.month}' time_str = f"{time_array.year}-{time_array.month}"
time_str = f'{time_str}-{time_array.day}' time_str = f"{time_str}-{time_array.day}"
time_str = f'{time_str} {time_array.hour}:{time_array.minute}' time_str = f"{time_str} {time_array.hour}:{time_array.minute}"
floor_pic_draw = ImageDraw.Draw(floor_pic) floor_pic_draw = ImageDraw.Draw(floor_pic)
floor_pic_draw.text( floor_pic_draw.text(
(450, 60), (450, 60),
f'{floor_name} {difficulty_name}', f"{floor_name} {difficulty_name}",
white_color, white_color,
sr_font_42, sr_font_42,
'mm', "mm",
) )
floor_pic_draw.text( floor_pic_draw.text(
(93, 120), (93, 120),
f'挑战时间:{time_str}', f"挑战时间:{time_str}",
gray_color, gray_color,
sr_font_22, sr_font_22,
'lm', "lm",
) )
floor_pic_draw.text( floor_pic_draw.text(
(800, 120), (800, 120),
f'当前积分:{detail.score}', f"当前积分:{detail.score}",
gray_color, gray_color,
sr_font_22, sr_font_22,
'rm', "rm",
) )
# 角色 # 角色
@ -478,10 +462,10 @@ async def draw_rogue_img(
if len(detail.base_type_list) > 0: if len(detail.base_type_list) > 0:
floor_pic_draw.text( floor_pic_draw.text(
(93, 370), (93, 370),
'获得祝福', "获得祝福",
white_color, white_color,
sr_font_34, sr_font_34,
'lm', "lm",
) )
floor_pic.paste(content_center, (0, 390), content_center) floor_pic.paste(content_center, (0, 390), content_center)
for buff in detail.buffs: for buff in detail.buffs:
@ -501,14 +485,12 @@ async def draw_rogue_img(
if len(detail.miracles) > 0: if len(detail.miracles) > 0:
floor_pic_draw.text( floor_pic_draw.text(
(93, 370 + buff_height + 60), (93, 370 + buff_height + 60),
'获得奇物', "获得奇物",
white_color, white_color,
sr_font_34, sr_font_34,
'lm', "lm",
)
floor_pic.paste(
content_center, (0, 370 + buff_height + 80), content_center
) )
floor_pic.paste(content_center, (0, 370 + buff_height + 80), content_center)
await _draw_rogue_miracles( await _draw_rogue_miracles(
detail.miracles, detail.miracles,
floor_pic, floor_pic,
@ -529,16 +511,16 @@ async def draw_rogue_img(
# ) # )
res = await convert_img(img) res = await convert_img(img)
logger.info('[查询模拟宇宙]绘图已完成,等待发送!') logger.info("[查询模拟宇宙]绘图已完成,等待发送!")
return res return res
async def draw_rogue_locust_img( async def draw_rogue_locust_img(
qid: Union[str, int], qid: Union[str, int],
uid: str, uid: str,
sender: Union[str, str], sender: Dict[str, Any],
) -> Union[bytes, str]: ) -> Union[bytes, str]:
raw_rogue_data = await mys_api.get_rogue_locust_info(uid, '3') raw_rogue_data = await mys_api.get_rogue_locust_info(uid, "3")
if isinstance(raw_rogue_data, int): if isinstance(raw_rogue_data, int):
return get_error(raw_rogue_data) return get_error(raw_rogue_data)
@ -598,22 +580,22 @@ async def draw_rogue_locust_img(
# 获取查询者数据 # 获取查询者数据
if len(rogue_detail) == 0: if len(rogue_detail) == 0:
return '你还没有挑战寰宇蝗灾~' return "你还没有挑战寰宇蝗灾~"
# 获取背景图片各项参数 # 获取背景图片各项参数
based_w = 900 based_w = 900
img = Image.new('RGB', (based_w, based_h), (10, 18, 49)) img = Image.new("RGB", (based_w, based_h), (10, 18, 49))
img.paste(img_bg, (0, 0)) img.paste(img_bg, (0, 0))
# img = img.crop((0, 0, based_w, based_h)) # img = img.crop((0, 0, based_w, based_h))
rogue_title = Image.open(TEXT_PATH / 'head.png') rogue_title = Image.open(TEXT_PATH / "head.png")
img.paste(rogue_title, (0, 0), rogue_title) img.paste(rogue_title, (0, 0), rogue_title)
# 获取头像 # 获取头像
_id = str(qid) _id = str(qid)
if _id.startswith('http'): if _id.startswith("http"):
char_pic = await get_qq_avatar(avatar_url=_id) char_pic = await get_qq_avatar(avatar_url=_id)
elif sender.get('avatar') is not None: elif sender.get("avatar") is not None:
char_pic = await get_qq_avatar(avatar_url=sender['avatar']) char_pic = await get_qq_avatar(avatar_url=sender["avatar"])
else: else:
char_pic = await get_qq_avatar(qid=qid) char_pic = await get_qq_avatar(qid=qid)
char_pic = await draw_pic_with_ring(char_pic, 250, None, False) char_pic = await draw_pic_with_ring(char_pic, 250, None, False)
@ -622,83 +604,77 @@ async def draw_rogue_locust_img(
# 绘制抬头 # 绘制抬头
img_draw = ImageDraw.Draw(img) img_draw = ImageDraw.Draw(img)
img_draw.text((450, 442), f'UID {uid}', white_color, sr_font_28, 'mm') img_draw.text((450, 442), f"UID {uid}", white_color, sr_font_28, "mm")
# 总体数据 # 总体数据
rogue_data = Image.open(TEXT_PATH / 'data.png') rogue_data = Image.open(TEXT_PATH / "data.png")
img.paste(rogue_data, (0, 500), rogue_data) img.paste(rogue_data, (0, 500), rogue_data)
# 行者之道激活 # 行者之道激活
img_draw.text( img_draw.text(
(165, 569), (165, 569),
f'{raw_rogue_data.basic.cnt.narrow}', f"{raw_rogue_data.basic.cnt.narrow}",
white_color, white_color,
sr_font_42, sr_font_42,
'mm', "mm",
) )
img_draw.text( img_draw.text(
(165, 615), (165, 615),
'行者之道', "行者之道",
gray_color, gray_color,
sr_font_28, sr_font_28,
'mm', "mm",
) )
# 奇物解锁 # 奇物解锁
img_draw.text( img_draw.text(
(450, 569), (450, 569),
f'{raw_rogue_data.basic.cnt.miracle}', f"{raw_rogue_data.basic.cnt.miracle}",
white_color, white_color,
sr_font_42, sr_font_42,
'mm', "mm",
) )
img_draw.text( img_draw.text(
(450, 615), (450, 615),
'已解锁奇物', "已解锁奇物",
gray_color, gray_color,
sr_font_28, sr_font_28,
'mm', "mm",
) )
# 事件解锁 # 事件解锁
img_draw.text( img_draw.text(
(730, 569), (730, 569),
f'{raw_rogue_data.basic.cnt.event}', f"{raw_rogue_data.basic.cnt.event}",
white_color, white_color,
sr_font_42, sr_font_42,
'mm', "mm",
) )
img_draw.text( img_draw.text(
(730, 615), (730, 615),
'已解锁事件', "已解锁事件",
gray_color, gray_color,
sr_font_28, sr_font_28,
'mm', "mm",
) )
for index_floor, detail in enumerate(rogue_detail): for index_floor, detail in enumerate(rogue_detail):
if detail_h_list[index_floor] is None: if detail_h_list[index_floor] is None:
continue continue
floor_pic = Image.open(TEXT_PATH / 'detail_bg.png').convert('RGBA') floor_pic = Image.open(TEXT_PATH / "detail_bg.png").convert("RGBA")
floor_pic = floor_pic.resize((900, detail_h_list[index_floor])) floor_pic = floor_pic.resize((900, detail_h_list[index_floor]))
floor_top_pic = Image.open(TEXT_PATH / 'floor_bg_top.png').convert( floor_top_pic = Image.open(TEXT_PATH / "floor_bg_top.png").convert("RGBA")
'RGBA'
)
floor_pic.paste(floor_top_pic, (0, 0), floor_top_pic) floor_pic.paste(floor_top_pic, (0, 0), floor_top_pic)
floor_center_pic = Image.open( floor_center_pic = Image.open(TEXT_PATH / "floor_bg_center.png").convert("RGBA")
TEXT_PATH / 'floor_bg_center.png'
).convert('RGBA')
floor_center_pic = floor_center_pic.resize( floor_center_pic = floor_center_pic.resize(
(900, detail_h_list[index_floor] - 170) (900, detail_h_list[index_floor] - 170)
) )
floor_pic.paste(floor_center_pic, (0, 100), floor_center_pic) floor_pic.paste(floor_center_pic, (0, 100), floor_center_pic)
floor_bot_pic = Image.open(TEXT_PATH / 'floor_bg_bot.png').convert( floor_bot_pic = Image.open(TEXT_PATH / "floor_bg_bot.png").convert("RGBA")
'RGBA'
)
floor_pic.paste( floor_pic.paste(
floor_bot_pic, (0, detail_h_list[index_floor] - 70), floor_bot_pic floor_bot_pic, (0, detail_h_list[index_floor] - 70), floor_bot_pic
) )
@ -707,39 +683,39 @@ async def draw_rogue_locust_img(
difficulty_name = difficultylist[detail.difficulty] difficulty_name = difficultylist[detail.difficulty]
time_array = detail.finish_time time_array = detail.finish_time
time_str = f'{time_array.year}-{time_array.month}' time_str = f"{time_array.year}-{time_array.month}"
time_str = f'{time_str}-{time_array.day}' time_str = f"{time_str}-{time_array.day}"
time_str = f'{time_str} {time_array.hour}:{time_array.minute}' time_str = f"{time_str} {time_array.hour}:{time_array.minute}"
floor_pic_draw = ImageDraw.Draw(floor_pic) floor_pic_draw = ImageDraw.Draw(floor_pic)
floor_pic_draw.text( floor_pic_draw.text(
(450, 60), (450, 60),
f'{floor_name} {difficulty_name}', f"{floor_name} {difficulty_name}",
white_color, white_color,
sr_font_42, sr_font_42,
'mm', "mm",
) )
floor_pic_draw.text( floor_pic_draw.text(
(93, 120), (93, 120),
f'挑战时间:{time_str}', f"挑战时间:{time_str}",
gray_color, gray_color,
sr_font_22, sr_font_22,
'lm', "lm",
) )
if detail.fury.type == 1: if detail.fury.type == 1:
floor_pic_draw.text( floor_pic_draw.text(
(800, 120), (800, 120),
f'扰动等级:{detail.fury.point}', f"扰动等级:{detail.fury.point}",
gray_color, gray_color,
sr_font_22, sr_font_22,
'rm', "rm",
) )
else: else:
floor_pic_draw.text( floor_pic_draw.text(
(800, 120), (800, 120),
f'位面紊乱倒计时:{detail.fury.point}', f"位面紊乱倒计时:{detail.fury.point}",
gray_color, gray_color,
sr_font_22, sr_font_22,
'rm', "rm",
) )
# 角色 # 角色
@ -767,10 +743,10 @@ async def draw_rogue_locust_img(
if len(detail.base_type_list) > 0: if len(detail.base_type_list) > 0:
floor_pic_draw.text( floor_pic_draw.text(
(93, 370), (93, 370),
'获得祝福', "获得祝福",
white_color, white_color,
sr_font_34, sr_font_34,
'lm', "lm",
) )
floor_pic.paste(content_center, (0, 390), content_center) floor_pic.paste(content_center, (0, 390), content_center)
for buff in detail.buffs: for buff in detail.buffs:
@ -791,10 +767,10 @@ async def draw_rogue_locust_img(
if len(detail.miracles) > 0: if len(detail.miracles) > 0:
floor_pic_draw.text( floor_pic_draw.text(
(93, 370 + miracles_height + 60), (93, 370 + miracles_height + 60),
'获得奇物', "获得奇物",
white_color, white_color,
sr_font_34, sr_font_34,
'lm', "lm",
) )
floor_pic.paste( floor_pic.paste(
content_center, (0, 370 + miracles_height + 80), content_center content_center, (0, 370 + miracles_height + 80), content_center
@ -812,10 +788,10 @@ async def draw_rogue_locust_img(
if len(detail.blocks) > 0: if len(detail.blocks) > 0:
floor_pic_draw.text( floor_pic_draw.text(
(93, 370 + blocks_height + 60), (93, 370 + blocks_height + 60),
'通过区域类型', "通过区域类型",
white_color, white_color,
sr_font_34, sr_font_34,
'lm', "lm",
) )
floor_pic.paste( floor_pic.paste(
content_center, (0, 370 + blocks_height + 80), content_center content_center, (0, 370 + blocks_height + 80), content_center
@ -842,5 +818,5 @@ async def draw_rogue_locust_img(
# ) # )
res = await convert_img(img) res = await convert_img(img)
logger.info('[查询寰宇蝗灾]绘图已完成,等待发送!') logger.info("[查询寰宇蝗灾]绘图已完成,等待发送!")
return res return res

View File

@ -6,14 +6,14 @@ from PIL import Image
from aiohttp import ClientSession from aiohttp import ClientSession
from gsuid_core.data_store import get_res_path from gsuid_core.data_store import get_res_path
T = TypeVar('T') T = TypeVar("T")
ROLEINFO_PATH = get_res_path() / 'StarRailUID' / 'roleinfo' ROLEINFO_PATH = get_res_path() / "StarRailUID" / "roleinfo"
ROLEINFO_PATH.mkdir(parents=True, exist_ok=True) ROLEINFO_PATH.mkdir(parents=True, exist_ok=True)
async def get_icon(url: str) -> Image.Image: async def get_icon(url: str) -> Image.Image:
name = url.split('/')[-1] name = url.split("/")[-1]
path = ROLEINFO_PATH / name path = ROLEINFO_PATH / name
if (path).exists(): if (path).exists():
content = path.read_bytes() content = path.read_bytes()
@ -21,6 +21,6 @@ async def get_icon(url: str) -> Image.Image:
async with ClientSession() as client: async with ClientSession() as client:
async with client.get(url) as resp: async with client.get(url) as resp:
content = await resp.read() content = await resp.read()
with Path.open(path, 'wb') as f: with Path.open(path, "wb") as f:
f.write(content) f.write(content)
return Image.open(BytesIO(content)).convert('RGBA') return Image.open(BytesIO(content)).convert("RGBA")

View File

@ -1,47 +1,45 @@
import re import re
from gsuid_core.sv import SV from .draw_roleinfo_card import get_detail_img, get_role_img
from gsuid_core.bot import Bot
from gsuid_core.models import Event
from gsuid_core.logger import logger
from ..utils.convert import get_uid
from ..utils.sr_prefix import PREFIX
from ..utils.error_reply import UID_HINT from ..utils.error_reply import UID_HINT
from .draw_roleinfo_card import get_role_img, get_detail_img from ..utils.sr_prefix import PREFIX
sv_get_info = SV('sr查询信息') from gsuid_core.bot import Bot
from gsuid_core.logger import logger
from gsuid_core.models import Event
from gsuid_core.sv import SV
from gsuid_core.utils.database.api import get_uid
from gsuid_core.utils.database.models import GsBind
sv_get_info = SV("sr查询信息")
@sv_get_info.on_command(f'{PREFIX}uid') @sv_get_info.on_command(f"{PREFIX}uid")
async def send_role_info(bot: Bot, ev: Event): async def send_role_info(bot: Bot, ev: Event):
name = ''.join(re.findall('[\u4e00-\u9fa5]', ev.text)) name = "".join(re.findall("[\u4e00-\u9fa5]", ev.text))
if name: if name:
return None return None
uid = await get_uid(bot, ev) uid = await get_uid(bot, ev, GsBind, "sr")
if uid is None: if uid is None:
return '你还没有绑定UID噢,请使用[sr绑定uid123]完成绑定!' return "你还没有绑定UID噢,请使用[sr绑定uid123]完成绑定!"
logger.info(f'[sr查询信息]UID: {uid}') logger.info(f"[sr查询信息]UID: {uid}")
await bot.logger.info('开始执行[sr查询信息]') await bot.logger.info("开始执行[sr查询信息]")
await bot.send(await get_role_img(uid)) await bot.send(await get_role_img(uid))
return None return None
@sv_get_info.on_command(f'{PREFIX}练度统计') @sv_get_info.on_command(f"{PREFIX}练度统计")
async def send_detail_info(bot: Bot, ev: Event): async def send_detail_info(bot: Bot, ev: Event):
name = ''.join(re.findall('[\u4e00-\u9fa5]', ev.text)) name = "".join(re.findall("[\u4e00-\u9fa5]", ev.text))
if name: if name:
return None return None
get_uid_ = await get_uid(bot, ev, True) uid, user_id = await get_uid(bot, ev, GsBind, "sr", True)
if get_uid_ is None:
return await bot.send(UID_HINT)
uid, user_id = get_uid_
if uid is None: if uid is None:
return await bot.send(UID_HINT) return await bot.send(UID_HINT)
logger.info(f'[sr查询信息]UID: {uid}') logger.info(f"[sr查询信息]UID: {uid}")
await bot.logger.info('开始执行[sr查询信息]') await bot.logger.info("开始执行[sr查询信息]")
await bot.send(await get_detail_img(user_id, uid, ev.sender)) await bot.send(await get_detail_img(user_id, uid, ev.sender))
return None return None

View File

@ -1,26 +1,16 @@
import asyncio import asyncio
from pathlib import Path from pathlib import Path
from typing import Dict, List, Union, Optional from typing import Any, Dict, List, Optional, Union
from PIL import Image, ImageDraw
from gsuid_core.logger import logger
from gsuid_core.utils.error_reply import get_error
from gsuid_core.utils.image.image_tools import (
get_qq_avatar,
draw_pic_with_ring,
)
from ..utils.mys_api import mys_api
from .utils import get_icon, wrap_list from .utils import get_icon, wrap_list
from ..utils.image.convert import convert_img
from ..utils.fonts.first_world import fw_font_24
from ..sruid_utils.api.mys.models import ( from ..sruid_utils.api.mys.models import (
Stats,
AvatarDetail, AvatarDetail,
RoleBasicInfo,
AvatarListItem, AvatarListItem,
AvatarListItemDetail, AvatarListItemDetail,
RoleBasicInfo,
Stats,
) )
from ..utils.fonts.first_world import fw_font_24
from ..utils.fonts.starrail_fonts import ( from ..utils.fonts.starrail_fonts import (
sr_font_22, sr_font_22,
sr_font_24, sr_font_24,
@ -28,41 +18,41 @@ from ..utils.fonts.starrail_fonts import (
sr_font_30, sr_font_30,
sr_font_36, sr_font_36,
) )
from ..utils.mys_api import mys_api
TEXT_PATH = Path(__file__).parent / 'texture2D' from PIL import Image, ImageDraw
from gsuid_core.logger import logger
bg1 = Image.open(TEXT_PATH / 'bg1.png') from gsuid_core.utils.error_reply import get_error
bg2 = Image.open(TEXT_PATH / 'bg2.png') from gsuid_core.utils.image.convert import convert_img
bg3 = Image.open(TEXT_PATH / 'bg3.png') from gsuid_core.utils.image.image_tools import (
user_avatar = ( draw_pic_with_ring,
Image.open(TEXT_PATH / '200101.png').resize((220, 220)).convert('RGBA') get_qq_avatar,
) )
char_bg_4 = Image.open(TEXT_PATH / 'rarity4_bg.png').convert('RGBA')
char_bg_5 = Image.open(TEXT_PATH / 'rarity5_bg.png').convert('RGBA') TEXT_PATH = Path(__file__).parent / "texture2D"
circle = Image.open(TEXT_PATH / 'char_weapon_bg.png').convert('RGBA')
bg_img = Image.open(TEXT_PATH / 'bg_light.jpg') bg1 = Image.open(TEXT_PATH / "bg1.png")
rank_bg = Image.open(TEXT_PATH / 'rank_bg.png').convert('RGBA') bg2 = Image.open(TEXT_PATH / "bg2.png")
bg3 = Image.open(TEXT_PATH / "bg3.png")
user_avatar = Image.open(TEXT_PATH / "200101.png").resize((220, 220)).convert("RGBA")
char_bg_4 = Image.open(TEXT_PATH / "rarity4_bg.png").convert("RGBA")
char_bg_5 = Image.open(TEXT_PATH / "rarity5_bg.png").convert("RGBA")
circle = Image.open(TEXT_PATH / "char_weapon_bg.png").convert("RGBA")
bg_img = Image.open(TEXT_PATH / "bg_light.jpg")
rank_bg = Image.open(TEXT_PATH / "rank_bg.png").convert("RGBA")
bg_color = (248, 248, 248) bg_color = (248, 248, 248)
white_color = (255, 255, 255) white_color = (255, 255, 255)
color_color = (40, 18, 7) color_color = (40, 18, 7)
first_color = (22, 8, 31) first_color = (22, 8, 31)
elements = { elements = {
'ice': Image.open(TEXT_PATH / 'IconNatureColorIce.png').convert('RGBA'), "ice": Image.open(TEXT_PATH / "IconNatureColorIce.png").convert("RGBA"),
'fire': Image.open(TEXT_PATH / 'IconNatureColorFire.png').convert('RGBA'), "fire": Image.open(TEXT_PATH / "IconNatureColorFire.png").convert("RGBA"),
'imaginary': Image.open( "imaginary": Image.open(TEXT_PATH / "IconNatureColorImaginary.png").convert("RGBA"),
TEXT_PATH / 'IconNatureColorImaginary.png' "quantum": Image.open(TEXT_PATH / "IconNatureColorQuantum.png").convert("RGBA"),
).convert('RGBA'), "lightning": Image.open(TEXT_PATH / "IconNatureColorThunder.png").convert("RGBA"),
'quantum': Image.open(TEXT_PATH / 'IconNatureColorQuantum.png').convert( "wind": Image.open(TEXT_PATH / "IconNatureColorWind.png").convert("RGBA"),
'RGBA' "physical": Image.open(TEXT_PATH / "IconNaturePhysical.png").convert("RGBA"),
),
'lightning': Image.open(TEXT_PATH / 'IconNatureColorThunder.png').convert(
'RGBA'
),
'wind': Image.open(TEXT_PATH / 'IconNatureColorWind.png').convert('RGBA'),
'physical': Image.open(TEXT_PATH / 'IconNaturePhysical.png').convert(
'RGBA'
),
} }
@ -70,14 +60,12 @@ async def get_role_img(uid: str) -> Union[bytes, str]:
return await draw_role_card(uid) return await draw_role_card(uid)
async def get_detail_img( async def get_detail_img(qid: Union[str, int], uid: str, sender) -> Union[bytes, str]:
qid: Union[str, int], uid: str, sender
) -> Union[bytes, str]:
return await get_detail_card(qid, uid, sender) return await get_detail_card(qid, uid, sender)
def _lv(level: int) -> str: def _lv(level: int) -> str:
return f'Lv.0{level}' if level < 10 else f'Lv.{level}' return f"Lv.0{level}" if level < 10 else f"Lv.{level}"
async def _draw_card_1( async def _draw_card_1(
@ -100,16 +88,14 @@ async def _draw_card_1(
bg1_draw = ImageDraw.Draw(img_bg1) bg1_draw = ImageDraw.Draw(img_bg1)
# 写Nickname # 写Nickname
bg1_draw.text( bg1_draw.text((400, 85), nickname, font=sr_font_36, fill=white_color, anchor="mm")
(400, 85), nickname, font=sr_font_36, fill=white_color, anchor='mm'
)
# 写UID # 写UID
bg1_draw.text( bg1_draw.text(
(400, 165), (400, 165),
f'UID {sr_uid}', f"UID {sr_uid}",
font=sr_font_30, font=sr_font_30,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
# 贴头像 # 贴头像
img_bg1.paste(user_avatar, (286, 213), mask=user_avatar) img_bg1.paste(user_avatar, (286, 213), mask=user_avatar)
@ -120,31 +106,31 @@ async def _draw_card_1(
str(active_days), str(active_days),
font=sr_font_36, font=sr_font_36,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) # 活跃天数 ) # 活跃天数
bg1_draw.text( bg1_draw.text(
(270, 590), (270, 590),
str(avater_num), str(avater_num),
font=sr_font_36, font=sr_font_36,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) # 解锁角色 ) # 解锁角色
bg1_draw.text( bg1_draw.text(
(398, 590), (398, 590),
str(achievement_num), str(achievement_num),
font=sr_font_36, font=sr_font_36,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) # 达成成就 ) # 达成成就
bg1_draw.text( bg1_draw.text(
(525, 590), (525, 590),
str(chest_num), str(chest_num),
font=sr_font_36, font=sr_font_36,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) # 战利品开启 ) # 战利品开启
bg1_draw.text( bg1_draw.text(
(666, 590), str(level), font=sr_font_36, fill=white_color, anchor='mm' (666, 590), str(level), font=sr_font_36, fill=white_color, anchor="mm"
) # 开拓等级 ) # 开拓等级
# 画忘却之庭 # 画忘却之庭
@ -153,7 +139,7 @@ async def _draw_card_1(
abyss_process, abyss_process,
font=sr_font_30, font=sr_font_30,
fill=first_color, fill=first_color,
anchor='mm', anchor="mm",
) )
return img_bg1 return img_bg1
@ -174,10 +160,10 @@ async def _draw_avatar_card(
char_bg.paste(rank_bg, (89, 6), mask=rank_bg) char_bg.paste(rank_bg, (89, 6), mask=rank_bg)
char_draw.text( char_draw.text(
(100, 21), (100, 21),
f'{avatar.rank}', f"{avatar.rank}",
font=sr_font_22, font=sr_font_22,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
if equip := equips[avatar.id]: if equip := equips[avatar.id]:
@ -190,7 +176,7 @@ async def _draw_avatar_card(
_lv(avatar.level), _lv(avatar.level),
font=sr_font_24, font=sr_font_24,
fill=color_color, fill=color_color,
anchor='mm', anchor="mm",
) )
return char_bg return char_bg
@ -214,12 +200,9 @@ async def _draw_card_2(
) -> Image.Image: ) -> Image.Image:
# 角色部分 每五个一组 # 角色部分 每五个一组
lines = await asyncio.gather( lines = await asyncio.gather(
*[ *[_draw_line(five_avatars, equips) for five_avatars in wrap_list(avatars, 5)]
_draw_line(five_avatars, equips)
for five_avatars in wrap_list(avatars, 5)
]
) )
img_card_2 = Image.new('RGBA', (800, len(lines) * 200)) img_card_2 = Image.new("RGBA", (800, len(lines) * 200))
y = 0 y = 0
for line in lines: for line in lines:
@ -237,8 +220,8 @@ async def draw_role_card(sr_uid: str) -> Union[bytes, str]:
return get_error(role_basic_info) return get_error(role_basic_info)
else: else:
role_basic_info = {} role_basic_info = {}
role_basic_info['nickname'] = '开拓者' role_basic_info["nickname"] = "开拓者"
role_basic_info['level'] = 0 role_basic_info["level"] = 0
if isinstance(role_index, int): if isinstance(role_index, int):
return get_error(role_index) return get_error(role_index)
@ -266,7 +249,7 @@ async def draw_role_card(sr_uid: str) -> Union[bytes, str]:
) )
img2: Image.Image img2: Image.Image
height = img2.size[1] height = img2.size[1]
img = Image.new('RGBA', (800, 880 + height), bg_color) img = Image.new("RGBA", (800, 880 + height), bg_color)
img.paste(img1, (0, 0)) img.paste(img1, (0, 0))
img.paste(img2, (0, 810)) img.paste(img2, (0, 810))
img.paste(bg3, (0, height + 810)) img.paste(bg3, (0, height + 810))
@ -279,69 +262,69 @@ async def _draw_detail_card(
index: int, index: int,
char_info: Image.Image, char_info: Image.Image,
) -> Image.Image: ) -> Image.Image:
if str(avatar.rarity) == '5': if str(avatar.rarity) == "5":
avatar_img = Image.open(TEXT_PATH / 'bar_5.png') avatar_img = Image.open(TEXT_PATH / "bar_5.png")
else: else:
avatar_img = Image.open(TEXT_PATH / 'bar_4.png') avatar_img = Image.open(TEXT_PATH / "bar_4.png")
avatar_draw = ImageDraw.Draw(avatar_img) avatar_draw = ImageDraw.Draw(avatar_img)
char_icon = (await get_icon(avatar.icon)).resize((40, 40)) char_icon = (await get_icon(avatar.icon)).resize((40, 40))
element_icon = elements[avatar.element] element_icon = elements[avatar.element]
avatar_img.paste(char_icon, (75, 10), mask=char_icon) avatar_img.paste(char_icon, (75, 10), mask=char_icon)
avatar_draw.text( avatar_draw.text(
(130, 30), (130, 30),
f'{avatar.name}', f"{avatar.name}",
first_color, first_color,
sr_font_24, sr_font_24,
'lm', "lm",
) )
avatar_img.paste(element_icon, (270, 10), mask=element_icon) avatar_img.paste(element_icon, (270, 10), mask=element_icon)
avatar_draw.text( avatar_draw.text(
(339, 30), (339, 30),
f'{avatar.level}', f"{avatar.level}",
first_color, first_color,
sr_font_24, sr_font_24,
'mm', "mm",
) )
avatar_draw.text( avatar_draw.text(
(385, 30), (385, 30),
f'{avatar.rank}', f"{avatar.rank}",
first_color, first_color,
sr_font_24, sr_font_24,
'mm', "mm",
) )
avatar_draw.text( avatar_draw.text(
(429, 30), (429, 30),
f'{avatar_detail.skills[0].cur_level}', f"{avatar_detail.skills[0].cur_level}",
first_color, first_color,
sr_font_24, sr_font_24,
'mm', "mm",
) )
avatar_draw.text( avatar_draw.text(
(469, 30), (469, 30),
f'{avatar_detail.skills[1].cur_level}', f"{avatar_detail.skills[1].cur_level}",
first_color, first_color,
sr_font_24, sr_font_24,
'mm', "mm",
) )
avatar_draw.text( avatar_draw.text(
(515, 30), (515, 30),
f'{avatar_detail.skills[2].cur_level}', f"{avatar_detail.skills[2].cur_level}",
first_color, first_color,
sr_font_24, sr_font_24,
'mm', "mm",
) )
avatar_draw.text( avatar_draw.text(
(553, 30), (553, 30),
f'{avatar_detail.skills[3].cur_level}', f"{avatar_detail.skills[3].cur_level}",
first_color, first_color,
sr_font_24, sr_font_24,
'mm', "mm",
) )
if avatar.equip: if avatar.equip:
@ -350,26 +333,26 @@ async def _draw_detail_card(
avatar_draw.text( avatar_draw.text(
(680, 30), (680, 30),
f'{avatar.equip.rank}', f"{avatar.equip.rank}",
first_color, first_color,
sr_font_24, sr_font_24,
'mm', "mm",
) )
avatar_draw.text( avatar_draw.text(
(734, 30), (734, 30),
f'Lv.{avatar.equip.level}', f"Lv.{avatar.equip.level}",
first_color, first_color,
sr_font_24, sr_font_24,
'lm', "lm",
) )
avatar_draw.text( avatar_draw.text(
(804, 30), (804, 30),
f'{avatar.equip.name}', f"{avatar.equip.name}",
first_color, first_color,
sr_font_24, sr_font_24,
'lm', "lm",
) )
char_info.paste(avatar_img, (0, 585 + 62 * index), mask=avatar_img) char_info.paste(avatar_img, (0, 585 + 62 * index), mask=avatar_img)
@ -378,7 +361,7 @@ async def _draw_detail_card(
async def get_detail_card( async def get_detail_card(
qid: Union[str, int], sr_uid: str, sender: Union[str, str] qid: Union[str, int], sr_uid: str, sender: Dict[str, Any]
) -> Union[bytes, str]: ) -> Union[bytes, str]:
# 获取角色列表 # 获取角色列表
avatar_list = await mys_api.get_avatar_info(sr_uid, 1001) avatar_list = await mys_api.get_avatar_info(sr_uid, 1001)
@ -393,15 +376,15 @@ async def get_detail_card(
char_info = char_info.resize((1050, img_height)) char_info = char_info.resize((1050, img_height))
char_img_draw = ImageDraw.Draw(char_info) char_img_draw = ImageDraw.Draw(char_info)
char_title = Image.open(TEXT_PATH / 'title.png') char_title = Image.open(TEXT_PATH / "title.png")
char_info.paste(char_title, (0, 0), char_title) char_info.paste(char_title, (0, 0), char_title)
# 获取头像 # 获取头像
_id = str(qid) _id = str(qid)
if _id.startswith('http'): if _id.startswith("http"):
char_pic = await get_qq_avatar(avatar_url=_id) char_pic = await get_qq_avatar(avatar_url=_id)
elif sender.get('avatar') is not None: elif sender.get("avatar") is not None:
char_pic = await get_qq_avatar(avatar_url=sender['avatar']) char_pic = await get_qq_avatar(avatar_url=sender["avatar"])
else: else:
char_pic = await get_qq_avatar(qid=qid) char_pic = await get_qq_avatar(qid=qid)
char_pic = await draw_pic_with_ring(char_pic, 250, None, False) char_pic = await draw_pic_with_ring(char_pic, 250, None, False)
@ -409,11 +392,9 @@ async def get_detail_card(
char_info.paste(char_pic, (400, 88), char_pic) char_info.paste(char_pic, (400, 88), char_pic)
# 绘制抬头 # 绘制抬头
char_img_draw.text( char_img_draw.text((525, 420), f"UID {sr_uid}", white_color, sr_font_28, "mm")
(525, 420), f'UID {sr_uid}', white_color, sr_font_28, 'mm'
)
title_img = Image.open(TEXT_PATH / 'bar_title.png') title_img = Image.open(TEXT_PATH / "bar_title.png")
char_info.paste(title_img, (0, 515), mask=title_img) char_info.paste(title_img, (0, 515), mask=title_img)
for index, avatar in enumerate(avatar_list.avatar_list): for index, avatar in enumerate(avatar_list.avatar_list):
@ -431,12 +412,12 @@ async def get_detail_card(
# 写底层文字 # 写底层文字
char_img_draw.text( char_img_draw.text(
(525, img_height - 45), (525, img_height - 45),
'--SR skill statistics by StarrailUID & Code by jiluoQAQ & Power by GsCore--', "--SR skill statistics by StarrailUID & Code by jiluoQAQ & Power by GsCore--",
(255, 255, 255), (255, 255, 255),
fw_font_24, fw_font_24,
'mm', "mm",
) )
res = await convert_img(char_info) res = await convert_img(char_info)
logger.info('[查询练度统计]绘图已完成,等待发送!') logger.info("[查询练度统计]绘图已完成,等待发送!")
return res return res

View File

@ -6,9 +6,9 @@ from PIL import Image
from aiohttp import ClientSession from aiohttp import ClientSession
from gsuid_core.data_store import get_res_path from gsuid_core.data_store import get_res_path
T = TypeVar('T') T = TypeVar("T")
ROLEINFO_PATH = get_res_path() / 'StarRailUID' / 'roleinfo' ROLEINFO_PATH = get_res_path() / "StarRailUID" / "roleinfo"
ROLEINFO_PATH.mkdir(parents=True, exist_ok=True) ROLEINFO_PATH.mkdir(parents=True, exist_ok=True)
@ -18,7 +18,7 @@ def wrap_list(lst: List[T], n: int) -> Generator[List[T], None, None]:
async def get_icon(url: str) -> Image.Image: async def get_icon(url: str) -> Image.Image:
name = url.split('/')[-1] name = url.split("/")[-1]
path = ROLEINFO_PATH / name path = ROLEINFO_PATH / name
if (path).exists(): if (path).exists():
content = path.read_bytes() content = path.read_bytes()
@ -26,6 +26,6 @@ async def get_icon(url: str) -> Image.Image:
async with ClientSession() as client: async with ClientSession() as client:
async with client.get(url) as resp: async with client.get(url) as resp:
content = await resp.read() content = await resp.read()
with Path.open(path, 'wb') as f: with Path.open(path, "wb") as f:
f.write(content) f.write(content)
return Image.open(BytesIO(content)).convert('RGBA') return Image.open(BytesIO(content)).convert("RGBA")

View File

@ -11,40 +11,40 @@ from gsuid_core.utils.boardcast.send_msg import send_board_cast_msg
from gsuid_core.utils.database.models import GsBind from gsuid_core.utils.database.models import GsBind
from gsuid_core.utils.sign.sign import daily_sign, sign_in from gsuid_core.utils.sign.sign import daily_sign, sign_in
SIGN_TIME = srconfig.get_config('SignTime').data SIGN_TIME = srconfig.get_config("SignTime").data
IS_REPORT = srconfig.get_config('PrivateSignReport').data IS_REPORT = srconfig.get_config("PrivateSignReport").data
sv_sign = SV('星穹铁道签到') sv_sign = SV("星穹铁道签到")
sv_sign_config = SV('星穹铁道管理', pm=2) sv_sign_config = SV("星穹铁道管理", pm=2)
@sv_sign.on_fullmatch(f'{PREFIX}签到') @sv_sign.on_fullmatch(f"{PREFIX}签到")
async def get_sign_func(bot: Bot, ev: Event): async def get_sign_func(bot: Bot, ev: Event):
logger.info(f'[星穹铁道] [签到] 用户: {ev.user_id}') logger.info(f"[星穹铁道] [签到] 用户: {ev.user_id}")
uid = await GsBind.get_uid_by_game(ev.user_id, ev.bot_id, 'sr') uid = await GsBind.get_uid_by_game(ev.user_id, ev.bot_id, "sr")
if uid is None: if uid is None:
return await bot.send(UID_HINT) return await bot.send(UID_HINT)
logger.info(f'[星穹铁道] [签到] UID: {uid}') logger.info(f"[星穹铁道] [签到] UID: {uid}")
await bot.send(await sign_in(uid, 'sr')) await bot.send(await sign_in(uid, "sr"))
return None return None
@sv_sign_config.on_fullmatch(f'{PREFIX}全部重签') @sv_sign_config.on_fullmatch(f"{PREFIX}全部重签")
async def recheck(bot: Bot, ev: Event): async def recheck(bot: Bot, ev: Event):
await bot.logger.info('开始执行[全部重签]') await bot.logger.info("开始执行[全部重签]")
await bot.send('[星穹铁道] [全部重签] 已开始执行!') await bot.send("[星穹铁道] [全部重签] 已开始执行!")
result = await daily_sign('sr') result = await daily_sign("sr")
if not IS_REPORT: if not IS_REPORT:
result['private_msg_dict'] = {} result["private_msg_dict"] = {}
await send_board_cast_msg(result) await send_board_cast_msg(result)
await bot.send('[星穹铁道] [全部重签] 执行完成!') await bot.send("[星穹铁道] [全部重签] 执行完成!")
# 每日零点半执行米游社星穹铁道签到 # 每日零点半执行米游社星穹铁道签到
@scheduler.scheduled_job('cron', hour=SIGN_TIME[0], minute=SIGN_TIME[1]) @scheduler.scheduled_job("cron", hour=SIGN_TIME[0], minute=SIGN_TIME[1])
async def sr_sign_at_night(): async def sr_sign_at_night():
if srconfig.get_config('SchedSignin').data: if srconfig.get_config("SchedSignin").data:
result = await daily_sign('sr') result = await daily_sign("sr")
if not IS_REPORT: if not IS_REPORT:
result['private_msg_dict'] = {} result["private_msg_dict"] = {}
await send_board_cast_msg(result) await send_board_cast_msg(result)

View File

@ -1,82 +1,83 @@
import asyncio import asyncio
from gsuid_core.sv import SV from .draw_stamina_card import get_stamina_img
from .notice import get_notice_list
from .stamina_text import get_stamina_text
from ..utils.error_reply import UID_HINT
from ..utils.sr_prefix import PREFIX
from gsuid_core.aps import scheduler
from gsuid_core.bot import Bot from gsuid_core.bot import Bot
from gsuid_core.gss import gss from gsuid_core.gss import gss
from gsuid_core.models import Event
from gsuid_core.aps import scheduler
from gsuid_core.logger import logger from gsuid_core.logger import logger
from gsuid_core.models import Event
from gsuid_core.segment import MessageSegment from gsuid_core.segment import MessageSegment
from gsuid_core.sv import SV
from gsuid_core.utils.database.api import get_uid
from gsuid_core.utils.database.models import GsBind
from ..utils.convert import get_uid sv_get_stamina = SV("sr查询体力")
from .notice import get_notice_list sv_get_stamina_admin = SV("sr强制推送", pm=1)
from ..utils.sr_prefix import PREFIX
from ..utils.error_reply import UID_HINT
from .stamina_text import get_stamina_text
from .draw_stamina_card import get_stamina_img
sv_get_stamina = SV('sr查询体力')
sv_get_stamina_admin = SV('sr强制推送', pm=1)
@sv_get_stamina.on_fullmatch(f'{PREFIX}当前状态') @sv_get_stamina.on_fullmatch(f"{PREFIX}当前状态")
async def send_daily_info(bot: Bot, ev: Event): async def send_daily_info(bot: Bot, ev: Event):
await bot.logger.info('开始执行[sr每日信息文字版]') await bot.logger.info("开始执行[sr每日信息文字版]")
uid = await get_uid(bot, ev) uid = await get_uid(bot, ev, GsBind, "sr")
if uid is None: if uid is None:
return await bot.send(UID_HINT) return await bot.send(UID_HINT)
await bot.logger.info(f'[sr每日信息文字版]UID: {uid}') await bot.logger.info(f"[sr每日信息文字版]UID: {uid}")
im = await get_stamina_text(uid) im = await get_stamina_text(uid)
await bot.send(im) await bot.send(im)
return None return None
@sv_get_stamina_admin.on_fullmatch(f'{PREFIX}强制推送体力提醒') @sv_get_stamina_admin.on_fullmatch(f"{PREFIX}强制推送体力提醒")
async def force_notice_job(bot: Bot, ev: Event): async def force_notice_job(bot: Bot, ev: Event):
await bot.logger.info('开始执行[sr强制推送体力信息]') await bot.logger.info("开始执行[sr强制推送体力信息]")
await sr_notice_job() await sr_notice_job()
@scheduler.scheduled_job('cron', minute='*/30') @scheduler.scheduled_job("cron", minute="*/30")
async def sr_notice_job(): async def sr_notice_job():
result = await get_notice_list() result = await get_notice_list()
logger.info('[sr推送检查]完成!等待消息推送中...') logger.info("[sr推送检查]完成!等待消息推送中...")
logger.debug(result) logger.debug(result)
# 执行私聊推送 # 执行私聊推送
for bot_id in result: for bot_id in result:
for BOT_ID in gss.active_bot: for BOT_ID in gss.active_bot:
bot = gss.active_bot[BOT_ID] bot = gss.active_bot[BOT_ID]
for user_id in result[bot_id]['direct']: for user_id in result[bot_id]["direct"]:
msg = result[bot_id]['direct'][user_id] msg = result[bot_id]["direct"][user_id]
await bot.target_send(msg, 'direct', user_id, bot_id, '', '') await bot.target_send(msg, "direct", user_id, bot_id, "", "")
await asyncio.sleep(0.5) await asyncio.sleep(0.5)
logger.info('[sr推送检查] 私聊推送完成') logger.info("[sr推送检查] 私聊推送完成")
for gid in result[bot_id]['group']: for gid in result[bot_id]["group"]:
msg_list = [] msg_list = []
for user_id in result[bot_id]['group'][gid]: for user_id in result[bot_id]["group"][gid]:
msg_list.append(MessageSegment.at(user_id)) msg_list.append(MessageSegment.at(user_id))
msg = result[bot_id]['group'][gid][user_id] msg = result[bot_id]["group"][gid][user_id]
msg_list.append(MessageSegment.text(msg)) msg_list.append(MessageSegment.text(msg))
await bot.target_send(msg_list, 'group', gid, bot_id, '', '') await bot.target_send(msg_list, "group", gid, bot_id, "", "")
await asyncio.sleep(0.5) await asyncio.sleep(0.5)
logger.info('[sr推送检查] 群聊推送完成') logger.info("[sr推送检查] 群聊推送完成")
@sv_get_stamina.on_fullmatch( @sv_get_stamina.on_fullmatch(
( (
f'{PREFIX}每日', f"{PREFIX}每日",
f'{PREFIX}mr', f"{PREFIX}mr",
f'{PREFIX}实时便笺', f"{PREFIX}实时便笺",
f'{PREFIX}便笺', f"{PREFIX}便笺",
f'{PREFIX}便签', f"{PREFIX}便签",
) )
) )
async def send_daily_info_pic(bot: Bot, ev: Event): async def send_daily_info_pic(bot: Bot, ev: Event):
await bot.logger.info('开始执行[sr每日信息]') await bot.logger.info("开始执行[sr每日信息]")
user_id = ev.at if ev.at else ev.user_id user_id = ev.at if ev.at else ev.user_id
await bot.logger.info(f'[sr每日信息]QQ号: {user_id}') await bot.logger.info(f"[sr每日信息]QQ号: {user_id}")
im = await get_stamina_img(bot.bot_id, user_id) im = await get_stamina_img(bot.bot_id, user_id)
await bot.send(im) await bot.send(im)

View File

@ -3,16 +3,14 @@ from io import BytesIO
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
import aiohttp
from PIL import Image, ImageDraw from PIL import Image, ImageDraw
import aiohttp
from gsuid_core.logger import logger from gsuid_core.logger import logger
from gsuid_core.utils.database.models import GsBind, GsUser from gsuid_core.utils.database.models import GsBind, GsUser
from gsuid_core.utils.image.convert import convert_img
from ..utils.mys_api import mys_api
from ..utils.image.convert import convert_img
from ..sruid_utils.api.mys.models import Expedition from ..sruid_utils.api.mys.models import Expedition
from ..starrailuid_config.sr_config import srconfig from ..starrailuid_config.sr_config import srconfig
from ..utils.image.image_tools import get_simple_bg
from ..utils.error_reply import get_error as get_error_msg from ..utils.error_reply import get_error as get_error_msg
from ..utils.fonts.starrail_fonts import ( from ..utils.fonts.starrail_fonts import (
sr_font_22, sr_font_22,
@ -21,18 +19,20 @@ from ..utils.fonts.starrail_fonts import (
sr_font_36, sr_font_36,
sr_font_50, sr_font_50,
) )
from ..utils.image.image_tools import get_simple_bg
from ..utils.mys_api import mys_api
use_widget = srconfig.get_config('WidgetResin').data use_widget = srconfig.get_config("WidgetResin").data
TEXT_PATH = Path(__file__).parent / 'texture2D' TEXT_PATH = Path(__file__).parent / "texture2D"
note_bg = Image.open(TEXT_PATH / 'note_bg.png') note_bg = Image.open(TEXT_PATH / "note_bg.png")
note_travel_bg = Image.open(TEXT_PATH / 'note_travel_bg.png') note_travel_bg = Image.open(TEXT_PATH / "note_travel_bg.png")
warn_pic = Image.open(TEXT_PATH / 'warn.png') warn_pic = Image.open(TEXT_PATH / "warn.png")
based_w = 700 based_w = 700
based_h = 1200 based_h = 1200
white_overlay = Image.new('RGBA', (based_w, based_h), (255, 251, 242, 225)) white_overlay = Image.new("RGBA", (based_w, based_h), (255, 251, 242, 225))
first_color = (29, 29, 29) first_color = (29, 29, 29)
second_color = (98, 98, 98) second_color = (98, 98, 98)
@ -45,7 +45,7 @@ red_color = (235, 61, 75)
def seconds2hours(seconds: int) -> str: def seconds2hours(seconds: int) -> str:
m, s = divmod(int(seconds), 60) m, s = divmod(int(seconds), 60)
h, m = divmod(m, 60) h, m = divmod(m, 60)
return '%02d:%02d:%02d' % (h, m, s) return "%02d:%02d:%02d" % (h, m, s)
async def download_image(url: str) -> Image.Image: async def download_image(url: str) -> Image.Image:
@ -68,14 +68,14 @@ async def _draw_task_img(
for i in range(2): for i in range(2):
avatar_url = char.avatars[i] avatar_url = char.avatars[i]
image = await download_image(avatar_url) image = await download_image(avatar_url)
char_pic = image.convert('RGBA').resize( char_pic = image.convert("RGBA").resize(
(40, 40), (40, 40),
Image.Resampling.LANCZOS, # type: ignore Image.Resampling.LANCZOS, # type: ignore
) )
note_travel_img.paste(char_pic, (495 + 68 * i, 20), char_pic) note_travel_img.paste(char_pic, (495 + 68 * i, 20), char_pic)
img.paste(note_travel_img, (0, 790 + index * 80), note_travel_img) img.paste(note_travel_img, (0, 790 + index * 80), note_travel_img)
if char.status == 'Finished': if char.status == "Finished":
status_mark = '待收取' status_mark = "待收取"
else: else:
status_mark = str(remaining_time) status_mark = str(remaining_time)
img_draw.text( img_draw.text(
@ -83,55 +83,55 @@ async def _draw_task_img(
expedition_name, expedition_name,
font=sr_font_22, font=sr_font_22,
fill=white_color, fill=white_color,
anchor='lm', anchor="lm",
) )
img_draw.text( img_draw.text(
(380, 830 + index * 80), (380, 830 + index * 80),
status_mark, status_mark,
font=sr_font_22, font=sr_font_22,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
else: else:
note_travel_img = note_travel_bg.copy() note_travel_img = note_travel_bg.copy()
img.paste(note_travel_img, (0, 790 + index * 80), note_travel_img) img.paste(note_travel_img, (0, 790 + index * 80), note_travel_img)
img_draw.text( img_draw.text(
(120, 830 + index * 80), (120, 830 + index * 80),
'等待加入探索队列...', "等待加入探索队列...",
font=sr_font_22, font=sr_font_22,
fill=white_color, fill=white_color,
anchor='lm', anchor="lm",
) )
async def get_stamina_img(bot_id: str, user_id: str): async def get_stamina_img(bot_id: str, user_id: str):
try: try:
uid_list = await GsBind.get_uid_list_by_game(user_id, bot_id, 'sr') uid_list = await GsBind.get_uid_list_by_game(user_id, bot_id, "sr")
logger.info(f'[每日信息]UID: {uid_list}') logger.info(f"[每日信息]UID: {uid_list}")
if uid_list is None: if uid_list is None:
return '请先绑定一个UID再来查询哦~' return "请先绑定一个UID再来查询哦~"
# 进行校验UID是否绑定CK # 进行校验UID是否绑定CK
useable_uid_list = [] useable_uid_list = []
for uid in uid_list: for uid in uid_list:
status = await GsUser.get_user_cookie_by_uid(uid, 'sr') status = await GsUser.get_user_cookie_by_uid(uid, "sr")
if status is not None: if status is not None:
useable_uid_list.append(uid) useable_uid_list.append(uid)
logger.info(f'[每日信息]可用UID: {useable_uid_list}') logger.info(f"[每日信息]可用UID: {useable_uid_list}")
if len(useable_uid_list) == 0: if len(useable_uid_list) == 0:
return '请先绑定一个可用CK & UID再来查询哦~' return "请先绑定一个可用CK & UID再来查询哦~"
# 开始绘图任务 # 开始绘图任务
task = [] task = []
img = Image.new( img = Image.new(
'RGBA', (based_w * len(useable_uid_list), based_h), (0, 0, 0, 0) "RGBA", (based_w * len(useable_uid_list), based_h), (0, 0, 0, 0)
) )
for uid_index, uid in enumerate(useable_uid_list): for uid_index, uid in enumerate(useable_uid_list):
task.append(_draw_all_stamina_img(img, uid, uid_index)) task.append(_draw_all_stamina_img(img, uid, uid_index))
await asyncio.gather(*task) await asyncio.gather(*task)
res = await convert_img(img) res = await convert_img(img)
logger.info('[查询每日信息]绘图已完成,等待发送!') logger.info("[查询每日信息]绘图已完成,等待发送!")
except TypeError: except TypeError:
logger.exception('[查询每日信息]绘图失败!') logger.exception("[查询每日信息]绘图失败!")
res = '你绑定过的UID中可能存在过期CK~请重新绑定一下噢~' res = "你绑定过的UID中可能存在过期CK~请重新绑定一下噢~"
return res return res
@ -147,18 +147,18 @@ def get_error(img: Image.Image, uid: str, daily_data: int):
# 写UID # 写UID
img_draw.text( img_draw.text(
(350, 680), (350, 680),
f'UID{uid}', f"UID{uid}",
font=sr_font_26, font=sr_font_26,
fill=first_color, fill=first_color,
anchor='mm', anchor="mm",
) )
error_text = get_error_msg(daily_data) error_text = get_error_msg(daily_data)
img_draw.text( img_draw.text(
(350, 650), (350, 650),
f'{error_text}, 错误码{daily_data}', f"{error_text}, 错误码{daily_data}",
font=sr_font_26, font=sr_font_26,
fill=red_color, fill=red_color,
anchor='mm', anchor="mm",
) )
return img return img
@ -166,7 +166,7 @@ def get_error(img: Image.Image, uid: str, daily_data: int):
async def seconds2hours_zhcn(seconds: int) -> str: async def seconds2hours_zhcn(seconds: int) -> str:
m, s = divmod(int(seconds), 60) m, s = divmod(int(seconds), 60)
h, m = divmod(m, 60) h, m = divmod(m, 60)
return '%02d小时%02d' % (h, m) return "%02d小时%02d" % (h, m)
async def draw_stamina_img(sr_uid: str) -> Image.Image: async def draw_stamina_img(sr_uid: str) -> Image.Image:
@ -181,7 +181,7 @@ async def draw_stamina_img(sr_uid: str) -> Image.Image:
# daily_data = transform_fake_resin(_daily_data) # daily_data = transform_fake_resin(_daily_data)
daily_data = _daily_data daily_data = _daily_data
else: else:
daily_data = await mys_api.get_daily_data(sr_uid) daily_data = await mys_api.get_sr_daily_data(sr_uid)
if isinstance(daily_data, int): if isinstance(daily_data, int):
return get_error(img, sr_uid, daily_data) return get_error(img, sr_uid, daily_data)
@ -194,13 +194,13 @@ async def draw_stamina_img(sr_uid: str) -> Image.Image:
nickname = role_basic_info.nickname nickname = role_basic_info.nickname
level = role_basic_info.level level = role_basic_info.level
else: else:
nickname = '开拓者' nickname = "开拓者"
level = '0' level = "0"
# 开拓力 # 开拓力
stamina = daily_data.current_stamina stamina = daily_data.current_stamina
max_stamina = daily_data.max_stamina max_stamina = daily_data.max_stamina
stamina_str = f'{stamina}/{max_stamina}' stamina_str = f"{stamina}/{max_stamina}"
stamina_percent = stamina / max_stamina stamina_percent = stamina / max_stamina
if stamina_percent > 0.8: if stamina_percent > 0.8:
stamina_color = red_color stamina_color = red_color
@ -216,31 +216,23 @@ async def draw_stamina_img(sr_uid: str) -> Image.Image:
# 派遣 # 派遣
task_task = [] task_task = []
for i in range(4): for i in range(4):
char = ( char = daily_data.expeditions[i] if i < len(daily_data.expeditions) else None
daily_data.expeditions[i]
if i < len(daily_data.expeditions)
else None
)
task_task.append(_draw_task_img(img, img_draw, i, char)) task_task.append(_draw_task_img(img, img_draw, i, char))
await asyncio.gather(*task_task) await asyncio.gather(*task_task)
# 绘制树脂圆环 # 绘制树脂圆环
ring_pic = Image.open(TEXT_PATH / 'ring.apng') ring_pic = Image.open(TEXT_PATH / "ring.apng")
percent = ( percent = round(stamina_percent * 89) if round(stamina_percent * 89) <= 89 else 89
round(stamina_percent * 89)
if round(stamina_percent * 89) <= 89
else 89
)
ring_pic.seek(percent) ring_pic.seek(percent)
img.paste(ring_pic, (0, 5), ring_pic) img.paste(ring_pic, (0, 5), ring_pic)
# 写树脂剩余时间 # 写树脂剩余时间
img_draw.text( img_draw.text(
(350, 490), (350, 490),
f'还剩{stamina_recovery_time}', f"还剩{stamina_recovery_time}",
font=sr_font_24, font=sr_font_24,
fill=stamina_color, fill=stamina_color,
anchor='mm', anchor="mm",
) )
# 写Nickname # 写Nickname
img_draw.text( img_draw.text(
@ -248,23 +240,23 @@ async def draw_stamina_img(sr_uid: str) -> Image.Image:
nickname, nickname,
font=sr_font_36, font=sr_font_36,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
# 写开拓等级 # 写开拓等级
img_draw.text( img_draw.text(
(350, 190), (350, 190),
f'开拓等级{level}', f"开拓等级{level}",
font=sr_font_24, font=sr_font_24,
fill=white_color, fill=white_color,
anchor='mm', anchor="mm",
) )
# 写UID # 写UID
img_draw.text( img_draw.text(
(350, 663), (350, 663),
f'UID{sr_uid}', f"UID{sr_uid}",
font=sr_font_26, font=sr_font_26,
fill=first_color, fill=first_color,
anchor='mm', anchor="mm",
) )
# 写树脂 # 写树脂
img_draw.text( img_draw.text(
@ -272,7 +264,7 @@ async def draw_stamina_img(sr_uid: str) -> Image.Image:
stamina_str, stamina_str,
font=sr_font_50, font=sr_font_50,
fill=first_color, fill=first_color,
anchor='mm', anchor="mm",
) )
return img return img

View File

@ -8,11 +8,11 @@ from ..sruid_utils.api.mys.models import DailyNoteData
from ..starrailuid_config.sr_config import srconfig from ..starrailuid_config.sr_config import srconfig
from ..utils.mys_api import mys_api from ..utils.mys_api import mys_api
MR_NOTICE = '\n可发送[srmr]或者[sr每日]来查看更多信息!\n' MR_NOTICE = "\n可发送[srmr]或者[sr每日]来查看更多信息!\n"
NOTICE = { NOTICE = {
'stamina': f'你的开拓力快满啦!{MR_NOTICE}', "stamina": f"你的开拓力快满啦!{MR_NOTICE}",
'go': f'你有派遣信息即将可收取!{MR_NOTICE}', "go": f"你有派遣信息即将可收取!{MR_NOTICE}",
} }
@ -22,11 +22,11 @@ async def get_notice_list() -> Dict[str, Dict[str, Dict]]:
user_list = await GsUser.get_all_push_user_list() user_list = await GsUser.get_all_push_user_list()
for user in user_list: for user in user_list:
if user.sr_uid is not None: if user.sr_uid is not None:
raw_data = await mys_api.get_daily_data(user.sr_uid) raw_data = await mys_api.get_sr_daily_data(user.sr_uid)
if isinstance(raw_data, int): if isinstance(raw_data, int):
logger.error(f'[sr推送提醒]获取{user.sr_uid}的数据失败!') logger.error(f"[sr推送提醒]获取{user.sr_uid}的数据失败!")
continue continue
push_data = await GsPush.select_data_by_uid(user.sr_uid, 'sr') push_data = await GsPush.select_data_by_uid(user.sr_uid, "sr")
msg_dict = await all_check( msg_dict = await all_check(
user.bot_id, user.bot_id,
raw_data, raw_data,
@ -48,59 +48,59 @@ async def all_check(
) -> Dict[str, Dict[str, Dict]]: ) -> Dict[str, Dict[str, Dict]]:
for mode in NOTICE.keys(): for mode in NOTICE.keys():
# 检查条件 # 检查条件
if push_data[f'{mode}_is_push'] == 'on': if push_data[f"{mode}_is_push"] == "on":
if srconfig.get_config('CrazyNotice').data: if srconfig.get_config("CrazyNotice").data:
if not await check(mode, raw_data, push_data[f'{mode}_value']): if not await check(mode, raw_data, push_data[f"{mode}_value"]):
await GsPush.update_data_by_uid( await GsPush.update_data_by_uid(
uid, bot_id, 'sr', **{f'{mode}_is_push': 'off'} uid, bot_id, "sr", **{f"{mode}_is_push": "off"}
) )
continue continue
# 准备推送 # 准备推送
if await check(mode, raw_data, push_data[f'{mode}_value']): if await check(mode, raw_data, push_data[f"{mode}_value"]):
if push_data[f'{mode}_push'] == 'off': if push_data[f"{mode}_push"] == "off":
pass pass
# on 推送到私聊 # on 推送到私聊
else: else:
# 初始化 # 初始化
if bot_id not in msg_dict: if bot_id not in msg_dict:
msg_dict[bot_id] = {'direct': {}, 'group': {}} msg_dict[bot_id] = {"direct": {}, "group": {}}
if push_data[f'{mode}_push'] == 'on': if push_data[f"{mode}_push"] == "on":
# 添加私聊信息 # 添加私聊信息
if user_id not in msg_dict[bot_id]['direct']: if user_id not in msg_dict[bot_id]["direct"]:
msg_dict[bot_id]['direct'][user_id] = NOTICE[mode] msg_dict[bot_id]["direct"][user_id] = NOTICE[mode]
else: else:
msg_dict[bot_id]['direct'][user_id] += NOTICE[mode] msg_dict[bot_id]["direct"][user_id] += NOTICE[mode]
await GsPush.update_data_by_uid( await GsPush.update_data_by_uid(
uid, bot_id, 'sr', **{f'{mode}_is_push': 'on'} uid, bot_id, "sr", **{f"{mode}_is_push": "on"}
) )
# 群号推送到群聊 # 群号推送到群聊
else: else:
# 初始化 # 初始化
gid = push_data[f'{mode}_push'] gid = push_data[f"{mode}_push"]
if gid not in msg_dict[bot_id]['group']: if gid not in msg_dict[bot_id]["group"]:
msg_dict[bot_id]['group'][gid] = {} msg_dict[bot_id]["group"][gid] = {}
if user_id not in msg_dict[bot_id]['group'][gid]: if user_id not in msg_dict[bot_id]["group"][gid]:
msg_dict[bot_id]['group'][gid][user_id] = NOTICE[mode] msg_dict[bot_id]["group"][gid][user_id] = NOTICE[mode]
else: else:
msg_dict[bot_id]['group'][gid][user_id] += NOTICE[mode] msg_dict[bot_id]["group"][gid][user_id] += NOTICE[mode]
await GsPush.update_data_by_uid( await GsPush.update_data_by_uid(
uid, bot_id, 'sr', **{f'{mode}_is_push': 'on'} uid, bot_id, "sr", **{f"{mode}_is_push": "on"}
) )
return msg_dict return msg_dict
async def check(mode: str, data: DailyNoteData, limit: int) -> bool: async def check(mode: str, data: DailyNoteData, limit: int) -> bool:
if mode == 'resin': if mode == "resin":
if data.current_stamina >= limit: if data.current_stamina >= limit:
return True return True
if data.current_stamina >= data.max_stamina: if data.current_stamina >= data.max_stamina:
return True return True
return False return False
if mode == 'go': if mode == "go":
for i in data.expeditions: for i in data.expeditions:
if i.status == 'Ongoing': if i.status == "Ongoing":
if i.remaining_time <= limit * 60: if i.remaining_time <= limit * 60:
return True return True
else: else:

View File

@ -2,8 +2,8 @@ from typing import List
from gsuid_core.logger import logger from gsuid_core.logger import logger
from ..utils.mys_api import mys_api
from ..utils.error_reply import get_error from ..utils.error_reply import get_error
from ..utils.mys_api import mys_api
daily_im = """*数据刷新可能存在一定延迟,请以当前游戏实际数据为准 daily_im = """*数据刷新可能存在一定延迟,请以当前游戏实际数据为准
============== ==============
@ -16,31 +16,27 @@ daily_im = """*数据刷新可能存在一定延迟,请以当前游戏实际数
def seconds2hours(seconds: int) -> str: def seconds2hours(seconds: int) -> str:
m, s = divmod(int(seconds), 60) m, s = divmod(int(seconds), 60)
h, m = divmod(m, 60) h, m = divmod(m, 60)
return '%02d:%02d:%02d' % (h, m, s) return "%02d:%02d:%02d" % (h, m, s)
async def get_stamina_text(uid: str) -> str: async def get_stamina_text(uid: str) -> str:
try: try:
dailydata = await mys_api.get_daily_data(uid) dailydata = await mys_api.get_sr_daily_data(uid)
if isinstance(dailydata, int): if isinstance(dailydata, int):
return get_error(dailydata) return get_error(dailydata)
max_stamina = dailydata.max_stamina max_stamina = dailydata.max_stamina
rec_time = '' rec_time = ""
current_stamina = dailydata.current_stamina current_stamina = dailydata.current_stamina
if current_stamina < 160: if current_stamina < 160:
stamina_recover_time = seconds2hours( stamina_recover_time = seconds2hours(dailydata.stamina_recover_time)
dailydata.stamina_recover_time
)
next_stamina_rec_time = seconds2hours( next_stamina_rec_time = seconds2hours(
8 * 60 8 * 60
- ( - (
(dailydata.max_stamina - dailydata.current_stamina) (dailydata.max_stamina - dailydata.current_stamina) * 8 * 60
* 8
* 60
- dailydata.stamina_recover_time - dailydata.stamina_recover_time
) )
) )
rec_time = f' ({next_stamina_rec_time}/{stamina_recover_time})' rec_time = f" ({next_stamina_rec_time}/{stamina_recover_time})"
accepted_epedition_num = dailydata.accepted_expedition_num accepted_epedition_num = dailydata.accepted_expedition_num
total_expedition_num = dailydata.total_expedition_num total_expedition_num = dailydata.total_expedition_num
@ -49,16 +45,14 @@ async def get_stamina_text(uid: str) -> str:
for expedition in dailydata.expeditions: for expedition in dailydata.expeditions:
expedition_name = expedition.name expedition_name = expedition.name
if expedition.status == 'Finished': if expedition.status == "Finished":
expedition_info.append(f'{expedition_name} 探索完成') expedition_info.append(f"{expedition_name} 探索完成")
finished_expedition_num += 1 finished_expedition_num += 1
else: else:
remaining_time: str = seconds2hours(expedition.remaining_time) remaining_time: str = seconds2hours(expedition.remaining_time)
expedition_info.append( expedition_info.append(f"{expedition_name} 剩余时间{remaining_time}")
f'{expedition_name} 剩余时间{remaining_time}'
)
expedition_data = '\n'.join(expedition_info) expedition_data = "\n".join(expedition_info)
return daily_im.format( return daily_im.format(
current_stamina, current_stamina,
max_stamina, max_stamina,
@ -69,5 +63,5 @@ async def get_stamina_text(uid: str) -> str:
expedition_data, expedition_data,
) )
except TypeError: except TypeError:
logger.exception('[查询当前状态]查询失败!') logger.exception("[查询当前状态]查询失败!")
return '你绑定过的UID中可能存在过期CK~请重新绑定一下噢~' return "你绑定过的UID中可能存在过期CK~请重新绑定一下噢~"

View File

@ -7,72 +7,72 @@ from ..utils.message import send_diff_msg
from ..utils.sr_prefix import PREFIX from ..utils.sr_prefix import PREFIX
from .draw_user_card import get_user_card from .draw_user_card import get_user_card
sv_user_config = SV('sr用户管理', pm=2) sv_user_config = SV("sr用户管理", pm=2)
sv_user_info = SV('sr用户信息') sv_user_info = SV("sr用户信息")
@sv_user_info.on_fullmatch(f'{PREFIX}绑定信息') @sv_user_info.on_fullmatch(f"{PREFIX}绑定信息")
async def send_bind_card(bot: Bot, ev: Event): async def send_bind_card(bot: Bot, ev: Event):
await bot.logger.info('sr开始执行[查询用户绑定状态]') await bot.logger.info("sr开始执行[查询用户绑定状态]")
uid_list = await get_user_card(ev.bot_id, ev.user_id) uid_list = await get_user_card(ev.bot_id, ev.user_id)
if not uid_list: if not uid_list:
return await bot.send('你还没有绑定SR_UID哦!') return await bot.send("你还没有绑定SR_UID哦!")
await bot.logger.info('sr[查询用户绑定状态]完成!等待图片发送中...') await bot.logger.info("sr[查询用户绑定状态]完成!等待图片发送中...")
await bot.send(uid_list) await bot.send(uid_list)
return None return None
@sv_user_info.on_command( @sv_user_info.on_command(
( (
f'{PREFIX}绑定uid', f"{PREFIX}绑定uid",
f'{PREFIX}切换uid', f"{PREFIX}切换uid",
f'{PREFIX}删除uid', f"{PREFIX}删除uid",
f'{PREFIX}解绑uid', f"{PREFIX}解绑uid",
) )
) )
async def send_link_uid_msg(bot: Bot, ev: Event): async def send_link_uid_msg(bot: Bot, ev: Event):
await bot.logger.info('sr开始执行[绑定/解绑用户信息]') await bot.logger.info("sr开始执行[绑定/解绑用户信息]")
qid = ev.user_id qid = ev.user_id
await bot.logger.info(f'sr[绑定/解绑]UserID: {qid}') await bot.logger.info(f"sr[绑定/解绑]UserID: {qid}")
sr_uid = ev.text.strip() sr_uid = ev.text.strip()
if sr_uid and not sr_uid.isdigit(): if sr_uid and not sr_uid.isdigit():
return await bot.send('你输入了错误的格式!') return await bot.send("你输入了错误的格式!")
if '绑定' in ev.command: if "绑定" in ev.command:
data = await GsBind.insert_uid( data = await GsBind.insert_uid(
qid, ev.bot_id, sr_uid, ev.group_id, 9, game_name='sr' qid, ev.bot_id, sr_uid, ev.group_id, 9, game_name="sr"
) )
return await send_diff_msg( return await send_diff_msg(
bot, bot,
data, data,
{ {
0: f'✅[崩铁]绑定UID{sr_uid}成功!', 0: f"✅[崩铁]绑定UID{sr_uid}成功!",
-1: f'❌SR_UID{sr_uid}的位数不正确!', -1: f"❌SR_UID{sr_uid}的位数不正确!",
-2: f'❌SR_UID{sr_uid}已经绑定过了!', -2: f"❌SR_UID{sr_uid}已经绑定过了!",
-3: '❌你输入了错误的格式!', -3: "❌你输入了错误的格式!",
}, },
) )
if '切换' in ev.command: if "切换" in ev.command:
data = await GsBind.switch_uid_by_game(qid, ev.bot_id, sr_uid, 'sr') data = await GsBind.switch_uid_by_game(qid, ev.bot_id, sr_uid, "sr")
return await send_diff_msg( return await send_diff_msg(
bot, bot,
data, data,
{ {
0: f'✅[崩铁]切换uid{sr_uid}成功!', 0: f"✅[崩铁]切换uid{sr_uid}成功!",
-1: '❌[崩铁]不存在绑定记录!', -1: "❌[崩铁]不存在绑定记录!",
-2: '❌[崩铁]请绑定两个以上UID再进行切换!', -2: "❌[崩铁]请绑定两个以上UID再进行切换!",
-3: '❌[崩铁]请绑定两个以上UID再进行切换!', -3: "❌[崩铁]请绑定两个以上UID再进行切换!",
}, },
) )
data = await GsBind.delete_uid(qid, ev.bot_id, sr_uid, 'sr') data = await GsBind.delete_uid(qid, ev.bot_id, sr_uid, "sr")
return await send_diff_msg( return await send_diff_msg(
bot, bot,
data, data,
{ {
0: f'✅[崩铁]删除UID{sr_uid}成功!', 0: f"✅[崩铁]删除UID{sr_uid}成功!",
-1: f'❌[崩铁]该UID{sr_uid}不在已绑定列表中!', -1: f"❌[崩铁]该UID{sr_uid}不在已绑定列表中!",
}, },
) )

View File

@ -20,104 +20,104 @@ from ..utils.resource.RESOURCE_PATH import (
WIKI_MATERIAL_FOR_ROLE, WIKI_MATERIAL_FOR_ROLE,
) )
sv_sr_wiki = SV('星铁WIKI') sv_sr_wiki = SV("星铁WIKI")
sv_sr_guide = SV('星铁攻略') sv_sr_guide = SV("星铁攻略")
@sv_sr_wiki.on_prefix('sr角色图鉴') @sv_sr_wiki.on_prefix("sr角色图鉴")
async def send_role_wiki_pic(bot: Bot, ev: Event): async def send_role_wiki_pic(bot: Bot, ev: Event):
char_name = ' '.join(re.findall('[\u4e00-\u9fa5]+', ev.text)) char_name = " ".join(re.findall("[\u4e00-\u9fa5]+", ev.text))
await bot.logger.info(f'开始获取{char_name}图鉴') await bot.logger.info(f"开始获取{char_name}图鉴")
if '开拓者' in str(char_name): if "开拓者" in str(char_name):
char_name = '开拓者' char_name = "开拓者"
char_id = await name_to_avatar_id(char_name) char_id = await name_to_avatar_id(char_name)
if char_id == '': if char_id == "":
char_name = await alias_to_char_name(char_name) char_name = await alias_to_char_name(char_name)
char_id = await name_to_avatar_id(char_name) char_id = await name_to_avatar_id(char_name)
img = WIKI_ROLE_PATH / f'{char_id}.png' img = WIKI_ROLE_PATH / f"{char_id}.png"
if img.exists(): if img.exists():
img = await convert_img(img) img = await convert_img(img)
await bot.logger.info(f'获得{char_name}图鉴图片成功!') await bot.logger.info(f"获得{char_name}图鉴图片成功!")
await bot.send(img) await bot.send(img)
else: else:
await bot.logger.warning(f'未找到{char_name}图鉴图片') await bot.logger.warning(f"未找到{char_name}图鉴图片")
@sv_sr_guide.on_prefix('sr角色攻略') @sv_sr_guide.on_prefix("sr角色攻略")
async def send_role_guide_pic(bot: Bot, ev: Event): async def send_role_guide_pic(bot: Bot, ev: Event):
char_name = ' '.join(re.findall('[\u4e00-\u9fa5]+', ev.text)) char_name = " ".join(re.findall("[\u4e00-\u9fa5]+", ev.text))
await bot.logger.info(f'开始获取{char_name}图鉴') await bot.logger.info(f"开始获取{char_name}图鉴")
if '开拓者' in str(char_name): if "开拓者" in str(char_name):
char_name = '开拓者' char_name = "开拓者"
char_id = await name_to_avatar_id(char_name) char_id = await name_to_avatar_id(char_name)
if char_id == '': if char_id == "":
char_name = await alias_to_char_name(char_name) char_name = await alias_to_char_name(char_name)
char_id = await name_to_avatar_id(char_name) char_id = await name_to_avatar_id(char_name)
img = GUIDE_CHARACTER_PATH / f'{char_id}.png' img = GUIDE_CHARACTER_PATH / f"{char_id}.png"
if img.exists(): if img.exists():
img = await convert_img(img) img = await convert_img(img)
await bot.logger.info(f'获得{char_id}图鉴图片成功!') await bot.logger.info(f"获得{char_id}图鉴图片成功!")
await bot.send(img) await bot.send(img)
else: else:
await bot.logger.warning(f'未找到{char_id}图鉴图片') await bot.logger.warning(f"未找到{char_id}图鉴图片")
@sv_sr_guide.on_prefix('sr光锥攻略') @sv_sr_guide.on_prefix("sr光锥攻略")
async def send_weapon_guide_pic(bot: Bot, ev: Event): async def send_weapon_guide_pic(bot: Bot, ev: Event):
msg = ' '.join(re.findall('[\u4e00-\u9fa5]+', ev.text)) msg = " ".join(re.findall("[\u4e00-\u9fa5]+", ev.text))
await bot.logger.info(f'开始获取{msg}图鉴') await bot.logger.info(f"开始获取{msg}图鉴")
light_cone_id = await name_to_weapon_id(msg) light_cone_id = await name_to_weapon_id(msg)
img = GUIDE_LIGHT_CONE_PATH / f'{light_cone_id}.png' img = GUIDE_LIGHT_CONE_PATH / f"{light_cone_id}.png"
if img.exists(): if img.exists():
img = await convert_img(img) img = await convert_img(img)
await bot.logger.info(f'获得{light_cone_id}光锥图片成功!') await bot.logger.info(f"获得{light_cone_id}光锥图片成功!")
await bot.send(img) await bot.send(img)
else: else:
await bot.logger.warning(f'未找到{light_cone_id}光锥图片') await bot.logger.warning(f"未找到{light_cone_id}光锥图片")
@sv_sr_wiki.on_prefix('sr遗器') @sv_sr_wiki.on_prefix("sr遗器")
async def send_relic_wiki_pic(bot: Bot, ev: Event): async def send_relic_wiki_pic(bot: Bot, ev: Event):
msg = ' '.join(re.findall('[\u4e00-\u9fa5]+', ev.text)) msg = " ".join(re.findall("[\u4e00-\u9fa5]+", ev.text))
await bot.logger.info(f'开始获取{msg}遗器') await bot.logger.info(f"开始获取{msg}遗器")
set_id = await name_to_relic_set_id(msg) set_id = await name_to_relic_set_id(msg)
img = WIKI_RELIC_PATH / f'{set_id}.png' img = WIKI_RELIC_PATH / f"{set_id}.png"
if img.exists(): if img.exists():
img = await convert_img(img) img = await convert_img(img)
await bot.logger.info(f'获得{msg}遗器图片成功!') await bot.logger.info(f"获得{msg}遗器图片成功!")
await bot.send(img) await bot.send(img)
else: else:
await bot.logger.warning(f'未找到{msg}遗器图片') await bot.logger.warning(f"未找到{msg}遗器图片")
@sv_sr_wiki.on_prefix('sr突破材料') @sv_sr_wiki.on_prefix("sr突破材料")
async def send_material_for_role_wiki_pic(bot: Bot, ev: Event): async def send_material_for_role_wiki_pic(bot: Bot, ev: Event):
char_name = ' '.join(re.findall('[\u4e00-\u9fa5]+', ev.text)) char_name = " ".join(re.findall("[\u4e00-\u9fa5]+", ev.text))
await bot.logger.info(f'开始获取{char_name}突破材料') await bot.logger.info(f"开始获取{char_name}突破材料")
if '开拓者' in str(char_name): if "开拓者" in str(char_name):
char_name = '开拓者' char_name = "开拓者"
char_id = await name_to_avatar_id(char_name) char_id = await name_to_avatar_id(char_name)
if char_id == '': if char_id == "":
char_name = await alias_to_char_name(char_name) char_name = await alias_to_char_name(char_name)
char_id = await name_to_avatar_id(char_name) char_id = await name_to_avatar_id(char_name)
img = WIKI_MATERIAL_FOR_ROLE / f'{char_id}.png' img = WIKI_MATERIAL_FOR_ROLE / f"{char_id}.png"
if img.exists(): if img.exists():
img = await convert_img(img) img = await convert_img(img)
await bot.logger.info(f'获得{char_name}突破材料图片成功!') await bot.logger.info(f"获得{char_name}突破材料图片成功!")
await bot.send(img) await bot.send(img)
else: else:
await bot.logger.warning(f'未找到{char_name}突破材料图片') await bot.logger.warning(f"未找到{char_name}突破材料图片")
@sv_sr_wiki.on_prefix('sr武器') @sv_sr_wiki.on_prefix("sr武器")
async def send_light_cone_wiki_pic(bot: Bot, ev: Event): async def send_light_cone_wiki_pic(bot: Bot, ev: Event):
msg = ' '.join(re.findall('[\u4e00-\u9fa5]+', ev.text)) msg = " ".join(re.findall("[\u4e00-\u9fa5]+", ev.text))
await bot.logger.info(f'开始获取{msg}武器') await bot.logger.info(f"开始获取{msg}武器")
light_cone_id = await name_to_weapon_id(msg) light_cone_id = await name_to_weapon_id(msg)
img = WIKI_LIGHT_CONE_PATH / f'{light_cone_id}.png' img = WIKI_LIGHT_CONE_PATH / f"{light_cone_id}.png"
if img.exists(): if img.exists():
img = await convert_img(img) img = await convert_img(img)
await bot.logger.info(f'获得{msg}武器图片成功!') await bot.logger.info(f"获得{msg}武器图片成功!")
await bot.send(img) await bot.send(img)
else: else:
await bot.logger.warning(f'未找到{msg}武器图片') await bot.logger.warning(f"未找到{msg}武器图片")

View File

@ -1,36 +1,12 @@
import re from typing import Optional, Tuple, Union
from typing import Tuple, Union, Optional, overload
from gsuid_core.bot import Bot from gsuid_core.bot import Bot
from gsuid_core.models import Event from gsuid_core.models import Event
from gsuid_core.utils.database.api import get_uid as get_uid_db
from gsuid_core.utils.database.models import GsBind from gsuid_core.utils.database.models import GsBind
@overload
async def get_uid( async def get_uid(
bot: Bot, ev: Event, get_user_id: bool = False, only_uid: bool = False bot: Bot, ev: Event, get_user_id: bool = False
) -> Optional[str]: ...
@overload
async def get_uid(
bot: Bot, ev: Event, get_user_id: bool = True, only_uid: bool = False
) -> Tuple[Optional[str], str]: ...
async def get_uid(
bot: Bot, ev: Event, get_user_id: bool = False, only_uid: bool = False
) -> Union[Optional[str], Tuple[Optional[str], str]]: ) -> Union[Optional[str], Tuple[Optional[str], str]]:
uid_data = re.findall(r'\d{9}', ev.text) return await get_uid_db(bot, ev, GsBind, "sr", get_user_id) # type: ignore
user_id = ev.at if ev.at else ev.user_id
if uid_data:
sr_uid: Optional[str] = uid_data[0]
if sr_uid:
ev.text = ev.text.replace(sr_uid, '')
else:
sr_uid = await GsBind.get_uid_by_game(ev.user_id, ev.bot_id, 'sr')
if only_uid:
sr_uid = await GsBind.get_uid_by_game(ev.user_id, ev.bot_id, 'sr')
if get_user_id:
return sr_uid, user_id
return sr_uid

View File

@ -1,16 +1,16 @@
from typing import Union from typing import Union
UID_HINT = '你还没有绑定过uid哦!\n请使用[sr绑定uid123456]命令绑定!' UID_HINT = "你还没有绑定过uid哦!\n请使用[sr绑定uid123456]命令绑定!"
MYS_HINT = '你还没有绑定过mysid哦!\n请使用[绑定mys1234]命令绑定!' MYS_HINT = "你还没有绑定过mysid哦!\n请使用[绑定mys1234]命令绑定!"
CK_HINT = """你还没有绑定过Cookie哦!发送【ck帮助】获取帮助! CK_HINT = """你还没有绑定过Cookie哦!发送【ck帮助】获取帮助!
警告:绑定Cookie可能会带来未知的账号风险,请确保信任机器人管理员""" 警告:绑定Cookie可能会带来未知的账号风险,请确保信任机器人管理员"""
CHAR_HINT = '您的支援/星海同行角色没有{}的数据哦!\n请先把{}放入支援/星海同行中再使用【sr强制刷新】命令来缓存数据进行查询! !' CHAR_HINT = "您的支援/星海同行角色没有{}的数据哦!\n请先把{}放入支援/星海同行中再使用【sr强制刷新】命令来缓存数据进行查询! !"
VERIFY_HINT = """出现验证码! VERIFY_HINT = """出现验证码!
如已绑定CK: 请至米游社软件->我的->我的角色处解锁验证码 如已绑定CK: 请至米游社软件->我的->我的角色处解锁验证码
(可使用[gs关闭推送]命令关闭体力推送以减少出现验证码风险) (可使用[gs关闭推送]命令关闭体力推送以减少出现验证码风险)
如未绑定CK: 可联系管理员使用[gs清除缓存]命令 如未绑定CK: 可联系管理员使用[gs清除缓存]命令
""" """
SK_HINT = '你还没有绑定过Stoken或者Stoken已失效~\n请群聊发送 [扫码登陆] 或加好友私聊Bot [添加]后跟SK格式 以绑定SK' SK_HINT = "你还没有绑定过Stoken或者Stoken已失效~\n请群聊发送 [扫码登陆] 或加好友私聊Bot [添加]后跟SK格式 以绑定SK"
UPDATE_HINT = """更新失败!更多错误信息请查看控制台... UPDATE_HINT = """更新失败!更多错误信息请查看控制台...
>> 可以尝试使用 >> 可以尝试使用
>> [gs强制更新](危险) >> [gs强制更新](危险)
@ -21,27 +21,27 @@ def get_error(retcode: Union[int, str]) -> str:
if retcode == -51: if retcode == -51:
return CK_HINT return CK_HINT
if retcode == -100: if retcode == -100:
return '您的cookie已经失效, 请重新获取!' return "您的cookie已经失效, 请重新获取!"
if retcode == 10001: if retcode == 10001:
return '您的cookie已经失效, 请重新获取!' return "您的cookie已经失效, 请重新获取!"
if retcode == 10101: if retcode == 10101:
return '当前查询CK已超过每日30次上限!' return "当前查询CK已超过每日30次上限!"
if retcode == 10102: if retcode == 10102:
return '当前查询id已经设置了隐私, 无法查询!' return "当前查询id已经设置了隐私, 无法查询!"
if retcode == 1034: if retcode == 1034:
return VERIFY_HINT return VERIFY_HINT
if retcode == -10001: if retcode == -10001:
return '请求体出错, 请检查具体实现代码...' return "请求体出错, 请检查具体实现代码..."
if retcode == 10104: if retcode == 10104:
return CK_HINT return CK_HINT
if retcode == -512009: if retcode == -512009:
return '[留影叙佳期]已经获取过该内容~!' return "[留影叙佳期]已经获取过该内容~!"
if retcode == -201: if retcode == -201:
return '你的账号可能已被封禁, 请联系米游社客服...' return "你的账号可能已被封禁, 请联系米游社客服..."
if retcode == -501101: if retcode == -501101:
return '当前角色冒险等阶未达到10级, 暂时无法参加此活动...' return "当前角色冒险等阶未达到10级, 暂时无法参加此活动..."
if retcode == 400: if retcode == 400:
return '[MINIGG]暂未找到此内容...' return "[MINIGG]暂未找到此内容..."
if retcode == -400: if retcode == -400:
return '请输入更详细的名称...' return "请输入更详细的名称..."
return f'API报错, 错误码为{retcode}!' return f"API报错, 错误码为{retcode}!"

View File

@ -88,8 +88,6 @@ class SingleRelicSubAffix(Struct):
AvatarPromotionConfig = convert(AvatarPromotion, List[SingleAvatarPromotion]) AvatarPromotionConfig = convert(AvatarPromotion, List[SingleAvatarPromotion])
EquipmentPromotionConfig = convert( EquipmentPromotionConfig = convert(EquipmentPromotion, List[SingleEquipmentPromotion])
EquipmentPromotion, List[SingleEquipmentPromotion]
)
RelicMainAffixConfig = convert(RelicMainAffix, List[SingleRelicMainAffix]) RelicMainAffixConfig = convert(RelicMainAffix, List[SingleRelicMainAffix])
RelicSubAffixConfig = convert(RelicSubAffix, List[SingleRelicSubAffix]) RelicSubAffixConfig = convert(RelicSubAffix, List[SingleRelicSubAffix])

View File

@ -3,17 +3,17 @@ from pathlib import Path
EXCEL = Path(__file__).parent EXCEL = Path(__file__).parent
with Path.open(EXCEL / 'RelicMainAffixConfig.json', encoding='utf8') as f: with Path.open(EXCEL / "RelicMainAffixConfig.json", encoding="utf8") as f:
RelicMainAffix = json.load(f) RelicMainAffix = json.load(f)
with Path.open(EXCEL / 'RelicSubAffixConfig.json', encoding='utf8') as f: with Path.open(EXCEL / "RelicSubAffixConfig.json", encoding="utf8") as f:
RelicSubAffix = json.load(f) RelicSubAffix = json.load(f)
with Path.open(EXCEL / 'AvatarPromotionConfig.json', encoding='utf8') as f: with Path.open(EXCEL / "AvatarPromotionConfig.json", encoding="utf8") as f:
AvatarPromotion = json.load(f) AvatarPromotion = json.load(f)
with Path.open(EXCEL / 'EquipmentPromotionConfig.json', encoding='utf8') as f: with Path.open(EXCEL / "EquipmentPromotionConfig.json", encoding="utf8") as f:
EquipmentPromotion = json.load(f) EquipmentPromotion = json.load(f)
with Path.open(EXCEL / 'light_cone_ranks.json', encoding='utf8') as f: with Path.open(EXCEL / "light_cone_ranks.json", encoding="utf8") as f:
light_cone_ranks = json.load(f) light_cone_ranks = json.load(f)

View File

@ -2,7 +2,7 @@ from pathlib import Path
from PIL import ImageFont from PIL import ImageFont
FONT_ORIGIN_PATH = Path(__file__).parent / 'FirstWorld.ttf' FONT_ORIGIN_PATH = Path(__file__).parent / "FirstWorld.ttf"
def first_word_origin(size: int) -> ImageFont.FreeTypeFont: def first_word_origin(size: int) -> ImageFont.FreeTypeFont:

View File

@ -2,7 +2,7 @@ from pathlib import Path
from PIL import ImageFont from PIL import ImageFont
FONT_ORIGIN_PATH = Path(__file__).parent / 'starrail_origin.ttf' FONT_ORIGIN_PATH = Path(__file__).parent / "starrail_origin.ttf"
def starrail_font_origin(size: int) -> ImageFont.FreeTypeFont: def starrail_font_origin(size: int) -> ImageFont.FreeTypeFont:

View File

@ -1,107 +0,0 @@
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
) -> Union[str, bytes]:
"""
:说明:
将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
if 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
if hasattr(font, 'getsize'):
size, _ = font.getsize(line) # type: ignore
else:
size, _, _, _ = font.getbbox(line)
if size >= limit:
result += f'{line}\n'
line = ''
result += line
return result
def get_height(content: str, size: int) -> int:
line_count = content.count('\n')
return (line_count + 1) * size

View File

@ -7,9 +7,9 @@ from gsuid_core.utils.image.image_tools import TEXT_PATH, CustomizeImage
from ..resource.RESOURCE_PATH import CU_BG_PATH from ..resource.RESOURCE_PATH import CU_BG_PATH
from ...starrailuid_config.sr_config import srconfig from ...starrailuid_config.sr_config import srconfig
BG_PATH = Path(__file__).parent / 'bg' BG_PATH = Path(__file__).parent / "bg"
NM_BG_PATH = BG_PATH / 'nm_bg' NM_BG_PATH = BG_PATH / "nm_bg"
SP_BG_PATH = BG_PATH / 'sp_bg' SP_BG_PATH = BG_PATH / "sp_bg"
if list(CU_BG_PATH.iterdir()) != []: if list(CU_BG_PATH.iterdir()) != []:
bg_path = CU_BG_PATH bg_path = CU_BG_PATH
@ -35,10 +35,10 @@ async def get_color_bg(
bg: Optional[str] = None, bg: Optional[str] = None,
without_mask: bool = False, without_mask: bool = False,
) -> Image.Image: ) -> Image.Image:
image = '' image = ""
if bg and srconfig.get_config('DefaultBaseBG').data: if bg and srconfig.get_config("DefaultBaseBG").data:
path = SP_BG_PATH / f'{bg}.jpg' path = SP_BG_PATH / f"{bg}.jpg"
path2 = CU_BG_PATH / f'{bg}.jpg' path2 = CU_BG_PATH / f"{bg}.jpg"
if path2.exists(): if path2.exists():
image = Image.open(path2) image = Image.open(path2)
elif path.exists(): elif path.exists():
@ -47,9 +47,7 @@ async def get_color_bg(
img = CI_img.get_image(image, based_w, based_h) img = CI_img.get_image(image, based_w, based_h)
color = CI_img.get_bg_color(img) color = CI_img.get_bg_color(img)
if not without_mask: if not without_mask:
color_mask = Image.new('RGBA', (based_w, based_h), color) color_mask = Image.new("RGBA", (based_w, based_h), color)
enka_mask = Image.open(TEXT_PATH / 'bg_mask.png').resize( enka_mask = Image.open(TEXT_PATH / "bg_mask.png").resize((based_w, based_h))
(based_w, based_h)
)
img.paste(color_mask, (0, 0), enka_mask) img.paste(color_mask, (0, 0), enka_mask)
return img return img

View File

@ -12,36 +12,34 @@ class RelicSetStatusAdd(Struct):
Value: float Value: float
MAP = Path(__file__).parent / 'data' MAP = Path(__file__).parent / "data"
version = StarRail_version version = StarRail_version
avatarId2Name_fileName = f'avatarId2Name_mapping_{version}.json' avatarId2Name_fileName = f"avatarId2Name_mapping_{version}.json"
avatarId2EnName_fileName = f'avatarId2EnName_mapping_{version}.json' avatarId2EnName_fileName = f"avatarId2EnName_mapping_{version}.json"
EquipmentID2Name_fileName = f'EquipmentID2Name_mapping_{version}.json' EquipmentID2Name_fileName = f"EquipmentID2Name_mapping_{version}.json"
EquipmentID2EnName_fileName = f'EquipmentID2EnName_mapping_{version}.json' EquipmentID2EnName_fileName = f"EquipmentID2EnName_mapping_{version}.json"
skillId2Name_fileName = f'skillId2Name_mapping_{version}.json' skillId2Name_fileName = f"skillId2Name_mapping_{version}.json"
skillId2Type_fileName = f'skillId2Type_mapping_{version}.json' skillId2Type_fileName = f"skillId2Type_mapping_{version}.json"
Property2Name_fileName = f'Property2Name_mapping_{version}.json' Property2Name_fileName = f"Property2Name_mapping_{version}.json"
RelicId2SetId_fileName = f'RelicId2SetId_mapping_{version}.json' RelicId2SetId_fileName = f"RelicId2SetId_mapping_{version}.json"
SetId2Name_fileName = f'SetId2Name_mapping_{version}.json' SetId2Name_fileName = f"SetId2Name_mapping_{version}.json"
rankId2Name_fileName = f'rankId2Name_mapping_{version}.json' rankId2Name_fileName = f"rankId2Name_mapping_{version}.json"
characterSkillTree_fileName = f'characterSkillTree_mapping_{version}.json' characterSkillTree_fileName = f"characterSkillTree_mapping_{version}.json"
avatarId2DamageType_fileName = f'avatarId2DamageType_mapping_{version}.json' avatarId2DamageType_fileName = f"avatarId2DamageType_mapping_{version}.json"
avatarId2Rarity_fileName = f'avatarId2Rarity_mapping_{version}.json' avatarId2Rarity_fileName = f"avatarId2Rarity_mapping_{version}.json"
EquipmentID2AbilityProperty_fileName = ( EquipmentID2AbilityProperty_fileName = (
f'EquipmentID2AbilityProperty_mapping_{version}.json' f"EquipmentID2AbilityProperty_mapping_{version}.json"
) )
RelicSetSkill_fileName = f'RelicSetSkill_mapping_{version}.json' RelicSetSkill_fileName = f"RelicSetSkill_mapping_{version}.json"
skillId2AttackType_fileName = f'skillId2AttackType_mapping_{version}.json' skillId2AttackType_fileName = f"skillId2AttackType_mapping_{version}.json"
EquipmentID2Rarity_fileName = f'EquipmentID2Rarity_mapping_{version}.json' EquipmentID2Rarity_fileName = f"EquipmentID2Rarity_mapping_{version}.json"
RelicId2Rarity_fileName = f'RelicId2Rarity_mapping_{version}.json' RelicId2Rarity_fileName = f"RelicId2Rarity_mapping_{version}.json"
ItemId2Name_fileName = f'ItemId2Name_mapping_{version}.json' ItemId2Name_fileName = f"ItemId2Name_mapping_{version}.json"
RelicId2MainAffixGroup_fileName = ( RelicId2MainAffixGroup_fileName = f"RelicId2MainAffixGroup_mapping_{version}.json"
f'RelicId2MainAffixGroup_mapping_{version}.json' AvatarRelicScore_fileName = "AvatarRelicScore.json"
) avatarRankSkillUp_fileName = f"avatarRankSkillUp_mapping_{version}.json"
AvatarRelicScore_fileName = 'AvatarRelicScore.json'
avatarRankSkillUp_fileName = f'avatarRankSkillUp_mapping_{version}.json'
class TS(TypedDict): class TS(TypedDict):
@ -54,51 +52,49 @@ class LU(TypedDict):
num: int num: int
with Path.open(MAP / avatarId2Name_fileName, encoding='UTF-8') as f: with Path.open(MAP / avatarId2Name_fileName, encoding="UTF-8") as f:
avatarId2Name = msgjson.decode(f.read(), type=Dict[str, str]) avatarId2Name = msgjson.decode(f.read(), type=Dict[str, str])
with Path.open(MAP / avatarId2EnName_fileName, encoding='UTF-8') as f: with Path.open(MAP / avatarId2EnName_fileName, encoding="UTF-8") as f:
avatarId2EnName = msgjson.decode(f.read(), type=Dict[str, str]) avatarId2EnName = msgjson.decode(f.read(), type=Dict[str, str])
with Path.open(MAP / EquipmentID2Name_fileName, encoding='UTF-8') as f: with Path.open(MAP / EquipmentID2Name_fileName, encoding="UTF-8") as f:
EquipmentID2Name = msgjson.decode(f.read(), type=Dict[str, str]) EquipmentID2Name = msgjson.decode(f.read(), type=Dict[str, str])
with Path.open(MAP / EquipmentID2EnName_fileName, encoding='UTF-8') as f: with Path.open(MAP / EquipmentID2EnName_fileName, encoding="UTF-8") as f:
EquipmentID2EnName = msgjson.decode(f.read(), type=Dict[str, str]) EquipmentID2EnName = msgjson.decode(f.read(), type=Dict[str, str])
with Path.open(MAP / skillId2Name_fileName, encoding='UTF-8') as f: with Path.open(MAP / skillId2Name_fileName, encoding="UTF-8") as f:
skillId2Name = msgjson.decode(f.read(), type=Dict[str, str]) skillId2Name = msgjson.decode(f.read(), type=Dict[str, str])
with Path.open(MAP / skillId2Type_fileName, encoding='UTF-8') as f: with Path.open(MAP / skillId2Type_fileName, encoding="UTF-8") as f:
skillId2Effect = msgjson.decode(f.read(), type=Dict[str, str]) skillId2Effect = msgjson.decode(f.read(), type=Dict[str, str])
with Path.open(MAP / Property2Name_fileName, encoding='UTF-8') as f: with Path.open(MAP / Property2Name_fileName, encoding="UTF-8") as f:
Property2Name = msgjson.decode(f.read(), type=Dict[str, str]) Property2Name = msgjson.decode(f.read(), type=Dict[str, str])
with Path.open(MAP / RelicId2SetId_fileName, encoding='UTF-8') as f: with Path.open(MAP / RelicId2SetId_fileName, encoding="UTF-8") as f:
RelicId2SetId = msgjson.decode(f.read(), type=Dict[str, int]) RelicId2SetId = msgjson.decode(f.read(), type=Dict[str, int])
with Path.open(MAP / SetId2Name_fileName, encoding='UTF-8') as f: with Path.open(MAP / SetId2Name_fileName, encoding="UTF-8") as f:
SetId2Name = msgjson.decode(f.read(), type=Dict[str, str]) SetId2Name = msgjson.decode(f.read(), type=Dict[str, str])
with Path.open(MAP / rankId2Name_fileName, encoding='UTF-8') as f: with Path.open(MAP / rankId2Name_fileName, encoding="UTF-8") as f:
rankId2Name = msgjson.decode(f.read(), type=Dict[str, str]) rankId2Name = msgjson.decode(f.read(), type=Dict[str, str])
with Path.open(MAP / characterSkillTree_fileName, encoding='UTF-8') as f: with Path.open(MAP / characterSkillTree_fileName, encoding="UTF-8") as f:
characterSkillTree = msgjson.decode(f.read(), type=Dict[str, Dict]) characterSkillTree = msgjson.decode(f.read(), type=Dict[str, Dict])
with Path.open(MAP / avatarId2DamageType_fileName, encoding='UTF-8') as f: with Path.open(MAP / avatarId2DamageType_fileName, encoding="UTF-8") as f:
avatarId2DamageType = msgjson.decode(f.read(), type=Dict[str, str]) avatarId2DamageType = msgjson.decode(f.read(), type=Dict[str, str])
with Path.open(MAP / 'char_alias.json', encoding='UTF-8') as f: with Path.open(MAP / "char_alias.json", encoding="UTF-8") as f:
alias_data = msgjson.decode(f.read(), type=Dict[str, Dict[str, List]]) alias_data = msgjson.decode(f.read(), type=Dict[str, Dict[str, List]])
with Path.open(MAP / avatarId2Rarity_fileName, encoding='UTF-8') as f: with Path.open(MAP / avatarId2Rarity_fileName, encoding="UTF-8") as f:
avatarId2Rarity = msgjson.decode(f.read(), type=Dict[str, str]) avatarId2Rarity = msgjson.decode(f.read(), type=Dict[str, str])
with Path.open( with Path.open(MAP / EquipmentID2AbilityProperty_fileName, encoding="UTF-8") as f:
MAP / EquipmentID2AbilityProperty_fileName, encoding='UTF-8'
) as f:
EquipmentID2AbilityProperty = msgjson.decode( EquipmentID2AbilityProperty = msgjson.decode(
f.read(), type=Dict[str, Dict[str, List]] f.read(), type=Dict[str, Dict[str, List]]
) )
@ -107,25 +103,23 @@ with Path.open(
# RelicSetSkill = convert(json.load(f), Dict[str, Dict[str, object]]) # RelicSetSkill = convert(json.load(f), Dict[str, Dict[str, object]])
# print(RelicSetSkill) # print(RelicSetSkill)
with Path.open(MAP / skillId2AttackType_fileName, encoding='UTF-8') as f: with Path.open(MAP / skillId2AttackType_fileName, encoding="UTF-8") as f:
skillId2AttackType = msgjson.decode(f.read(), type=Dict[str, str]) skillId2AttackType = msgjson.decode(f.read(), type=Dict[str, str])
with Path.open(MAP / EquipmentID2Rarity_fileName, encoding='UTF-8') as f: with Path.open(MAP / EquipmentID2Rarity_fileName, encoding="UTF-8") as f:
EquipmentID2Rarity = msgjson.decode(f.read(), type=Dict[str, int]) EquipmentID2Rarity = msgjson.decode(f.read(), type=Dict[str, int])
with Path.open(MAP / RelicId2Rarity_fileName, encoding='UTF-8') as f: with Path.open(MAP / RelicId2Rarity_fileName, encoding="UTF-8") as f:
RelicId2Rarity = msgjson.decode(f.read(), type=Dict[str, int]) RelicId2Rarity = msgjson.decode(f.read(), type=Dict[str, int])
with Path.open(MAP / ItemId2Name_fileName, encoding='UTF-8') as f: with Path.open(MAP / ItemId2Name_fileName, encoding="UTF-8") as f:
ItemId2Name = msgjson.decode(f.read(), type=Dict[str, str]) ItemId2Name = msgjson.decode(f.read(), type=Dict[str, str])
with Path.open(MAP / RelicId2MainAffixGroup_fileName, encoding='UTF-8') as f: with Path.open(MAP / RelicId2MainAffixGroup_fileName, encoding="UTF-8") as f:
RelicId2MainAffixGroup = msgjson.decode(f.read(), type=Dict[str, int]) RelicId2MainAffixGroup = msgjson.decode(f.read(), type=Dict[str, int])
with Path.open(MAP / AvatarRelicScore_fileName, encoding='UTF-8') as f: with Path.open(MAP / AvatarRelicScore_fileName, encoding="UTF-8") as f:
AvatarRelicScore = msgjson.decode(f.read(), type=List[Dict]) AvatarRelicScore = msgjson.decode(f.read(), type=List[Dict])
with Path.open(MAP / avatarRankSkillUp_fileName, encoding='UTF-8') as f: with Path.open(MAP / avatarRankSkillUp_fileName, encoding="UTF-8") as f:
AvatarRankSkillUp = msgjson.decode( AvatarRankSkillUp = msgjson.decode(f.read(), type=Dict[str, Union[List[LU], None]])
f.read(), type=Dict[str, Union[List[LU], None]]
)

View File

@ -1,54 +1,54 @@
import json import json
with open('./data/characters.json', 'r', encoding='utf8') as f: with open("./data/characters.json", "r", encoding="utf8") as f:
characters = json.load(f) characters = json.load(f)
with open('./data/character_ranks.json', 'r', encoding='utf8') as f: with open("./data/character_ranks.json", "r", encoding="utf8") as f:
character_ranks = json.load(f) character_ranks = json.load(f)
with open('./data/character_skills.json', 'r', encoding='utf8') as f: with open("./data/character_skills.json", "r", encoding="utf8") as f:
character_skills = json.load(f) character_skills = json.load(f)
with open('./data/character_skill_trees.json', 'r', encoding='utf8') as f: with open("./data/character_skill_trees.json", "r", encoding="utf8") as f:
character_skill_trees = json.load(f) character_skill_trees = json.load(f)
with open('./data/AvatarConfig.json', 'r', encoding='utf8') as f: with open("./data/AvatarConfig.json", "r", encoding="utf8") as f:
AvatarConfig = json.load(f) AvatarConfig = json.load(f)
with open('./data/TextMapCN.json', 'r', encoding='utf8') as f: with open("./data/TextMapCN.json", "r", encoding="utf8") as f:
TextMapCN = json.load(f) TextMapCN = json.load(f)
with open('./data/TextMapEN.json', 'r', encoding='utf8') as f: with open("./data/TextMapEN.json", "r", encoding="utf8") as f:
TextMapEN = json.load(f) TextMapEN = json.load(f)
with open('./data/EquipmentConfig.json', 'r', encoding='utf8') as f: with open("./data/EquipmentConfig.json", "r", encoding="utf8") as f:
EquipmentConfig = json.load(f) EquipmentConfig = json.load(f)
with open('./data/AvatarSkillConfig.json', 'r', encoding='utf8') as f: with open("./data/AvatarSkillConfig.json", "r", encoding="utf8") as f:
AvatarSkillConfig = json.load(f) AvatarSkillConfig = json.load(f)
with open('./data/AvatarPropertyConfig.json', 'r', encoding='utf8') as f: with open("./data/AvatarPropertyConfig.json", "r", encoding="utf8") as f:
AvatarPropertyConfig = json.load(f) AvatarPropertyConfig = json.load(f)
with open('./data/EquipmentSkillConfig.json', 'r', encoding='utf8') as f: with open("./data/EquipmentSkillConfig.json", "r", encoding="utf8") as f:
EquipmentSkillConfig = json.load(f) EquipmentSkillConfig = json.load(f)
with open('./data/RelicConfig.json', 'r', encoding='utf8') as f: with open("./data/RelicConfig.json", "r", encoding="utf8") as f:
RelicConfig = json.load(f) RelicConfig = json.load(f)
with open('./data/RelicSetConfig.json', 'r', encoding='utf8') as f: with open("./data/RelicSetConfig.json", "r", encoding="utf8") as f:
RelicSetConfig = json.load(f) RelicSetConfig = json.load(f)
with open('./data/RelicSetSkillConfig.json', 'r', encoding='utf8') as f: with open("./data/RelicSetSkillConfig.json", "r", encoding="utf8") as f:
RelicSetSkillConfig = json.load(f) RelicSetSkillConfig = json.load(f)
with open('./data/light_cones.json', 'r', encoding='utf8') as f: with open("./data/light_cones.json", "r", encoding="utf8") as f:
light_cones = json.load(f) light_cones = json.load(f)
with open('./data/relics_new.json', 'r', encoding='utf8') as f: with open("./data/relics_new.json", "r", encoding="utf8") as f:
relics_new = json.load(f) relics_new = json.load(f)
with open('./data/ItemConfigRelic.json', 'r', encoding='utf8') as f: with open("./data/ItemConfigRelic.json", "r", encoding="utf8") as f:
ItemConfigRelic = json.load(f) ItemConfigRelic = json.load(f)
avatarId2Name = {} avatarId2Name = {}
@ -74,32 +74,32 @@ RelicId2MainAffixGroup = {}
for char in characters: for char in characters:
char_item = characters[char] char_item = characters[char]
rank_list = characters[char]['ranks'] rank_list = characters[char]["ranks"]
rarity = characters[char]['rarity'] rarity = characters[char]["rarity"]
avatarId2Rarity[char] = str(rarity) avatarId2Rarity[char] = str(rarity)
for rank in rank_list: for rank in rank_list:
if character_ranks.get(str(rank)): if character_ranks.get(str(rank)):
eidolon = character_ranks[str(rank)] eidolon = character_ranks[str(rank)]
rank_id = eidolon['id'] rank_id = eidolon["id"]
rank_name = eidolon['name'] rank_name = eidolon["name"]
rankId2Name[rank_id] = rank_name rankId2Name[rank_id] = rank_name
for item in AvatarConfig: for item in AvatarConfig:
avatar_item = AvatarConfig[item] avatar_item = AvatarConfig[item]
avatar_id = avatar_item['AvatarID'] avatar_id = avatar_item["AvatarID"]
avatar_name_hash = avatar_item['AvatarName']['Hash'] avatar_name_hash = avatar_item["AvatarName"]["Hash"]
avatar_damage_type = avatar_item['DamageType'] avatar_damage_type = avatar_item["DamageType"]
avatar_en_name = '' avatar_en_name = ""
avatar_name = '' avatar_name = ""
for item in TextMapCN: for item in TextMapCN:
if str(item) == str(avatar_name_hash): if str(item) == str(avatar_name_hash):
avatar_name = TextMapCN[item] avatar_name = TextMapCN[item]
if avatar_name == '{NICKNAME}': if avatar_name == "{NICKNAME}":
avatar_name = '开拓者' avatar_name = "开拓者"
break break
for item in TextMapEN: for item in TextMapEN:
if str(item) == str(avatar_name_hash): if str(item) == str(avatar_name_hash):
avatar_en_name = TextMapEN[item].replace(' ', '') avatar_en_name = TextMapEN[item].replace(" ", "")
break break
avatarId2EnName[avatar_id] = avatar_en_name avatarId2EnName[avatar_id] = avatar_en_name
avatarId2Name[avatar_id] = avatar_name avatarId2Name[avatar_id] = avatar_name
@ -108,9 +108,9 @@ for item in AvatarConfig:
for item in EquipmentConfig: for item in EquipmentConfig:
equipment_item = EquipmentConfig[item] equipment_item = EquipmentConfig[item]
equipment_id = equipment_item['EquipmentID'] equipment_id = equipment_item["EquipmentID"]
equipment_name_hash = equipment_item['EquipmentName']['Hash'] equipment_name_hash = equipment_item["EquipmentName"]["Hash"]
equipment_name = '' equipment_name = ""
for item in TextMapCN: for item in TextMapCN:
if str(item) == str(equipment_name_hash): if str(item) == str(equipment_name_hash):
equipment_name = TextMapCN[item] equipment_name = TextMapCN[item]
@ -122,30 +122,30 @@ for item in EquipmentSkillConfig:
equipment_item = EquipmentSkillConfig[item] equipment_item = EquipmentSkillConfig[item]
EquipmentID2AbilityProperty[str(item)] = {} EquipmentID2AbilityProperty[str(item)] = {}
for i in equipment_item: for i in equipment_item:
equipment_ability_property = equipment_item[str(i)]['AbilityProperty'] equipment_ability_property = equipment_item[str(i)]["AbilityProperty"]
EquipmentID2AbilityProperty[str(item)][i] = equipment_ability_property EquipmentID2AbilityProperty[str(item)][i] = equipment_ability_property
for item in EquipmentConfig: for item in EquipmentConfig:
equipment_item = EquipmentConfig[item] equipment_item = EquipmentConfig[item]
equipment_id = equipment_item['EquipmentID'] equipment_id = equipment_item["EquipmentID"]
equipment_name_hash = equipment_item['EquipmentName']['Hash'] equipment_name_hash = equipment_item["EquipmentName"]["Hash"]
equipment_name = '' equipment_name = ""
for item in TextMapEN: for item in TextMapEN:
if str(item) == str(equipment_name_hash): if str(item) == str(equipment_name_hash):
equipment_name = TextMapEN[item].replace(' ', '') equipment_name = TextMapEN[item].replace(" ", "")
break break
EquipmentID2EnName[equipment_id] = equipment_name EquipmentID2EnName[equipment_id] = equipment_name
for skill in AvatarSkillConfig: for skill in AvatarSkillConfig:
skill_item = AvatarSkillConfig[skill] skill_item = AvatarSkillConfig[skill]
skill_id = skill_item['1']['SkillID'] skill_id = skill_item["1"]["SkillID"]
skill_name_hash = skill_item['1']['SkillName']['Hash'] skill_name_hash = skill_item["1"]["SkillName"]["Hash"]
skill_type_hash = skill_item['1']['SkillTag']['Hash'] skill_type_hash = skill_item["1"]["SkillTag"]["Hash"]
skill_attack_type = skill_item['1'].get('AttackType', '') skill_attack_type = skill_item["1"].get("AttackType", "")
skill_name = '' skill_name = ""
skill_type = '' skill_type = ""
for item in TextMapCN: for item in TextMapCN:
if str(item) == str(skill_name_hash): if str(item) == str(skill_name_hash):
skill_name = TextMapCN[item] skill_name = TextMapCN[item]
@ -160,12 +160,12 @@ for skill in AvatarSkillConfig:
for avatar_property in AvatarPropertyConfig: for avatar_property in AvatarPropertyConfig:
PropertyType = AvatarPropertyConfig[avatar_property]['PropertyType'] PropertyType = AvatarPropertyConfig[avatar_property]["PropertyType"]
PropertyName = AvatarPropertyConfig[avatar_property]['PropertyName'] PropertyName = AvatarPropertyConfig[avatar_property]["PropertyName"]
PropertyNameHash = AvatarPropertyConfig[avatar_property][ PropertyNameHash = AvatarPropertyConfig[avatar_property]["PropertyNameFilter"][
'PropertyNameFilter' "Hash"
]['Hash'] ]
Property_Name = '' Property_Name = ""
for item in TextMapCN: for item in TextMapCN:
if str(item) == str(PropertyNameHash): if str(item) == str(PropertyNameHash):
Property_Name = TextMapCN[item] Property_Name = TextMapCN[item]
@ -174,13 +174,13 @@ for avatar_property in AvatarPropertyConfig:
for relic in RelicConfig: for relic in RelicConfig:
Relic2SetId[relic] = RelicConfig[relic]['SetID'] Relic2SetId[relic] = RelicConfig[relic]["SetID"]
RelicId2MainAffixGroup[relic] = RelicConfig[relic]['MainAffixGroup'] RelicId2MainAffixGroup[relic] = RelicConfig[relic]["MainAffixGroup"]
for set_group in RelicSetConfig: for set_group in RelicSetConfig:
set_name_hash = RelicSetConfig[set_group]['SetName']['Hash'] set_name_hash = RelicSetConfig[set_group]["SetName"]["Hash"]
set_name = '' set_name = ""
for item in TextMapCN: for item in TextMapCN:
if str(item) == str(set_name_hash): if str(item) == str(set_name_hash):
set_name = TextMapCN[item] set_name = TextMapCN[item]
@ -189,13 +189,13 @@ for set_group in RelicSetConfig:
for character in characters: for character in characters:
char_id = characters[character]['id'] char_id = characters[character]["id"]
characterSkillTree[str(char_id)] = ( characterSkillTree[str(char_id)] = (
{} {}
if str(char_id) not in characterSkillTree if str(char_id) not in characterSkillTree
else characterSkillTree[str(char_id)] else characterSkillTree[str(char_id)]
) )
skill_tree_list = characters[character]['skill_trees'] skill_tree_list = characters[character]["skill_trees"]
for skill in skill_tree_list: for skill in skill_tree_list:
skill_tree = character_skill_trees[skill] skill_tree = character_skill_trees[skill]
characterSkillTree[str(char_id)][str(skill)] = skill_tree characterSkillTree[str(char_id)][str(skill)] = skill_tree
@ -203,38 +203,34 @@ for character in characters:
for set_ in RelicSetSkillConfig: for set_ in RelicSetSkillConfig:
for item in RelicSetSkillConfig[set_]: for item in RelicSetSkillConfig[set_]:
set_id = RelicSetSkillConfig[set_][item]['SetID'] set_id = RelicSetSkillConfig[set_][item]["SetID"]
property_list = RelicSetSkillConfig[set_][item]['PropertyList'] property_list = RelicSetSkillConfig[set_][item]["PropertyList"]
RelicSetSkill[set_] = ( RelicSetSkill[set_] = {} if set_ not in RelicSetSkill else RelicSetSkill[set_]
{} if set_ not in RelicSetSkill else RelicSetSkill[set_]
)
RelicSetSkill[set_][item] = ( RelicSetSkill[set_][item] = (
{} {} if item not in RelicSetSkill[set_] else RelicSetSkill[set_][item]
if item not in RelicSetSkill[set_]
else RelicSetSkill[set_][item]
) )
for property_ in property_list: for property_ in property_list:
property_id = property_['NAOGDGBJNOJ'] property_id = property_["NAOGDGBJNOJ"]
property_value = property_['MBOHKHKHFPD']['Value'] property_value = property_["MBOHKHKHFPD"]["Value"]
RelicSetSkill[set_][item]['Property'] = property_id RelicSetSkill[set_][item]["Property"] = property_id
RelicSetSkill[set_][item]['Value'] = property_value RelicSetSkill[set_][item]["Value"] = property_value
for light_cone in light_cones: for light_cone in light_cones:
rarity = light_cones[light_cone]['rarity'] rarity = light_cones[light_cone]["rarity"]
light_cone_id = light_cones[light_cone]['id'] light_cone_id = light_cones[light_cone]["id"]
EquipmentID2Rarity[light_cone_id] = rarity EquipmentID2Rarity[light_cone_id] = rarity
for item in relics_new: for item in relics_new:
rarity = relics_new[item]['rarity'] rarity = relics_new[item]["rarity"]
relic_id = relics_new[item]['id'] relic_id = relics_new[item]["id"]
RelicId2Rarity[relic_id] = rarity RelicId2Rarity[relic_id] = rarity
for item in ItemConfigRelic: for item in ItemConfigRelic:
item_id = ItemConfigRelic[item]['ID'] item_id = ItemConfigRelic[item]["ID"]
item_name_hash = ItemConfigRelic[item]['ItemName']['Hash'] item_name_hash = ItemConfigRelic[item]["ItemName"]["Hash"]
item_name = '' item_name = ""
for item in TextMapCN: for item in TextMapCN:
if str(item) == str(item_name_hash): if str(item) == str(item_name_hash):
item_name = TextMapCN[item] item_name = TextMapCN[item]

View File

@ -20,7 +20,7 @@ async def avatar_id_to_name(avatar_id: str) -> str:
async def name_to_avatar_id(name: str) -> str: async def name_to_avatar_id(name: str) -> str:
avatar_id = '' avatar_id = ""
for i in avatarId2Name: for i in avatarId2Name:
if avatarId2Name[i] == name: if avatarId2Name[i] == name:
avatar_id = i avatar_id = i
@ -33,16 +33,16 @@ async def avatar_id_to_char_star(char_id: str) -> str:
async def alias_to_char_name(char_name: str) -> str: async def alias_to_char_name(char_name: str) -> str:
for i in alias_data['characters']: for i in alias_data["characters"]:
if char_name in alias_data['characters'][i]: if char_name in alias_data["characters"][i]:
return alias_data['characters'][i][0] return alias_data["characters"][i][0]
return char_name return char_name
async def alias_to_weapon_name(weapon_name: str) -> str: async def alias_to_weapon_name(weapon_name: str) -> str:
for i in alias_data['light_cones']: for i in alias_data["light_cones"]:
if weapon_name in alias_data['light_cones'][i]: if weapon_name in alias_data["light_cones"][i]:
return alias_data['light_cones'][i][0] return alias_data["light_cones"][i][0]
return weapon_name return weapon_name
@ -51,7 +51,7 @@ async def weapon_id_to_name(weapon_id: str) -> str:
async def name_to_weapon_id(name: str) -> str: async def name_to_weapon_id(name: str) -> str:
weapon_id = '' weapon_id = ""
for i in EquipmentID2Name: for i in EquipmentID2Name:
if EquipmentID2Name[i] == name: if EquipmentID2Name[i] == name:
weapon_id = i weapon_id = i
@ -64,7 +64,7 @@ async def weapon_id_to_en_name(weapon_id: str) -> str:
async def en_name_to_weapon_id(name: str) -> str: async def en_name_to_weapon_id(name: str) -> str:
weapon_id = '' weapon_id = ""
for i in EquipmentID2EnName: for i in EquipmentID2EnName:
if EquipmentID2EnName[i] == name: if EquipmentID2EnName[i] == name:
weapon_id = i weapon_id = i

View File

@ -1,66 +1,55 @@
import copy import copy
import time import time
from typing import Any, Dict, Union, Literal, Optional from typing import Dict, Literal, Optional, Union
import msgspec
from gsuid_core.utils.api.mys_api import _MysApi
# from gsuid_core.utils.api.mys.models import MysSign, SignList
from gsuid_core.utils.api.mys.tools import ( from gsuid_core.utils.api.mys.tools import (
mys_version,
_random_int_ds,
generate_os_ds, generate_os_ds,
get_ds_token,
get_web_ds_token, get_web_ds_token,
mys_version,
) )
from gsuid_core.utils.api.mys_api import _MysApi
import msgspec
from ..sruid_utils.api.mys.api import _API from ..sruid_utils.api.mys.api import _API
from ..sruid_utils.api.mys.models import ( from ..sruid_utils.api.mys.models import (
MysSign, AbyssBossData,
AbyssData,
AbyssStoryData,
AvatarDetail,
AvatarInfo,
DailyNoteData,
GachaLog, GachaLog,
MonthlyAward,
MysSign,
RogueData,
RogueLocustData,
RoleBasicInfo,
RoleIndex,
SignInfo, SignInfo,
SignList, SignList,
AbyssData,
RogueData,
RoleIndex,
AvatarInfo,
AvatarDetail,
MonthlyAward,
DailyNoteData,
RoleBasicInfo,
WidgetStamina, WidgetStamina,
RogueLocustData, AbyssStoryData, AbyssBossData,
) )
RECOGNIZE_SERVER = { RECOGNIZE_SERVER = {
'1': 'prod_gf_cn', "1": "prod_gf_cn",
'2': 'prod_gf_cn', "2": "prod_gf_cn",
'5': 'prod_qd_cn', "5": "prod_qd_cn",
'6': 'prod_official_usa', "6": "prod_official_usa",
'7': 'prod_official_euro', "7": "prod_official_euro",
'8': 'prod_official_asia', "8": "prod_official_asia",
'9': 'prod_official_cht', "9": "prod_official_cht",
} }
def get_ds_token2(
q: str = '',
b: Optional[Dict[str, Any]] = None,
):
salt = 't0qEgfub6cvueAPgR5m9aQWWVciEer7v'
return _random_int_ds(salt, q, b)
class MysApi(_MysApi): class MysApi(_MysApi):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
async def get_sr_ck( async def get_sr_ck(
self, uid: str, mode: Literal['OWNER', 'RANDOM'] = 'RANDOM' self, uid: str, mode: Literal["OWNER", "RANDOM"] = "RANDOM"
) -> Optional[str]: ) -> Optional[str]:
return await self.get_ck(uid, mode, 'sr') return await self.get_ck(uid, mode, "sr")
def check_os(self, uid: str) -> bool:
return False if int(str(uid)[0]) < 6 else True
async def simple_sr_req( async def simple_sr_req(
self, self,
@ -76,40 +65,38 @@ class MysApi(_MysApi):
params, params,
header, header,
cookie, cookie,
'sr', "sr",
) )
async def get_daily_data(self, uid: str) -> Union[DailyNoteData, int]: async def get_sr_daily_data(self, uid: str) -> Union[DailyNoteData, int]:
is_os = self.check_os(uid) if self.check_os(uid, game_name="sr"):
if is_os:
HEADER = copy.deepcopy(self._HEADER_OS) HEADER = copy.deepcopy(self._HEADER_OS)
ck = await self.get_sr_ck(uid, 'OWNER') ck = await self.get_sr_ck(uid, "OWNER")
if ck is None: if ck is None:
return -51 return -51
HEADER['Cookie'] = ck HEADER["Cookie"] = ck
HEADER['DS'] = generate_os_ds() HEADER["DS"] = generate_os_ds()
header = HEADER header = HEADER
data = await self.simple_sr_req( data = await self.simple_sr_req(
'STAR_RAIL_NOTE_URL', "STAR_RAIL_NOTE_URL",
uid, uid,
params={ params={
'role_id': uid, "role_id": uid,
'server': RECOGNIZE_SERVER.get(str(uid)[0], 'prod_gf_cn'), "server": RECOGNIZE_SERVER.get(str(uid)[0], "prod_gf_cn"),
}, },
header=header, header=header,
) )
else: else:
data = await self.simple_sr_req( data = await self.simple_sr_req(
'STAR_RAIL_NOTE_URL', uid, header=self._HEADER "STAR_RAIL_NOTE_URL", uid, header=self._HEADER
) )
if isinstance(data, Dict): if isinstance(data, Dict):
# workaround for mistake params in hoyolab # workaround for mistake params in hoyolab
if data['data']['accepted_epedition_num']: if data["data"]["accepted_epedition_num"]:
data['data']['accepted_expedition_num'] = data['data'][ data["data"]["accepted_expedition_num"] = data["data"][
'accepted_epedition_num' "accepted_epedition_num"
] ]
data = msgspec.convert(data['data'], type=DailyNoteData) data = msgspec.convert(data["data"], type=DailyNoteData)
# data = cast(DailyNoteData, data['data'])
return data return data
async def get_widget_stamina_data( async def get_widget_stamina_data(
@ -117,389 +104,373 @@ class MysApi(_MysApi):
uid: str, uid: str,
) -> Union[WidgetStamina, int]: ) -> Union[WidgetStamina, int]:
header = copy.deepcopy(self._HEADER) header = copy.deepcopy(self._HEADER)
sk = await self.get_stoken(uid, 'sr') sk = await self.get_stoken(uid, "sr")
if sk is None: if sk is None:
return -51 return -51
header['Cookie'] = sk header["Cookie"] = sk
header['x-rpc-channel'] = 'beta' header["x-rpc-channel"] = "beta"
device_id = await self.get_user_device_id(uid, 'sr') device_id = await self.get_user_device_id(uid, "sr")
header['x-rpc-device_id'] = '23' if device_id is None else device_id header["x-rpc-device_id"] = "23" if device_id is None else device_id
header['x-rpc-app_version'] = '2.53.0' header["x-rpc-app_version"] = "2.53.0"
header['x-rpc-device_model'] = 'Mi 10' header["x-rpc-device_model"] = "Mi 10"
fp = await self.get_user_fp(uid, 'sr') fp = await self.get_user_fp(uid, "sr")
header['x-rpc-device_fp'] = 'Asmr489' if fp is None else fp header["x-rpc-device_fp"] = "Asmr489" if fp is None else fp
header['x-rpc-client_type'] = '2' header["x-rpc-client_type"] = "2"
header['DS'] = get_ds_token2() header["DS"] = get_ds_token()
header['Referer'] = 'https://app.mihoyo.com' header["Referer"] = "https://app.mihoyo.com"
del header['Origin'] del header["Origin"]
header['x-rpc-sys_version'] = '12' header["x-rpc-sys_version"] = "12"
header['User-Agent'] = 'okhttp/4.8.0' header["User-Agent"] = "okhttp/4.8.0"
data = await self._mys_request( data = await self._mys_request(
_API['STAR_RAIL_WIDGRT_URL'], _API["STAR_RAIL_WIDGRT_URL"],
'GET', "GET",
header, header,
) )
if isinstance(data, Dict): if isinstance(data, Dict):
data = msgspec.convert(data['data'], type=WidgetStamina) data = msgspec.convert(data["data"], type=WidgetStamina)
# data = cast(WidgetStamina, data['data'])
return data return data
async def get_role_index(self, uid: str) -> Union[RoleIndex, int]: async def get_role_index(self, uid: str) -> Union[RoleIndex, int]:
is_os = self.check_os(uid) if self.check_os(uid, game_name="sr"):
if is_os:
HEADER = copy.deepcopy(self._HEADER_OS) HEADER = copy.deepcopy(self._HEADER_OS)
ck = await self.get_sr_ck(uid, 'OWNER') ck = await self.get_sr_ck(uid, "OWNER")
if ck is None: if ck is None:
return -51 return -51
HEADER['Cookie'] = ck HEADER["Cookie"] = ck
HEADER['DS'] = generate_os_ds() HEADER["DS"] = generate_os_ds()
header = HEADER header = HEADER
data = await self.simple_sr_req( data = await self.simple_sr_req(
'STAR_RAIL_INDEX_URL', "STAR_RAIL_INDEX_URL",
uid, uid,
params={ params={
'role_id': uid, "role_id": uid,
'server': RECOGNIZE_SERVER.get(str(uid)[0], 'prod_gf_cn'), "server": RECOGNIZE_SERVER.get(str(uid)[0], "prod_gf_cn"),
}, },
header=header, header=header,
) )
else: else:
data = await self.simple_sr_req( data = await self.simple_sr_req(
'STAR_RAIL_INDEX_URL', uid, header=self._HEADER "STAR_RAIL_INDEX_URL", uid, header=self._HEADER
) )
if isinstance(data, Dict): if isinstance(data, Dict):
data = msgspec.convert(data['data'], type=RoleIndex) data = msgspec.convert(data["data"], type=RoleIndex)
# data = cast(RoleIndex, data['data'])
return data return data
async def get_gacha_log_by_link_in_authkey( async def get_gacha_log_by_link_in_authkey(
self, self,
uid: str, uid: str,
authkey: str, authkey: str,
gacha_type: str = '11', gacha_type: str = "11",
page: int = 1, page: int = 1,
end_id: str = '0', end_id: str = "0",
) -> Union[int, GachaLog]: ) -> Union[int, GachaLog]:
# server_id = 'cn_qd01' if
# uid[0] == '5' else 'cn_gf01'
server_id = RECOGNIZE_SERVER.get(str(uid)[0]) server_id = RECOGNIZE_SERVER.get(str(uid)[0])
if self.check_os(uid): if self.check_os(uid):
HEADER = copy.deepcopy(self._HEADER_OS) HEADER = copy.deepcopy(self._HEADER_OS)
ck = await self.get_sr_ck(uid, 'OWNER') ck = await self.get_sr_ck(uid, "OWNER")
if ck is None: if ck is None:
return -51 return -51
HEADER['Cookie'] = ck HEADER["Cookie"] = ck
HEADER['DS'] = generate_os_ds() HEADER["DS"] = generate_os_ds()
header = HEADER header = HEADER
url = self.MAPI['STAR_RAIL_GACHA_LOG_URL_OS'] url = self.MAPI["STAR_RAIL_GACHA_LOG_URL_OS"]
game_biz = 'hkrpg_global' game_biz = "hkrpg_global"
else: else:
header = self._HEADER header = self._HEADER
url = self.MAPI['STAR_RAIL_GACHA_LOG_URL'] url = self.MAPI["STAR_RAIL_GACHA_LOG_URL"]
game_biz = 'hkrpg_cn' game_biz = "hkrpg_cn"
data = await self._mys_request( data = await self._mys_request(
url=url, url=url,
method='GET', method="GET",
header=header, header=header,
params={ params={
'authkey_ver': '1', "authkey_ver": "1",
'sign_type': '2', "sign_type": "2",
'auth_appid': 'webview_gacha', "auth_appid": "webview_gacha",
'default_gacha_type': 11, "default_gacha_type": 11,
'gacha_id': 'dbebc8d9fbb0d4ffa067423482ce505bc5ea', "gacha_id": "dbebc8d9fbb0d4ffa067423482ce505bc5ea",
'timestamp': str(int(time.time())), "timestamp": str(int(time.time())),
'lang': 'zh-cn', "lang": "zh-cn",
'plat_type': 'pc', "plat_type": "pc",
'region': server_id, "region": server_id,
'authkey': authkey, "authkey": authkey,
'game_biz': game_biz, "game_biz": game_biz,
'gacha_type': gacha_type, "gacha_type": gacha_type,
'page': page, "page": page,
'size': '20', "size": "20",
'end_id': end_id, "end_id": end_id,
}, },
) )
if isinstance(data, Dict): if isinstance(data, Dict):
data = msgspec.convert(data['data'], type=GachaLog) data = msgspec.convert(data["data"], type=GachaLog)
# data = cast(GachaLog, data['data'])
return data return data
async def get_avatar_info( async def get_avatar_info(
self, uid: str, avatar_id: int, need_wiki: bool = False self, uid: str, avatar_id: int, need_wiki: bool = False
) -> Union[AvatarInfo, int]: ) -> Union[AvatarInfo, int]:
is_os = self.check_os(uid) if self.check_os(uid, game_name="sr"):
if is_os:
HEADER = copy.deepcopy(self._HEADER_OS) HEADER = copy.deepcopy(self._HEADER_OS)
ck = await self.get_sr_ck(uid, 'OWNER') ck = await self.get_sr_ck(uid, "OWNER")
if ck is None: if ck is None:
return -51 return -51
HEADER['Cookie'] = ck HEADER["Cookie"] = ck
HEADER['DS'] = generate_os_ds() HEADER["DS"] = generate_os_ds()
header = HEADER header = HEADER
data = await self.simple_sr_req( data = await self.simple_sr_req(
'STAR_RAIL_AVATAR_INFO_URL', "STAR_RAIL_AVATAR_INFO_URL",
uid, uid,
params={ params={
'need_wiki': 'true' if need_wiki else 'false', "need_wiki": "true" if need_wiki else "false",
'role_id': uid, "role_id": uid,
'server': RECOGNIZE_SERVER.get(str(uid)[0], 'prod_gf_cn'), "server": RECOGNIZE_SERVER.get(str(uid)[0], "prod_official_asia"),
}, },
header=header, header=header,
) )
else: else:
data = await self.simple_sr_req( data = await self.simple_sr_req(
'STAR_RAIL_AVATAR_INFO_URL', "STAR_RAIL_AVATAR_INFO_URL",
uid, uid,
params={ params={
'id': avatar_id, "id": avatar_id,
'need_wiki': 'true' if need_wiki else 'false', "need_wiki": "true" if need_wiki else "false",
'role_id': uid, "role_id": uid,
'server': RECOGNIZE_SERVER.get(str(uid)[0], 'prod_gf_cn'), "server": RECOGNIZE_SERVER.get(str(uid)[0], "prod_gf_cn"),
}, },
header=self._HEADER, header=self._HEADER,
) )
if isinstance(data, Dict): if isinstance(data, Dict):
data = msgspec.convert(data['data'], type=AvatarInfo) data = msgspec.convert(data["data"], type=AvatarInfo)
# data = cast(AvatarInfo, data['data'])
return data return data
async def get_avatar_detail(self, uid: str, avatarid: str): async def get_avatar_detail(self, uid: str, avatarid: str):
data = await self.simple_sr_req( data = await self.simple_sr_req(
'STAR_RAIL_AVATAR_DETAIL_URL', "STAR_RAIL_AVATAR_DETAIL_URL",
uid, uid,
params={ params={
'game': 'hkrpg', "game": "hkrpg",
'lang': 'zh-cn', "lang": "zh-cn",
'item_id': avatarid, "item_id": avatarid,
'tab_from': 'TabOwned', "tab_from": "TabOwned",
'change_target_level': '0', "change_target_level": "0",
'uid': uid, "uid": uid,
'region': RECOGNIZE_SERVER.get(str(uid)[0], 'prod_gf_cn'), "region": RECOGNIZE_SERVER.get(str(uid)[0], "prod_gf_cn"),
}, },
header=self._HEADER, header=self._HEADER,
) )
if isinstance(data, Dict): if isinstance(data, Dict):
data = msgspec.convert(data['data'], type=AvatarDetail) data = msgspec.convert(data["data"], type=AvatarDetail)
return data return data
async def get_sign_list(self, uid) -> Union[SignList, int]: async def get_sr_sign_list(self, uid) -> Union[SignList, int]:
is_os = self.check_os(uid) is_os = self.check_os(uid)
if is_os: if is_os:
params = { params = {
'act_id': 'e202303301540311', "act_id": "e202303301540311",
'lang': 'zh-cn', "lang": "zh-cn",
} }
else: else:
params = { params = {
'act_id': 'e202304121516551', "act_id": "e202304121516551",
'lang': 'zh-cn', "lang": "zh-cn",
} }
data = await self._mys_req_get( data = await self._mys_req_get(
'STAR_RAIL_SIGN_LIST_URL', "STAR_RAIL_SIGN_LIST_URL",
is_os, is_os,
params, params,
) )
if isinstance(data, Dict): if isinstance(data, Dict):
data = msgspec.convert(data['data'], type=SignList) data = msgspec.convert(data["data"], type=SignList)
# data = cast(SignList, data['data'])
return data return data
async def get_sign_info(self, uid) -> Union[SignInfo, int]: async def get_sr_sign_info(self, uid) -> Union[SignInfo, int]:
# server_id = RECOGNIZE_SERVER.get(str(uid)[0])
is_os = self.check_os(uid) is_os = self.check_os(uid)
if is_os: if is_os:
# TODO # TODO
params = { params = {
'act_id': 'e202303301540311', "act_id": "e202303301540311",
'lang': 'zh-cn', "lang": "zh-cn",
} }
HEADER = copy.deepcopy(self._HEADER_OS) HEADER = copy.deepcopy(self._HEADER_OS)
ck = await self.get_sr_ck(uid, 'OWNER') ck = await self.get_sr_ck(uid, "OWNER")
if ck is None: if ck is None:
return -51 return -51
HEADER['Cookie'] = ck HEADER["Cookie"] = ck
HEADER['DS'] = generate_os_ds() HEADER["DS"] = generate_os_ds()
header = HEADER header = HEADER
else: else:
params = { params = {
'act_id': 'e202304121516551', "act_id": "e202304121516551",
'lang': 'zh-cn', "lang": "zh-cn",
'region': 'prod_gf_cn', "region": "prod_gf_cn",
'uid': uid, "uid": uid,
} }
header = self._HEADER header = self._HEADER
data = await self._mys_req_get( data = await self._mys_req_get(
'STAR_RAIL_SIGN_INFO_URL', "STAR_RAIL_SIGN_INFO_URL",
is_os, is_os,
params, params,
header, header,
) )
if isinstance(data, Dict): if isinstance(data, Dict):
data = msgspec.convert(data['data'], type=SignInfo) data = msgspec.convert(data["data"], type=SignInfo)
# data = cast(SignInfo, data['data'])
return data return data
async def get_abyss_info( async def get_abyss_info(
self, self,
uid: str, uid: str,
schedule_type='1', schedule_type="1",
ck: Optional[str] = None, ck: Optional[str] = None,
) -> Union[AbyssData, int]: ) -> Union[AbyssData, int]:
server_id = self.RECOGNIZE_SERVER.get(uid[0]) server_id = self.RECOGNIZE_SERVER.get(uid[0])
is_os = self.check_os(uid) if self.check_os(uid, game_name="sr"):
if is_os:
HEADER = copy.deepcopy(self._HEADER_OS) HEADER = copy.deepcopy(self._HEADER_OS)
ck = await self.get_sr_ck(uid, 'OWNER') ck = await self.get_sr_ck(uid, "OWNER")
if ck is None: if ck is None:
return -51 return -51
HEADER['Cookie'] = ck HEADER["Cookie"] = ck
HEADER['DS'] = generate_os_ds() HEADER["DS"] = generate_os_ds()
header = HEADER header = HEADER
data = await self.simple_sr_req( data = await self.simple_sr_req(
'CHALLENGE_INFO_URL', "CHALLENGE_INFO_URL",
uid, uid,
params={ params={
'need_all': 'true', "need_all": "true",
'role_id': uid, "role_id": uid,
'schedule_type': schedule_type, "schedule_type": schedule_type,
'server': server_id, "server": server_id,
}, },
header=header, header=header,
) )
else: else:
data = await self.simple_sr_req( data = await self.simple_sr_req(
'CHALLENGE_INFO_URL', "CHALLENGE_INFO_URL",
uid, uid,
params={ params={
'isPrev': 'true', "isPrev": "true",
'need_all': 'true', "need_all": "true",
'role_id': uid, "role_id": uid,
'schedule_type': schedule_type, "schedule_type": schedule_type,
'server': server_id, "server": server_id,
}, },
cookie=ck, cookie=ck,
header=self._HEADER, header=self._HEADER,
) )
if isinstance(data, Dict): if isinstance(data, Dict):
data = msgspec.convert(data['data'], type=AbyssData) data = msgspec.convert(data["data"], type=AbyssData)
# data = cast(AbyssData, data['data'])
return data return data
async def get_abyss_story_info( async def get_abyss_story_info(
self, self,
uid: str, uid: str,
schedule_type='1', schedule_type="1",
ck: Optional[str] = None, ck: Optional[str] = None,
) -> Union[AbyssData, int]: ) -> Union[AbyssStoryData, int]:
server_id = self.RECOGNIZE_SERVER.get(uid[0]) server_id = self.RECOGNIZE_SERVER.get(uid[0])
is_os = self.check_os(uid) if self.check_os(uid, game_name="sr"):
if is_os:
HEADER = copy.deepcopy(self._HEADER_OS) HEADER = copy.deepcopy(self._HEADER_OS)
ck = await self.get_sr_ck(uid, 'OWNER') ck = await self.get_sr_ck(uid, "OWNER")
if ck is None: if ck is None:
return -51 return -51
HEADER['Cookie'] = ck HEADER["Cookie"] = ck
HEADER['DS'] = generate_os_ds() HEADER["DS"] = generate_os_ds()
header = HEADER header = HEADER
data = await self.simple_sr_req( data = await self.simple_sr_req(
'CHALLENGE_STORY_INFO_URL', "CHALLENGE_STORY_INFO_URL",
uid, uid,
params={ params={
'need_all': 'true', "need_all": "true",
'role_id': uid, "role_id": uid,
'schedule_type': schedule_type, "schedule_type": schedule_type,
'server': server_id, "server": server_id,
}, },
header=header, header=header,
) )
else: else:
data = await self.simple_sr_req( data = await self.simple_sr_req(
'CHALLENGE_STORY_INFO_URL', "CHALLENGE_STORY_INFO_URL",
uid, uid,
params={ params={
'isPrev': 'true', "isPrev": "true",
'need_all': 'true', "need_all": "true",
'role_id': uid, "role_id": uid,
'schedule_type': schedule_type, "schedule_type": schedule_type,
'server': server_id, "server": server_id,
}, },
cookie=ck, cookie=ck,
header=self._HEADER, header=self._HEADER,
) )
if isinstance(data, Dict): if isinstance(data, Dict):
data = msgspec.convert(data['data'], type=AbyssStoryData) data = msgspec.convert(data["data"], type=AbyssStoryData)
return data return data
async def get_abyss_boss_info( async def get_abyss_boss_info(
self, self,
uid: str, uid: str,
schedule_type='1', schedule_type="1",
ck: Optional[str] = None, ck: Optional[str] = None,
) -> Union[AbyssBossData, int]: ) -> Union[AbyssBossData, int]:
server_id = self.RECOGNIZE_SERVER.get(uid[0]) server_id = self.RECOGNIZE_SERVER.get(uid[0])
is_os = self.check_os(uid) if self.check_os(uid, game_name="sr"):
if is_os:
HEADER = copy.deepcopy(self._HEADER_OS) HEADER = copy.deepcopy(self._HEADER_OS)
ck = await self.get_sr_ck(uid, 'OWNER') ck = await self.get_sr_ck(uid, "OWNER")
if ck is None: if ck is None:
return -51 return -51
HEADER['Cookie'] = ck HEADER["Cookie"] = ck
HEADER['DS'] = generate_os_ds() HEADER["DS"] = generate_os_ds()
header = HEADER header = HEADER
data = await self.simple_sr_req( data = await self.simple_sr_req(
'CHALLENGE_BOSS_INFO_URL', "CHALLENGE_BOSS_INFO_URL",
uid, uid,
params={ params={
'need_all': 'true', "need_all": "true",
'role_id': uid, "role_id": uid,
'schedule_type': schedule_type, "schedule_type": schedule_type,
'server': server_id, "server": server_id,
}, },
header=header, header=header,
) )
else: else:
data = await self.simple_sr_req( data = await self.simple_sr_req(
'CHALLENGE_BOSS_INFO_URL', "CHALLENGE_BOSS_INFO_URL",
uid, uid,
params={ params={
'isPrev': 'true', "isPrev": "true",
'need_all': 'true', "need_all": "true",
'role_id': uid, "role_id": uid,
'schedule_type': schedule_type, "schedule_type": schedule_type,
'server': server_id, "server": server_id,
}, },
cookie=ck, cookie=ck,
header=self._HEADER, header=self._HEADER,
) )
if isinstance(data, Dict): if isinstance(data, Dict):
data = msgspec.convert(data['data'], type=AbyssBossData) data = msgspec.convert(data["data"], type=AbyssBossData)
# data = cast(AbyssData, data['data'])
return data return data
async def get_rogue_info( async def get_rogue_info(
self, self,
uid: str, uid: str,
schedule_type='3', schedule_type="3",
ck: Optional[str] = None, ck: Optional[str] = None,
) -> Union[RogueData, int]: ) -> Union[RogueData, int]:
server_id = self.RECOGNIZE_SERVER.get(uid[0]) server_id = self.RECOGNIZE_SERVER.get(uid[0])
data = await self.simple_sr_req( data = await self.simple_sr_req(
'ROGUE_INFO_URL', "ROGUE_INFO_URL",
uid, uid,
params={ params={
'need_detail': 'true', "need_detail": "true",
'role_id': uid, "role_id": uid,
'schedule_type': schedule_type, "schedule_type": schedule_type,
'server': server_id, "server": server_id,
}, },
cookie=ck, cookie=ck,
header=self._HEADER, header=self._HEADER,
) )
if isinstance(data, Dict): if isinstance(data, Dict):
data = msgspec.convert(data['data'], type=RogueData) data = msgspec.convert(data["data"], type=RogueData)
# data = cast(RogueData, data['data'])
return data return data
async def get_rogue_locust_info( async def get_rogue_locust_info(
@ -508,99 +479,96 @@ class MysApi(_MysApi):
ck: Optional[str] = None, ck: Optional[str] = None,
) -> Union[RogueLocustData, int]: ) -> Union[RogueLocustData, int]:
server_id = self.RECOGNIZE_SERVER.get(uid[0]) server_id = self.RECOGNIZE_SERVER.get(uid[0])
ck = await self.get_sr_ck(uid, 'OWNER') ck = await self.get_sr_ck(uid, "OWNER")
data = await self.simple_sr_req( data = await self.simple_sr_req(
'ROGUE_LOCUST_INFO_URL', "ROGUE_LOCUST_INFO_URL",
uid, uid,
params={ params={
'need_detail': 'true', "need_detail": "true",
'role_id': uid, "role_id": uid,
'server': server_id, "server": server_id,
}, },
cookie=ck, cookie=ck,
header=self._HEADER, header=self._HEADER,
) )
if isinstance(data, Dict): if isinstance(data, Dict):
data = msgspec.convert(data['data'], type=RogueLocustData) data = msgspec.convert(data["data"], type=RogueLocustData)
# data = cast(RogueLocustData, data['data'])
return data return data
async def mys_sign( async def sr_mys_sign(
self, uid, header=None, server_id='cn_gf01' self, uid, header=None, server_id="cn_gf01"
) -> Union[MysSign, int]: ) -> Union[MysSign, int]:
if header is None: if header is None:
header = {} header = {}
ck = await self.get_sr_ck(uid, 'OWNER') ck = await self.get_sr_ck(uid, "OWNER")
if ck is None: if ck is None:
return -51 return -51
if int(str(uid)[0]) < 6: if int(str(uid)[0]) < 6:
HEADER = copy.deepcopy(self._HEADER) HEADER = copy.deepcopy(self._HEADER)
HEADER['Cookie'] = ck HEADER["Cookie"] = ck
HEADER['x-rpc-app_version'] = mys_version HEADER["x-rpc-app_version"] = mys_version
HEADER['x-rpc-client_type'] = '5' HEADER["x-rpc-client_type"] = "5"
HEADER['X_Requested_With'] = 'com.mihoyo.hyperion' HEADER["X_Requested_With"] = "com.mihoyo.hyperion"
HEADER['DS'] = get_web_ds_token(True) HEADER["DS"] = get_web_ds_token(True)
HEADER['Referer'] = 'https://webstatic.mihoyo.com' HEADER["Referer"] = "https://webstatic.mihoyo.com"
HEADER.update(header) HEADER.update(header)
data = await self._mys_request( data = await self._mys_request(
url=_API['STAR_RAIL_SIGN_URL'], url=_API["STAR_RAIL_SIGN_URL"],
method='POST', method="POST",
header=HEADER, header=HEADER,
data={ data={
'act_id': 'e202304121516551', "act_id": "e202304121516551",
'region': 'prod_gf_cn', "region": "prod_gf_cn",
'uid': uid, "uid": uid,
'lang': 'zh-cn', "lang": "zh-cn",
}, },
) )
else: else:
HEADER = copy.deepcopy(self._HEADER_OS) HEADER = copy.deepcopy(self._HEADER_OS)
HEADER['Cookie'] = ck HEADER["Cookie"] = ck
HEADER['DS'] = generate_os_ds() HEADER["DS"] = generate_os_ds()
HEADER.update(header) HEADER.update(header)
data = await self._mys_request( data = await self._mys_request(
url=_API['STAR_RAIL_SIGN_URL_OS'], url=_API["STAR_RAIL_SIGN_URL_OS"],
method='POST', method="POST",
header=HEADER, header=HEADER,
data={ data={
'act_id': 'e202303301540311', "act_id": "e202303301540311",
'lang': 'zh-cn', "lang": "zh-cn",
}, },
) )
if isinstance(data, Dict): if isinstance(data, Dict):
data = msgspec.convert(data['data'], type=MysSign) data = msgspec.convert(data["data"], type=MysSign)
# data = cast(MysSign, data['data'])
return data return data
async def get_award(self, sr_uid, month) -> Union[MonthlyAward, int]: async def get_sr_award(self, sr_uid, month) -> Union[MonthlyAward, int]:
server_id = RECOGNIZE_SERVER.get(str(sr_uid)[0]) server_id = RECOGNIZE_SERVER.get(str(sr_uid)[0])
ck = await self.get_sr_ck(sr_uid, 'OWNER') ck = await self.get_sr_ck(sr_uid, "OWNER")
if ck is None: if ck is None:
return -51 return -51
if int(str(sr_uid)[0]) < 6: if int(str(sr_uid)[0]) < 6:
HEADER = copy.deepcopy(self._HEADER) HEADER = copy.deepcopy(self._HEADER)
HEADER['Cookie'] = ck HEADER["Cookie"] = ck
HEADER['DS'] = get_web_ds_token(True) HEADER["DS"] = get_web_ds_token(True)
data = await self._mys_request( data = await self._mys_request(
url=_API['STAR_RAIL_MONTH_INFO_URL'], url=_API["STAR_RAIL_MONTH_INFO_URL"],
method='GET', method="GET",
header=HEADER, header=HEADER,
params={'uid': sr_uid, 'region': server_id, 'month': month}, params={"uid": sr_uid, "region": server_id, "month": month},
) )
else: else:
HEADER = copy.deepcopy(self._HEADER_OS) HEADER = copy.deepcopy(self._HEADER_OS)
HEADER['Cookie'] = ck HEADER["Cookie"] = ck
HEADER['DS'] = generate_os_ds() HEADER["DS"] = generate_os_ds()
data = await self._mys_request( data = await self._mys_request(
url=_API['STAR_RAIL_MONTH_INFO_URL'], url=_API["STAR_RAIL_MONTH_INFO_URL"],
method='GET', method="GET",
header=HEADER, header=HEADER,
params={'uid': sr_uid, 'region': server_id, 'month': month}, params={"uid": sr_uid, "region": server_id, "month": month},
use_proxy=True, use_proxy=True,
) )
if isinstance(data, Dict): if isinstance(data, Dict):
data = msgspec.convert(data['data'], type=MonthlyAward) data = msgspec.convert(data["data"], type=MonthlyAward)
# data = cast(MonthlyAward, data['data'])
return data return data
async def get_role_basic_info( async def get_role_basic_info(
@ -608,11 +576,10 @@ class MysApi(_MysApi):
sr_uid: str, sr_uid: str,
) -> Union[RoleBasicInfo, int]: ) -> Union[RoleBasicInfo, int]:
data = await self.simple_sr_req( data = await self.simple_sr_req(
'STAR_RAIL_ROLE_BASIC_INFO_URL', sr_uid, header=self._HEADER "STAR_RAIL_ROLE_BASIC_INFO_URL", sr_uid, header=self._HEADER
) )
if isinstance(data, Dict): if isinstance(data, Dict):
data = msgspec.convert(data['data'], type=RoleBasicInfo) data = msgspec.convert(data["data"], type=RoleBasicInfo)
# data = cast(RoleBasicInfo, data['data'])
return data return data

View File

@ -3,35 +3,35 @@ from pathlib import Path
from gsuid_core.data_store import get_res_path from gsuid_core.data_store import get_res_path
MAIN_PATH = get_res_path() / 'StarRailUID' MAIN_PATH = get_res_path() / "StarRailUID"
sys.path.append(str(MAIN_PATH)) sys.path.append(str(MAIN_PATH))
CU_BG_PATH = MAIN_PATH / 'bg' CU_BG_PATH = MAIN_PATH / "bg"
CONFIG_PATH = MAIN_PATH / 'config.json' CONFIG_PATH = MAIN_PATH / "config.json"
PLAYER_PATH = MAIN_PATH / 'players' PLAYER_PATH = MAIN_PATH / "players"
RESOURCE_PATH = MAIN_PATH / 'resource' RESOURCE_PATH = MAIN_PATH / "resource"
WIKI_PATH = MAIN_PATH / 'wiki' WIKI_PATH = MAIN_PATH / "wiki"
GUIDE_PATH = MAIN_PATH / 'guide' GUIDE_PATH = MAIN_PATH / "guide"
CHAR_ICON_PATH = RESOURCE_PATH / 'character' CHAR_ICON_PATH = RESOURCE_PATH / "character"
CHAR_PORTRAIT_PATH = RESOURCE_PATH / 'character_portrait' CHAR_PORTRAIT_PATH = RESOURCE_PATH / "character_portrait"
CONSUMABLE_PATH = RESOURCE_PATH / 'consumable' CONSUMABLE_PATH = RESOURCE_PATH / "consumable"
ELEMENT_PATH = RESOURCE_PATH / 'element' ELEMENT_PATH = RESOURCE_PATH / "element"
WEAPON_PATH = RESOURCE_PATH / 'light_cone' WEAPON_PATH = RESOURCE_PATH / "light_cone"
RELIC_PATH = RESOURCE_PATH / 'relic' RELIC_PATH = RESOURCE_PATH / "relic"
SKILL_PATH = RESOURCE_PATH / 'skill' SKILL_PATH = RESOURCE_PATH / "skill"
TEMP_PATH = RESOURCE_PATH / 'temp' TEMP_PATH = RESOURCE_PATH / "temp"
CHAR_PREVIEW_PATH = RESOURCE_PATH / 'character_preview' CHAR_PREVIEW_PATH = RESOURCE_PATH / "character_preview"
WIKI_LIGHT_CONE_PATH = WIKI_PATH / 'light_cone' WIKI_LIGHT_CONE_PATH = WIKI_PATH / "light_cone"
WIKI_MATERIAL_FOR_ROLE = WIKI_PATH / 'character_material' WIKI_MATERIAL_FOR_ROLE = WIKI_PATH / "character_material"
WIKI_RELIC_PATH = WIKI_PATH / 'relic_set' WIKI_RELIC_PATH = WIKI_PATH / "relic_set"
WIKI_ROLE_PATH = WIKI_PATH / 'character_overview' WIKI_ROLE_PATH = WIKI_PATH / "character_overview"
GUIDE_LIGHT_CONE_PATH = GUIDE_PATH / 'light_cone' GUIDE_LIGHT_CONE_PATH = GUIDE_PATH / "light_cone"
GUIDE_CHARACTER_PATH = GUIDE_PATH / 'character_overview' GUIDE_CHARACTER_PATH = GUIDE_PATH / "character_overview"
TEXT2D_PATH = Path(__file__).parent / 'texture2d' TEXT2D_PATH = Path(__file__).parent / "texture2d"
def init_dir(): def init_dir():

View File

@ -20,22 +20,22 @@ from gsuid_core.utils.download_resource.download_core import download_all_file
async def check_use(): async def check_use():
await download_all_file( await download_all_file(
'StarRailUID', "StarRailUID",
{ {
'resource/character': CHAR_ICON_PATH, "resource/character": CHAR_ICON_PATH,
'resource/character_portrait': CHAR_PORTRAIT_PATH, "resource/character_portrait": CHAR_PORTRAIT_PATH,
'resource/character_preview': CHAR_PREVIEW_PATH, "resource/character_preview": CHAR_PREVIEW_PATH,
'resource/consumable': CONSUMABLE_PATH, "resource/consumable": CONSUMABLE_PATH,
'resource/element': ELEMENT_PATH, "resource/element": ELEMENT_PATH,
'guide/character_overview': GUIDE_CHARACTER_PATH, "guide/character_overview": GUIDE_CHARACTER_PATH,
'guide/light_cone': GUIDE_LIGHT_CONE_PATH, "guide/light_cone": GUIDE_LIGHT_CONE_PATH,
'resource/relic': RELIC_PATH, "resource/relic": RELIC_PATH,
'resource/skill': SKILL_PATH, "resource/skill": SKILL_PATH,
'resource/light_cone': WEAPON_PATH, "resource/light_cone": WEAPON_PATH,
'wiki/light_cone': WIKI_LIGHT_CONE_PATH, "wiki/light_cone": WIKI_LIGHT_CONE_PATH,
'wiki/character_material': WIKI_MATERIAL_FOR_ROLE, "wiki/character_material": WIKI_MATERIAL_FOR_ROLE,
'wiki/relic_set': WIKI_RELIC_PATH, "wiki/relic_set": WIKI_RELIC_PATH,
'wiki/character_overview': WIKI_ROLE_PATH, "wiki/character_overview": WIKI_ROLE_PATH,
}, },
) )
return 'sr全部资源下载完成!' return "sr全部资源下载完成!"

View File

@ -1,3 +1,3 @@
from ..starrailuid_config.sr_config import srconfig from ..starrailuid_config.sr_config import srconfig
PREFIX = srconfig.get_config('StarRailPrefix').data PREFIX = srconfig.get_config("StarRailPrefix").data

View File

@ -1,2 +1,2 @@
StarRailUID_version = '0.1.0' StarRailUID_version = "0.1.0"
StarRail_version = '2.4.0' StarRail_version = "2.4.0"

View File

@ -38,33 +38,37 @@ pytest = "^7.2.0"
pytest-asyncio = "^0.20.3" pytest-asyncio = "^0.20.3"
[tool.ruff] [tool.ruff]
line-length = 79 line-length = 88
target-version = "py38"
[tool.ruff.lint]
select = [ select = [
"E", "W", # pycodestyle "E",
"F", # pyflakes "W", # pycodestyle
"F", # pyflakes
# "I", # isort # "I", # isort
"RUF", # ruff "RUF", # ruff
"TRY", # tryceratops "TRY", # tryceratops
"UP", "UP",
# pylint # pylint
"PLW", # Warning "PLW", # Warning
"PLR", # Refactor "PLR", # Refactor
"PLE", # Error "PLE", # Error
"PTH", # flake8-use-pathlib "PTH", # flake8-use-pathlib
"SLF", # flake8-self "SLF", # flake8-self
"RET", # flake8-return "RET", # flake8-return
"RSE", # flake8-raise "RSE", # flake8-raise
"T20", # flake8-print "T20", # flake8-print
"PIE", # flake8-pie "PIE", # flake8-pie
"ISC", # flake8-implicit-str-concat "ISC", # flake8-implicit-str-concat
"C4", # flake8-comprehensions "C4", # flake8-comprehensions
"COM", # flake8-commas "COM", # flake8-commas
"A", # flake8-builtins "A", # flake8-builtins
"B", # flake8-bugbear "B", # flake8-bugbear
"ASYNC", # flake8-async "ASYNC", # flake8-async
"Q", # flake8-quotes "Q", # flake8-quotes
] ]
ignore = [ ignore = [
"ISC", "ISC",
@ -76,32 +80,19 @@ ignore = [
"PLR0915", "PLR0915",
"PLR0913", "PLR0913",
"PLR0911", "PLR0911",
"PLW0603", # Using the global statement "PLW0603", # Using the global statement
"TRY002", "TRY002",
"TRY003" "TRY003",
] ]
exclude = [ exclude = ["gen.py", ".ruff_cache"]
"gen.py",
".ruff_cache"
]
# Assume Python 3.8
target-version = "py38"
[tool.ruff.flake8-quotes] [tool.ruff.lint.isort]
inline-quotes = "single"
[tool.ruff.format]
quote-style = "single"
[tool.ruff.isort]
case-sensitive = true case-sensitive = true
force-sort-within-sections = true force-sort-within-sections = true
extra-standard-library = ["typing_extensions"] extra-standard-library = ["typing_extensions"]
#force-wrap-aliases = true
combine-as-imports = true combine-as-imports = true
order-by-type = true order-by-type = true
relative-imports-order = "closest-to-furthest" relative-imports-order = "closest-to-furthest"
section-order = ["future", "standard-library", "first-party", "local-folder", "third-party"]
[tool.pdm] [tool.pdm]
[tool.pdm.build] [tool.pdm.build]
@ -117,36 +108,32 @@ name = "StarRailUID"
version = "0.1.0" version = "0.1.0"
description = "支持 NoneBot2 & HoshinoBot & ZeroBot & YunzaiBot 的全功能星穹铁道Bot插件" description = "支持 NoneBot2 & HoshinoBot & ZeroBot & YunzaiBot 的全功能星穹铁道Bot插件"
authors = [ authors = [
{name = "qwerdvd", email = "105906879+qwerdvd@users.noreply.github.com"}, { name = "qwerdvd", email = "105906879+qwerdvd@users.noreply.github.com" },
] ]
dependencies = [ dependencies = [
"beautifulsoup4>=4.12.2", "beautifulsoup4>=4.12.2",
"msgspec>=0.18.4", "msgspec>=0.18.4",
"httpx>=0.25.0", "httpx>=0.25.0",
"pillow>=10.1.0", "pillow>=10.1.0",
"aiofiles>=23.2.1", "aiofiles>=23.2.1",
"aiohttp>=3.8.6", "aiohttp>=3.8.6",
"qrcode[pil]>=7.4.2", "qrcode[pil]>=7.4.2",
"starrail-damage-cal>=1.2.1", "starrail-damage-cal>=1.2.1",
] ]
requires-python = ">=3.8.1,<4.0" requires-python = ">=3.8.1,<4.0"
readme = "README.md" readme = "README.md"
license = {text = "GPL-3.0-or-later"} license = { text = "GPL-3.0-or-later" }
[tool.pdm.dev-dependencies] [tool.pdm.dev-dependencies]
dev = [ dev = [
"ruff>=0.0.276", "ruff>=0.0.276",
"pre-commit>=3.3.2", "pre-commit>=3.3.2",
"flake8>=6.0.0", "flake8>=6.0.0",
"isort>=5.12.0", "isort>=5.12.0",
"pycln>=2.1.2" "pycln>=2.1.2",
]
test = [
"nonebug>=0.3.0",
"pytest>=7.2.0",
"pytest-asyncio>=0.20.3"
] ]
test = ["nonebug>=0.3.0", "pytest>=7.2.0", "pytest-asyncio>=0.20.3"]
[build-system] [build-system]
requires = ["pdm-backend"] requires = ["pdm-backend"]