2024-05-10 11:39:07 +00:00
|
|
|
|
import contextlib
|
2023-07-19 05:52:30 +00:00
|
|
|
|
from typing import Optional, List, TYPE_CHECKING
|
2023-04-28 17:50:27 +00:00
|
|
|
|
|
2024-05-10 11:39:07 +00:00
|
|
|
|
from simnet import Region
|
2023-07-19 05:52:30 +00:00
|
|
|
|
from simnet.errors import BadRequest as SimnetBadRequest
|
2023-08-21 14:43:01 +00:00
|
|
|
|
from telegram import Update, Message
|
2023-04-28 17:50:27 +00:00
|
|
|
|
from telegram.constants import ChatAction
|
|
|
|
|
from telegram.ext import CallbackContext, filters
|
|
|
|
|
|
|
|
|
|
from core.plugin import Plugin, handler
|
|
|
|
|
from core.services.cookies.error import TooManyRequestPublicCookies
|
2024-03-29 15:14:24 +00:00
|
|
|
|
from core.services.players.services import PlayerInfoService
|
2023-04-28 17:50:27 +00:00
|
|
|
|
from core.services.template.models import RenderResult
|
|
|
|
|
from core.services.template.services import TemplateService
|
2024-06-18 17:33:28 +00:00
|
|
|
|
from gram_core.config import config
|
|
|
|
|
from gram_core.plugin.methods.inline_use_data import IInlineUseData
|
2023-10-19 10:58:51 +00:00
|
|
|
|
from plugins.tools.genshin import GenshinHelper
|
2024-03-29 13:40:23 +00:00
|
|
|
|
from plugins.tools.head_icon import HeadIconService
|
2024-03-29 15:14:24 +00:00
|
|
|
|
from plugins.tools.phone_theme import PhoneThemeService
|
2023-04-28 17:50:27 +00:00
|
|
|
|
from utils.log import logger
|
2023-08-26 13:21:26 +00:00
|
|
|
|
from utils.uid import mask_number
|
2023-04-28 17:50:27 +00:00
|
|
|
|
|
2023-07-19 05:52:30 +00:00
|
|
|
|
if TYPE_CHECKING:
|
|
|
|
|
from simnet import StarRailClient
|
|
|
|
|
|
2023-04-28 17:50:27 +00:00
|
|
|
|
__all__ = ("PlayerStatsPlugins",)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PlayerStatsPlugins(Plugin):
|
|
|
|
|
"""玩家统计查询"""
|
|
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
template: TemplateService,
|
|
|
|
|
helper: GenshinHelper,
|
2024-03-29 13:40:23 +00:00
|
|
|
|
head_icon: HeadIconService,
|
2024-03-29 15:14:24 +00:00
|
|
|
|
phone_theme: PhoneThemeService,
|
|
|
|
|
player_info_service: PlayerInfoService,
|
2023-04-28 17:50:27 +00:00
|
|
|
|
):
|
|
|
|
|
self.template_service = template
|
|
|
|
|
self.helper = helper
|
2024-03-29 13:40:23 +00:00
|
|
|
|
self.head_icon = head_icon
|
2024-03-29 15:14:24 +00:00
|
|
|
|
self.phone_theme = phone_theme
|
|
|
|
|
self.player_info_service = player_info_service
|
2023-04-28 17:50:27 +00:00
|
|
|
|
|
2024-06-12 12:43:28 +00:00
|
|
|
|
async def get_uid(self, user_id: int, reply: Optional[Message], player_id: int, offset: int) -> int:
|
2023-06-07 13:32:23 +00:00
|
|
|
|
"""通过消息获取 uid,优先级:args > reply > self"""
|
2024-06-12 12:43:28 +00:00
|
|
|
|
uid, user_id_ = player_id, user_id
|
2023-06-07 13:32:23 +00:00
|
|
|
|
if reply:
|
|
|
|
|
try:
|
|
|
|
|
user_id_ = reply.from_user.id
|
|
|
|
|
except AttributeError:
|
|
|
|
|
pass
|
|
|
|
|
if not uid:
|
2024-06-12 12:43:28 +00:00
|
|
|
|
player_info = await self.helper.players_service.get_player(user_id_, offset=offset)
|
2023-06-07 13:32:23 +00:00
|
|
|
|
if player_info is not None:
|
|
|
|
|
uid = player_info.player_id
|
|
|
|
|
if (not uid) and (user_id_ != user_id):
|
2024-06-12 12:43:28 +00:00
|
|
|
|
player_info = await self.helper.players_service.get_player(user_id, offset=offset)
|
2023-06-07 13:32:23 +00:00
|
|
|
|
if player_info is not None:
|
|
|
|
|
uid = player_info.player_id
|
|
|
|
|
return uid
|
|
|
|
|
|
2024-03-25 12:43:11 +00:00
|
|
|
|
@handler.command("stats", player=True, block=False)
|
|
|
|
|
@handler.message(filters.Regex("^玩家统计查询(.*)"), player=True, block=False)
|
2024-06-12 12:43:28 +00:00
|
|
|
|
async def command_start(self, update: Update, _: CallbackContext) -> Optional[int]:
|
2024-03-10 12:50:32 +00:00
|
|
|
|
user_id = await self.get_real_user_id(update)
|
2024-06-12 12:43:28 +00:00
|
|
|
|
uid, offset = self.get_real_uid_or_offset(update)
|
2023-04-28 17:50:27 +00:00
|
|
|
|
message = update.effective_message
|
2024-03-10 12:50:32 +00:00
|
|
|
|
self.log_user(update, logger.info, "查询游戏用户命令请求")
|
2023-04-28 17:50:27 +00:00
|
|
|
|
try:
|
2024-06-12 12:43:28 +00:00
|
|
|
|
uid: int = await self.get_uid(user_id, message.reply_to_message, uid, offset)
|
2024-03-10 12:50:32 +00:00
|
|
|
|
async with self.helper.genshin_or_public(user_id, uid=uid) as client:
|
2023-10-19 10:58:51 +00:00
|
|
|
|
render_result = await self.render(client, uid)
|
2023-04-28 17:50:27 +00:00
|
|
|
|
except TooManyRequestPublicCookies:
|
|
|
|
|
await message.reply_text("用户查询次数过多 请稍后重试")
|
|
|
|
|
return
|
|
|
|
|
except AttributeError as exc:
|
|
|
|
|
logger.error("角色数据有误")
|
|
|
|
|
logger.exception(exc)
|
|
|
|
|
await message.reply_text("角色数据有误 估计是彦卿晕了")
|
|
|
|
|
return
|
|
|
|
|
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
2024-06-11 04:44:34 +00:00
|
|
|
|
await render_result.reply_photo(message, filename=f"{user_id}.png")
|
2023-04-28 17:50:27 +00:00
|
|
|
|
|
2023-07-19 05:52:30 +00:00
|
|
|
|
async def render(self, client: "StarRailClient", uid: Optional[int] = None) -> RenderResult:
|
2023-04-28 17:50:27 +00:00
|
|
|
|
if uid is None:
|
2023-07-19 05:52:30 +00:00
|
|
|
|
uid = client.player_id
|
2023-04-28 17:50:27 +00:00
|
|
|
|
|
|
|
|
|
user_info = await client.get_starrail_user(uid)
|
2023-06-07 13:32:23 +00:00
|
|
|
|
try:
|
|
|
|
|
rogue = await client.get_starrail_rogue(uid)
|
2023-07-19 05:52:30 +00:00
|
|
|
|
except SimnetBadRequest:
|
2023-06-07 13:32:23 +00:00
|
|
|
|
rogue = None
|
2024-05-10 11:39:07 +00:00
|
|
|
|
ledger = None
|
|
|
|
|
if (not client.public) and client.region != Region.OVERSEAS:
|
|
|
|
|
with contextlib.suppress(SimnetBadRequest):
|
|
|
|
|
ledger = await client.get_starrail_ledger_month_info(uid)
|
2023-04-28 17:50:27 +00:00
|
|
|
|
logger.debug(user_info)
|
2024-03-29 15:14:24 +00:00
|
|
|
|
await self.set_name_card(uid, user_info.phone_background_image_url)
|
2023-04-28 17:50:27 +00:00
|
|
|
|
data = {
|
2023-08-26 13:21:26 +00:00
|
|
|
|
"uid": mask_number(uid),
|
2023-06-07 13:32:23 +00:00
|
|
|
|
"info": user_info.info,
|
2023-04-28 17:50:27 +00:00
|
|
|
|
"stats": user_info.stats,
|
|
|
|
|
"stats_labels": [
|
|
|
|
|
("活跃天数", "active_days"),
|
|
|
|
|
("获取角色数", "avatar_num"),
|
2024-03-29 13:40:23 +00:00
|
|
|
|
("成就达成数", "achievement_num"),
|
2023-04-28 17:50:27 +00:00
|
|
|
|
("战利品开启数", "chest_num"),
|
2024-03-29 13:40:23 +00:00
|
|
|
|
("逐光捡金", "abyss_process"),
|
|
|
|
|
("梦境护照贴纸", "dream_paster_num"),
|
2023-04-28 17:50:27 +00:00
|
|
|
|
],
|
2023-06-07 13:32:23 +00:00
|
|
|
|
"rogue": rogue.basic_info if rogue else None,
|
|
|
|
|
"rogue_labels": [
|
|
|
|
|
("技能树已激活", "unlocked_skill_points"),
|
|
|
|
|
("已解锁奇物", "unlocked_miracle_num"),
|
|
|
|
|
("已解锁祝福", "unlocked_buff_num"),
|
|
|
|
|
],
|
2024-05-08 15:42:46 +00:00
|
|
|
|
"ledger": ledger,
|
|
|
|
|
"ledger_labels": [
|
|
|
|
|
("本月星琼", "current_hcoin"),
|
|
|
|
|
("本月通专票", "current_rails_pass"),
|
|
|
|
|
("上月星琼", "last_hcoin"),
|
|
|
|
|
("上月通专票", "last_rails_pass"),
|
|
|
|
|
],
|
2023-04-28 17:50:27 +00:00
|
|
|
|
"style": "xianzhou", # nosec
|
2024-03-29 13:40:23 +00:00
|
|
|
|
"avatar": (await self.head_icon.get_head_icon(uid)).as_uri(),
|
2024-03-29 15:14:24 +00:00
|
|
|
|
"background": (await self.phone_theme.get_phone_theme(uid)).as_uri(),
|
2023-04-28 17:50:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return await self.template_service.render(
|
|
|
|
|
"starrail/stats/stats.html",
|
|
|
|
|
data,
|
|
|
|
|
{"width": 650, "height": 440},
|
|
|
|
|
full_page=True,
|
|
|
|
|
)
|
2024-03-29 15:14:24 +00:00
|
|
|
|
|
|
|
|
|
async def set_name_card(self, player_id: int, image_url: str):
|
|
|
|
|
if not image_url:
|
|
|
|
|
return
|
|
|
|
|
try:
|
|
|
|
|
phone_theme_id = int(image_url.split("/")[-1].replace(".png", ""))
|
|
|
|
|
except (IndexError, ValueError):
|
|
|
|
|
return
|
|
|
|
|
await self.phone_theme.set_to_cache(player_id, phone_theme_id)
|
|
|
|
|
await self.player_info_service.set_name_card(player_id, phone_theme_id)
|
2024-06-18 17:33:28 +00:00
|
|
|
|
|
|
|
|
|
async def stats_use_by_inline(self, update: "Update", context: "ContextTypes.DEFAULT_TYPE"):
|
|
|
|
|
callback_query = update.callback_query
|
|
|
|
|
user = update.effective_user
|
|
|
|
|
user_id = user.id
|
|
|
|
|
uid = IInlineUseData.get_uid_from_context(context)
|
|
|
|
|
|
|
|
|
|
self.log_user(update, logger.info, "查询游戏用户命令请求")
|
|
|
|
|
notice = None
|
|
|
|
|
try:
|
|
|
|
|
async with self.helper.genshin_or_public(user_id, uid=uid) as client:
|
|
|
|
|
if not client.public:
|
|
|
|
|
await client.get_record_cards()
|
|
|
|
|
render_result = await self.render(client, client.player_id)
|
|
|
|
|
except TooManyRequestPublicCookies:
|
|
|
|
|
notice = "用户查询次数过多 请稍后重试"
|
|
|
|
|
except AttributeError as exc:
|
|
|
|
|
logger.error("角色数据有误")
|
|
|
|
|
logger.exception(exc)
|
|
|
|
|
notice = f"角色数据有误 估计是{config.notice.bot_name}晕了"
|
|
|
|
|
except ValueError as exc:
|
|
|
|
|
logger.warning("获取 uid 发生错误! 错误信息为 %s", str(exc))
|
|
|
|
|
notice = "UID 内部错误"
|
|
|
|
|
|
|
|
|
|
if notice:
|
|
|
|
|
await callback_query.answer(notice, show_alert=True)
|
|
|
|
|
return
|
|
|
|
|
await render_result.edit_inline_media(callback_query)
|
|
|
|
|
|
|
|
|
|
async def get_inline_use_data(self) -> List[Optional[IInlineUseData]]:
|
|
|
|
|
return [
|
|
|
|
|
IInlineUseData(
|
|
|
|
|
text="玩家统计",
|
|
|
|
|
hash="stats",
|
|
|
|
|
callback=self.stats_use_by_inline,
|
|
|
|
|
player=True,
|
|
|
|
|
),
|
|
|
|
|
]
|