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,
) -> Union[HakushHsrCharacter, None]:
async with AsyncClient(
base_url='https://api.hakush.in/hsr/data',
base_url="https://api.hakush.in/hsr/data",
headers=_HEADER,
timeout=30,
) 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:
return convert(req.json(), type=HakushHsrCharacter)
return None
@ -30,39 +30,35 @@ async def get_lightcone_data(
lightcone_id: str,
) -> Union[HakushHsrLightcone, None]:
async with AsyncClient(
base_url='https://api.hakush.in/hsr/data',
base_url="https://api.hakush.in/hsr/data",
headers=_HEADER,
timeout=30,
) 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:
return convert(req.json(), type=HakushHsrLightcone)
return None
async def get_character_index() -> (
Union[Dict[str, HakushHsrCharacterIndex], None]
):
async def get_character_index() -> Union[Dict[str, HakushHsrCharacterIndex], None]:
async with AsyncClient(
base_url='https://api.hakush.in/hsr/data',
base_url="https://api.hakush.in/hsr/data",
headers=_HEADER,
timeout=30,
) as client:
req = await client.get('/character.json')
req = await client.get("/character.json")
if req.status_code == 200:
return convert(req.json(), type=Dict[str, HakushHsrCharacterIndex])
return None
async def get_lightcone_index() -> (
Union[Dict[str, HakushHsrLightconeIndex], None]
):
async def get_lightcone_index() -> Union[Dict[str, HakushHsrLightconeIndex], None]:
async with AsyncClient(
base_url='https://api.hakush.in/hsr/data',
base_url="https://api.hakush.in/hsr/data",
headers=_HEADER,
timeout=30,
) as client:
req = await client.get('/character.json')
req = await client.get("/character.json")
if req.status_code == 200:
return convert(req.json(), type=Dict[str, HakushHsrLightconeIndex])
return None

View File

@ -3,4 +3,4 @@
from .models import MihomoData as MihomoData
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 with AsyncClient(
base_url='http://api.mihomo.me',
base_url="http://api.mihomo.me",
headers=_HEADER,
timeout=30,
) as client:
req = await client.get(f'/sr_info/{uid}')
req = await client.get(f"/sr_info/{uid}")
path = PLAYER_PATH / str(uid)
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)
return convert(req.json(), type=MihomoData)

View File

