diff --git a/modules/apihelper/abyss_team.py b/modules/apihelper/abyss_team.py index bcf9c72..7b4a6c5 100644 --- a/modules/apihelper/abyss_team.py +++ b/modules/apihelper/abyss_team.py @@ -1,4 +1,3 @@ -import secrets import time from typing import List, Optional, Any @@ -11,15 +10,19 @@ class Member(BaseModel): attr: str name: str + @validator("name") + def name_validator(cls, v): # pylint: disable=R0201 + return "空" if v == "旅行者" else v + class TeamRate(BaseModel): rate: float formation: List[Member] owner_num: Optional[int] - @validator('rate', pre=True) + @validator("rate", pre=True) def str2float(cls, v): # pylint: disable=R0201 - return float(v.replace('%', '')) / 100.0 if isinstance(v, str) else v + return float(v.replace("%", "")) / 100.0 if isinstance(v, str) else v class FullTeamRate(BaseModel): @@ -30,10 +33,11 @@ class FullTeamRate(BaseModel): @property def rate(self) -> float: - return self.up.rate + self.down.rate + return (self.up.rate + self.down.rate) / 2 class TeamRateResult(BaseModel): + version: str rate_list_up: List[TeamRate] rate_list_down: List[TeamRate] rate_list_full: List[FullTeamRate] = [] @@ -50,28 +54,35 @@ class TeamRateResult(BaseModel): def sort(self, characters: List[str]): for team in self.rate_list_full: team.owner_num = sum(member.name in characters for member in team.up.formation + team.down.formation) - team.nice = team.owner_num / 8 * team.rate + team.nice = team.owner_num / 8 + team.rate self.rate_list_full.sort(key=lambda x: x.nice, reverse=True) - def random_team(self, characters: List[str]) -> FullTeamRate: - self.sort(characters) - max_nice = self.rate_list_full[0].nice - nice_teams: List[FullTeamRate] = [] + def random_team(self) -> List[FullTeamRate]: + data: List[FullTeamRate] = [] for team in self.rate_list_full: - if team.nice < max_nice: - break - nice_teams.append(team) - return secrets.choice(nice_teams) + add = True + for team_ in data: + if {member.name for member in team.up.formation} & {member.name for member in team_.up.formation}: + add = False + break + if {member.name for member in team.down.formation} & {member.name for member in team_.down.formation}: + add = False + break + if add: + data.append(team) + if len(data) >= 3: + break + return data class AbyssTeamData: TEAM_RATE_API = "https://www.youchuang.fun/gamerole/formationRate" HEADERS = { - 'Host': 'www.youchuang.fun', - 'Referer': 'https://servicewechat.com/wxce4dbe0cb0f764b3/91/page-frame.html', - 'User-Agent': 'Mozilla/5.0 (iPad; CPU OS 15_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) ' - 'Mobile/15E148 MicroMessenger/8.0.20(0x1800142f) NetType/WIFI Language/zh_CN', - 'content-type': 'application/json' + "Host": "www.youchuang.fun", + "Referer": "https://servicewechat.com/wxce4dbe0cb0f764b3/91/page-frame.html", + "User-Agent": "Mozilla/5.0 (iPad; CPU OS 15_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) " + "Mobile/15E148 MicroMessenger/8.0.20(0x1800142f) NetType/WIFI Language/zh_CN", + "content-type": "application/json", } VERSION = "3.1" @@ -87,9 +98,12 @@ class AbyssTeamData: data_up_json = data_up.json()["result"] data_down = await self.client.post(self.TEAM_RATE_API, json={"version": self.VERSION, "layer": 2}) data_down_json = data_down.json()["result"] - self.data = TeamRateResult(rate_list_up=parse_obj_as(List[TeamRate], data_up_json["rateList"]), - rate_list_down=parse_obj_as(List[TeamRate], data_down_json["rateList"]), - user_count=data_up_json["userCount"]) + self.data = TeamRateResult( + version=self.VERSION, + rate_list_up=parse_obj_as(List[TeamRate], data_up_json["rateList"]), + rate_list_down=parse_obj_as(List[TeamRate], data_down_json["rateList"]), + user_count=data_up_json["userCount"], + ) self.time = time.time() return self.data.copy(deep=True) diff --git a/plugins/genshin/abyss_team.py b/plugins/genshin/abyss_team.py index d554071..7be984b 100644 --- a/plugins/genshin/abyss_team.py +++ b/plugins/genshin/abyss_team.py @@ -1,4 +1,4 @@ -from telegram import Update, User +from telegram import Update from telegram.constants import ChatAction from telegram.ext import CallbackContext, CommandHandler, MessageHandler, filters @@ -20,69 +20,67 @@ from utils.log import logger class AbyssTeam(Plugin, BasePlugin): """深境螺旋推荐配队查询""" - def __init__(self, user_service: UserService = None, template_service: TemplateService = None, - assets: AssetsService = None): + def __init__( + self, user_service: UserService = None, template_service: TemplateService = None, assets: AssetsService = None + ): self.template_service = template_service self.user_service = user_service self.assets_service = assets self.team_data = AbyssTeamData() - @staticmethod - def _get_role_star_bg(value: int): - if value == 4: - return "./../abyss/background/roleStarBg4.png" - elif value == 5: - return "./../abyss/background/roleStarBg5.png" - else: - raise ValueError("错误的数据") - - @staticmethod - async def _get_data_from_user(user: User): - try: - logger.debug("尝试获取已绑定的原神账号") - client = await get_genshin_client(user.id) - logger.debug(f"获取成功, UID: {client.uid}") - characters = await client.get_genshin_characters(client.uid) - return [character.name for character in characters] - except (UserNotFoundError, CookiesNotFoundError): - logger.info(f"未查询到用户({user.full_name} {user.id}) 所绑定的账号信息") - return [] - @handler(CommandHandler, command="abyss_team", block=False) @handler(MessageHandler, filters=filters.Regex("^深渊推荐配队(.*)"), block=False) @restricts() @error_callable - async def command_start(self, update: Update, _: CallbackContext) -> None: + async def command_start(self, update: Update, context: CallbackContext) -> None: user = update.effective_user message = update.effective_message logger.info(f"用户 {user.full_name}[{user.id}] 查深渊推荐配队命令请求") + + try: + client = await get_genshin_client(user.id) + except (CookiesNotFoundError, UserNotFoundError): + reply_message = await message.reply_text("未查询到账号信息,请先私聊派蒙绑定账号") + if filters.ChatType.GROUPS.filter(message): + self._add_delete_message_job(context, reply_message.chat_id, reply_message.message_id, 10) + self._add_delete_message_job(context, message.chat_id, message.message_id, 10) + return + await message.reply_chat_action(ChatAction.TYPING) team_data = await self.team_data.get_data() # 尝试获取用户已绑定的原神账号信息 - user_data = await self._get_data_from_user(user) - random_team = team_data.random_team(user_data) - abyss_team_data = { - "up": [], - "down": [] - } - for i in random_team.up.formation: - temp = { - "icon": (await self.assets_service.avatar(roleToId(i.name)).icon()).as_uri(), - "name": i.name, - "background": self._get_role_star_bg(i.star), - "hava": (i.name in user_data) if user_data else True, + characters = await client.get_genshin_characters(client.uid) + user_data = [character.name for character in characters] + team_data.sort(user_data) + random_team = team_data.random_team() + abyss_teams_data = {"uid": client.uid, "version": team_data.version, "teams": []} + for i in random_team: + team = { + "up": [], + "up_rate": f"{i.up.rate * 100: .2f}%", + "down": [], + "down_rate": f"{i.down.rate * 100: .2f}%", } - abyss_team_data["up"].append(temp) - for i in random_team.down.formation: - temp = { - "icon": (await self.assets_service.avatar(roleToId(i.name)).icon()).as_uri(), - "name": i.name, - "background": self._get_role_star_bg(i.star), - "hava": (i.name in user_data) if user_data else True, - } - abyss_team_data["down"].append(temp) + + for lane in ["up", "down"]: + for member in getattr(i, lane).formation: + temp = { + "icon": (await self.assets_service.avatar(roleToId(member.name)).icon()).as_uri(), + "name": member.name.replace("空", "旅行者"), + "star": member.star, + "hava": (member.name in user_data) if user_data else True, + } + team[lane].append(temp) + + abyss_teams_data["teams"].append(team) + await message.reply_chat_action(ChatAction.UPLOAD_PHOTO) - png_data = await self.template_service.render('genshin/abyss_team', "abyss_team.html", abyss_team_data, - {"width": 865, "height": 504}, full_page=False) - await message.reply_photo(png_data, filename=f"abyss_team_{user.id}.png", - allow_sending_without_reply=True) + png_data = await self.template_service.render( + "genshin/abyss_team", + "abyss_team.html", + abyss_teams_data, + {"width": 785, "height": 800}, + full_page=True, + query_selector=".bg-contain", + ) + await message.reply_photo(png_data, filename=f"abyss_team_{user.id}.png", allow_sending_without_reply=True) diff --git a/resources/genshin/abyss/background/abyss-bg-grad.png b/resources/genshin/abyss/background/abyss-bg-grad.png new file mode 100644 index 0000000..d58ac08 Binary files /dev/null and b/resources/genshin/abyss/background/abyss-bg-grad.png differ diff --git a/resources/genshin/abyss_team/abyss_team.html b/resources/genshin/abyss_team/abyss_team.html index a5951f9..d08ec3f 100644 --- a/resources/genshin/abyss_team/abyss_team.html +++ b/resources/genshin/abyss_team/abyss_team.html @@ -1,69 +1,90 @@ - - + + abyss - - + + + - - -
-
深境螺旋 - 推荐配队
-
-
第 12 层上半
-
- {% for i in up %} -
-
-
-
{{i.name}}
-
- {% endfor %} + + +
+
+ 深境螺旋 - 推荐配队 +
+ +
+
UID {{ uid }}
+
版本 {{ version }}
+
+ + {% for team in teams %} +
+
+ 推荐配队 {{ loop.index }}
-
-
-
第 12 层下半
-
- {% for i in down %} -
-
-
-
{{i.name}}
+ {% for lane in ["up", "down"] %} +
+ {% for i in team[lane] %} +
+
+
- {% endfor %} +
{{ i.name }}
+
+ {% endfor %} + +
+
+ {{ lane == 'up' and '上' or '下' }}半 +
+
+ 使用率 {{ team[lane + "_rate"] }} +
+
+ {% endfor %} +
+ {% endfor %} + +
+ 数据来源:游创工坊 +
-
-
- - \ No newline at end of file + + diff --git a/tests/test_abyss_team_data.py b/tests/test_abyss_team_data.py index 5ef3a2d..f35a25e 100644 --- a/tests/test_abyss_team_data.py +++ b/tests/test_abyss_team_data.py @@ -30,7 +30,7 @@ async def test_abyss_team_data(abyss_team_data: AbyssTeamData): team_data.sort(["迪奥娜", "芭芭拉", "凯亚", "琴"]) assert isinstance(team_data.rate_list_full[0], FullTeamRate) assert isinstance(team_data.rate_list_full[-1], FullTeamRate) - random_team = team_data.random_team(["迪奥娜", "芭芭拉", "凯亚", "琴"]) + random_team = team_data.random_team()[0] assert isinstance(random_team, FullTeamRate) member_up = {i.name for i in random_team.up.formation} member_down = {i.name for i in random_team.down.formation}