@ -1,75 +1,65 @@
# flake8: noqa
OLD_URL = 'https://api-takumi.mihoyo.com'
OS_OLD_URL = 'https://api-os-takumi.mihoyo.com'
NEW_URL = 'https://api-takumi-record.mihoyo.com'
OS_URL = 'https://sg-public-api.hoyolab.com'
OS_INFO_URL = 'https://bbs-api-os.hoyolab.com'
OLD_URL = "https://api-takumi.mihoyo.com"
OS_OLD_URL = "https://api-os-takumi.mihoyo.com"
NEW_URL = "https://api-takumi-record.mihoyo.com"
OS_URL = "https://sg-public-api.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_OS = f'{OS_URL}/event/luna/os/info'
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_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_URL = f'{OLD_URL}/event/luna/sign'
STAR_RAIL_SIGN_URL_OS = f'{OS_URL}/event/luna/os/sign'
STAR_RAIL_MONTH_INFO_URL = (
f'{OLD_URL}/event/srledger/month_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_LIST_URL = f"{OLD_URL}/event/luna/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_REWARD_URL = f"{OLD_URL}/event/luna/extra_reward"
STAR_RAIL_SIGN_URL = f"{OLD_URL}/event/luna/sign"
STAR_RAIL_SIGN_URL_OS = f"{OS_URL}/event/luna/os/sign"
STAR_RAIL_MONTH_INFO_URL = f"{OLD_URL}/event/srledger/month_info" # 开拓阅历接口
STAR_RAIL_MONTH_DETAIL_URL = (
f'{OLD_URL}/event/srledger/month_detail' # 开拓阅历详情接口
f"{OLD_URL}/event/srledger/month_detail" # 开拓阅历详情接口
)
STAR_RAIL_NOTE_URL = (
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_INDEX_URL_OS = (
f'{OS_INFO_URL}/game_record/hkrpg/api/index' # OS角色橱窗接口
)
STAR_RAIL_NOTE_URL = 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_INDEX_URL_OS = f"{OS_INFO_URL}/game_record/hkrpg/api/index" # OS角色橱窗接口
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 = (
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 = (
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 = (
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_DETAIL_URL = f'{OLD_URL}/event/rpgcalc/avatar/detail'
STAR_RAIL_AVATAR_LIST_URL = f"{OLD_URL}/event/rpgcalc/avatar/list"
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_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_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' # 角色模拟宇宙信息接口
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_STORY_INFO_URL = (
f"{NEW_URL}/game_record/app/hkrpg/api/challenge_story" # 虚构叙事
)
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 = (
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_OS = (
f'{OS_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 = 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_OS = 'https://sg-public-data-api.hoyoverse.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"
# 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()

View File

@ -1,3 +1,3 @@
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
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.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 ..utils.convert import get_uid
from ..utils.sr_prefix import PREFIX
from .draw_abyss_card import draw_abyss_img
sv_srabyss = SV('sr查询深渊')
sv_srabyss = SV("sr查询深渊")
@sv_srabyss.on_command(
(
f'{PREFIX}查询深渊',
f'{PREFIX}查询上期深渊',
f'{PREFIX}上期深渊',
f'{PREFIX}深渊',
f"{PREFIX}查询深渊",
f"{PREFIX}查询上期深渊",
f"{PREFIX}上期深渊",
f"{PREFIX}深渊",
),
block=True,
)
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:
return None
await bot.logger.info('开始执行[sr查询深渊信息]')
get_uid_ = await get_uid(bot, ev, True)
if get_uid_ is None:
return await bot.send(UID_HINT)
uid, user_id = get_uid_
await bot.logger.info("开始执行[sr查询深渊信息]")
uid, user_id = await get_uid(bot, ev, GsBind, "sr", True)
if uid is None:
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:
schedule_type = '2'
if "上期" in ev.command:
schedule_type = "2"
else:
schedule_type = '1'
await bot.logger.info(f'[sr查询深渊信息]深渊期数: {schedule_type}')
schedule_type = "1"
await bot.logger.info(f"[sr查询深渊信息]深渊期数: {schedule_type}")
im = await draw_abyss_img(user_id, uid, ev.sender, schedule_type)
await bot.send(im)

View File

@ -1,17 +1,7 @@
from pathlib import Path
from typing import Union, Optional
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 typing import Any, Dict, Union
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 ..utils.fonts.starrail_fonts import (
sr_font_22,
@ -20,39 +10,41 @@ from ..utils.fonts.starrail_fonts import (
sr_font_34,
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)
gray_color = (175, 175, 175)
img_bg = Image.open(TEXT_PATH / 'bg.jpg')
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_5 = Image.open(TEXT_PATH / 'char5_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_gray = Image.open(TEXT_PATH / 'star_gray.png').convert('RGBA')
img_bg = Image.open(TEXT_PATH / "bg.jpg")
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_5 = Image.open(TEXT_PATH / "char5_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_gray = Image.open(TEXT_PATH / "star_gray.png").convert("RGBA")
elements = {
'ice': Image.open(TEXT_PATH / 'IconNatureColorIce.png').convert('RGBA'),
'fire': Image.open(TEXT_PATH / 'IconNatureColorFire.png').convert('RGBA'),
'imaginary': Image.open(
TEXT_PATH / 'IconNatureColorImaginary.png'
).convert('RGBA'),
'quantum': Image.open(TEXT_PATH / 'IconNatureColorQuantum.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'
),
"ice": Image.open(TEXT_PATH / "IconNatureColorIce.png").convert("RGBA"),
"fire": Image.open(TEXT_PATH / "IconNatureColorFire.png").convert("RGBA"),
"imaginary": Image.open(TEXT_PATH / "IconNatureColorImaginary.png").convert("RGBA"),
"quantum": Image.open(TEXT_PATH / "IconNatureColorQuantum.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:
return Image.open(TEXT_PATH / f'star{star}.png')
return Image.open(TEXT_PATH / f"star{star}.png")
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_card_draw.text(
(162, 31),
f'{char.rank}',
f"{char.rank}",
font=sr_font_22,
fill=white_color,
anchor='mm',
anchor="mm",
)
char_card_draw.text(
(100, 165),
f'等级 {char.level}',
f"等级 {char.level}",
font=sr_font_22,
fill=white_color,
anchor='mm',
anchor="mm",
)
floor_pic.paste(
char_bg,
@ -92,16 +84,16 @@ async def _draw_abyss_card(
async def _draw_floor_card(
level_star: int,
level_star: Union[int, str],
floor_pic: Image.Image,
img: Image.Image,
index_floor: int,
floor_name: str,
round_num: int,
round_num: Union[int, None],
):
for index_num in [0, 1, 2]:
star_num = index_num + 1
if star_num <= level_star:
if star_num <= int(level_star):
star_pic = star_yes.copy()
else:
star_pic = star_gray.copy()
@ -112,14 +104,14 @@ async def _draw_floor_card(
floor_name,
font=sr_font_42,
fill=white_color,
anchor='mm',
anchor="mm",
)
floor_pic_draw.text(
(802, 60),
f'使用轮: {round_num}',
f"使用轮: {round_num}",
font=sr_font_28,
fill=gray_color,
anchor='rm',
anchor="rm",
)
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(
qid: Union[str, int],
uid: str,
sender: Union[str, str],
schedule_type: str = '1',
sender: Dict[str, Any],
schedule_type: str = "1",
) -> Union[bytes, str]:
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)
# 获取查询者数据
if raw_abyss_data.max_floor == '':
return '你还没有挑战本期深渊!\n可以使用[sr上期深渊]命令查询上期~'
# 过滤掉 is_fast快速通关 为 True 的项
floor_detail = [detail for detail in raw_abyss_data.all_floor_detail if not detail.is_fast]
if raw_abyss_data.max_floor == "":
return "你还没有挑战本期深渊!\n可以使用[sr上期深渊]命令查询上期~"
# 过滤掉 is_fast (快速通关) 为 True 的项
floor_detail = [
detail for detail in raw_abyss_data.all_floor_detail if not detail.is_fast
]
floor_num = len(floor_detail)
# 获取背景图片各项参数
@ -147,15 +141,15 @@ async def draw_abyss_img(
based_h = 657 + 570 * floor_num
img = img_bg.copy()
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)
# 获取头像
_id = str(qid)
if _id.startswith('http'):
if _id.startswith("http"):
char_pic = await get_qq_avatar(avatar_url=_id)
elif sender.get('avatar') is not None:
char_pic = await get_qq_avatar(avatar_url=sender['avatar'])
elif sender.get("avatar") is not None:
char_pic = await get_qq_avatar(avatar_url=sender["avatar"])
else:
char_pic = await get_qq_avatar(qid=qid)
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.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_draw.text(
(220, 565),
f'{raw_abyss_data.max_floor}',
f"{raw_abyss_data.max_floor}",
white_color,
sr_font_34,
'lm',
"lm",
)
# 挑战次数
img_draw.text(
(220, 612),
f'{raw_abyss_data.battle_num}',
f"{raw_abyss_data.battle_num}",
white_color,
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_draw.text(
(695, 590),
f'{raw_abyss_data.star_num}/36',
f"{raw_abyss_data.star_num}/36",
white_color,
sr_font_42,
'lm',
"lm",
)
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
floor_name = level.name
round_num = level.round_num
@ -211,23 +205,24 @@ async def draw_abyss_img(
time_array = node_1.challenge_time
else:
time_array = node_2.challenge_time
time_str = f'{time_array.year}-{time_array.month}'
time_str = f'{time_str}-{time_array.day}'
time_str = f'{time_str} {time_array.hour}:{time_array.minute}:00'
assert time_array is not None
time_str = f"{time_array.year}-{time_array.month}"
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.text(
(112, 120 + index_part * 219),
f'节点{node_num}',
f"节点{node_num}",
white_color,
sr_font_30,
'lm',
"lm",
)
floor_pic_draw.text(
(201, 120 + index_part * 219),
f'{time_str}',
f"{time_str}",
gray_color,
sr_font_22,
'lm',
"lm",
)
if node_num == 1:
avatars_array = node_1
@ -251,5 +246,5 @@ async def draw_abyss_img(
)
res = await convert_img(img)
logger.info('[查询深渊信息]绘图已完成,等待发送!')
logger.info("[查询深渊信息]绘图已完成,等待发送!")
return res

View File

@ -6,14 +6,14 @@ from PIL import Image
from aiohttp import ClientSession
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)
async def get_icon(url: str) -> Image.Image:
name = url.split('/')[-1]
name = url.split("/")[-1]
path = ROLEINFO_PATH / name
if (path).exists():
content = path.read_bytes()
@ -21,6 +21,6 @@ async def get_icon(url: str) -> Image.Image:
async with ClientSession() as client:
async with client.get(url) as resp:
content = await resp.read()
with Path.open(path, 'wb') as f:
with Path.open(path, "wb") as f:
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
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.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 ..utils.convert import get_uid
from ..utils.sr_prefix import PREFIX
from .draw_abyss_card import draw_abyss_img
sv_abyss_boss = SV('sr查询末日幻影')
sv_abyss_boss = SV("sr查询末日幻影")
@sv_abyss_boss.on_command(
(
f'{PREFIX}查询末日幻影',
f'{PREFIX}查询上期末日幻影',
f'{PREFIX}上期末日',
f'{PREFIX}末日',
f"{PREFIX}查询末日幻影",
f"{PREFIX}查询上期末日幻影",
f"{PREFIX}上期末日",
f"{PREFIX}末日",
),
block=True,
)
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:
return None
await bot.logger.info('开始执行[sr查询末日幻影信息]')
get_uid_ = await get_uid(bot, ev, True)
if get_uid_ is None:
return await bot.send(UID_HINT)
uid, user_id = get_uid_
await bot.logger.info("开始执行[sr查询末日幻影信息]")
uid, user_id = await get_uid(bot, ev, GsBind, "sr", True)
if uid is None:
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:
schedule_type = '2'
if "上期" in ev.command:
schedule_type = "2"
else:
schedule_type = '1'
await bot.logger.info(f'[sr查询末日幻影信息]末日幻影期数: {schedule_type}')
schedule_type = "1"
await bot.logger.info(f"[sr查询末日幻影信息]末日幻影期数: {schedule_type}")
im = await draw_abyss_img(user_id, uid, ev.sender, schedule_type)
await bot.send(im)

View File

@ -1,17 +1,7 @@
from pathlib import Path
from typing import Union, Optional
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 typing import Any, Dict, Union
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 ..utils.fonts.starrail_fonts import (
sr_font_22,
@ -20,39 +10,41 @@ from ..utils.fonts.starrail_fonts import (
sr_font_34,
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)
gray_color = (175, 175, 175)
img_bg = Image.open(TEXT_PATH / 'bg.jpg')
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_5 = Image.open(TEXT_PATH / 'char5_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_gray = Image.open(TEXT_PATH / 'star_gray.png').convert('RGBA')
img_bg = Image.open(TEXT_PATH / "bg.jpg")
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_5 = Image.open(TEXT_PATH / "char5_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_gray = Image.open(TEXT_PATH / "star_gray.png").convert("RGBA")
elements = {
'ice': Image.open(TEXT_PATH / 'IconNatureColorIce.png').convert('RGBA'),
'fire': Image.open(TEXT_PATH / 'IconNatureColorFire.png').convert('RGBA'),
'imaginary': Image.open(
TEXT_PATH / 'IconNatureColorImaginary.png'
).convert('RGBA'),
'quantum': Image.open(TEXT_PATH / 'IconNatureColorQuantum.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'
),
"ice": Image.open(TEXT_PATH / "IconNatureColorIce.png").convert("RGBA"),
"fire": Image.open(TEXT_PATH / "IconNatureColorFire.png").convert("RGBA"),
"imaginary": Image.open(TEXT_PATH / "IconNatureColorImaginary.png").convert("RGBA"),
"quantum": Image.open(TEXT_PATH / "IconNatureColorQuantum.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:
return Image.open(TEXT_PATH / f'star{star}.png')
return Image.open(TEXT_PATH / f"star{star}.png")
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_card_draw.text(
(162, 31),
f'{char.rank}',
f"{char.rank}",
font=sr_font_22,
fill=white_color,
anchor='mm',
anchor="mm",
)
char_card_draw.text(
(100, 165),
f'等级 {char.level}',
f"等级 {char.level}",
font=sr_font_22,
fill=white_color,
anchor='mm',
anchor="mm",
)
floor_pic.paste(
char_bg,
@ -114,7 +106,7 @@ async def _draw_floor_card(
floor_name,
font=sr_font_42,
fill=white_color,
anchor='mm',
anchor="mm",
)
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(
qid: Union[str, int],
uid: str,
sender: Union[str, str],
schedule_type: str = '1',
sender: Dict[str, Any],
schedule_type: str = "1",
) -> Union[bytes, str]:
raw_abyss_data = await mys_api.get_abyss_boss_info(uid, schedule_type)
if isinstance(raw_abyss_data, int):
return get_error(raw_abyss_data)
# 获取查询者数据
if raw_abyss_data.max_floor == '':
return '你还没有挑战本期末日幻影!\n可以使用[sr上期末日幻影]命令查询上期~'
# 过滤掉 is_fast快速通关 为 True 的项
floor_detail = [detail for detail in raw_abyss_data.all_floor_detail if not detail.is_fast]
if raw_abyss_data.max_floor == "":
return "你还没有挑战本期末日幻影!\n可以使用[sr上期末日幻影]命令查询上期~"
# 过滤掉 is_fast (快速通关) 为 True 的项
floor_detail = [
detail for detail in raw_abyss_data.all_floor_detail if not detail.is_fast
]
floor_num = len(floor_detail)
# 获取背景图片各项参数
@ -141,15 +135,15 @@ async def draw_abyss_img(
based_h = 657 + 570 * floor_num
img = img_bg.copy()
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)
# 获取头像
_id = str(qid)
if _id.startswith('http'):
if _id.startswith("http"):
char_pic = await get_qq_avatar(avatar_url=_id)
elif sender.get('avatar') is not None:
char_pic = await get_qq_avatar(avatar_url=sender['avatar'])
elif sender.get("avatar") is not None:
char_pic = await get_qq_avatar(avatar_url=sender["avatar"])
else:
char_pic = await get_qq_avatar(qid=qid)
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.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_draw.text(
(220, 565),
f'{raw_abyss_data.max_floor}',
f"{raw_abyss_data.max_floor}",
white_color,
sr_font_34,
'lm',
"lm",
)
# 挑战次数
img_draw.text(
(220, 612),
f'{raw_abyss_data.battle_num}',
f"{raw_abyss_data.battle_num}",
white_color,
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_draw.text(
(695, 590),
f'{raw_abyss_data.star_num}/12',
f"{raw_abyss_data.star_num}/12",
white_color,
sr_font_42,
'lm',
"lm",
)
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)
floor_name = level.name
node_1 = level.node_1
@ -204,23 +198,24 @@ async def draw_abyss_img(
time_array = node_1.challenge_time
else:
time_array = node_2.challenge_time
time_str = f'{time_array.year}-{time_array.month}'
time_str = f'{time_str}-{time_array.day}'
time_str = f'{time_str} {time_array.hour}:{time_array.minute}:00'
assert time_array is not None
time_str = f"{time_array.year}-{time_array.month}"
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.text(
(112, 120 + index_part * 219),
f'节点{node_num}',
f"节点{node_num}",
white_color,
sr_font_30,
'lm',
"lm",
)
floor_pic_draw.text(
(201, 120 + index_part * 219),
f'{time_str}',
f"{time_str}",
gray_color,
sr_font_22,
'lm',
"lm",
)
if node_num == 1:
avatars_array = node_1
@ -240,9 +235,8 @@ async def draw_abyss_img(
img,
index_floor,
floor_name,
)
res = await convert_img(img)
logger.info('[查询末日幻影信息]绘图已完成,等待发送!')
logger.info("[查询末日幻影信息]绘图已完成,等待发送!")
return res

View File

@ -6,14 +6,14 @@ from PIL import Image
from aiohttp import ClientSession
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)
async def get_icon(url: str) -> Image.Image:
name = url.split('/')[-1]
name = url.split("/")[-1]
path = ROLEINFO_PATH / name
if (path).exists():
content = path.read_bytes()
@ -21,6 +21,6 @@ async def get_icon(url: str) -> Image.Image:
async with ClientSession() as client:
async with client.get(url) as resp:
content = await resp.read()
with Path.open(path, 'wb') as f:
with Path.open(path, "wb") as f:
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
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.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 ..utils.convert import get_uid
from ..utils.sr_prefix import PREFIX
from .draw_abyss_card import draw_abyss_img
sv_abyss_story = SV('sr查询虚构叙事')
sv_abyss_story = SV("sr查询虚构叙事")
@sv_abyss_story.on_command(
(
f'{PREFIX}查询虚构叙事',
f'{PREFIX}xg',
f'{PREFIX}查询上期虚构叙事',
f'{PREFIX}sqxg',
f'{PREFIX}上期虚构',
f'{PREFIX}虚构',
f"{PREFIX}查询虚构叙事",
f"{PREFIX}xg",
f"{PREFIX}查询上期虚构叙事",
f"{PREFIX}sqxg",
f"{PREFIX}上期虚构",
f"{PREFIX}虚构",
),
block=True,
)
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:
return None
await bot.logger.info('开始执行[sr查询虚构叙事信息]')
get_uid_ = await get_uid(bot, ev, True)
if get_uid_ is None:
return await bot.send(UID_HINT)
uid, user_id = get_uid_
await bot.logger.info("开始执行[sr查询虚构叙事信息]")
uid, user_id = await get_uid(bot, ev, GsBind, "sr", True)
if uid is None:
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:
schedule_type = '2'
if "sq" in ev.command or "上期" in ev.command:
schedule_type = "2"
else:
schedule_type = '1'
await bot.logger.info(f'[sr查询虚构叙事信息]虚构叙事期数: {schedule_type}')
schedule_type = "1"
await bot.logger.info(f"[sr查询虚构叙事信息]虚构叙事期数: {schedule_type}")
im = await draw_abyss_img(user_id, uid, ev.sender, schedule_type)
await bot.send(im)

View File

@ -1,17 +1,7 @@
from pathlib import Path
from typing import Union, Optional
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 typing import Any, Dict, Union
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 ..utils.fonts.starrail_fonts import (
sr_font_22,
@ -20,39 +10,41 @@ from ..utils.fonts.starrail_fonts import (
sr_font_34,
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)
gray_color = (175, 175, 175)
img_bg = Image.open(TEXT_PATH / 'bg.jpg')
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_5 = Image.open(TEXT_PATH / 'char5_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_gray = Image.open(TEXT_PATH / 'star_gray.png').convert('RGBA')
img_bg = Image.open(TEXT_PATH / "bg.jpg")
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_5 = Image.open(TEXT_PATH / "char5_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_gray = Image.open(TEXT_PATH / "star_gray.png").convert("RGBA")
elements = {
'ice': Image.open(TEXT_PATH / 'IconNatureColorIce.png').convert('RGBA'),
'fire': Image.open(TEXT_PATH / 'IconNatureColorFire.png').convert('RGBA'),
'imaginary': Image.open(
TEXT_PATH / 'IconNatureColorImaginary.png'
).convert('RGBA'),
'quantum': Image.open(TEXT_PATH / 'IconNatureColorQuantum.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'
),
"ice": Image.open(TEXT_PATH / "IconNatureColorIce.png").convert("RGBA"),
"fire": Image.open(TEXT_PATH / "IconNatureColorFire.png").convert("RGBA"),
"imaginary": Image.open(TEXT_PATH / "IconNatureColorImaginary.png").convert("RGBA"),
"quantum": Image.open(TEXT_PATH / "IconNatureColorQuantum.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:
return Image.open(TEXT_PATH / f'star{star}.png')
return Image.open(TEXT_PATH / f"star{star}.png")
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_card_draw.text(
(162, 31),
f'{char.rank}',
f"{char.rank}",
font=sr_font_22,
fill=white_color,
anchor='mm',
anchor="mm",
)
# 不存在自动下载
# 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_draw.text(
(100, 165),
f'等级 {char.level}',
f"等级 {char.level}",
font=sr_font_22,
fill=white_color,
anchor='mm',
anchor="mm",
)
floor_pic.paste(
char_bg,
@ -102,16 +94,16 @@ async def _draw_abyss_card(
async def _draw_floor_card(
level_star: int,
level_star: Union[int, str],
floor_pic: Image.Image,
img: Image.Image,
index_floor: int,
floor_name: str,
round_num: int,
round_num: Union[int, None],
):
for index_num in [0, 1, 2]:
star_num = index_num + 1
if star_num <= level_star:
if star_num <= int(level_star):
star_pic = star_yes.copy()
else:
star_pic = star_gray.copy()
@ -122,14 +114,14 @@ async def _draw_floor_card(
floor_name,
font=sr_font_42,
fill=white_color,
anchor='mm',
anchor="mm",
)
floor_pic_draw.text(
(802, 60),
f'使用轮: {round_num}',
f"使用轮: {round_num}",
font=sr_font_28,
fill=gray_color,
anchor='rm',
anchor="rm",
)
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(
qid: Union[str, int],
uid: str,
sender: Union[str, str],
schedule_type: str = '1',
sender: Dict[str, Any],
schedule_type: str = "1",
) -> Union[bytes, str]:
raw_abyss_data = await mys_api.get_abyss_story_info(uid, schedule_type)
if isinstance(raw_abyss_data, int):
return get_error(raw_abyss_data)
# 获取查询者数据
if raw_abyss_data.max_floor == '':
return '你还没有挑战本期虚构叙事!\n可以使用[sr上期虚构叙事]命令查询上期~'
# 过滤掉 is_fast快速通关 为 True 的项
floor_detail = [detail for detail in raw_abyss_data.all_floor_detail if not detail.is_fast]
if raw_abyss_data.max_floor == "":
return "你还没有挑战本期虚构叙事!\n可以使用[sr上期虚构叙事]命令查询上期~"
# 过滤掉 is_fast (快速通关) 为 True 的项
floor_detail = [
detail for detail in raw_abyss_data.all_floor_detail if not detail.is_fast
]
floor_num = len(floor_detail)
# 获取背景图片各项参数
@ -156,15 +150,15 @@ async def draw_abyss_img(
based_h = 657 + 570 * floor_num
img = img_bg.copy()
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)
# 获取头像
_id = str(qid)
if _id.startswith('http'):
if _id.startswith("http"):
char_pic = await get_qq_avatar(avatar_url=_id)
elif sender.get('avatar') is not None:
char_pic = await get_qq_avatar(avatar_url=sender['avatar'])
elif sender.get("avatar") is not None:
char_pic = await get_qq_avatar(avatar_url=sender["avatar"])
else:
char_pic = await get_qq_avatar(qid=qid)
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.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_draw.text(
(220, 565),
f'{raw_abyss_data.max_floor}',
f"{raw_abyss_data.max_floor}",
white_color,
sr_font_34,
'lm',
"lm",
)
# 挑战次数
img_draw.text(
(220, 612),
f'{raw_abyss_data.battle_num}',
f"{raw_abyss_data.battle_num}",
white_color,
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_draw.text(
(695, 590),
f'{raw_abyss_data.star_num}/12',
f"{raw_abyss_data.star_num}/12",
white_color,
sr_font_42,
'lm',
"lm",
)
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
floor_name = level.name
round_num = level.round_num
@ -220,23 +214,24 @@ async def draw_abyss_img(
time_array = node_1.challenge_time
else:
time_array = node_2.challenge_time
time_str = f'{time_array.year}-{time_array.month}'
time_str = f'{time_str}-{time_array.day}'
time_str = f'{time_str} {time_array.hour}:{time_array.minute}:00'
assert time_array is not None
time_str = f"{time_array.year}-{time_array.month}"
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.text(
(112, 120 + index_part * 219),
f'节点{node_num}',
f"节点{node_num}",
white_color,
sr_font_30,
'lm',
"lm",
)
floor_pic_draw.text(
(201, 120 + index_part * 219),
f'{time_str}',
f"{time_str}",
gray_color,
sr_font_22,
'lm',
"lm",
)
if node_num == 1:
avatars_array = node_1
@ -261,5 +256,5 @@ async def draw_abyss_img(
)
res = await convert_img(img)
logger.info('[查询虚构叙事信息]绘图已完成,等待发送!')
logger.info("[查询虚构叙事信息]绘图已完成,等待发送!")
return res

View File

@ -6,14 +6,14 @@ from PIL import Image
from aiohttp import ClientSession
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)
async def get_icon(url: str) -> Image.Image:
name = url.split('/')[-1]
name = url.split("/")[-1]
path = ROLEINFO_PATH / name
if (path).exists():
content = path.read_bytes()
@ -21,6 +21,6 @@ async def get_icon(url: str) -> Image.Image:
async with ClientSession() as client:
async with client.get(url) as resp:
content = await resp.read()
with Path.open(path, 'wb') as f:
with Path.open(path, "wb") as f:
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 ..utils.convert import get_uid
from ..utils.error_reply import UID_HINT
from ..utils.map.name_covert import (
alias_to_char_name,
@ -10,26 +9,29 @@ from ..utils.mys_api import mys_api
from ..utils.sr_prefix import PREFIX
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
if TYPE_CHECKING:
from gsuid_core.bot import Bot
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)
async def send_char_calc_info(bot: 'Bot', ev: 'Event'):
@sv_char_calc.on_command(f"{PREFIX}养成计算", block=True)
async def send_char_calc_info(bot: "Bot", ev: "Event"):
name = ev.text.strip()
char_id = await name_to_avatar_id(name)
if char_id == '':
if char_id == "":
result_fake_name = await alias_to_char_name(name)
if result_fake_name is None:
return '请输入正确的角色名'
return "请输入正确的角色名"
fake_name = result_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:
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
skill_list = []
for skill in avatar_skills:
skill_list.append(
f'{skill.point_id}({skill.cur_level}/{skill.max_level})'
)
skill_list.append(f"{skill.point_id}({skill.cur_level}/{skill.max_level})")
return None

View File

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

View File

@ -19,12 +19,12 @@ second_color = (67, 61, 56)
white_color = (247, 247, 247)
gray_color = (175, 175, 175)
TEXT_PATH = Path(__file__).parent / 'texture2D'
char_mask = Image.open(TEXT_PATH / 'ring_mask.png')
char_bg_mask = Image.open(TEXT_PATH / 'char_bg_mask.png')
tag = Image.open(TEXT_PATH / 'tag.png')
footbar = Image.open(TEXT_PATH / 'footbar.png')
pic_500 = Image.open(TEXT_PATH / '500.png')
TEXT_PATH = Path(__file__).parent / "texture2D"
char_mask = Image.open(TEXT_PATH / "ring_mask.png")
char_bg_mask = Image.open(TEXT_PATH / "char_bg_mask.png")
tag = Image.open(TEXT_PATH / "tag.png")
footbar = Image.open(TEXT_PATH / "footbar.png")
pic_500 = Image.open(TEXT_PATH / "500.png")
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)]
char_data_list.append(
{
'avatarName': avatarName,
'avatarId': str(char),
"avatarName": avatarName,
"avatarId": str(char),
}
)
if showfrom == 0:
line1 = f'展柜内有 {len(char_data_list)} 个角色!'
line1 = f"展柜内有 {len(char_data_list)} 个角色!"
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:
line1 = f'UID {uid} 刷新成功'
line2 = (
f'可以使用 sr查询{char_data_list[0]["avatarName"]} 查询详情角色面板'
)
line1 = f"UID {uid} 刷新成功"
line2 = f'可以使用 sr查询{char_data_list[0]["avatarName"]} 查询详情角色面板'
char_num = len(char_data_list)
if char_num <= 4:
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
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.paste(tag, (0, 0), tag)
img_draw = ImageDraw.Draw(img, 'RGBA')
img_draw = ImageDraw.Draw(img, "RGBA")
# 写底层文字
img_draw.text(
(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),
fw_font_28,
'mm',
"mm",
)
img_draw.text(
@ -93,14 +91,14 @@ async def draw_enka_card(uid: str, char_list: List, showfrom: int = 0):
line1,
white_color,
sr_font_58,
'lm',
"lm",
)
img_draw.text(
(225, 175),
line2,
gray_color,
sr_font_24,
'lm',
"lm",
)
tasks = []
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):
char_id = char_data['avatarId']
char_name = char_data['avatarName']
char_id = char_data["avatarId"]
char_name = char_data["avatarName"]
char_star = await avatar_id_to_char_star(str(char_id))
char_card = Image.open(TEXT_PATH / f'char{char_star}_bg.png')
char_temp = Image.new('RGBA', (300, 650))
char_card = Image.open(TEXT_PATH / f"char{char_star}_bg.png")
char_temp = Image.new("RGBA", (300, 650))
char_img = (
Image.open(str(CHAR_PREVIEW_PATH / f'{char_id}.png'))
.convert('RGBA')
Image.open(str(CHAR_PREVIEW_PATH / f"{char_id}.png"))
.convert("RGBA")
.resize((449, 615))
)
if char_name == '希儿':
if char_name == "希儿":
char_img = char_img.resize((449, 650))
char_img = char_img.crop((135, 0, 379, 457))
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_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(
(150, 585),
char_name,
white_color,
sr_font_30,
'mm',
"mm",
)
x = 42 + index * 325
img.paste(char_card, (x, 199), char_card)
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_card = Image.open(TEXT_PATH / f'ring_{char_star}.png')
_path = CHAR_PREVIEW_PATH / f'{char_id}.png'
char_img = Image.open(_path).convert('RGBA')
char_card = Image.open(TEXT_PATH / f"ring_{char_star}.png")
_path = CHAR_PREVIEW_PATH / f"{char_id}.png"
char_img = Image.open(_path).convert("RGBA")
char_img = char_img.resize(
(int(char_img.size[0] * 0.76), int(char_img.size[1] * 0.76))
)
char_temp = Image.new('RGBA', (300, 400))
card_temp = Image.new('RGBA', (300, 400))
char_temp = Image.new("RGBA", (300, 400))
card_temp = Image.new("RGBA", (300, 400))
char_temp.paste(char_img, (19, 57), char_img)
card_temp.paste(char_temp, (0, 0), char_mask)
char_draw = ImageDraw.Draw(card_temp)
char_draw.text(
(144, 285),
char_data['avatarName'],
'white',
char_data["avatarName"],
"white",
sr_font_30,
'mm',
"mm",
)
img.paste(

View File

@ -7,18 +7,16 @@ from gsuid_core.models import Event
from gsuid_core.sv import SV
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):
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:
return await bot.send('[星穹铁道] 你还没有绑定UID哦!')
logger.info(
f'[{ev.user_id}] [UID{uid}]尝试[{ev.command[2:]}]了[{ev.text}]功能'
)
return await bot.send("[星穹铁道] 你还没有绑定UID哦!")
logger.info(f"[{ev.user_id}] [UID{uid}]尝试[{ev.command[2:]}]了[{ev.text}]功能")
await bot.send(await set_config_func(uid, ev))
return None

View File

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

View File

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

View File

@ -4,7 +4,7 @@ from .config_default import CONIFG_DEFAULT
from ..utils.resource.RESOURCE_PATH import CONFIG_PATH
srconfig = StringConfig(
'StarRailUID',
"StarRailUID",
CONFIG_PATH,
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.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
from ..utils.sr_prefix import PREFIX
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 = 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):
await bot.logger.info('开始执行[sr抽卡记录]')
get_uid_ = await get_uid(bot, ev, True, False)
if get_uid_ is None:
return await bot.send(UID_HINT)
uid, user_id = get_uid_
await bot.logger.info("开始执行[sr抽卡记录]")
uid, user_id = await get_uid(bot, ev, GsBind, "sr", True)
if uid is None:
return await bot.send(UID_HINT)
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
@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):
await bot.logger.info('开始执行[sr导入抽卡链接]')
uid = await get_uid(bot, ev, only_uid=True)
await bot.logger.info("开始执行[sr导入抽卡链接]")
uid = await get_uid(bot, ev, GsBind, "sr")
if uid is None:
return await bot.send(UID_HINT)
gacha_url = ev.text.strip()
if not gacha_url or not isinstance(gacha_url, str):
return await bot.send('请给出正确的抽卡记录链接')
return await bot.send("请给出正确的抽卡记录链接")
is_force = False
if ev.command.startswith('强制'):
await bot.logger.info('[WARNING]本次为强制刷新')
if ev.command.startswith("强制"):
await bot.logger.info("[WARNING]本次为强制刷新")
is_force = True
await bot.send(
f'UID{uid}开始执行[刷新抽卡记录],需要一定时间...请勿重复触发!'
)
await bot.send(f"UID{uid}开始执行[刷新抽卡记录],需要一定时间...请勿重复触发!")
im = await save_gachalogs(uid, gacha_url, None, is_force)
return await bot.send(im)

View File

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

View File

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

View File

@ -6,11 +6,11 @@ from gsuid_core.logger import logger
from .get_help import get_core_help
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):
logger.info('开始执行[sr帮助]')
logger.info("开始执行[sr帮助]")
im = await get_core_help()
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 ..utils.fonts.starrail_fonts import starrail_font_origin
TEXT_PATH = Path(__file__).parent / 'texture2d'
HELP_DATA = Path(__file__).parent / 'Help.json'
TEXT_PATH = Path(__file__).parent / "texture2d"
HELP_DATA = Path(__file__).parent / "Help.json"
async def get_help_data() -> Optional[Dict[str, PluginHelp]]:
if HELP_DATA.exists():
async with aiofiles.open(HELP_DATA, 'rb') as file:
return msgjson.decode(
await file.read(), type=Dict[str, PluginHelp]
)
async with aiofiles.open(HELP_DATA, "rb") as file:
return msgjson.decode(await file.read(), type=Dict[str, PluginHelp])
return None
async def get_core_help() -> Union[bytes, str]:
help_data = await get_help_data()
if help_data is None:
return '暂未找到帮助数据...'
return "暂未找到帮助数据..."
return await get_help(
'StarRailUID',
f'版本号:{StarRail_version}',
"StarRailUID",
f"版本号:{StarRail_version}",
help_data,
Image.open(TEXT_PATH / 'bg.jpg'),
Image.open(TEXT_PATH / 'ICON.png'),
Image.open(TEXT_PATH / 'badge.png'),
Image.open(TEXT_PATH / 'banner.png'),
Image.open(TEXT_PATH / 'button.png'),
Image.open(TEXT_PATH / "bg.jpg"),
Image.open(TEXT_PATH / "ICON.png"),
Image.open(TEXT_PATH / "badge.png"),
Image.open(TEXT_PATH / "banner.png"),
Image.open(TEXT_PATH / "button.png"),
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.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 .note_text import award
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 = 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):
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:
return UID_HINT
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(
(
f'{PREFIX}开拓月历',
f'{PREFIX}zj',
f'{PREFIX}月历',
f"{PREFIX}开拓月历",
f"{PREFIX}zj",
f"{PREFIX}月历",
)
)
async def send_monthly_pic(bot: Bot, ev: Event):
await bot.logger.info('开始执行[sr开拓月历]')
sr_uid = await get_uid(bot, ev)
await bot.logger.info("开始执行[sr开拓月历]")
sr_uid = await get_uid(bot, ev, GsBind, "sr")
if sr_uid is None:
return UID_HINT
im = await draw_note_img(str(sr_uid))

View File

@ -1,23 +1,23 @@
from datetime import datetime
import json
from pathlib import Path
from typing import Union
from datetime import datetime
from PIL import Image, ImageDraw
from msgspec import json as msgjson
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 ..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.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')
avatar_default = Image.open(TEXT_PATH / '200101.png')
monthly_bg = Image.open(TEXT_PATH / "monthly_bg.png")
avatar_default = Image.open(TEXT_PATH / "200101.png")
first_color = (29, 29, 29)
second_color = (67, 61, 56)
@ -26,20 +26,20 @@ black_color = (54, 54, 54)
white_color = (213, 213, 213)
COLOR_MAP = {
'每日活跃': (248, 227, 157),
'活动奖励': (99, 231, 176),
'冒险奖励': (114, 205, 251),
'模拟宇宙奖励': (160, 149, 248),
'忘却之庭奖励': (221, 119, 250),
'邮件奖励': (244, 110, 104),
'其他': (255, 242, 200),
'Daily Activity': (248, 227, 157),
'Events': (99, 231, 176),
'Adventure': (114, 205, 251),
'moni': (160, 149, 248),
'Spiral Abyss': (221, 119, 250),
'Quests': (244, 110, 104),
'Other': (255, 242, 200),
"每日活跃": (248, 227, 157),
"活动奖励": (99, 231, 176),
"冒险奖励": (114, 205, 251),
"模拟宇宙奖励": (160, 149, 248),
"忘却之庭奖励": (221, 119, 250),
"邮件奖励": (244, 110, 104),
"其他": (255, 242, 200),
"Daily Activity": (248, 227, 157),
"Events": (99, 231, 176),
"Adventure": (114, 205, 251),
"moni": (160, 149, 248),
"Spiral Abyss": (221, 119, 250),
"Quests": (244, 110, 104),
"Other": (255, 242, 200),
}
@ -50,25 +50,25 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
# 获取当前时间
now = datetime.now()
current_year_mon = now.strftime('%Y-%m')
add_month = ''
current_year_mon = now.strftime("%Y-%m")
add_month = ""
if int(now.month) < 10:
add_month = '0'
add_month = "0"
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):
return get_error(data)
# 保存数据
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:
save_json_data = msgjson.format(msgjson.encode(data), indent=4)
save_data = json.dumps(
{
'data_time': now.strftime('%Y-%m-%d %H:%M:%S'),
'data': save_json_data.decode('utf-8'),
"data_time": now.strftime("%Y-%m-%d %H:%M:%S"),
"data": save_json_data.decode("utf-8"),
},
ensure_ascii=False,
)
@ -80,33 +80,31 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
if last_month == 0:
last_month = 12
last_year -= 1
last_year_mon = f'{last_year}-{last_month:02d}'
last_monthly_path = path / f'monthly_{last_year_mon}.json'
last_year_mon = f"{last_year}-{last_month:02d}"
last_monthly_path = path / f"monthly_{last_year_mon}.json"
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 = msgjson.decode(
last_monthly_data['data'], type=MonthlyAward
last_monthly_data["data"], type=MonthlyAward
)
else:
add_month = ''
add_month = ""
if int(last_month) < 10:
add_month = '0'
add_month = "0"
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):
return get_error(last_monthly_data)
# 保存上月数据
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:
save_json_data = msgjson.format(
msgjson.encode(last_monthly_data), indent=4
)
save_json_data = msgjson.format(msgjson.encode(last_monthly_data), indent=4)
save_data = json.dumps(
{
'data_time': now.strftime('%Y-%m-%d %H:%M:%S'),
'data': save_json_data.decode('utf-8'),
"data_time": now.strftime("%Y-%m-%d %H:%M:%S"),
"data": save_json_data.decode("utf-8"),
},
ensure_ascii=False,
)
@ -141,7 +139,7 @@ async def draw_note_img(sr_uid: str) -> Union[bytes, str]:
img = monthly_bg.copy()
avatar_img = avatar_default.copy()
char_pic = avatar_img.convert('RGBA').resize(
char_pic = avatar_img.convert("RGBA").resize(
(125, 125),
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)
# 写Nickname
img_draw.text(
(310, 184), nickname, font=sr_font_34, fill=first_color, anchor='lm'
)
img_draw.text((310, 184), nickname, font=sr_font_34, fill=first_color, anchor="lm")
# 写UID
img_draw.text(
(267, 219),
f'UID {sr_uid}',
f"UID {sr_uid}",
font=sr_font_20,
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,
font=sr_font_28,
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,
font=sr_font_28,
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,
font=sr_font_28,
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,
font=sr_font_28,
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,
font=sr_font_28,
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,
font=sr_font_28,
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,
font=sr_font_28,
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,
font=sr_font_28,
fill=black_color,
anchor='lm',
anchor="lm",
)
xy = ((0, 0), (2100, 2100))
temp = -90
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.ellipse(xy, fill=(128, 128, 128))
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)
for _index, i in enumerate(data.month_data.group_by):
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
# 绘制蒙版圆形
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))
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)
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)
for _index, i in enumerate(last_monthly_data.month_data.group_by):
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
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.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))
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 = await convert_img(img)
logger.info('[开拓月历] 图片绘制完成!等待发送...')
logger.info("[开拓月历] 图片绘制完成!等待发送...")
return img
async def int_carry(i: int) -> str:
if i >= 100000:
i_str = f'{i / 10000:.1f}W'
i_str = f"{i / 10000:.1f}W"
else:
i_str = str(i)
return i_str

View File

@ -1,7 +1,7 @@
from datetime import datetime
from ..utils.mys_api import mys_api
from ..utils.error_reply import get_error
from ..utils.mys_api import mys_api
month_im = """==============
SR_UID:{}
@ -24,7 +24,7 @@ SR_UID:{}
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):
return get_error(data)
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
lastmonth_stone = data.month_data.last_hcoin
lastmonth_rails_pass = data.month_data.last_rails_pass
group_str = ''
group_str = ""
for i in data.month_data.group_by:
group_str = (
group_str
+ i.action_name
+ ':'
+ ":"
+ str(i.num)
+ '('
+ "("
+ str(i.percent)
+ '%)'
+ '\n'
+ "%)"
+ "\n"
)
return month_im.format(

View File

@ -6,18 +6,16 @@ from gsuid_core.logger import logger
from ..utils.sr_prefix import PREFIX
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):
await bot.send('sr正在开始下载~可能需要较久的时间!')
await bot.send("sr正在开始下载~可能需要较久的时间!")
im = await check_use()
await bot.send(im)
async def startup():
logger.info(
'[sr资源文件下载] 正在检查与下载缺失的资源文件,可能需要较长时间,请稍等'
)
logger.info(f'[sr资源文件下载] {await check_use()}')
logger.info("[sr资源文件下载] 正在检查与下载缺失的资源文件,可能需要较长时间,请稍等")
logger.info(f"[sr资源文件下载] {await check_use()}")

View File

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

View File

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

View File

@ -6,14 +6,14 @@ from PIL import Image
from aiohttp import ClientSession
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)
async def get_icon(url: str) -> Image.Image:
name = url.split('/')[-1]
name = url.split("/")[-1]
path = ROLEINFO_PATH / name
if (path).exists():
content = path.read_bytes()
@ -21,6 +21,6 @@ async def get_icon(url: str) -> Image.Image:
async with ClientSession() as client:
async with client.get(url) as resp:
content = await resp.read()
with Path.open(path, 'wb') as f:
with Path.open(path, "wb") as f:
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
from gsuid_core.sv import SV
from gsuid_core.bot import Bot
from gsuid_core.models import Event
from gsuid_core.logger import logger
from ..utils.convert import get_uid
from ..utils.sr_prefix import PREFIX
from .draw_roleinfo_card import get_detail_img, get_role_img
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):
name = ''.join(re.findall('[\u4e00-\u9fa5]', ev.text))
name = "".join(re.findall("[\u4e00-\u9fa5]", ev.text))
if name:
return None
uid = await get_uid(bot, ev)
uid = await get_uid(bot, ev, GsBind, "sr")
if uid is None:
return '你还没有绑定UID噢,请使用[sr绑定uid123]完成绑定!'
return "你还没有绑定UID噢,请使用[sr绑定uid123]完成绑定!"
logger.info(f'[sr查询信息]UID: {uid}')
await bot.logger.info('开始执行[sr查询信息]')
logger.info(f"[sr查询信息]UID: {uid}")
await bot.logger.info("开始执行[sr查询信息]")
await bot.send(await get_role_img(uid))
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):
name = ''.join(re.findall('[\u4e00-\u9fa5]', ev.text))
name = "".join(re.findall("[\u4e00-\u9fa5]", ev.text))
if name:
return None
get_uid_ = await get_uid(bot, ev, True)
if get_uid_ is None:
return await bot.send(UID_HINT)
uid, user_id = get_uid_
uid, user_id = await get_uid(bot, ev, GsBind, "sr", True)
if uid is None:
return await bot.send(UID_HINT)
logger.info(f'[sr查询信息]UID: {uid}')
await bot.logger.info('开始执行[sr查询信息]')
logger.info(f"[sr查询信息]UID: {uid}")
await bot.logger.info("开始执行[sr查询信息]")
await bot.send(await get_detail_img(user_id, uid, ev.sender))
return None

View File

@ -1,26 +1,16 @@
import asyncio
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.image.convert import convert_img
from ..utils.fonts.first_world import fw_font_24
from ..sruid_utils.api.mys.models import (
Stats,
AvatarDetail,
RoleBasicInfo,
AvatarListItem,
AvatarListItemDetail,
RoleBasicInfo,
Stats,
)
from ..utils.fonts.first_world import fw_font_24
from ..utils.fonts.starrail_fonts import (
sr_font_22,
sr_font_24,
@ -28,41 +18,41 @@ from ..utils.fonts.starrail_fonts import (
sr_font_30,
sr_font_36,
)
from ..utils.mys_api import mys_api
TEXT_PATH = Path(__file__).parent / 'texture2D'
bg1 = Image.open(TEXT_PATH / 'bg1.png')
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')
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,
)
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')
TEXT_PATH = Path(__file__).parent / "texture2D"
bg1 = Image.open(TEXT_PATH / "bg1.png")
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)
white_color = (255, 255, 255)
color_color = (40, 18, 7)
first_color = (22, 8, 31)
elements = {
'ice': Image.open(TEXT_PATH / 'IconNatureColorIce.png').convert('RGBA'),
'fire': Image.open(TEXT_PATH / 'IconNatureColorFire.png').convert('RGBA'),
'imaginary': Image.open(
TEXT_PATH / 'IconNatureColorImaginary.png'
).convert('RGBA'),
'quantum': Image.open(TEXT_PATH / 'IconNatureColorQuantum.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'
),
"ice": Image.open(TEXT_PATH / "IconNatureColorIce.png").convert("RGBA"),
"fire": Image.open(TEXT_PATH / "IconNatureColorFire.png").convert("RGBA"),
"imaginary": Image.open(TEXT_PATH / "IconNatureColorImaginary.png").convert("RGBA"),
"quantum": Image.open(TEXT_PATH / "IconNatureColorQuantum.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)
async def get_detail_img(
qid: Union[str, int], uid: str, sender
) -> Union[bytes, str]:
async def get_detail_img(qid: Union[str, int], uid: str, sender) -> Union[bytes, str]:
return await get_detail_card(qid, uid, sender)
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(
@ -100,16 +88,14 @@ async def _draw_card_1(
bg1_draw = ImageDraw.Draw(img_bg1)
# 写Nickname
bg1_draw.text(
(400, 85), nickname, font=sr_font_36, fill=white_color, anchor='mm'
)
bg1_draw.text((400, 85), nickname, font=sr_font_36, fill=white_color, anchor="mm")
# 写UID
bg1_draw.text(
(400, 165),
f'UID {sr_uid}',
f"UID {sr_uid}",
font=sr_font_30,
fill=white_color,
anchor='mm',
anchor="mm",
)
# 贴头像
img_bg1.paste(user_avatar, (286, 213), mask=user_avatar)
@ -120,31 +106,31 @@ async def _draw_card_1(
str(active_days),
font=sr_font_36,
fill=white_color,
anchor='mm',
anchor="mm",
) # 活跃天数
bg1_draw.text(
(270, 590),
str(avater_num),
font=sr_font_36,
fill=white_color,
anchor='mm',
anchor="mm",
) # 解锁角色
bg1_draw.text(
(398, 590),
str(achievement_num),
font=sr_font_36,
fill=white_color,
anchor='mm',
anchor="mm",
) # 达成成就
bg1_draw.text(
(525, 590),
str(chest_num),
font=sr_font_36,
fill=white_color,
anchor='mm',
anchor="mm",
) # 战利品开启
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,
font=sr_font_30,
fill=first_color,
anchor='mm',
anchor="mm",
)
return img_bg1
@ -174,10 +160,10 @@ async def _draw_avatar_card(
char_bg.paste(rank_bg, (89, 6), mask=rank_bg)
char_draw.text(
(100, 21),
f'{avatar.rank}',
f"{avatar.rank}",
font=sr_font_22,
fill=white_color,
anchor='mm',
anchor="mm",
)
if equip := equips[avatar.id]:
@ -190,7 +176,7 @@ async def _draw_avatar_card(
_lv(avatar.level),
font=sr_font_24,
fill=color_color,
anchor='mm',
anchor="mm",
)
return char_bg
@ -214,12 +200,9 @@ async def _draw_card_2(
) -> Image.Image:
# 角色部分 每五个一组
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
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)
else:
role_basic_info = {}
role_basic_info['nickname'] = '开拓者'
role_basic_info['level'] = 0
role_basic_info["nickname"] = "开拓者"
role_basic_info["level"] = 0
if isinstance(role_index, int):
return get_error(role_index)
@ -266,7 +249,7 @@ async def draw_role_card(sr_uid: str) -> Union[bytes, str]:
)
img2: Image.Image
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(img2, (0, 810))
img.paste(bg3, (0, height + 810))
@ -279,69 +262,69 @@ async def _draw_detail_card(
index: int,
char_info: Image.Image,
) -> Image.Image:
if str(avatar.rarity) == '5':
avatar_img = Image.open(TEXT_PATH / 'bar_5.png')
if str(avatar.rarity) == "5":
avatar_img = Image.open(TEXT_PATH / "bar_5.png")
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)
char_icon = (await get_icon(avatar.icon)).resize((40, 40))
element_icon = elements[avatar.element]
avatar_img.paste(char_icon, (75, 10), mask=char_icon)
avatar_draw.text(
(130, 30),
f'{avatar.name}',
f"{avatar.name}",
first_color,
sr_font_24,
'lm',
"lm",
)
avatar_img.paste(element_icon, (270, 10), mask=element_icon)
avatar_draw.text(
(339, 30),
f'{avatar.level}',
f"{avatar.level}",
first_color,
sr_font_24,
'mm',
"mm",
)
avatar_draw.text(
(385, 30),
f'{avatar.rank}',
f"{avatar.rank}",
first_color,
sr_font_24,
'mm',
"mm",
)
avatar_draw.text(
(429, 30),
f'{avatar_detail.skills[0].cur_level}',
f"{avatar_detail.skills[0].cur_level}",
first_color,
sr_font_24,
'mm',
"mm",
)
avatar_draw.text(
(469, 30),
f'{avatar_detail.skills[1].cur_level}',
f"{avatar_detail.skills[1].cur_level}",
first_color,
sr_font_24,
'mm',
"mm",
)
avatar_draw.text(
(515, 30),
f'{avatar_detail.skills[2].cur_level}',
f"{avatar_detail.skills[2].cur_level}",
first_color,
sr_font_24,
'mm',
"mm",
)
avatar_draw.text(
(553, 30),
f'{avatar_detail.skills[3].cur_level}',
f"{avatar_detail.skills[3].cur_level}",
first_color,
sr_font_24,
'mm',
"mm",
)
if avatar.equip:
@ -350,26 +333,26 @@ async def _draw_detail_card(
avatar_draw.text(
(680, 30),
f'{avatar.equip.rank}',
f"{avatar.equip.rank}",
first_color,
sr_font_24,
'mm',
"mm",
)
avatar_draw.text(
(734, 30),
f'Lv.{avatar.equip.level}',
f"Lv.{avatar.equip.level}",
first_color,
sr_font_24,
'lm',
"lm",
)
avatar_draw.text(
(804, 30),
f'{avatar.equip.name}',
f"{avatar.equip.name}",
first_color,
sr_font_24,
'lm',
"lm",
)
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(
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]:
# 获取角色列表
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_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)
# 获取头像
_id = str(qid)
if _id.startswith('http'):
if _id.startswith("http"):
char_pic = await get_qq_avatar(avatar_url=_id)
elif sender.get('avatar') is not None:
char_pic = await get_qq_avatar(avatar_url=sender['avatar'])
elif sender.get("avatar") is not None:
char_pic = await get_qq_avatar(avatar_url=sender["avatar"])
else:
char_pic = await get_qq_avatar(qid=qid)
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_img_draw.text(
(525, 420), f'UID {sr_uid}', white_color, sr_font_28, 'mm'
)
char_img_draw.text((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)
for index, avatar in enumerate(avatar_list.avatar_list):
@ -431,12 +412,12 @@ async def get_detail_card(
# 写底层文字
char_img_draw.text(
(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),
fw_font_24,
'mm',
"mm",
)
res = await convert_img(char_info)
logger.info('[查询练度统计]绘图已完成,等待发送!')
logger.info("[查询练度统计]绘图已完成,等待发送!")
return res

View File

@ -6,9 +6,9 @@ from PIL import Image
from aiohttp import ClientSession
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)
@ -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:
name = url.split('/')[-1]
name = url.split("/")[-1]
path = ROLEINFO_PATH / name
if (path).exists():
content = path.read_bytes()
@ -26,6 +26,6 @@ async def get_icon(url: str) -> Image.Image:
async with ClientSession() as client:
async with client.get(url) as resp:
content = await resp.read()
with Path.open(path, 'wb') as f:
with Path.open(path, "wb") as f:
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.sign.sign import daily_sign, sign_in
SIGN_TIME = srconfig.get_config('SignTime').data
IS_REPORT = srconfig.get_config('PrivateSignReport').data
SIGN_TIME = srconfig.get_config("SignTime").data
IS_REPORT = srconfig.get_config("PrivateSignReport").data
sv_sign = SV('星穹铁道签到')
sv_sign_config = SV('星穹铁道管理', pm=2)
sv_sign = SV("星穹铁道签到")
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):
logger.info(f'[星穹铁道] [签到] 用户: {ev.user_id}')
uid = await GsBind.get_uid_by_game(ev.user_id, ev.bot_id, 'sr')
logger.info(f"[星穹铁道] [签到] 用户: {ev.user_id}")
uid = await GsBind.get_uid_by_game(ev.user_id, ev.bot_id, "sr")
if uid is None:
return await bot.send(UID_HINT)
logger.info(f'[星穹铁道] [签到] UID: {uid}')
await bot.send(await sign_in(uid, 'sr'))
logger.info(f"[星穹铁道] [签到] UID: {uid}")
await bot.send(await sign_in(uid, "sr"))
return None
@sv_sign_config.on_fullmatch(f'{PREFIX}全部重签')
@sv_sign_config.on_fullmatch(f"{PREFIX}全部重签")
async def recheck(bot: Bot, ev: Event):
await bot.logger.info('开始执行[全部重签]')
await bot.send('[星穹铁道] [全部重签] 已开始执行!')
result = await daily_sign('sr')
await bot.logger.info("开始执行[全部重签]")
await bot.send("[星穹铁道] [全部重签] 已开始执行!")
result = await daily_sign("sr")
if not IS_REPORT:
result['private_msg_dict'] = {}
result["private_msg_dict"] = {}
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():
if srconfig.get_config('SchedSignin').data:
result = await daily_sign('sr')
if srconfig.get_config("SchedSignin").data:
result = await daily_sign("sr")
if not IS_REPORT:
result['private_msg_dict'] = {}
result["private_msg_dict"] = {}
await send_board_cast_msg(result)

View File

@ -1,82 +1,83 @@
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.gss import gss
from gsuid_core.models import Event
from gsuid_core.aps import scheduler
from gsuid_core.logger import logger
from gsuid_core.models import Event
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
from .notice import get_notice_list
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 = 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):
await bot.logger.info('开始执行[sr每日信息文字版]')
uid = await get_uid(bot, ev)
await bot.logger.info("开始执行[sr每日信息文字版]")
uid = await get_uid(bot, ev, GsBind, "sr")
if uid is None:
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)
await bot.send(im)
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):
await bot.logger.info('开始执行[sr强制推送体力信息]')
await bot.logger.info("开始执行[sr强制推送体力信息]")
await sr_notice_job()
@scheduler.scheduled_job('cron', minute='*/30')
@scheduler.scheduled_job("cron", minute="*/30")
async def sr_notice_job():
result = await get_notice_list()
logger.info('[sr推送检查]完成!等待消息推送中...')
logger.info("[sr推送检查]完成!等待消息推送中...")
logger.debug(result)
# 执行私聊推送
for bot_id in result:
for BOT_ID in gss.active_bot:
bot = gss.active_bot[BOT_ID]
for user_id in result[bot_id]['direct']:
msg = result[bot_id]['direct'][user_id]
await bot.target_send(msg, 'direct', user_id, bot_id, '', '')
for user_id in result[bot_id]["direct"]:
msg = result[bot_id]["direct"][user_id]
await bot.target_send(msg, "direct", user_id, bot_id, "", "")
await asyncio.sleep(0.5)
logger.info('[sr推送检查] 私聊推送完成')
for gid in result[bot_id]['group']:
logger.info("[sr推送检查] 私聊推送完成")
for gid in result[bot_id]["group"]:
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 = result[bot_id]['group'][gid][user_id]
msg = result[bot_id]["group"][gid][user_id]
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)
logger.info('[sr推送检查] 群聊推送完成')
logger.info("[sr推送检查] 群聊推送完成")
@sv_get_stamina.on_fullmatch(
(
f'{PREFIX}每日',
f'{PREFIX}mr',
f'{PREFIX}实时便笺',
f'{PREFIX}便笺',
f'{PREFIX}便签',
f"{PREFIX}每日",
f"{PREFIX}mr",
f"{PREFIX}实时便笺",
f"{PREFIX}便笺",
f"{PREFIX}便签",
)
)
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
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)
await bot.send(im)

View File

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

View File

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

View File

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

View File

@ -7,72 +7,72 @@ from ..utils.message import send_diff_msg
from ..utils.sr_prefix import PREFIX
from .draw_user_card import get_user_card
sv_user_config = SV('sr用户管理', pm=2)
sv_user_info = SV('sr用户信息')
sv_user_config = SV("sr用户管理", pm=2)
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):
await bot.logger.info('sr开始执行[查询用户绑定状态]')
await bot.logger.info("sr开始执行[查询用户绑定状态]")
uid_list = await get_user_card(ev.bot_id, ev.user_id)
if not uid_list:
return await bot.send('你还没有绑定SR_UID哦!')
await bot.logger.info('sr[查询用户绑定状态]完成!等待图片发送中...')
return await bot.send("你还没有绑定SR_UID哦!")
await bot.logger.info("sr[查询用户绑定状态]完成!等待图片发送中...")
await bot.send(uid_list)
return None
@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):
await bot.logger.info('sr开始执行[绑定/解绑用户信息]')
await bot.logger.info("sr开始执行[绑定/解绑用户信息]")
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()
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(
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(
bot,
data,
{
0: f'✅[崩铁]绑定UID{sr_uid}成功!',
-1: f'❌SR_UID{sr_uid}的位数不正确!',
-2: f'❌SR_UID{sr_uid}已经绑定过了!',
-3: '❌你输入了错误的格式!',
0: f"✅[崩铁]绑定UID{sr_uid}成功!",
-1: f"❌SR_UID{sr_uid}的位数不正确!",
-2: f"❌SR_UID{sr_uid}已经绑定过了!",
-3: "❌你输入了错误的格式!",
},
)
if '切换' in ev.command:
data = await GsBind.switch_uid_by_game(qid, ev.bot_id, sr_uid, 'sr')
if "切换" in ev.command:
data = await GsBind.switch_uid_by_game(qid, ev.bot_id, sr_uid, "sr")
return await send_diff_msg(
bot,
data,
{
0: f'✅[崩铁]切换uid{sr_uid}成功!',
-1: '❌[崩铁]不存在绑定记录!',
-2: '❌[崩铁]请绑定两个以上UID再进行切换!',
-3: '❌[崩铁]请绑定两个以上UID再进行切换!',
0: f"✅[崩铁]切换uid{sr_uid}成功!",
-1: "❌[崩铁]不存在绑定记录!",
-2: "❌[崩铁]请绑定两个以上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(
bot,
data,
{
0: f'✅[崩铁]删除UID{sr_uid}成功!',
-1: f'❌[崩铁]该UID{sr_uid}不在已绑定列表中!',
0: 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,
)
sv_sr_wiki = SV('星铁WIKI')
sv_sr_guide = SV('星铁攻略')
sv_sr_wiki = SV("星铁WIKI")
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):
char_name = ' '.join(re.findall('[\u4e00-\u9fa5]+', ev.text))
await bot.logger.info(f'开始获取{char_name}图鉴')
if '开拓者' in str(char_name):
char_name = '开拓者'
char_name = " ".join(re.findall("[\u4e00-\u9fa5]+", ev.text))
await bot.logger.info(f"开始获取{char_name}图鉴")
if "开拓者" in str(char_name):
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_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():
img = await convert_img(img)
await bot.logger.info(f'获得{char_name}图鉴图片成功!')
await bot.logger.info(f"获得{char_name}图鉴图片成功!")
await bot.send(img)
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):
char_name = ' '.join(re.findall('[\u4e00-\u9fa5]+', ev.text))
await bot.logger.info(f'开始获取{char_name}图鉴')
if '开拓者' in str(char_name):
char_name = '开拓者'
char_name = " ".join(re.findall("[\u4e00-\u9fa5]+", ev.text))
await bot.logger.info(f"开始获取{char_name}图鉴")
if "开拓者" in str(char_name):
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_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():
img = await convert_img(img)
await bot.logger.info(f'获得{char_id}图鉴图片成功!')
await bot.logger.info(f"获得{char_id}图鉴图片成功!")
await bot.send(img)
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):
msg = ' '.join(re.findall('[\u4e00-\u9fa5]+', ev.text))
await bot.logger.info(f'开始获取{msg}图鉴')
msg = " ".join(re.findall("[\u4e00-\u9fa5]+", ev.text))
await bot.logger.info(f"开始获取{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():
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)
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):
msg = ' '.join(re.findall('[\u4e00-\u9fa5]+', ev.text))
await bot.logger.info(f'开始获取{msg}遗器')
msg = " ".join(re.findall("[\u4e00-\u9fa5]+", ev.text))
await bot.logger.info(f"开始获取{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():
img = await convert_img(img)
await bot.logger.info(f'获得{msg}遗器图片成功!')
await bot.logger.info(f"获得{msg}遗器图片成功!")
await bot.send(img)
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):
char_name = ' '.join(re.findall('[\u4e00-\u9fa5]+', ev.text))
await bot.logger.info(f'开始获取{char_name}突破材料')
if '开拓者' in str(char_name):
char_name = '开拓者'
char_name = " ".join(re.findall("[\u4e00-\u9fa5]+", ev.text))
await bot.logger.info(f"开始获取{char_name}突破材料")
if "开拓者" in str(char_name):
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_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():
img = await convert_img(img)
await bot.logger.info(f'获得{char_name}突破材料图片成功!')
await bot.logger.info(f"获得{char_name}突破材料图片成功!")
await bot.send(img)
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):
msg = ' '.join(re.findall('[\u4e00-\u9fa5]+', ev.text))
await bot.logger.info(f'开始获取{msg}武器')
msg = " ".join(re.findall("[\u4e00-\u9fa5]+", ev.text))
await bot.logger.info(f"开始获取{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():
img = await convert_img(img)
await bot.logger.info(f'获得{msg}武器图片成功!')
await bot.logger.info(f"获得{msg}武器图片成功!")
await bot.send(img)
else:
await bot.logger.warning(f'未找到{msg}武器图片')
await bot.logger.warning(f"未找到{msg}武器图片")

View File

@ -1,36 +1,12 @@
import re
from typing import Tuple, Union, Optional, overload
from typing import Optional, Tuple, Union
from gsuid_core.bot import Bot
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
@overload
async def get_uid(
bot: Bot, ev: Event, get_user_id: bool = False, only_uid: 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
bot: Bot, ev: Event, get_user_id: bool = False
) -> Union[Optional[str], Tuple[Optional[str], str]]:
uid_data = re.findall(r'\d{9}', ev.text)
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
return await get_uid_db(bot, ev, GsBind, "sr", get_user_id) # type: ignore

View File

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

View File

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

View File

@ -3,17 +3,17 @@ from pathlib import Path
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)
with Path.open(EXCEL / 'RelicSubAffixConfig.json', encoding='utf8') as f:
with Path.open(EXCEL / "RelicSubAffixConfig.json", encoding="utf8") as 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)
with Path.open(EXCEL / 'EquipmentPromotionConfig.json', encoding='utf8') as f:
with Path.open(EXCEL / "EquipmentPromotionConfig.json", encoding="utf8") as 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)

View File

@ -2,7 +2,7 @@ from pathlib import Path
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:

View File

@ -2,7 +2,7 @@ from pathlib import Path
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:

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

View File

@ -12,36 +12,34 @@ class RelicSetStatusAdd(Struct):
Value: float
MAP = Path(__file__).parent / 'data'
MAP = Path(__file__).parent / "data"
version = StarRail_version
avatarId2Name_fileName = f'avatarId2Name_mapping_{version}.json'
avatarId2EnName_fileName = f'avatarId2EnName_mapping_{version}.json'
EquipmentID2Name_fileName = f'EquipmentID2Name_mapping_{version}.json'
EquipmentID2EnName_fileName = f'EquipmentID2EnName_mapping_{version}.json'
skillId2Name_fileName = f'skillId2Name_mapping_{version}.json'
skillId2Type_fileName = f'skillId2Type_mapping_{version}.json'
Property2Name_fileName = f'Property2Name_mapping_{version}.json'
RelicId2SetId_fileName = f'RelicId2SetId_mapping_{version}.json'
SetId2Name_fileName = f'SetId2Name_mapping_{version}.json'
rankId2Name_fileName = f'rankId2Name_mapping_{version}.json'
characterSkillTree_fileName = f'characterSkillTree_mapping_{version}.json'
avatarId2DamageType_fileName = f'avatarId2DamageType_mapping_{version}.json'
avatarId2Rarity_fileName = f'avatarId2Rarity_mapping_{version}.json'
avatarId2Name_fileName = f"avatarId2Name_mapping_{version}.json"
avatarId2EnName_fileName = f"avatarId2EnName_mapping_{version}.json"
EquipmentID2Name_fileName = f"EquipmentID2Name_mapping_{version}.json"
EquipmentID2EnName_fileName = f"EquipmentID2EnName_mapping_{version}.json"
skillId2Name_fileName = f"skillId2Name_mapping_{version}.json"
skillId2Type_fileName = f"skillId2Type_mapping_{version}.json"
Property2Name_fileName = f"Property2Name_mapping_{version}.json"
RelicId2SetId_fileName = f"RelicId2SetId_mapping_{version}.json"
SetId2Name_fileName = f"SetId2Name_mapping_{version}.json"
rankId2Name_fileName = f"rankId2Name_mapping_{version}.json"
characterSkillTree_fileName = f"characterSkillTree_mapping_{version}.json"
avatarId2DamageType_fileName = f"avatarId2DamageType_mapping_{version}.json"
avatarId2Rarity_fileName = f"avatarId2Rarity_mapping_{version}.json"
EquipmentID2AbilityProperty_fileName = (
f'EquipmentID2AbilityProperty_mapping_{version}.json'
f"EquipmentID2AbilityProperty_mapping_{version}.json"
)
RelicSetSkill_fileName = f'RelicSetSkill_mapping_{version}.json'
skillId2AttackType_fileName = f'skillId2AttackType_mapping_{version}.json'
EquipmentID2Rarity_fileName = f'EquipmentID2Rarity_mapping_{version}.json'
RelicId2Rarity_fileName = f'RelicId2Rarity_mapping_{version}.json'
ItemId2Name_fileName = f'ItemId2Name_mapping_{version}.json'
RelicId2MainAffixGroup_fileName = (
f'RelicId2MainAffixGroup_mapping_{version}.json'
)
AvatarRelicScore_fileName = 'AvatarRelicScore.json'
avatarRankSkillUp_fileName = f'avatarRankSkillUp_mapping_{version}.json'
RelicSetSkill_fileName = f"RelicSetSkill_mapping_{version}.json"
skillId2AttackType_fileName = f"skillId2AttackType_mapping_{version}.json"
EquipmentID2Rarity_fileName = f"EquipmentID2Rarity_mapping_{version}.json"
RelicId2Rarity_fileName = f"RelicId2Rarity_mapping_{version}.json"
ItemId2Name_fileName = f"ItemId2Name_mapping_{version}.json"
RelicId2MainAffixGroup_fileName = f"RelicId2MainAffixGroup_mapping_{version}.json"
AvatarRelicScore_fileName = "AvatarRelicScore.json"
avatarRankSkillUp_fileName = f"avatarRankSkillUp_mapping_{version}.json"
class TS(TypedDict):
@ -54,51 +52,49 @@ class LU(TypedDict):
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])
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])
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])
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])
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])
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])
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])
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])
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])
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])
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])
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])
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]])
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])
with Path.open(
MAP / EquipmentID2AbilityProperty_fileName, encoding='UTF-8'
) as f:
with Path.open(MAP / EquipmentID2AbilityProperty_fileName, encoding="UTF-8") as f:
EquipmentID2AbilityProperty = msgjson.decode(
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]])
# 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])
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])
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])
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])
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])
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])
with Path.open(MAP / avatarRankSkillUp_fileName, encoding='UTF-8') as f:
AvatarRankSkillUp = msgjson.decode(
f.read(), type=Dict[str, Union[List[LU], None]]
)
with Path.open(MAP / avatarRankSkillUp_fileName, encoding="UTF-8") as f:
AvatarRankSkillUp = msgjson.decode(f.read(), type=Dict[str, Union[List[LU], None]])

View File

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

View File

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

View File

@ -3,35 +3,35 @@ from pathlib import 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))
CU_BG_PATH = MAIN_PATH / 'bg'
CONFIG_PATH = MAIN_PATH / 'config.json'
PLAYER_PATH = MAIN_PATH / 'players'
RESOURCE_PATH = MAIN_PATH / 'resource'
WIKI_PATH = MAIN_PATH / 'wiki'
GUIDE_PATH = MAIN_PATH / 'guide'
CU_BG_PATH = MAIN_PATH / "bg"
CONFIG_PATH = MAIN_PATH / "config.json"
PLAYER_PATH = MAIN_PATH / "players"
RESOURCE_PATH = MAIN_PATH / "resource"
WIKI_PATH = MAIN_PATH / "wiki"
GUIDE_PATH = MAIN_PATH / "guide"
CHAR_ICON_PATH = RESOURCE_PATH / 'character'
CHAR_PORTRAIT_PATH = RESOURCE_PATH / 'character_portrait'
CONSUMABLE_PATH = RESOURCE_PATH / 'consumable'
ELEMENT_PATH = RESOURCE_PATH / 'element'
WEAPON_PATH = RESOURCE_PATH / 'light_cone'
RELIC_PATH = RESOURCE_PATH / 'relic'
SKILL_PATH = RESOURCE_PATH / 'skill'
TEMP_PATH = RESOURCE_PATH / 'temp'
CHAR_PREVIEW_PATH = RESOURCE_PATH / 'character_preview'
CHAR_ICON_PATH = RESOURCE_PATH / "character"
CHAR_PORTRAIT_PATH = RESOURCE_PATH / "character_portrait"
CONSUMABLE_PATH = RESOURCE_PATH / "consumable"
ELEMENT_PATH = RESOURCE_PATH / "element"
WEAPON_PATH = RESOURCE_PATH / "light_cone"
RELIC_PATH = RESOURCE_PATH / "relic"
SKILL_PATH = RESOURCE_PATH / "skill"
TEMP_PATH = RESOURCE_PATH / "temp"
CHAR_PREVIEW_PATH = RESOURCE_PATH / "character_preview"
WIKI_LIGHT_CONE_PATH = WIKI_PATH / 'light_cone'
WIKI_MATERIAL_FOR_ROLE = WIKI_PATH / 'character_material'
WIKI_RELIC_PATH = WIKI_PATH / 'relic_set'
WIKI_ROLE_PATH = WIKI_PATH / 'character_overview'
WIKI_LIGHT_CONE_PATH = WIKI_PATH / "light_cone"
WIKI_MATERIAL_FOR_ROLE = WIKI_PATH / "character_material"
WIKI_RELIC_PATH = WIKI_PATH / "relic_set"
WIKI_ROLE_PATH = WIKI_PATH / "character_overview"
GUIDE_LIGHT_CONE_PATH = GUIDE_PATH / 'light_cone'
GUIDE_CHARACTER_PATH = GUIDE_PATH / 'character_overview'
GUIDE_LIGHT_CONE_PATH = GUIDE_PATH / "light_cone"
GUIDE_CHARACTER_PATH = GUIDE_PATH / "character_overview"
TEXT2D_PATH = Path(__file__).parent / 'texture2d'
TEXT2D_PATH = Path(__file__).parent / "texture2d"
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():
await download_all_file(
'StarRailUID',
"StarRailUID",
{
'resource/character': CHAR_ICON_PATH,
'resource/character_portrait': CHAR_PORTRAIT_PATH,
'resource/character_preview': CHAR_PREVIEW_PATH,
'resource/consumable': CONSUMABLE_PATH,
'resource/element': ELEMENT_PATH,
'guide/character_overview': GUIDE_CHARACTER_PATH,
'guide/light_cone': GUIDE_LIGHT_CONE_PATH,
'resource/relic': RELIC_PATH,
'resource/skill': SKILL_PATH,
'resource/light_cone': WEAPON_PATH,
'wiki/light_cone': WIKI_LIGHT_CONE_PATH,
'wiki/character_material': WIKI_MATERIAL_FOR_ROLE,
'wiki/relic_set': WIKI_RELIC_PATH,
'wiki/character_overview': WIKI_ROLE_PATH,
"resource/character": CHAR_ICON_PATH,
"resource/character_portrait": CHAR_PORTRAIT_PATH,
"resource/character_preview": CHAR_PREVIEW_PATH,
"resource/consumable": CONSUMABLE_PATH,
"resource/element": ELEMENT_PATH,
"guide/character_overview": GUIDE_CHARACTER_PATH,
"guide/light_cone": GUIDE_LIGHT_CONE_PATH,
"resource/relic": RELIC_PATH,
"resource/skill": SKILL_PATH,
"resource/light_cone": WEAPON_PATH,
"wiki/light_cone": WIKI_LIGHT_CONE_PATH,
"wiki/character_material": WIKI_MATERIAL_FOR_ROLE,
"wiki/relic_set": WIKI_RELIC_PATH,
"wiki/character_overview": WIKI_ROLE_PATH,
},
)
return 'sr全部资源下载完成!'
return "sr全部资源下载完成!"

View File

@ -1,3 +1,3 @@
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'
StarRail_version = '2.4.0'
StarRailUID_version = "0.1.0"
StarRail_version = "2.4.0"

View File

@ -38,9 +38,13 @@ pytest = "^7.2.0"
pytest-asyncio = "^0.20.3"
[tool.ruff]
line-length = 79
line-length = 88
target-version = "py38"
[tool.ruff.lint]
select = [
"E", "W", # pycodestyle
"E",
"W", # pycodestyle
"F", # pyflakes
# "I", # isort
"RUF", # ruff
@ -78,30 +82,17 @@ ignore = [
"PLR0911",
"PLW0603", # Using the global statement
"TRY002",
"TRY003"
"TRY003",
]
exclude = [
"gen.py",
".ruff_cache"
]
# Assume Python 3.8
target-version = "py38"
exclude = ["gen.py", ".ruff_cache"]
[tool.ruff.flake8-quotes]
inline-quotes = "single"
[tool.ruff.format]
quote-style = "single"
[tool.ruff.isort]
[tool.ruff.lint.isort]
case-sensitive = true
force-sort-within-sections = true
extra-standard-library = ["typing_extensions"]
#force-wrap-aliases = true
combine-as-imports = true
order-by-type = true
relative-imports-order = "closest-to-furthest"
section-order = ["future", "standard-library", "first-party", "local-folder", "third-party"]
[tool.pdm]
[tool.pdm.build]
@ -117,7 +108,7 @@ name = "StarRailUID"
version = "0.1.0"
description = "支持 NoneBot2 & HoshinoBot & ZeroBot & YunzaiBot 的全功能星穹铁道Bot插件"
authors = [
{name = "qwerdvd", email = "105906879+qwerdvd@users.noreply.github.com"},
{ name = "qwerdvd", email = "105906879+qwerdvd@users.noreply.github.com" },
]
dependencies = [
"beautifulsoup4>=4.12.2",
@ -131,7 +122,7 @@ dependencies = [
]
requires-python = ">=3.8.1,<4.0"
readme = "README.md"
license = {text = "GPL-3.0-or-later"}
license = { text = "GPL-3.0-or-later" }
[tool.pdm.dev-dependencies]
@ -140,13 +131,9 @@ dev = [
"pre-commit>=3.3.2",
"flake8>=6.0.0",
"isort>=5.12.0",
"pycln>=2.1.2"
]
test = [
"nonebug>=0.3.0",
"pytest>=7.2.0",
"pytest-asyncio>=0.20.3"
"pycln>=2.1.2",
]
test = ["nonebug>=0.3.0", "pytest>=7.2.0", "pytest-asyncio>=0.20.3"]
[build-system]
requires = ["pdm-backend"]