mirror of
https://github.com/PaiGramTeam/PaiGram.git
synced 2024-11-16 04:35:49 +00:00
✨ Use SIMNet
and Remove genshin.py
Co-authored-by: xtaodada <xtao@xtaolink.cn>
This commit is contained in:
parent
23f08f5639
commit
c1012d206b
@ -1,7 +1,7 @@
|
||||
from typing import List, Optional
|
||||
|
||||
import genshin
|
||||
from genshin import GenshinException, InvalidCookies, TooManyRequests, types, Game
|
||||
from simnet import GenshinClient, Region, Game
|
||||
from simnet.errors import InvalidCookies, BadRequest as SimnetBadRequest, TooManyRequests
|
||||
|
||||
from core.base_service import BaseService
|
||||
from core.basemodel import RegionEnum
|
||||
@ -86,15 +86,13 @@ class PublicCookiesService(BaseService):
|
||||
await self._cache.delete_public_cookies(public_id, region)
|
||||
continue
|
||||
if region == RegionEnum.HYPERION:
|
||||
client = genshin.Client(cookies=cookies.data, game=types.Game.GENSHIN, region=types.Region.CHINESE)
|
||||
client = GenshinClient(cookies=cookies.data, region=Region.CHINESE)
|
||||
elif region == RegionEnum.HOYOLAB:
|
||||
client = genshin.Client(
|
||||
cookies=cookies.data, game=types.Game.GENSHIN, region=types.Region.OVERSEAS, lang="zh-cn"
|
||||
)
|
||||
client = GenshinClient(cookies=cookies.data, region=Region.OVERSEAS, lang="zh-cn")
|
||||
else:
|
||||
raise CookieServiceError
|
||||
try:
|
||||
if client.cookie_manager.user_id is None:
|
||||
if client.account_id is None:
|
||||
raise RuntimeError("account_id not found")
|
||||
record_cards = await client.get_record_cards()
|
||||
for record_card in record_cards:
|
||||
@ -108,9 +106,9 @@ class PublicCookiesService(BaseService):
|
||||
await client.get_partial_genshin_user(account.uid)
|
||||
break
|
||||
except InvalidCookies as exc:
|
||||
if exc.retcode in (10001, -100):
|
||||
if exc.ret_code in (10001, -100):
|
||||
logger.warning("用户 [%s] Cookies无效", public_id)
|
||||
elif exc.retcode == 10103:
|
||||
elif exc.ret_code == 10103:
|
||||
logger.warning("用户 [%s] Cookies有效,但没有绑定到游戏帐户", public_id)
|
||||
else:
|
||||
logger.warning("Cookies无效 ")
|
||||
@ -125,10 +123,10 @@ class PublicCookiesService(BaseService):
|
||||
await self._repository.update(cookies)
|
||||
await self._cache.delete_public_cookies(cookies.user_id, region)
|
||||
continue
|
||||
except GenshinException as exc:
|
||||
if "invalid content type" in exc.msg:
|
||||
except SimnetBadRequest as exc:
|
||||
if "invalid content type" in exc.message:
|
||||
raise exc
|
||||
if exc.retcode == 1034:
|
||||
if exc.ret_code == 1034:
|
||||
logger.warning("用户 [%s] 触发验证", public_id)
|
||||
else:
|
||||
logger.warning("用户 [%s] 获取账号信息发生错误,错误信息为", public_id)
|
||||
@ -145,6 +143,8 @@ class PublicCookiesService(BaseService):
|
||||
except Exception as exc:
|
||||
await self._cache.delete_public_cookies(cookies.user_id, region)
|
||||
raise exc
|
||||
finally:
|
||||
await client.shutdown()
|
||||
logger.info("用户 user_id[%s] 请求用户 user_id[%s] 的公共Cookies 该Cookies使用次数为%s次 ", user_id, public_id, count)
|
||||
return cookies
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
import json
|
||||
import re
|
||||
import time
|
||||
from typing import Dict, Optional
|
||||
from typing import Dict, Optional, Union
|
||||
|
||||
from httpx import Cookies
|
||||
|
||||
from ..base.hyperionrequest import HyperionRequest
|
||||
from ...utility.devices import devices_methods
|
||||
@ -37,7 +39,7 @@ class Verify:
|
||||
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
|
||||
}
|
||||
|
||||
def __init__(self, account_id: int = None, cookies: Dict = None):
|
||||
def __init__(self, account_id: int = None, cookies: Union[Dict, Cookies] = None):
|
||||
self.account_id = account_id
|
||||
self.client = HyperionRequest(headers=self.BBS_HEADERS, cookies=cookies)
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
from genshin.models import GenshinBannerType
|
||||
from simnet.models.genshin.wish import BannerType
|
||||
|
||||
PAIMONMOE_VERSION = 3
|
||||
UIGF_VERSION = "v2.2"
|
||||
|
||||
|
||||
GACHA_TYPE_LIST = {
|
||||
GenshinBannerType.NOVICE: "新手祈愿",
|
||||
GenshinBannerType.PERMANENT: "常驻祈愿",
|
||||
GenshinBannerType.WEAPON: "武器祈愿",
|
||||
GenshinBannerType.CHARACTER1: "角色祈愿",
|
||||
GenshinBannerType.CHARACTER2: "角色祈愿",
|
||||
BannerType.NOVICE: "新手祈愿",
|
||||
BannerType.PERMANENT: "常驻祈愿",
|
||||
BannerType.WEAPON: "武器祈愿",
|
||||
BannerType.CHARACTER1: "角色祈愿",
|
||||
BannerType.CHARACTER2: "角色祈愿",
|
||||
}
|
||||
|
@ -5,14 +5,14 @@ import json
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from os import PathLike
|
||||
from pathlib import Path
|
||||
from typing import Dict, IO, List, Optional, Tuple, Union
|
||||
from typing import Dict, IO, List, Optional, Tuple, Union, TYPE_CHECKING
|
||||
|
||||
import aiofiles
|
||||
from genshin import AuthkeyTimeout, Client, InvalidAuthkey
|
||||
from genshin.models import GenshinBannerType
|
||||
from openpyxl import load_workbook
|
||||
from simnet import GenshinClient
|
||||
from simnet.errors import AuthkeyTimeout, InvalidAuthkey
|
||||
from simnet.models.genshin.wish import BannerType
|
||||
|
||||
from core.dependence.assets import AssetsService
|
||||
from metadata.pool.pool import get_pool_by_id
|
||||
from metadata.shortname import roleToId, weaponToId
|
||||
from modules.gacha_log.const import GACHA_TYPE_LIST, PAIMONMOE_VERSION
|
||||
@ -41,6 +41,10 @@ from modules.gacha_log.models import (
|
||||
)
|
||||
from utils.const import PROJECT_ROOT
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.dependence.assets import AssetsService
|
||||
|
||||
|
||||
GACHA_LOG_PATH = PROJECT_ROOT.joinpath("data", "apihelper", "gacha_log")
|
||||
GACHA_LOG_PATH.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@ -104,7 +108,7 @@ class GachaLog:
|
||||
async def save_gacha_log_info(self, user_id: str, uid: str, info: GachaLogInfo):
|
||||
"""保存抽卡记录数据
|
||||
:param user_id: 用户id
|
||||
:param uid: 原神uid
|
||||
:param uid: 玩家uid
|
||||
:param info: 抽卡记录数据
|
||||
"""
|
||||
save_path = self.gacha_log_path / f"{user_id}-{uid}.json"
|
||||
@ -164,20 +168,20 @@ class GachaLog:
|
||||
def import_data_backend(all_items: List[GachaItem], gacha_log: GachaLogInfo, temp_id_data: Dict) -> int:
|
||||
new_num = 0
|
||||
for item_info in all_items:
|
||||
pool_name = GACHA_TYPE_LIST[GenshinBannerType(int(item_info.gacha_type))]
|
||||
pool_name = GACHA_TYPE_LIST[BannerType(int(item_info.gacha_type))]
|
||||
if item_info.id not in temp_id_data[pool_name]:
|
||||
gacha_log.item_list[pool_name].append(item_info)
|
||||
temp_id_data[pool_name].append(item_info.id)
|
||||
new_num += 1
|
||||
return new_num
|
||||
|
||||
async def import_gacha_log_data(self, user_id: int, client: Client, data: dict, verify_uid: bool = True) -> int:
|
||||
async def import_gacha_log_data(self, user_id: int, player_id: int, data: dict, verify_uid: bool = True) -> int:
|
||||
new_num = 0
|
||||
try:
|
||||
uid = data["info"]["uid"]
|
||||
if not verify_uid:
|
||||
uid = client.uid
|
||||
elif int(uid) != client.uid:
|
||||
uid = player_id
|
||||
elif int(uid) != player_id:
|
||||
raise GachaLogAccountNotFound
|
||||
try:
|
||||
import_type = ImportType(data["info"]["export_app"])
|
||||
@ -218,22 +222,23 @@ class GachaLog:
|
||||
except Exception as exc:
|
||||
raise GachaLogException from exc
|
||||
|
||||
async def get_gacha_log_data(self, user_id: int, client: Client, authkey: str) -> int:
|
||||
async def get_gacha_log_data(self, user_id: int, client: GenshinClient, authkey: str) -> int:
|
||||
"""使用authkey获取抽卡记录数据,并合并旧数据
|
||||
:param user_id: 用户id
|
||||
:param client: genshin client
|
||||
:param client: GenshinClient
|
||||
:param authkey: authkey
|
||||
:return: 更新结果
|
||||
"""
|
||||
new_num = 0
|
||||
gacha_log, _ = await self.load_history_info(str(user_id), str(client.uid))
|
||||
gacha_log, _ = await self.load_history_info(str(user_id), str(client.player_id))
|
||||
if gacha_log.get_import_type == ImportType.PAIMONMOE:
|
||||
raise GachaLogMixedProvider
|
||||
# 将唯一 id 放入临时数据中,加快查找速度
|
||||
temp_id_data = {pool_name: [i.id for i in pool_data] for pool_name, pool_data in gacha_log.item_list.items()}
|
||||
try:
|
||||
for pool_id, pool_name in GACHA_TYPE_LIST.items():
|
||||
async for data in client.wish_history(pool_id, authkey=authkey):
|
||||
wish_history = await client.wish_history(pool_id.value, authkey=authkey)
|
||||
for data in wish_history:
|
||||
item = GachaItem(
|
||||
id=str(data.id),
|
||||
name=data.name,
|
||||
@ -262,7 +267,7 @@ class GachaLog:
|
||||
i.sort(key=lambda x: (x.time, x.id))
|
||||
gacha_log.update_time = datetime.datetime.now()
|
||||
gacha_log.import_type = ImportType.UIGF.value
|
||||
await self.save_gacha_log_info(str(user_id), str(client.uid), gacha_log)
|
||||
await self.save_gacha_log_info(str(user_id), str(client.player_id), gacha_log)
|
||||
return new_num
|
||||
|
||||
@staticmethod
|
||||
@ -281,7 +286,7 @@ class GachaLog:
|
||||
return False
|
||||
return True
|
||||
|
||||
async def get_all_5_star_items(self, data: List[GachaItem], assets: AssetsService, pool_name: str = "角色祈愿"):
|
||||
async def get_all_5_star_items(self, data: List[GachaItem], assets: "AssetsService", pool_name: str = "角色祈愿"):
|
||||
"""
|
||||
获取所有5星角色
|
||||
:param data: 抽卡记录
|
||||
@ -321,7 +326,7 @@ class GachaLog:
|
||||
return result, count
|
||||
|
||||
@staticmethod
|
||||
async def get_all_4_star_items(data: List[GachaItem], assets: AssetsService):
|
||||
async def get_all_4_star_items(data: List[GachaItem], assets: "AssetsService"):
|
||||
"""
|
||||
获取 no_fout_star
|
||||
:param data: 抽卡记录
|
||||
@ -482,16 +487,16 @@ class GachaLog:
|
||||
return f"{pool_name} · 非"
|
||||
return pool_name
|
||||
|
||||
async def get_analysis(self, user_id: int, client: Client, pool: GenshinBannerType, assets: AssetsService):
|
||||
async def get_analysis(self, user_id: int, player_id: int, pool: BannerType, assets: "AssetsService"):
|
||||
"""
|
||||
获取抽卡记录分析数据
|
||||
:param user_id: 用户id
|
||||
:param client: genshin client
|
||||
:param player_id: 玩家id
|
||||
:param pool: 池子类型
|
||||
:param assets: 资源服务
|
||||
:return: 分析数据
|
||||
"""
|
||||
gacha_log, status = await self.load_history_info(str(user_id), str(client.uid))
|
||||
gacha_log, status = await self.load_history_info(str(user_id), str(player_id))
|
||||
if not status:
|
||||
raise GachaLogNotFound
|
||||
pool_name = GACHA_TYPE_LIST[pool]
|
||||
@ -502,19 +507,19 @@ class GachaLog:
|
||||
all_five, no_five_star = await self.get_all_5_star_items(data, assets, pool_name)
|
||||
all_four, no_four_star = await self.get_all_4_star_items(data, assets)
|
||||
summon_data = None
|
||||
if pool == GenshinBannerType.CHARACTER1:
|
||||
if pool == BannerType.CHARACTER1:
|
||||
summon_data = self.get_301_pool_data(total, all_five, no_five_star, no_four_star)
|
||||
pool_name = self.count_fortune(pool_name, summon_data)
|
||||
elif pool == GenshinBannerType.WEAPON:
|
||||
elif pool == BannerType.WEAPON:
|
||||
summon_data = self.get_302_pool_data(total, all_five, all_four, no_five_star, no_four_star)
|
||||
pool_name = self.count_fortune(pool_name, summon_data, True)
|
||||
elif pool == GenshinBannerType.PERMANENT:
|
||||
elif pool == BannerType.PERMANENT:
|
||||
summon_data = self.get_200_pool_data(total, all_five, all_four, no_five_star, no_four_star)
|
||||
pool_name = self.count_fortune(pool_name, summon_data)
|
||||
last_time = data[0].time.strftime("%Y-%m-%d %H:%M")
|
||||
first_time = data[-1].time.strftime("%Y-%m-%d %H:%M")
|
||||
return {
|
||||
"uid": client.uid,
|
||||
"uid": player_id,
|
||||
"allNum": total,
|
||||
"type": pool.value,
|
||||
"typeName": pool_name,
|
||||
@ -526,17 +531,17 @@ class GachaLog:
|
||||
}
|
||||
|
||||
async def get_pool_analysis(
|
||||
self, user_id: int, client: Client, pool: GenshinBannerType, assets: AssetsService, group: bool
|
||||
self, user_id: int, player_id: int, pool: BannerType, assets: "AssetsService", group: bool
|
||||
) -> dict:
|
||||
"""获取抽卡记录分析数据
|
||||
:param user_id: 用户id
|
||||
:param client: genshin client
|
||||
:param player_id: 玩家id
|
||||
:param pool: 池子类型
|
||||
:param assets: 资源服务
|
||||
:param group: 是否群组
|
||||
:return: 分析数据
|
||||
"""
|
||||
gacha_log, status = await self.load_history_info(str(user_id), str(client.uid))
|
||||
gacha_log, status = await self.load_history_info(str(user_id), str(player_id))
|
||||
if not status:
|
||||
raise GachaLogNotFound
|
||||
pool_name = GACHA_TYPE_LIST[pool]
|
||||
@ -566,20 +571,20 @@ class GachaLog:
|
||||
)
|
||||
pool_data = [i for i in pool_data if i["count"] > 0]
|
||||
return {
|
||||
"uid": client.uid,
|
||||
"uid": player_id,
|
||||
"typeName": pool_name,
|
||||
"pool": pool_data[:6] if group else pool_data,
|
||||
"hasMore": len(pool_data) > 6,
|
||||
}
|
||||
|
||||
async def get_all_five_analysis(self, user_id: int, client: Client, assets: AssetsService) -> dict:
|
||||
async def get_all_five_analysis(self, user_id: int, player_id: int, assets: "AssetsService") -> dict:
|
||||
"""获取五星抽卡记录分析数据
|
||||
:param user_id: 用户id
|
||||
:param client: genshin client
|
||||
:param player_id: 玩家id
|
||||
:param assets: 资源服务
|
||||
:return: 分析数据
|
||||
"""
|
||||
gacha_log, status = await self.load_history_info(str(user_id), str(client.uid))
|
||||
gacha_log, status = await self.load_history_info(str(user_id), str(player_id))
|
||||
if not status:
|
||||
raise GachaLogNotFound
|
||||
pools = []
|
||||
@ -607,7 +612,7 @@ class GachaLog:
|
||||
for up_pool in pools
|
||||
]
|
||||
return {
|
||||
"uid": client.uid,
|
||||
"uid": player_id,
|
||||
"typeName": "五星列表",
|
||||
"pool": pool_data,
|
||||
"hasMore": False,
|
||||
|
@ -47,24 +47,24 @@ class GachaItem(BaseModel):
|
||||
if item_id := (roleToId(v) or weaponToId(v)):
|
||||
if item_id not in not_real_roles:
|
||||
return v
|
||||
raise ValueError("Invalid name")
|
||||
raise ValueError(f"Invalid name {v}")
|
||||
|
||||
@validator("gacha_type")
|
||||
def check_gacha_type(cls, v):
|
||||
if v not in {"100", "200", "301", "302", "400"}:
|
||||
raise ValueError("gacha_type must be 200, 301, 302 or 400")
|
||||
raise ValueError(f"gacha_type must be 200, 301, 302 or 400, invalid value: {v}")
|
||||
return v
|
||||
|
||||
@validator("item_type")
|
||||
def check_item_type(cls, item):
|
||||
if item not in {"角色", "武器"}:
|
||||
raise ValueError("error item type")
|
||||
raise ValueError(f"error item type {item}")
|
||||
return item
|
||||
|
||||
@validator("rank_type")
|
||||
def check_rank_type(cls, rank):
|
||||
if rank not in {"5", "4", "3"}:
|
||||
raise ValueError("error rank type")
|
||||
raise ValueError(f"error rank type {rank}")
|
||||
return rank
|
||||
|
||||
|
||||
|
@ -3,8 +3,9 @@ from pathlib import Path
|
||||
from typing import Tuple, Optional, List, Dict
|
||||
|
||||
import aiofiles
|
||||
from genshin import Client, AuthkeyTimeout, InvalidAuthkey
|
||||
from genshin.models import TransactionKind, BaseTransaction
|
||||
from simnet import GenshinClient
|
||||
from simnet.errors import AuthkeyTimeout, InvalidAuthkey
|
||||
from simnet.models.genshin.transaction import TransactionKind, BaseTransaction
|
||||
|
||||
from modules.pay_log.error import PayLogAuthkeyTimeout, PayLogInvalidAuthkey, PayLogNotFound
|
||||
from modules.pay_log.models import PayLog as PayLogModel, BaseInfo
|
||||
@ -16,6 +17,7 @@ try:
|
||||
except ImportError:
|
||||
import json as jsonlib
|
||||
|
||||
|
||||
PAY_LOG_PATH = PROJECT_ROOT.joinpath("data", "apihelper", "pay_log")
|
||||
PAY_LOG_PATH.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@ -32,7 +34,7 @@ class PayLog:
|
||||
@staticmethod
|
||||
async def save_json(path, data: PayLogModel):
|
||||
async with aiofiles.open(path, "w", encoding="utf-8") as f:
|
||||
return await f.write(data.json(ensure_ascii=False, indent=4))
|
||||
return await f.write(data.json(ensure_ascii=False, indent=4, by_alias=True))
|
||||
|
||||
def get_file_path(
|
||||
self,
|
||||
@ -112,20 +114,21 @@ class PayLog:
|
||||
async def get_log_data(
|
||||
self,
|
||||
user_id: int,
|
||||
client: Client,
|
||||
client: GenshinClient,
|
||||
authkey: str,
|
||||
) -> int:
|
||||
"""使用 authkey 获取历史记录数据,并合并旧数据
|
||||
:param user_id: 用户id
|
||||
:param client: genshin client
|
||||
:param client: GenshinClient
|
||||
:param authkey: authkey
|
||||
:return: 更新结果
|
||||
"""
|
||||
new_num = 0
|
||||
pay_log, have_old = await self.load_history_info(str(user_id), str(client.uid))
|
||||
pay_log, have_old = await self.load_history_info(str(user_id), str(client.player_id))
|
||||
history_ids = [i.id for i in pay_log.list]
|
||||
try:
|
||||
async for data in client.transaction_log(TransactionKind.CRYSTAL, authkey=authkey):
|
||||
transaction_log = await client.transaction_log(authkey=authkey, kind=TransactionKind.CRYSTAL.value)
|
||||
for data in transaction_log:
|
||||
if data.id not in history_ids:
|
||||
pay_log.list.append(data)
|
||||
new_num += 1
|
||||
@ -136,7 +139,7 @@ class PayLog:
|
||||
if new_num > 0 or have_old:
|
||||
pay_log.list.sort(key=lambda x: (x.time, x.id), reverse=True)
|
||||
pay_log.info.update_now()
|
||||
await self.save_pay_log_info(str(user_id), str(client.uid), pay_log)
|
||||
await self.save_pay_log_info(str(user_id), str(client.player_id), pay_log)
|
||||
return new_num
|
||||
|
||||
@staticmethod
|
||||
@ -180,13 +183,13 @@ class PayLog:
|
||||
raise PayLogNotFound
|
||||
return all_amount, month_datas
|
||||
|
||||
async def get_analysis(self, user_id: int, client: Client):
|
||||
async def get_analysis(self, user_id: int, player_id: int):
|
||||
"""获取分析数据
|
||||
:param user_id: 用户id
|
||||
:param client: genshin client
|
||||
:param player_id: 玩家id
|
||||
:return: 分析数据
|
||||
"""
|
||||
pay_log, status = await self.load_history_info(str(user_id), str(client.uid))
|
||||
pay_log, status = await self.load_history_info(str(user_id), str(player_id))
|
||||
if not status:
|
||||
raise PayLogNotFound
|
||||
# 单双倍结晶数
|
||||
@ -227,7 +230,7 @@ class PayLog:
|
||||
if price_data[i]["count"] > 0
|
||||
]
|
||||
return {
|
||||
"uid": client.uid,
|
||||
"uid": player_id,
|
||||
"datas": datas,
|
||||
"bar_data": month_datas,
|
||||
"pie_data": pie_datas,
|
||||
|
@ -1,9 +1,8 @@
|
||||
import datetime
|
||||
|
||||
from typing import Any, List
|
||||
|
||||
from genshin.models import BaseTransaction
|
||||
from pydantic import BaseModel, BaseConfig
|
||||
from simnet.models.genshin.transaction import BaseTransaction
|
||||
|
||||
try:
|
||||
import ujson as jsonlib
|
||||
|
@ -1,8 +1,13 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
import genshin
|
||||
from genshin import DataNotPublic, GenshinException, types, AccountNotFound, InvalidCookies
|
||||
from simnet import GenshinClient, Region
|
||||
from simnet.errors import (
|
||||
InvalidCookies,
|
||||
BadRequest as SimnetBadRequest,
|
||||
DataNotPublic,
|
||||
AccountNotFound,
|
||||
)
|
||||
from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, TelegramObject
|
||||
from telegram.ext import ConversationHandler, filters
|
||||
from telegram.helpers import escape_markdown
|
||||
@ -16,7 +21,6 @@ from core.services.players.models import PlayersDataBase as Player, PlayerInfoSQ
|
||||
from core.services.players.services import PlayersService, PlayerInfoService
|
||||
from utils.log import logger
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Update
|
||||
from telegram.ext import ContextTypes
|
||||
@ -133,27 +137,25 @@ class BindAccountPlugin(Plugin.Conversation):
|
||||
await message.reply_text("用户查询次数过多,请稍后重试", reply_markup=ReplyKeyboardRemove())
|
||||
return ConversationHandler.END
|
||||
if region == RegionEnum.HYPERION:
|
||||
client = genshin.Client(cookies=cookies.data, game=types.Game.GENSHIN, region=types.Region.CHINESE)
|
||||
client = GenshinClient(cookies=cookies.data, region=Region.CHINESE)
|
||||
elif region == RegionEnum.HOYOLAB:
|
||||
client = genshin.Client(
|
||||
cookies=cookies.data, game=types.Game.GENSHIN, region=types.Region.OVERSEAS, lang="zh-cn"
|
||||
)
|
||||
client = GenshinClient(cookies=cookies.data, region=Region.OVERSEAS, lang="zh-cn")
|
||||
else:
|
||||
return ConversationHandler.END
|
||||
try:
|
||||
record_card = await client.get_record_card(account_id)
|
||||
if record_card is None:
|
||||
await message.reply_text("请在设置展示主界面添加原神", reply_markup=ReplyKeyboardRemove())
|
||||
return ConversationHandler.END
|
||||
except DataNotPublic:
|
||||
await message.reply_text("角色未公开", reply_markup=ReplyKeyboardRemove())
|
||||
logger.warning("获取账号信息发生错误 %s 账户信息未公开", account_id)
|
||||
return ConversationHandler.END
|
||||
except GenshinException as exc:
|
||||
except SimnetBadRequest as exc:
|
||||
await message.reply_text("获取账号信息发生错误", reply_markup=ReplyKeyboardRemove())
|
||||
logger.error("获取账号信息发生错误")
|
||||
logger.exception(exc)
|
||||
return ConversationHandler.END
|
||||
if record_card.game != types.Game.GENSHIN:
|
||||
await message.reply_text("角色信息查询返回非原神游戏信息,请设置展示主界面为原神", reply_markup=ReplyKeyboardRemove())
|
||||
return ConversationHandler.END
|
||||
player_info = await self.players_service.get(
|
||||
user.id, player_id=record_card.uid, region=bind_account_plugin_data.region
|
||||
)
|
||||
@ -197,11 +199,9 @@ class BindAccountPlugin(Plugin.Conversation):
|
||||
await message.reply_text("用户查询次数过多,请稍后重试", reply_markup=ReplyKeyboardRemove())
|
||||
return ConversationHandler.END
|
||||
if region == RegionEnum.HYPERION:
|
||||
client = genshin.Client(cookies=cookies.data, game=types.Game.GENSHIN, region=types.Region.CHINESE)
|
||||
client = GenshinClient(cookies=cookies.data, region=Region.CHINESE)
|
||||
elif region == RegionEnum.HOYOLAB:
|
||||
client = genshin.Client(
|
||||
cookies=cookies.data, game=types.Game.GENSHIN, region=types.Region.OVERSEAS, lang="zh-cn"
|
||||
)
|
||||
client = GenshinClient(cookies=cookies.data, region=Region.OVERSEAS, lang="zh-cn")
|
||||
else:
|
||||
return ConversationHandler.END
|
||||
try:
|
||||
@ -218,8 +218,8 @@ class BindAccountPlugin(Plugin.Conversation):
|
||||
await self.public_cookies_service.undo(user.id, cookies, CookiesStatusEnum.INVALID_COOKIES)
|
||||
await message.reply_text("出错了呜呜呜 ~ 请稍后重试")
|
||||
return ConversationHandler.END
|
||||
except GenshinException as exc:
|
||||
if exc.retcode == 1034:
|
||||
except SimnetBadRequest as exc:
|
||||
if exc.ret_code == 1034:
|
||||
await self.public_cookies_service.undo(user.id)
|
||||
await message.reply_text("出错了呜呜呜 ~ 请稍后重试")
|
||||
return ConversationHandler.END
|
||||
@ -230,6 +230,8 @@ class BindAccountPlugin(Plugin.Conversation):
|
||||
except ValueError:
|
||||
await message.reply_text("ID 格式有误,请检查", reply_markup=ReplyKeyboardRemove())
|
||||
return ConversationHandler.END
|
||||
finally:
|
||||
await client.shutdown()
|
||||
player_info = await self.players_service.get(
|
||||
user.id, player_id=player_id, region=bind_account_plugin_data.region
|
||||
)
|
||||
|
@ -1,10 +1,10 @@
|
||||
from datetime import datetime
|
||||
from typing import Dict, Optional
|
||||
|
||||
import genshin
|
||||
from arkowrapper import ArkoWrapper
|
||||
from genshin import DataNotPublic, GenshinException, InvalidCookies, types
|
||||
from genshin.models import GenshinAccount
|
||||
from simnet import GenshinClient, Region
|
||||
from simnet.errors import DataNotPublic, InvalidCookies, BadRequest as SimnetBadRequest
|
||||
from simnet.models.lab.record import Account
|
||||
from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, TelegramObject, Update
|
||||
from telegram.constants import ParseMode
|
||||
from telegram.ext import CallbackContext, ConversationHandler, filters
|
||||
@ -34,7 +34,7 @@ class AccountCookiesPluginData(TelegramObject):
|
||||
cookies: dict = {}
|
||||
account_id: int = 0
|
||||
# player_id: int = 0
|
||||
genshin_account: Optional[GenshinAccount] = None
|
||||
genshin_account: Optional[Account] = None
|
||||
|
||||
def reset(self):
|
||||
self.player = None
|
||||
@ -214,76 +214,78 @@ class AccountCookiesPlugin(Plugin.Conversation):
|
||||
account_cookies_plugin_data: AccountCookiesPluginData = context.chat_data.get("account_cookies_plugin_data")
|
||||
cookies = CookiesModel(**account_cookies_plugin_data.cookies)
|
||||
if account_cookies_plugin_data.region == RegionEnum.HYPERION:
|
||||
client = genshin.Client(cookies=cookies.to_dict(), region=types.Region.CHINESE)
|
||||
region = Region.CHINESE
|
||||
elif account_cookies_plugin_data.region == RegionEnum.HOYOLAB:
|
||||
client = genshin.Client(cookies=cookies.to_dict(), region=types.Region.OVERSEAS)
|
||||
region = Region.OVERSEAS
|
||||
else:
|
||||
logger.error("用户 %s[%s] region 异常", user.full_name, user.id)
|
||||
await message.reply_text("数据错误", reply_markup=ReplyKeyboardRemove())
|
||||
return ConversationHandler.END
|
||||
if not cookies.check():
|
||||
await message.reply_text("检测到Cookie不完整,可能会出现问题。", reply_markup=ReplyKeyboardRemove())
|
||||
try:
|
||||
if client.cookie_manager.user_id is None and cookies.is_v2:
|
||||
logger.info("检测到用户 %s[%s] 使用 V2 Cookie 正在尝试获取 account_id", user.full_name, user.id)
|
||||
if client.region == types.Region.CHINESE:
|
||||
account_info = await client.get_hoyolab_user()
|
||||
account_id = account_info.hoyolab_id
|
||||
account_cookies_plugin_data.account_id = account_id
|
||||
cookies.set_v2_uid(account_id)
|
||||
logger.success("获取用户 %s[%s] account_id[%s] 成功", user.full_name, user.id, account_id)
|
||||
else:
|
||||
logger.warning("用户 %s[%s] region[%s] 也许是不正确的", user.full_name, user.id, client.region.name)
|
||||
else:
|
||||
account_cookies_plugin_data.account_id = client.cookie_manager.user_id
|
||||
genshin_accounts = await client.genshin_accounts()
|
||||
except DataNotPublic:
|
||||
logger.info("用户 %s[%s] 账号疑似被注销", user.full_name, user.id)
|
||||
await message.reply_text("账号疑似被注销,请检查账号状态", reply_markup=ReplyKeyboardRemove())
|
||||
return ConversationHandler.END
|
||||
except InvalidCookies:
|
||||
logger.info("用户 %s[%s] Cookies已经过期", user.full_name, user.id)
|
||||
await message.reply_text(
|
||||
"获取账号信息失败,返回Cookies已经过期,请尝试在无痕浏览器中登录获取Cookies。", reply_markup=ReplyKeyboardRemove()
|
||||
)
|
||||
return ConversationHandler.END
|
||||
except GenshinException as exc:
|
||||
logger.info("用户 %s[%s] 获取账号信息发生错误 [%s]%s", user.full_name, user.id, exc.retcode, exc.original)
|
||||
await message.reply_text(
|
||||
f"获取账号信息发生错误,错误信息为 {exc.original},请检查Cookie或者账号是否正常", reply_markup=ReplyKeyboardRemove()
|
||||
)
|
||||
return ConversationHandler.END
|
||||
except AccountIdNotFound:
|
||||
logger.info("用户 %s[%s] 无法获取账号ID", user.full_name, user.id)
|
||||
await message.reply_text("无法获取账号ID,请检查Cookie是否正常", reply_markup=ReplyKeyboardRemove())
|
||||
return ConversationHandler.END
|
||||
except (AttributeError, ValueError) as exc:
|
||||
logger.warning("用户 %s[%s] Cookies错误", user.full_name, user.id)
|
||||
logger.debug("用户 %s[%s] Cookies错误", user.full_name, user.id, exc_info=exc)
|
||||
await message.reply_text("Cookies错误,请检查是否正确", reply_markup=ReplyKeyboardRemove())
|
||||
return ConversationHandler.END
|
||||
if cookies.login_ticket is not None:
|
||||
async with GenshinClient(cookies=cookies.to_dict(), region=region) as client:
|
||||
check_cookie = cookies.check()
|
||||
if cookies.login_ticket is not None:
|
||||
try:
|
||||
cookies.cookie_token = await client.get_cookie_token_by_login_ticket()
|
||||
cookies.account_id = cookies.account_id
|
||||
cookies.ltuid = cookies.account_id
|
||||
logger.success("用户 %s[%s] 绑定时获取 cookie_token 成功", user.full_name, user.id)
|
||||
cookies.stoken = await client.get_stoken_by_login_ticket()
|
||||
logger.success("用户 %s[%s] 绑定时获取 stoken 成功", user.full_name, user.id)
|
||||
cookies.ltoken = await client.get_ltoken_by_stoken()
|
||||
logger.success("用户 %s[%s] 绑定时获取 ltoken 成功", user.full_name, user.id)
|
||||
check_cookie = True
|
||||
except SimnetBadRequest as exc:
|
||||
logger.warning("用户 %s[%s] 获取账号信息发生错误 [%s]%s", user.full_name, user.id, exc.ret_code, exc.original)
|
||||
except Exception as exc:
|
||||
logger.error("绑定时获取新Cookie失败 [%s]", (str(exc)))
|
||||
finally:
|
||||
cookies.login_ticket = None
|
||||
cookies.login_uid = None
|
||||
if not check_cookie:
|
||||
await message.reply_text("检测到Cookie不完整,可能会出现问题。", reply_markup=ReplyKeyboardRemove())
|
||||
try:
|
||||
if cookies.login_ticket is not None:
|
||||
auth_client = AuthClient(cookies=cookies)
|
||||
if await auth_client.get_stoken_by_login_ticket():
|
||||
logger.success("用户 %s[%s] 绑定时获取 stoken 成功", user.full_name, user.id)
|
||||
if await auth_client.get_cookie_token_by_stoken():
|
||||
logger.success("用户 %s[%s] 绑定时获取 cookie_token 成功", user.full_name, user.id)
|
||||
if await auth_client.get_ltoken_by_stoken():
|
||||
logger.success("用户 %s[%s] 绑定时获取 ltoken 成功", user.full_name, user.id)
|
||||
auth_client.cookies.remove_v2()
|
||||
except Exception as exc: # pylint: disable=W0703
|
||||
logger.error("绑定时获取新Cookie失败 [%s]", (str(exc)))
|
||||
finally:
|
||||
if cookies.user_id is not None:
|
||||
account_cookies_plugin_data.account_id = cookies.user_id
|
||||
cookies.login_ticket = None
|
||||
cookies.login_uid = None
|
||||
if client.account_id is None and cookies.is_v2:
|
||||
logger.info("检测到用户 %s[%s] 使用 V2 Cookie 正在尝试获取 account_id", user.full_name, user.id)
|
||||
if client.region == Region.CHINESE:
|
||||
account_info = await client.get_user_info()
|
||||
account_id = account_info.accident_id
|
||||
account_cookies_plugin_data.account_id = account_id
|
||||
cookies.set_v2_uid(account_id)
|
||||
logger.success("获取用户 %s[%s] account_id[%s] 成功", user.full_name, user.id, account_id)
|
||||
else:
|
||||
logger.warning("用户 %s[%s] region[%s] 也许是不正确的", user.full_name, user.id, client.region.name)
|
||||
else:
|
||||
account_cookies_plugin_data.account_id = client.account_id
|
||||
genshin_accounts = await client.get_genshin_accounts()
|
||||
except DataNotPublic:
|
||||
logger.info("用户 %s[%s] 账号疑似被注销", user.full_name, user.id)
|
||||
await message.reply_text("账号疑似被注销,请检查账号状态", reply_markup=ReplyKeyboardRemove())
|
||||
return ConversationHandler.END
|
||||
except InvalidCookies:
|
||||
logger.info("用户 %s[%s] Cookies已经过期", user.full_name, user.id)
|
||||
await message.reply_text(
|
||||
"获取账号信息失败,返回Cookies已经过期,请尝试在无痕浏览器中登录获取Cookies。", reply_markup=ReplyKeyboardRemove()
|
||||
)
|
||||
return ConversationHandler.END
|
||||
except SimnetBadRequest as exc:
|
||||
logger.info("用户 %s[%s] 获取账号信息发生错误 [%s]%s", user.full_name, user.id, exc.ret_code, exc.original)
|
||||
await message.reply_text(
|
||||
f"获取账号信息发生错误,错误信息为 {exc.original},请检查Cookie或者账号是否正常", reply_markup=ReplyKeyboardRemove()
|
||||
)
|
||||
return ConversationHandler.END
|
||||
except AccountIdNotFound:
|
||||
logger.info("用户 %s[%s] 无法获取账号ID", user.full_name, user.id)
|
||||
await message.reply_text("无法获取账号ID,请检查Cookie是否正常", reply_markup=ReplyKeyboardRemove())
|
||||
return ConversationHandler.END
|
||||
except (AttributeError, ValueError) as exc:
|
||||
logger.warning("用户 %s[%s] Cookies错误", user.full_name, user.id)
|
||||
logger.debug("用户 %s[%s] Cookies错误", user.full_name, user.id, exc_info=exc)
|
||||
await message.reply_text("Cookies错误,请检查是否正确", reply_markup=ReplyKeyboardRemove())
|
||||
return ConversationHandler.END
|
||||
if account_cookies_plugin_data.account_id is None:
|
||||
await message.reply_text("无法获取账号ID,请检查Cookie是否正确或请稍后重试")
|
||||
return ConversationHandler.END
|
||||
genshin_account: Optional[GenshinAccount] = None
|
||||
genshin_account: Optional[Account] = None
|
||||
level: int = 0
|
||||
# todo : 多账号绑定
|
||||
for temp in genshin_accounts:
|
||||
|
@ -7,6 +7,7 @@ from telegram.helpers import escape_markdown
|
||||
|
||||
from core.config import config
|
||||
from core.plugin import handler, Plugin
|
||||
from core.services.players import PlayersService
|
||||
from plugins.tools.challenge import ChallengeSystem, ChallengeSystemException
|
||||
from plugins.tools.genshin import PlayerNotFoundError, CookiesNotFoundError, GenshinHelper
|
||||
from plugins.tools.sign import SignSystem, NeedChallenge
|
||||
@ -14,10 +15,17 @@ from utils.log import logger
|
||||
|
||||
|
||||
class StartPlugin(Plugin):
|
||||
def __init__(self, sign_system: SignSystem, challenge_system: ChallengeSystem, genshin_helper: GenshinHelper):
|
||||
def __init__(
|
||||
self,
|
||||
player: PlayersService,
|
||||
sign_system: SignSystem,
|
||||
challenge_system: ChallengeSystem,
|
||||
genshin_helper: GenshinHelper,
|
||||
):
|
||||
self.challenge_system = challenge_system
|
||||
self.sign_system = sign_system
|
||||
self.genshin_helper = genshin_helper
|
||||
self.players_service = player
|
||||
|
||||
@handler.command("start", block=False)
|
||||
async def start(self, update: Update, context: CallbackContext) -> None:
|
||||
@ -77,14 +85,14 @@ class StartPlugin(Plugin):
|
||||
|
||||
async def process_sign_validate(self, message: Message, user: User, validate: str):
|
||||
try:
|
||||
client = await self.genshin_helper.get_genshin_client(user.id)
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
_, challenge = await self.sign_system.get_challenge(client.uid)
|
||||
if not challenge:
|
||||
await message.reply_text("验证请求已过期。", allow_sending_without_reply=True)
|
||||
return
|
||||
sign_text = await self.sign_system.start_sign(client, challenge=challenge, validate=validate)
|
||||
await message.reply_text(sign_text, allow_sending_without_reply=True)
|
||||
async with self.genshin_helper.genshin(user.id) as client:
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
_, challenge = await self.sign_system.get_challenge(client.player_id)
|
||||
if not challenge:
|
||||
await message.reply_text("验证请求已过期。", allow_sending_without_reply=True)
|
||||
return
|
||||
sign_text = await self.sign_system.start_sign(client, challenge=challenge, validate=validate)
|
||||
await message.reply_text(sign_text, allow_sending_without_reply=True)
|
||||
except (PlayerNotFoundError, CookiesNotFoundError):
|
||||
logger.warning("用户 %s[%s] 账号信息未找到", user.full_name, user.id)
|
||||
except NeedChallenge:
|
||||
@ -119,13 +127,13 @@ class StartPlugin(Plugin):
|
||||
)
|
||||
|
||||
async def get_sign_button(self, message: Message, user: User, bot_username: str):
|
||||
try:
|
||||
client = await self.genshin_helper.get_genshin_client(user.id)
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
button = await self.sign_system.get_challenge_button(bot_username, client.uid, user.id, callback=False)
|
||||
if not button:
|
||||
await message.reply_text("验证请求已过期。", allow_sending_without_reply=True)
|
||||
return
|
||||
await message.reply_text("请尽快点击下方按钮进行验证。", allow_sending_without_reply=True, reply_markup=button)
|
||||
except (PlayerNotFoundError, CookiesNotFoundError):
|
||||
player = await self.players_service.get_player(user.id)
|
||||
if player is None:
|
||||
logger.warning("用户 %s[%s] 账号信息未找到", user.full_name, user.id)
|
||||
return
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
button = await self.sign_system.get_challenge_button(bot_username, player.player_id, user.id, callback=False)
|
||||
if not button:
|
||||
await message.reply_text("验证请求已过期。", allow_sending_without_reply=True)
|
||||
return
|
||||
await message.reply_text("请尽快点击下方按钮进行验证。", allow_sending_without_reply=True, reply_markup=button)
|
||||
|
@ -6,8 +6,9 @@ from functools import lru_cache, partial
|
||||
from typing import Any, Coroutine, List, Match, Optional, Tuple, Union
|
||||
|
||||
from arkowrapper import ArkoWrapper
|
||||
from genshin import Client, GenshinException
|
||||
from pytz import timezone
|
||||
from simnet import GenshinClient
|
||||
from simnet.errors import BadRequest as SimnetBadRequest
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Message, Update
|
||||
from telegram.constants import ChatAction, ParseMode
|
||||
from telegram.ext import CallbackContext, filters
|
||||
@ -19,7 +20,7 @@ from core.services.cookies.error import TooManyRequestPublicCookies
|
||||
from core.services.template.models import RenderGroupResult, RenderResult
|
||||
from core.services.template.services import TemplateService
|
||||
from metadata.genshin import game_id_to_role_id
|
||||
from plugins.tools.genshin import GenshinHelper, CookiesNotFoundError, PlayerNotFoundError
|
||||
from plugins.tools.genshin import PlayerNotFoundError, CookiesNotFoundError, GenshinHelper
|
||||
from utils.helpers import async_re_sub
|
||||
from utils.log import logger
|
||||
|
||||
@ -29,7 +30,6 @@ try:
|
||||
except ImportError:
|
||||
import json as jsonlib
|
||||
|
||||
|
||||
TZ = timezone("Asia/Shanghai")
|
||||
cmd_pattern = r"(?i)^/abyss\s*((?:\d+)|(?:all))?\s*(pre)?"
|
||||
msg_pattern = r"^深渊数据((?:查询)|(?:总览))(上期)?\D?(\d*)?.*?$"
|
||||
@ -129,12 +129,38 @@ class AbyssPlugin(Plugin):
|
||||
extra={"markup": True},
|
||||
)
|
||||
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
|
||||
reply_text: Optional[Message] = None
|
||||
|
||||
if total:
|
||||
reply_text = await message.reply_text("派蒙需要时间整理深渊数据,还请耐心等待哦~")
|
||||
|
||||
try:
|
||||
try:
|
||||
client = await self.helper.get_genshin_client(user.id)
|
||||
uid = client.uid
|
||||
async with self.helper.genshin(user.id) as client:
|
||||
images = await self.get_rendered_pic(client, client.player_id, floor, total, previous)
|
||||
except CookiesNotFoundError:
|
||||
client, uid = await self.helper.get_public_genshin_client(user.id)
|
||||
# Cookie 不存在使用公开接口
|
||||
async with self.helper.public_genshin(user.id) as client:
|
||||
images = await self.get_rendered_pic(client, uid, floor, total, previous)
|
||||
except SimnetBadRequest as exc:
|
||||
if exc.ret_code == 1034 and client.player_id != uid:
|
||||
await message.reply_text("出错了呜呜呜 ~ 请稍后重试")
|
||||
return
|
||||
raise exc
|
||||
except AbyssUnlocked: # 若深渊未解锁
|
||||
await message.reply_text("还未解锁深渊哦~")
|
||||
return
|
||||
except NoMostKills: # 若深渊还未挑战
|
||||
await message.reply_text("还没有挑战本次深渊呢,咕咕咕~")
|
||||
return
|
||||
except AbyssNotFoundError:
|
||||
await message.reply_text("无法查询玩家挑战队伍详情,只能查询统计详情哦~")
|
||||
return
|
||||
except IndexError: # 若深渊为挑战此层
|
||||
await message.reply_text("还没有挑战本层呢,咕咕咕~")
|
||||
return
|
||||
except PlayerNotFoundError: # 若未找到账号
|
||||
buttons = [[InlineKeyboardButton("点我绑定账号", url=create_deep_linked_url(context.bot.username, "set_uid"))]]
|
||||
if filters.ChatType.GROUPS.filter(message):
|
||||
@ -152,41 +178,12 @@ class AbyssPlugin(Plugin):
|
||||
self.add_delete_message_job(reply_message)
|
||||
self.add_delete_message_job(message)
|
||||
return
|
||||
finally:
|
||||
if reply_text is not None:
|
||||
await reply_text.delete()
|
||||
|
||||
async def reply_message_func(content: str) -> None:
|
||||
_user = await client.get_genshin_user(uid)
|
||||
_reply_msg = await message.reply_text(
|
||||
f"旅行者 {_user.info.nickname}(<code>{uid}</code>) {content}", parse_mode=ParseMode.HTML
|
||||
)
|
||||
|
||||
reply_text: Optional[Message] = None
|
||||
|
||||
if total:
|
||||
reply_text = await message.reply_text("派蒙需要时间整理深渊数据,还请耐心等待哦~")
|
||||
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
|
||||
try:
|
||||
images = await self.get_rendered_pic(client, uid, floor, total, previous)
|
||||
except GenshinException as exc:
|
||||
if exc.retcode == 1034 and client.uid != uid:
|
||||
await message.reply_text("出错了呜呜呜 ~ 请稍后重试")
|
||||
return
|
||||
raise exc
|
||||
except AbyssUnlocked: # 若深渊未解锁
|
||||
await reply_message_func("还未解锁深渊哦~")
|
||||
return
|
||||
except NoMostKills: # 若深渊还未挑战
|
||||
await reply_message_func("还没有挑战本次深渊呢,咕咕咕~")
|
||||
return
|
||||
except AbyssNotFoundError:
|
||||
await reply_message_func("无法查询玩家挑战队伍详情,只能查询统计详情哦~")
|
||||
return
|
||||
except IndexError: # 若深渊为挑战此层
|
||||
await reply_message_func("还没有挑战本层呢,咕咕咕~")
|
||||
return
|
||||
if images is None:
|
||||
await reply_message_func(f"还没有第 {floor} 层的挑战数据")
|
||||
await message.reply_text(f"还没有第 {floor} 层的挑战数据")
|
||||
return
|
||||
|
||||
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
||||
@ -196,13 +193,10 @@ class AbyssPlugin(Plugin):
|
||||
message, allow_sending_without_reply=True, write_timeout=60
|
||||
)
|
||||
|
||||
if reply_text is not None:
|
||||
await reply_text.delete()
|
||||
|
||||
logger.info("用户 %s[%s] [bold]深渊挑战数据[/bold]: 成功发送图片", user.full_name, user.id, extra={"markup": True})
|
||||
|
||||
async def get_rendered_pic(
|
||||
self, client: Client, uid: int, floor: int, total: bool, previous: bool
|
||||
self, client: GenshinClient, uid: int, floor: int, total: bool, previous: bool
|
||||
) -> Union[
|
||||
Tuple[
|
||||
Union[BaseException, Any],
|
||||
@ -233,7 +227,7 @@ class AbyssPlugin(Plugin):
|
||||
return value.astimezone(TZ).strftime("%Y-%m-%d %H:%M:%S")
|
||||
return value
|
||||
|
||||
abyss_data = await client.get_spiral_abyss(uid, previous=previous, lang="zh-cn")
|
||||
abyss_data = await client.get_genshin_spiral_abyss(uid, previous=previous, lang="zh-cn")
|
||||
|
||||
if not abyss_data.unlocked:
|
||||
raise AbyssUnlocked()
|
||||
|
@ -1,89 +0,0 @@
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
|
||||
from telegram.constants import ChatAction
|
||||
from telegram.ext import CallbackContext, filters
|
||||
from telegram.helpers import create_deep_linked_url
|
||||
|
||||
from core.dependence.assets import AssetsService
|
||||
from core.plugin import Plugin, handler
|
||||
from core.services.template.services import TemplateService
|
||||
from metadata.shortname import roleToId
|
||||
from modules.apihelper.client.components.abyss import AbyssTeam as AbyssTeamClient
|
||||
from plugins.tools.genshin import GenshinHelper, CookiesNotFoundError, PlayerNotFoundError
|
||||
from utils.log import logger
|
||||
|
||||
__all__ = ("AbyssTeamPlugin",)
|
||||
|
||||
|
||||
class AbyssTeamPlugin(Plugin):
|
||||
"""深境螺旋推荐配队查询"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
template: TemplateService,
|
||||
helper: GenshinHelper,
|
||||
assets_service: AssetsService,
|
||||
):
|
||||
self.template_service = template
|
||||
self.helper = helper
|
||||
self.team_data = AbyssTeamClient()
|
||||
self.assets_service = assets_service
|
||||
|
||||
@handler.command("abyss_team", block=False)
|
||||
@handler.message(filters.Regex("^深渊推荐配队(.*)"), block=False)
|
||||
async def command_start(self, update: Update, context: CallbackContext) -> None:
|
||||
user = update.effective_user
|
||||
message = update.effective_message
|
||||
logger.info("用户 %s[%s] 查深渊推荐配队命令请求", user.full_name, user.id)
|
||||
|
||||
try:
|
||||
client = await self.helper.get_genshin_client(user.id)
|
||||
except (CookiesNotFoundError, PlayerNotFoundError):
|
||||
buttons = [[InlineKeyboardButton("点我绑定账号", url=create_deep_linked_url(context.bot.username, "set_cookie"))]]
|
||||
if filters.ChatType.GROUPS.filter(message):
|
||||
reply_message = await message.reply_text(
|
||||
"未查询到您所绑定的账号信息,请先私聊派蒙绑定账号", reply_markup=InlineKeyboardMarkup(buttons)
|
||||
)
|
||||
self.add_delete_message_job(reply_message, delay=30)
|
||||
self.add_delete_message_job(message, delay=30)
|
||||
else:
|
||||
await message.reply_text("未查询到您所绑定的账号信息,请先绑定账号", reply_markup=InlineKeyboardMarkup(buttons))
|
||||
return
|
||||
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
team_data = await self.team_data.get_data()
|
||||
# 尝试获取用户已绑定的原神账号信息
|
||||
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}%",
|
||||
}
|
||||
|
||||
for lane in ["up", "down"]:
|
||||
for member in getattr(i, lane).formation:
|
||||
name = member.name
|
||||
temp = {
|
||||
"icon": (await self.assets_service.avatar(roleToId(name.replace("旅行者", "空"))).icon()).as_uri(),
|
||||
"name": name,
|
||||
"star": member.star,
|
||||
"hava": (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)
|
||||
render_result = await self.template_service.render(
|
||||
"genshin/abyss_team/abyss_team.jinja2",
|
||||
abyss_teams_data,
|
||||
{"width": 785, "height": 800},
|
||||
full_page=True,
|
||||
query_selector=".bg-contain",
|
||||
)
|
||||
await render_result.reply_photo(message, filename=f"abyss_team_{user.id}.png", allow_sending_without_reply=True)
|
@ -1,9 +1,11 @@
|
||||
import asyncio
|
||||
from typing import List, Optional, Sequence, TYPE_CHECKING
|
||||
|
||||
from genshin import Client, GenshinException, InvalidCookies
|
||||
from genshin.models import CalculatorCharacterDetails, CalculatorTalent, Character
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update, User
|
||||
from simnet import GenshinClient
|
||||
from simnet.errors import BadRequest as SimnetBadRequest, InvalidCookies
|
||||
from simnet.models.genshin.calculator import CalculatorTalent, CalculatorCharacterDetails
|
||||
from simnet.models.genshin.chronicle.characters import Character
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, User
|
||||
from telegram.constants import ChatAction, ParseMode
|
||||
from telegram.ext import filters
|
||||
from telegram.helpers import create_deep_linked_url
|
||||
@ -17,10 +19,11 @@ from core.services.template.models import FileType
|
||||
from core.services.template.services import TemplateService
|
||||
from metadata.genshin import AVATAR_DATA
|
||||
from modules.wiki.base import Model
|
||||
from plugins.tools.genshin import CharacterDetails, CookiesNotFoundError, GenshinHelper, PlayerNotFoundError
|
||||
from plugins.tools.genshin import CharacterDetails, PlayerNotFoundError, CookiesNotFoundError, GenshinHelper
|
||||
from utils.log import logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Update
|
||||
from telegram.ext import ContextTypes
|
||||
|
||||
|
||||
@ -67,7 +70,9 @@ class AvatarListPlugin(Plugin):
|
||||
self.player_service = player_service
|
||||
self.player_info_service = player_info_service
|
||||
|
||||
async def get_user_client(self, update: "Update", context: "ContextTypes.DEFAULT_TYPE") -> Optional[Client]:
|
||||
async def get_user_client(
|
||||
self, update: "Update", context: "ContextTypes.DEFAULT_TYPE"
|
||||
) -> Optional["GenshinClient"]:
|
||||
message = update.effective_message
|
||||
user = update.effective_user
|
||||
try:
|
||||
@ -99,7 +104,7 @@ class AvatarListPlugin(Plugin):
|
||||
reply_markup=InlineKeyboardMarkup(buttons),
|
||||
)
|
||||
|
||||
async def get_avatar_data(self, character: Character, client: Client) -> Optional["AvatarData"]:
|
||||
async def get_avatar_data(self, character: Character, client: "GenshinClient") -> Optional["AvatarData"]:
|
||||
detail = await self.character_details.get_character_details(client, character)
|
||||
if detail is None:
|
||||
return None
|
||||
@ -136,7 +141,7 @@ class AvatarListPlugin(Plugin):
|
||||
)
|
||||
|
||||
async def get_avatars_data(
|
||||
self, characters: Sequence[Character], client: Client, max_length: int = None
|
||||
self, characters: Sequence[Character], client: "GenshinClient", max_length: int = None
|
||||
) -> List["AvatarData"]:
|
||||
async def _task(c):
|
||||
return await self.get_avatar_data(c, client)
|
||||
@ -201,31 +206,33 @@ class AvatarListPlugin(Plugin):
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
|
||||
try:
|
||||
characters = await client.get_genshin_characters(client.uid)
|
||||
characters = await client.get_genshin_characters(client.player_id)
|
||||
avatar_datas: List[AvatarData] = await self.get_avatars_data(
|
||||
characters, client, None if all_avatars else 20
|
||||
)
|
||||
except InvalidCookies as exc:
|
||||
await notice.delete()
|
||||
await client.get_genshin_user(client.uid)
|
||||
logger.warning("用户 %s[%s] 无法请求角色数数据 API返回信息为 [%s]%s", user.full_name, user.id, exc.retcode, exc.original)
|
||||
await client.get_genshin_user(client.player_id)
|
||||
logger.warning("用户 %s[%s] 无法请求角色数数据 API返回信息为 [%s]%s", user.full_name, user.id, exc.ret_code, exc.original)
|
||||
reply_message = await message.reply_text("出错了呜呜呜 ~ 当前访问令牌无法请求角色数数据,请尝试重新获取Cookie。")
|
||||
if filters.ChatType.GROUPS.filter(message):
|
||||
self.add_delete_message_job(reply_message, delay=30)
|
||||
self.add_delete_message_job(message, delay=30)
|
||||
return
|
||||
except GenshinException as e:
|
||||
except SimnetBadRequest as e:
|
||||
await notice.delete()
|
||||
if e.retcode == -502002:
|
||||
if e.ret_code == -502002:
|
||||
reply_message = await message.reply_html("请先在米游社中使用一次<b>养成计算器</b>后再使用此功能~")
|
||||
self.add_delete_message_job(reply_message, delay=20)
|
||||
return
|
||||
raise e
|
||||
finally:
|
||||
await client.shutdown()
|
||||
|
||||
name_card, avatar, nickname, rarity = await self.get_final_data(client.uid, user)
|
||||
name_card, avatar, nickname, rarity = await self.get_final_data(client.player_id, user)
|
||||
|
||||
render_data = {
|
||||
"uid": client.uid, # 玩家uid
|
||||
"uid": client.player_id, # 玩家uid
|
||||
"nickname": nickname, # 玩家昵称
|
||||
"avatar": avatar, # 玩家头像
|
||||
"rarity": rarity, # 玩家头像对应的角色星级
|
||||
|
@ -1,13 +1,13 @@
|
||||
import re
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
from typing import List, Optional, TYPE_CHECKING
|
||||
|
||||
from genshin import Client, GenshinException
|
||||
from genshin.client.routes import Route
|
||||
from genshin.utility import recognize_genshin_server
|
||||
from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton
|
||||
from simnet.client.routes import Route
|
||||
from simnet.errors import BadRequest as SimnetBadRequest
|
||||
from simnet.utils.player import recognize_genshin_server, recognize_genshin_game_biz
|
||||
from telegram import InlineKeyboardMarkup, InlineKeyboardButton
|
||||
from telegram.constants import ParseMode
|
||||
from telegram.ext import filters, MessageHandler, CommandHandler, CallbackContext
|
||||
from telegram.ext import filters, MessageHandler, CommandHandler
|
||||
from telegram.helpers import create_deep_linked_url
|
||||
|
||||
from core.basemodel import RegionEnum
|
||||
@ -17,10 +17,14 @@ from core.services.users.services import UserService
|
||||
from metadata.genshin import AVATAR_DATA
|
||||
from metadata.shortname import roleToId, roleToName
|
||||
from modules.apihelper.client.components.calendar import Calendar
|
||||
from plugins.tools.genshin import GenshinHelper, CookiesNotFoundError, PlayerNotFoundError
|
||||
from utils.genshin import fetch_hk4e_token_by_cookie, recognize_genshin_game_biz
|
||||
from plugins.tools.genshin import PlayerNotFoundError, CookiesNotFoundError, GenshinHelper
|
||||
from utils.log import logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from simnet import GenshinClient
|
||||
from telegram import Update
|
||||
from telegram.ext import ContextTypes
|
||||
|
||||
BIRTHDAY_URL = Route(
|
||||
"https://hk4e-api.mihoyo.com/event/birthdaystar/account/post_my_draw",
|
||||
)
|
||||
@ -61,7 +65,7 @@ class BirthdayPlugin(Plugin):
|
||||
return (self.birthday_list.get(key, [])).copy()
|
||||
|
||||
@handler.command(command="birthday", block=False)
|
||||
async def command_start(self, update: Update, context: CallbackContext) -> None:
|
||||
async def command_start(self, update: "Update", context: "ContextTypes.DEFAULT_TYPE") -> None:
|
||||
message = update.effective_message
|
||||
user = update.effective_user
|
||||
key = (
|
||||
@ -113,20 +117,20 @@ class BirthdayPlugin(Plugin):
|
||||
self.add_delete_message_job(reply_message)
|
||||
|
||||
@staticmethod
|
||||
async def get_card(client: Client, role_id: int) -> None:
|
||||
async def get_card(client: "GenshinClient", role_id: int) -> None:
|
||||
"""领取画片"""
|
||||
url = BIRTHDAY_URL.get_url()
|
||||
params = {
|
||||
"game_biz": recognize_genshin_game_biz(client.uid),
|
||||
"game_biz": recognize_genshin_game_biz(client.player_id),
|
||||
"lang": "zh-cn",
|
||||
"badge_uid": client.uid,
|
||||
"badge_region": recognize_genshin_server(client.uid),
|
||||
"badge_uid": client.player_id,
|
||||
"badge_region": recognize_genshin_server(client.player_id),
|
||||
"activity_id": "20220301153521",
|
||||
}
|
||||
json = {
|
||||
"role_id": role_id,
|
||||
}
|
||||
await client.cookie_manager.request(url, method="POST", params=params, json=json)
|
||||
await client.request_lab(url, method="POST", params=params, data=json)
|
||||
|
||||
@staticmethod
|
||||
def role_to_id(name: str) -> Optional[int]:
|
||||
@ -136,7 +140,7 @@ class BirthdayPlugin(Plugin):
|
||||
|
||||
@handler(CommandHandler, command="birthday_card", block=False)
|
||||
@handler(MessageHandler, filters=filters.Regex("^领取角色生日画片$"), block=False)
|
||||
async def command_birthday_card_start(self, update: Update, context: CallbackContext) -> None:
|
||||
async def command_birthday_card_start(self, update: "Update", context: "ContextTypes.DEFAULT_TYPE") -> None:
|
||||
message = update.effective_message
|
||||
user = update.effective_user
|
||||
logger.info("用户 %s[%s] 领取生日画片命令请求", user.full_name, user.id)
|
||||
@ -148,7 +152,28 @@ class BirthdayPlugin(Plugin):
|
||||
self.add_delete_message_job(reply_message)
|
||||
return
|
||||
try:
|
||||
client = await self.helper.get_genshin_client(user.id)
|
||||
async with self.helper.genshin(user.id) as client:
|
||||
if client.region == RegionEnum.HOYOLAB:
|
||||
text = "此功能当前只支持国服账号哦~"
|
||||
else:
|
||||
game_biz = recognize_genshin_game_biz(client.player_id)
|
||||
region = recognize_genshin_server(client.player_id)
|
||||
await client.get_hk4e_token_by_cookie_token(game_biz, region)
|
||||
for name in today_list.copy():
|
||||
if role_id := self.role_to_id(name):
|
||||
try:
|
||||
await self.get_card(client, role_id)
|
||||
except SimnetBadRequest as e:
|
||||
if e.ret_code in {-512008, -512009}: # 未过生日、已领取过
|
||||
today_list.remove(name)
|
||||
if today_list:
|
||||
text = f"成功领取了 {'、'.join(today_list)} 的生日画片~"
|
||||
else:
|
||||
text = "没有领取到生日画片哦 ~ 可能是已经领取过了"
|
||||
reply_message = await message.reply_text(text)
|
||||
if filters.ChatType.GROUPS.filter(reply_message):
|
||||
self.add_delete_message_job(message)
|
||||
self.add_delete_message_job(reply_message)
|
||||
except (CookiesNotFoundError, PlayerNotFoundError):
|
||||
buttons = [[InlineKeyboardButton("点我绑定账号", url=create_deep_linked_url(context.bot.username, "set_cookie"))]]
|
||||
if filters.ChatType.GROUPS.filter(message):
|
||||
@ -166,22 +191,3 @@ class BirthdayPlugin(Plugin):
|
||||
reply_markup=InlineKeyboardMarkup(buttons),
|
||||
)
|
||||
return
|
||||
if client.region == RegionEnum.HOYOLAB:
|
||||
text = "此功能当前只支持国服账号哦~"
|
||||
else:
|
||||
await fetch_hk4e_token_by_cookie(client)
|
||||
for name in today_list.copy():
|
||||
if role_id := self.role_to_id(name):
|
||||
try:
|
||||
await self.get_card(client, role_id)
|
||||
except GenshinException as e:
|
||||
if e.retcode in {-512008, -512009}: # 未过生日、已领取过
|
||||
today_list.remove(name)
|
||||
if today_list:
|
||||
text = f"成功领取了 {'、'.join(today_list)} 的生日画片~"
|
||||
else:
|
||||
text = "没有领取到生日画片哦 ~ 可能是已经领取过了"
|
||||
reply_message = await message.reply_text(text)
|
||||
if filters.ChatType.GROUPS.filter(reply_message):
|
||||
self.add_delete_message_job(message)
|
||||
self.add_delete_message_job(reply_message)
|
||||
|
@ -1,5 +1,4 @@
|
||||
import asyncio
|
||||
import contextlib
|
||||
import os
|
||||
import re
|
||||
from asyncio import Lock
|
||||
@ -9,29 +8,38 @@ from functools import partial
|
||||
from multiprocessing import Value
|
||||
from pathlib import Path
|
||||
from ssl import SSLZeroReturnError
|
||||
from typing import Any, Dict, Iterable, Iterator, List, Literal, Optional, Tuple
|
||||
from typing import Any, Dict, Iterable, Iterator, List, Literal, Optional, Tuple, TYPE_CHECKING
|
||||
|
||||
import ujson as json
|
||||
from aiofiles import open as async_open
|
||||
from arkowrapper import ArkoWrapper
|
||||
from bs4 import BeautifulSoup
|
||||
from genshin import Client, GenshinException, InvalidCookies
|
||||
from genshin.models import Character
|
||||
from httpx import AsyncClient, HTTPError
|
||||
from pydantic import BaseModel
|
||||
from telegram import Message, Update, User
|
||||
from simnet.errors import InvalidCookies, BadRequest as SimnetBadRequest
|
||||
from simnet.models.genshin.chronicle.characters import Character
|
||||
from telegram import Message, User
|
||||
from telegram.constants import ChatAction, ParseMode
|
||||
from telegram.error import RetryAfter, TimedOut
|
||||
from telegram.ext import CallbackContext
|
||||
|
||||
from core.dependence.assets import AssetsCouldNotFound, AssetsService, AssetsServiceType
|
||||
from core.plugin import Plugin, handler
|
||||
from core.services.template.models import FileType, RenderGroupResult
|
||||
from core.services.template.services import TemplateService
|
||||
from metadata.genshin import AVATAR_DATA, HONEY_DATA
|
||||
from plugins.tools.genshin import GenshinHelper, PlayerNotFoundError, CookiesNotFoundError, CharacterDetails
|
||||
from plugins.tools.genshin import CharacterDetails, PlayerNotFoundError, CookiesNotFoundError, GenshinHelper
|
||||
from utils.log import logger
|
||||
|
||||
try:
|
||||
import ujson as jsonlib
|
||||
|
||||
except ImportError:
|
||||
import json as jsonlib
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Update
|
||||
from telegram.ext import ContextTypes
|
||||
from simnet import GenshinClient
|
||||
|
||||
INTERVAL = 1
|
||||
|
||||
DATA_TYPE = Dict[str, List[List[str]]]
|
||||
@ -126,24 +134,24 @@ class DailyMaterial(Plugin):
|
||||
asyncio.create_task(task_daily()) # 创建后台任务
|
||||
if not data and DATA_FILE_PATH.exists(): # 若存在,则读取至内存中
|
||||
async with async_open(DATA_FILE_PATH) as file:
|
||||
data = json.loads(await file.read())
|
||||
data = jsonlib.loads(await file.read())
|
||||
self.data = data
|
||||
|
||||
async def _get_skills_data(self, client: Client, character: Character) -> Optional[List[int]]:
|
||||
async def _get_skills_data(self, client: "GenshinClient", character: Character) -> Optional[List[int]]:
|
||||
detail = await self.character_details.get_character_details(client, character)
|
||||
if detail is None:
|
||||
return None
|
||||
talents = [t for t in detail.talents if t.type in ["attack", "skill", "burst"]]
|
||||
return [t.level for t in talents]
|
||||
|
||||
async def _get_data_from_user(self, user: User) -> Tuple[Optional[Client], Dict[str, List[Any]]]:
|
||||
async def _get_data_from_user(self, user: User) -> Tuple[Optional["GenshinClient"], Dict[str, List[Any]]]:
|
||||
"""获取已经绑定的账号的角色、武器信息"""
|
||||
user_data = {"avatar": [], "weapon": []}
|
||||
try:
|
||||
logger.debug("尝试获取已绑定的原神账号")
|
||||
client = await self.helper.get_genshin_client(user.id)
|
||||
logger.debug("获取账号数据成功: UID=%s", client.uid)
|
||||
characters = await client.get_genshin_characters(client.uid)
|
||||
logger.debug("获取账号数据成功: UID=%s", client.player_id)
|
||||
characters = await client.get_genshin_characters(client.player_id)
|
||||
for character in characters:
|
||||
if character.name == "旅行者": # 跳过主角
|
||||
continue
|
||||
@ -153,7 +161,7 @@ class DailyMaterial(Plugin):
|
||||
ItemData(
|
||||
id=cid,
|
||||
name=character.name,
|
||||
rarity=character.rarity,
|
||||
rarity=int(character.rarity),
|
||||
level=character.level,
|
||||
constellation=character.constellation,
|
||||
gid=character.id,
|
||||
@ -187,7 +195,7 @@ class DailyMaterial(Plugin):
|
||||
return None, user_data
|
||||
|
||||
@handler.command("daily_material", block=False)
|
||||
async def daily_material(self, update: Update, context: CallbackContext):
|
||||
async def daily_material(self, update: "Update", context: "ContextTypes.DEFAULT_TYPE"):
|
||||
user = update.effective_user
|
||||
message = update.effective_message
|
||||
args = self.get_args(context)
|
||||
@ -240,7 +248,7 @@ class DailyMaterial(Plugin):
|
||||
client, user_data = await self._get_data_from_user(user)
|
||||
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
render_data = RenderData(title=title, time=time, uid=client.uid if client else client)
|
||||
render_data = RenderData(title=title, time=time, uid=client.player_id if client else client)
|
||||
|
||||
calculator_sync: bool = True # 默认养成计算器同步为开启
|
||||
for type_ in ["avatar", "weapon"]:
|
||||
@ -258,8 +266,8 @@ class DailyMaterial(Plugin):
|
||||
i.skills = skills
|
||||
except InvalidCookies:
|
||||
calculator_sync = False
|
||||
except GenshinException as e:
|
||||
if e.retcode == -502002:
|
||||
except SimnetBadRequest as e:
|
||||
if e.ret_code == -502002:
|
||||
calculator_sync = False # 发现角色养成计算器没启用 设置状态为 False 并防止下次继续获取
|
||||
self.add_delete_message_job(notice, delay=5)
|
||||
await notice.edit_text(
|
||||
@ -341,7 +349,7 @@ class DailyMaterial(Plugin):
|
||||
logger.debug("角色、武器培养素材图发送成功")
|
||||
|
||||
@handler.command("refresh_daily_material", admin=True, block=False)
|
||||
async def refresh(self, update: Update, context: CallbackContext):
|
||||
async def refresh(self, update: "Update", context: "ContextTypes.DEFAULT_TYPE"):
|
||||
user = update.effective_user
|
||||
message = update.effective_message
|
||||
|
||||
@ -408,7 +416,7 @@ class DailyMaterial(Plugin):
|
||||
# noinspection PyUnresolvedReferences
|
||||
result[stage][day][1] = list(set(result[stage][day][1])) # 去重
|
||||
async with async_open(DATA_FILE_PATH, "w", encoding="utf-8") as file:
|
||||
await file.write(json.dumps(result)) # skipcq: PY-W0079
|
||||
await file.write(jsonlib.dumps(result)) # skipcq: PY-W0079
|
||||
logger.info("每日素材刷新成功")
|
||||
break
|
||||
except (HTTPError, SSLZeroReturnError):
|
||||
@ -437,11 +445,13 @@ class DailyMaterial(Plugin):
|
||||
"""修改提示消息"""
|
||||
async with lock:
|
||||
if message is not None and time_() >= (the_time.value + INTERVAL):
|
||||
with contextlib.suppress(TimedOut, RetryAfter):
|
||||
try:
|
||||
await message.edit_text(
|
||||
"\n".join(message.text_html.split("\n")[:2] + [text]), parse_mode=ParseMode.HTML
|
||||
)
|
||||
the_time.value = time_()
|
||||
except (TimedOut, RetryAfter):
|
||||
pass
|
||||
|
||||
async def task(item_id, name, item_type):
|
||||
logger.debug("正在开始下载 %s 的图标素材", name)
|
||||
|
@ -1,20 +1,24 @@
|
||||
import datetime
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
import genshin
|
||||
from genshin import DataNotPublic
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
|
||||
from simnet.errors import DataNotPublic
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from telegram.constants import ChatAction
|
||||
from telegram.ext import ConversationHandler, filters, CallbackContext
|
||||
from telegram.ext import ConversationHandler, filters
|
||||
from telegram.helpers import create_deep_linked_url
|
||||
|
||||
from core.plugin import Plugin, handler
|
||||
from core.services.template.models import RenderResult
|
||||
from core.services.template.services import TemplateService
|
||||
from plugins.tools.genshin import GenshinHelper, CookiesNotFoundError, PlayerNotFoundError
|
||||
from plugins.tools.genshin import PlayerNotFoundError, CookiesNotFoundError, GenshinHelper
|
||||
from utils.log import logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from simnet import GenshinClient
|
||||
from telegram import Update
|
||||
from telegram.ext import ContextTypes
|
||||
|
||||
__all__ = ("DailyNotePlugin",)
|
||||
|
||||
|
||||
@ -29,8 +33,8 @@ class DailyNotePlugin(Plugin):
|
||||
self.template_service = template
|
||||
self.helper = helper
|
||||
|
||||
async def _get_daily_note(self, client: genshin.Client) -> RenderResult:
|
||||
daily_info = await client.get_genshin_notes(client.uid)
|
||||
async def _get_daily_note(self, client: "GenshinClient") -> RenderResult:
|
||||
daily_info = await client.get_genshin_notes(client.player_id)
|
||||
|
||||
day = datetime.now().strftime("%m-%d %H:%M") + " 星期" + "一二三四五六日"[datetime.now().weekday()]
|
||||
resin_recovery_time = (
|
||||
@ -60,7 +64,7 @@ class DailyNotePlugin(Plugin):
|
||||
transformer_recovery_time = daily_info.transformer_recovery_time.strftime("%m-%d %H:%M")
|
||||
|
||||
render_data = {
|
||||
"uid": client.uid,
|
||||
"uid": client.player_id,
|
||||
"day": day,
|
||||
"resin_recovery_time": resin_recovery_time,
|
||||
"current_resin": daily_info.current_resin,
|
||||
@ -92,16 +96,15 @@ class DailyNotePlugin(Plugin):
|
||||
|
||||
@handler.command("dailynote", block=False)
|
||||
@handler.message(filters.Regex("^当前状态(.*)"), block=False)
|
||||
async def command_start(self, update: Update, _: CallbackContext) -> Optional[int]:
|
||||
async def command_start(self, update: "Update", _: "ContextTypes.DEFAULT_TYPE") -> Optional[int]:
|
||||
message = update.effective_message
|
||||
user = update.effective_user
|
||||
logger.info("用户 %s[%s] 每日便签命令请求", user.full_name, user.id)
|
||||
|
||||
try:
|
||||
# 获取当前用户的 genshin.Client
|
||||
client = await self.helper.get_genshin_client(user.id)
|
||||
# 渲染
|
||||
render_result = await self._get_daily_note(client)
|
||||
async with self.helper.genshin(user.id) as client:
|
||||
render_result = await self._get_daily_note(client)
|
||||
except (CookiesNotFoundError, PlayerNotFoundError):
|
||||
buttons = [
|
||||
[
|
||||
@ -127,4 +130,4 @@ class DailyNotePlugin(Plugin):
|
||||
return ConversationHandler.END
|
||||
|
||||
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
||||
await render_result.reply_photo(message, filename=f"{client.uid}.png", allow_sending_without_reply=True)
|
||||
await render_result.reply_photo(message, filename=f"{client.player_id}.png", allow_sending_without_reply=True)
|
||||
|
@ -1,20 +1,26 @@
|
||||
import os
|
||||
import re
|
||||
from datetime import datetime, timedelta
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from genshin import DataNotPublic, InvalidCookies, GenshinException
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
|
||||
from simnet.errors import DataNotPublic, BadRequest as SimnetBadRequest, InvalidCookies
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from telegram.constants import ChatAction
|
||||
from telegram.ext import filters, CallbackContext
|
||||
from telegram.ext import filters
|
||||
from telegram.helpers import create_deep_linked_url
|
||||
|
||||
from core.plugin import Plugin, handler
|
||||
from core.services.cookies import CookiesService
|
||||
from core.services.template.models import RenderResult
|
||||
from core.services.template.services import TemplateService
|
||||
from plugins.tools.genshin import CookiesNotFoundError, GenshinHelper, PlayerNotFoundError
|
||||
from plugins.tools.genshin import PlayerNotFoundError, CookiesNotFoundError, GenshinHelper
|
||||
from utils.log import logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Update
|
||||
from telegram.ext import ContextTypes
|
||||
from simnet import GenshinClient
|
||||
|
||||
__all__ = ("LedgerPlugin",)
|
||||
|
||||
|
||||
@ -32,8 +38,8 @@ class LedgerPlugin(Plugin):
|
||||
self.current_dir = os.getcwd()
|
||||
self.helper = helper
|
||||
|
||||
async def _start_get_ledger(self, client, month=None) -> RenderResult:
|
||||
diary_info = await client.get_diary(client.uid, month=month)
|
||||
async def _start_get_ledger(self, client: "GenshinClient", month=None) -> RenderResult:
|
||||
diary_info = await client.get_genshin_diary(client.player_id, month=month)
|
||||
color = ["#73a9c6", "#d56565", "#70b2b4", "#bd9a5a", "#739970", "#7a6da7", "#597ea0"]
|
||||
categories = [
|
||||
{
|
||||
@ -51,7 +57,7 @@ class LedgerPlugin(Plugin):
|
||||
return f"{round(amount / 10000, 2)}w" if amount >= 10000 else amount
|
||||
|
||||
ledger_data = {
|
||||
"uid": client.uid,
|
||||
"uid": client.player_id,
|
||||
"day": diary_info.month,
|
||||
"current_primogems": format_amount(diary_info.month_data.current_primogems),
|
||||
"gacha": int(diary_info.month_data.current_primogems / 160),
|
||||
@ -69,7 +75,7 @@ class LedgerPlugin(Plugin):
|
||||
|
||||
@handler.command(command="ledger", block=False)
|
||||
@handler.message(filters=filters.Regex("^旅行札记查询(.*)"), block=False)
|
||||
async def command_start(self, update: Update, context: CallbackContext) -> None:
|
||||
async def command_start(self, update: "Update", context: "ContextTypes.DEFAULT_TYPE") -> None:
|
||||
user = update.effective_user
|
||||
message = update.effective_message
|
||||
|
||||
@ -106,19 +112,19 @@ class LedgerPlugin(Plugin):
|
||||
logger.info("用户 %s[%s] 查询旅行札记", user.full_name, user.id)
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
try:
|
||||
client = await self.helper.get_genshin_client(user.id)
|
||||
try:
|
||||
render_result = await self._start_get_ledger(client, month)
|
||||
except InvalidCookies as exc: # 如果抛出InvalidCookies 判断是否真的玄学过期(或权限不足?)
|
||||
await client.get_genshin_user(client.uid)
|
||||
logger.warning(
|
||||
"用户 %s[%s] 无法请求旅行札记数据 API返回信息为 [%s]%s", user.full_name, user.id, exc.retcode, exc.original
|
||||
)
|
||||
reply_message = await message.reply_text("出错了呜呜呜 ~ 当前访问令牌无法请求角色数数据,请尝试重新获取Cookie。")
|
||||
if filters.ChatType.GROUPS.filter(message):
|
||||
self.add_delete_message_job(reply_message, delay=30)
|
||||
self.add_delete_message_job(message, delay=30)
|
||||
return
|
||||
async with self.helper.genshin(user.id) as client:
|
||||
try:
|
||||
render_result = await self._start_get_ledger(client, month)
|
||||
except InvalidCookies as exc: # 如果抛出InvalidCookies 判断是否真的玄学过期(或权限不足?)
|
||||
await client.get_genshin_user(client.player_id)
|
||||
logger.warning(
|
||||
"用户 %s[%s] 无法请求旅行札记数据 API返回信息为 [%s]%s", user.full_name, user.id, exc.ret_code, exc.original
|
||||
)
|
||||
reply_message = await message.reply_text("出错了呜呜呜 ~ 当前访问令牌无法请求角色数数据,请尝试重新获取Cookie。")
|
||||
if filters.ChatType.GROUPS.filter(message):
|
||||
self.add_delete_message_job(reply_message, delay=30)
|
||||
self.add_delete_message_job(message, delay=30)
|
||||
return
|
||||
except (PlayerNotFoundError, CookiesNotFoundError):
|
||||
buttons = [
|
||||
[
|
||||
@ -142,10 +148,10 @@ class LedgerPlugin(Plugin):
|
||||
self.add_delete_message_job(reply_message, delay=30)
|
||||
self.add_delete_message_job(message, delay=30)
|
||||
return
|
||||
except GenshinException as exc:
|
||||
if exc.retcode == -120:
|
||||
except SimnetBadRequest as exc:
|
||||
if exc.ret_code == -120:
|
||||
await message.reply_text("当前角色冒险等阶不足,暂时无法获取信息")
|
||||
return
|
||||
raise exc
|
||||
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
||||
await render_result.reply_photo(message, filename=f"{client.uid}.png", allow_sending_without_reply=True)
|
||||
await render_result.reply_photo(message, filename=f"{client.player_id}.png", allow_sending_without_reply=True)
|
||||
|
@ -1,4 +1,5 @@
|
||||
import genshin
|
||||
from simnet import GenshinClient, Region
|
||||
from simnet.utils.player import recognize_genshin_game_biz, recognize_genshin_server
|
||||
from telegram import Update, User, InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from telegram.constants import ChatAction
|
||||
from telegram.ext import CallbackContext, CommandHandler, MessageHandler, filters, ConversationHandler
|
||||
@ -12,14 +13,17 @@ from core.services.template.services import TemplateService
|
||||
from modules.gacha_log.helpers import from_url_get_authkey
|
||||
from modules.pay_log.error import PayLogNotFound, PayLogAccountNotFound, PayLogInvalidAuthkey, PayLogAuthkeyTimeout
|
||||
from modules.pay_log.log import PayLog
|
||||
from plugins.tools.genshin import GenshinHelper, PlayerNotFoundError
|
||||
from plugins.tools.genshin import GenshinHelper
|
||||
from plugins.tools.player_info import PlayerInfoSystem
|
||||
from utils.genshin import get_authkey_by_stoken
|
||||
from utils.log import logger
|
||||
|
||||
INPUT_URL, CONFIRM_DELETE = range(10100, 10102)
|
||||
|
||||
|
||||
class PlayerNotFoundError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class PayLogPlugin(Plugin.Conversation):
|
||||
"""充值记录导入/导出/分析"""
|
||||
|
||||
@ -28,15 +32,15 @@ class PayLogPlugin(Plugin.Conversation):
|
||||
template_service: TemplateService,
|
||||
players_service: PlayersService,
|
||||
cookie_service: CookiesService,
|
||||
helper: GenshinHelper,
|
||||
player_info: PlayerInfoSystem,
|
||||
genshin_helper: GenshinHelper,
|
||||
):
|
||||
self.template_service = template_service
|
||||
self.players_service = players_service
|
||||
self.cookie_service = cookie_service
|
||||
self.pay_log = PayLog()
|
||||
self.helper = helper
|
||||
self.player_info = player_info
|
||||
self.genshin_helper = genshin_helper
|
||||
|
||||
async def _refresh_user_data(self, user: User, authkey: str = None) -> str:
|
||||
"""刷新用户数据
|
||||
@ -46,7 +50,7 @@ class PayLogPlugin(Plugin.Conversation):
|
||||
"""
|
||||
try:
|
||||
logger.debug("尝试获取已绑定的原神账号")
|
||||
client = await self.helper.get_genshin_client(user.id, need_cookie=False)
|
||||
client = await self.genshin_helper.get_genshin_client(user.id)
|
||||
new_num = await self.pay_log.get_log_data(user.id, client, authkey)
|
||||
return "更新完成,本次没有新增数据" if new_num == 0 else f"更新完成,本次共新增{new_num}条充值记录"
|
||||
except PayLogNotFound:
|
||||
@ -79,14 +83,14 @@ class PayLogPlugin(Plugin.Conversation):
|
||||
(value for key, value in cookies.data.items() if key in ["ltuid", "login_uid"]), None
|
||||
):
|
||||
cookies.data["stuid"] = stuid
|
||||
client = genshin.Client(
|
||||
cookies=cookies.data,
|
||||
game=genshin.types.Game.GENSHIN,
|
||||
region=genshin.Region.CHINESE,
|
||||
lang="zh-cn",
|
||||
uid=player_info.player_id,
|
||||
)
|
||||
authkey = await get_authkey_by_stoken(client, auth_appid="csc")
|
||||
async with GenshinClient(
|
||||
cookies=cookies.data, region=Region.CHINESE, lang="zh-cn", player_id=player_info.player_id
|
||||
) as client:
|
||||
authkey = await client.get_authkey_by_stoken(
|
||||
recognize_genshin_game_biz(client.player_id),
|
||||
recognize_genshin_server(client.player_id),
|
||||
"csc",
|
||||
)
|
||||
if not authkey:
|
||||
await message.reply_text(
|
||||
"<b>开始导入充值历史记录:请通过 https://paimon.moe/wish/import 获取抽卡记录链接后发送给我"
|
||||
@ -130,17 +134,16 @@ class PayLogPlugin(Plugin.Conversation):
|
||||
message = update.effective_message
|
||||
user = update.effective_user
|
||||
logger.info("用户 %s[%s] 删除充值记录命令请求", user.full_name, user.id)
|
||||
try:
|
||||
client = await self.helper.get_genshin_client(user.id, need_cookie=False)
|
||||
except PlayerNotFoundError:
|
||||
player_info = await self.players_service.get_player(user.id)
|
||||
if player_info is None:
|
||||
logger.info("未查询到用户 %s[%s] 所绑定的账号信息", user.full_name, user.id)
|
||||
await message.reply_text("未查询到您所绑定的账号信息,请先绑定账号")
|
||||
return ConversationHandler.END
|
||||
_, status = await self.pay_log.load_history_info(str(user.id), str(client.uid), only_status=True)
|
||||
_, status = await self.pay_log.load_history_info(str(user.id), str(player_info.player_id), only_status=True)
|
||||
if not status:
|
||||
await message.reply_text("你还没有导入充值记录哦~")
|
||||
return ConversationHandler.END
|
||||
context.chat_data["uid"] = client.uid
|
||||
context.chat_data["uid"] = player_info.player_id
|
||||
await message.reply_text("你确定要删除充值记录吗?(此项操作无法恢复),如果确定请发送 ”确定“,发送其他内容取消")
|
||||
return CONFIRM_DELETE
|
||||
|
||||
@ -167,15 +170,15 @@ class PayLogPlugin(Plugin.Conversation):
|
||||
cid = int(args[0])
|
||||
if cid < 0:
|
||||
raise ValueError("Invalid cid")
|
||||
client = await self.helper.get_genshin_client(cid, need_cookie=False)
|
||||
if client is None:
|
||||
player_info = await self.players_service.get_player(cid)
|
||||
if player_info is None:
|
||||
await message.reply_text("该用户暂未绑定账号")
|
||||
return
|
||||
_, status = await self.pay_log.load_history_info(str(cid), str(client.uid), only_status=True)
|
||||
_, status = await self.pay_log.load_history_info(str(cid), str(player_info.player_id), only_status=True)
|
||||
if not status:
|
||||
await message.reply_text("该用户还没有导入充值记录")
|
||||
return
|
||||
status = await self.pay_log.remove_history_info(str(cid), str(client.uid))
|
||||
status = await self.pay_log.remove_history_info(str(cid), str(player_info.player_id))
|
||||
await message.reply_text("充值记录已强制删除" if status else "充值记录删除失败")
|
||||
except PayLogNotFound:
|
||||
await message.reply_text("该用户还没有导入充值记录")
|
||||
@ -189,9 +192,11 @@ class PayLogPlugin(Plugin.Conversation):
|
||||
user = update.effective_user
|
||||
logger.info("用户 %s[%s] 导出充值记录命令请求", user.full_name, user.id)
|
||||
try:
|
||||
client = await self.helper.get_genshin_client(user.id, need_cookie=False)
|
||||
player_info = await self.players_service.get_player(user.id)
|
||||
if player_info is None:
|
||||
raise PlayerNotFoundError
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
path = self.pay_log.get_file_path(str(user.id), str(client.uid))
|
||||
path = self.pay_log.get_file_path(str(user.id), str(player_info.player_id))
|
||||
if not path.exists():
|
||||
raise PayLogNotFound
|
||||
await message.reply_chat_action(ChatAction.UPLOAD_DOCUMENT)
|
||||
@ -214,11 +219,13 @@ class PayLogPlugin(Plugin.Conversation):
|
||||
user = update.effective_user
|
||||
logger.info("用户 %s[%s] 充值记录统计命令请求", user.full_name, user.id)
|
||||
try:
|
||||
client = await self.helper.get_genshin_client(user.id, need_cookie=False)
|
||||
player_info = await self.players_service.get_player(user.id)
|
||||
if player_info is None:
|
||||
raise PlayerNotFoundError
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
data = await self.pay_log.get_analysis(user.id, client)
|
||||
data = await self.pay_log.get_analysis(user.id, player_info.player_id)
|
||||
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
||||
name_card = await self.player_info.get_name_card(client.uid, user)
|
||||
name_card = await self.player_info.get_name_card(player_info.player_id, user)
|
||||
data["name_card"] = name_card
|
||||
png_data = await self.template_service.render(
|
||||
"genshin/pay_log/pay_log.jinja2", data, full_page=True, query_selector=".container"
|
||||
|
@ -1,11 +1,11 @@
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from genshin import Client, GenshinException, InvalidCookies
|
||||
from genshin.client.routes import InternationalRoute # noqa F401
|
||||
from genshin.utility import recognize_genshin_server, get_ds_headers
|
||||
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from simnet.client.routes import InternationalRoute
|
||||
from simnet.errors import InvalidCookies, BadRequest as SIMNetBadRequest
|
||||
from simnet.utils.player import recognize_genshin_server, recognize_genshin_game_biz
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from telegram.constants import ParseMode
|
||||
from telegram.ext import CallbackContext
|
||||
from telegram.ext import filters
|
||||
from telegram.helpers import create_deep_linked_url
|
||||
|
||||
@ -13,10 +13,14 @@ from core.dependence.redisdb import RedisDB
|
||||
from core.plugin import Plugin, handler
|
||||
from core.services.cookies import CookiesService
|
||||
from core.services.users.services import UserService
|
||||
from plugins.tools.genshin import GenshinHelper, PlayerNotFoundError, CookiesNotFoundError
|
||||
from utils.genshin import fetch_hk4e_token_by_cookie, recognize_genshin_game_biz
|
||||
from plugins.tools.genshin import PlayerNotFoundError, CookiesNotFoundError, GenshinHelper
|
||||
from utils.log import logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Update
|
||||
from telegram.ext import ContextTypes
|
||||
from simnet import GenshinClient
|
||||
|
||||
try:
|
||||
import ujson as jsonlib
|
||||
|
||||
@ -46,53 +50,36 @@ class RegTimePlugin(Plugin):
|
||||
self.helper = helper
|
||||
|
||||
@staticmethod
|
||||
async def get_reg_time(client: Client) -> str:
|
||||
async def get_reg_time(client: "GenshinClient") -> str:
|
||||
"""获取原神注册时间"""
|
||||
await fetch_hk4e_token_by_cookie(client)
|
||||
game_biz = recognize_genshin_game_biz(client.player_id)
|
||||
region = recognize_genshin_server(client.player_id)
|
||||
await client.get_hk4e_token_by_cookie_token(game_biz, region)
|
||||
url = REG_TIME_URL.get_url(client.region)
|
||||
params = {
|
||||
"game_biz": recognize_genshin_game_biz(client.uid),
|
||||
"lang": "zh-cn",
|
||||
"badge_uid": client.uid,
|
||||
"badge_region": recognize_genshin_server(client.uid),
|
||||
}
|
||||
headers = get_ds_headers(
|
||||
client.region,
|
||||
params=params,
|
||||
lang="zh-cn",
|
||||
)
|
||||
data = await client.cookie_manager.request(url, method="GET", params=params, headers=headers)
|
||||
params = {"game_biz": game_biz, "lang": "zh-cn", "badge_uid": client.player_id, "badge_region": region}
|
||||
data = await client.request_lab(url, method="GET", params=params)
|
||||
if time := jsonlib.loads(data.get("data", "{}")).get("1", 0):
|
||||
return datetime.fromtimestamp(time).strftime("%Y-%m-%d %H:%M:%S")
|
||||
raise RegTimePlugin.NotFoundRegTimeError
|
||||
|
||||
async def get_reg_time_from_cache(self, client: Client) -> str:
|
||||
async def get_reg_time_from_cache(self, client: "GenshinClient") -> str:
|
||||
"""从缓存中获取原神注册时间"""
|
||||
if reg_time := await self.cache.get(f"{self.cache_key}{client.uid}"):
|
||||
if reg_time := await self.cache.get(f"{self.cache_key}{client.player_id}"):
|
||||
return reg_time.decode("utf-8")
|
||||
reg_time = await self.get_reg_time(client)
|
||||
await self.cache.set(f"{self.cache_key}{client.uid}", reg_time)
|
||||
await self.cache.set(f"{self.cache_key}{client.player_id}", reg_time)
|
||||
return reg_time
|
||||
|
||||
@handler.command("reg_time", block=False)
|
||||
@handler.message(filters.Regex(r"^原神账号注册时间$"), block=False)
|
||||
async def reg_time(self, update: Update, context: CallbackContext) -> None:
|
||||
async def reg_time(self, update: "Update", context: "ContextTypes.DEFAULT_TYPE") -> None:
|
||||
message = update.effective_message
|
||||
user = update.effective_user
|
||||
logger.info("用户 %s[%s] 原神注册时间命令请求", user.full_name, user.id)
|
||||
try:
|
||||
client = await self.helper.get_genshin_client(user.id)
|
||||
game_uid = client.uid
|
||||
try:
|
||||
async with self.helper.genshin(user.id) as client:
|
||||
game_uid = client.player_id
|
||||
reg_time = await self.get_reg_time_from_cache(client)
|
||||
except InvalidCookies as exc:
|
||||
await client.get_genshin_user(client.uid)
|
||||
logger.warning("用户 %s[%s] 无法请求注册时间 API返回信息为 [%s]%s", user.full_name, user.id, exc.retcode, exc.original)
|
||||
reply_message = await message.reply_text("出错了呜呜呜 ~ 当前访问令牌无法请求角色数数据,")
|
||||
if filters.ChatType.GROUPS.filter(message):
|
||||
self.add_delete_message_job(reply_message, delay=30)
|
||||
self.add_delete_message_job(message, delay=30)
|
||||
return
|
||||
await message.reply_text(f"你的原神账号 [{game_uid}] 注册时间为:{reg_time}")
|
||||
except (PlayerNotFoundError, CookiesNotFoundError):
|
||||
buttons = [[InlineKeyboardButton("点我绑定账号", url=create_deep_linked_url(context.bot.username, "set_cookie"))]]
|
||||
@ -110,8 +97,17 @@ class RegTimePlugin(Plugin):
|
||||
parse_mode=ParseMode.HTML,
|
||||
reply_markup=InlineKeyboardMarkup(buttons),
|
||||
)
|
||||
except GenshinException as exc:
|
||||
if exc.retcode == -501101:
|
||||
except InvalidCookies as exc:
|
||||
async with self.helper.genshin(user.id) as client:
|
||||
await client.get_genshin_user(client.player_id)
|
||||
logger.warning("用户 %s[%s] 无法请求注册时间 API返回信息为 [%s]%s", user.full_name, user.id, exc.ret_code, exc.original)
|
||||
reply_message = await message.reply_text("出错了呜呜呜 ~ 当前访问令牌无法请求角色数数据,")
|
||||
if filters.ChatType.GROUPS.filter(message):
|
||||
self.add_delete_message_job(reply_message, delay=30)
|
||||
self.add_delete_message_job(message, delay=30)
|
||||
return
|
||||
except SIMNetBadRequest as exc:
|
||||
if exc.ret_code == -501101:
|
||||
await message.reply_text("当前角色冒险等阶未达到10级,暂时无法获取信息")
|
||||
else:
|
||||
raise exc
|
||||
|
@ -10,10 +10,12 @@ from telegram.helpers import create_deep_linked_url
|
||||
from core.config import config
|
||||
from core.handler.callbackqueryhandler import CallbackQueryHandler
|
||||
from core.plugin import Plugin, handler
|
||||
from core.services.cookies import CookiesService
|
||||
from core.services.players import PlayersService
|
||||
from core.services.sign.models import Sign as SignUser, SignStatusEnum
|
||||
from core.services.sign.services import SignServices
|
||||
from core.services.users.services import UserAdminService
|
||||
from plugins.tools.genshin import GenshinHelper, CookiesNotFoundError, PlayerNotFoundError
|
||||
from plugins.tools.genshin import PlayerNotFoundError, CookiesNotFoundError, GenshinHelper
|
||||
from plugins.tools.sign import SignSystem, NeedChallenge
|
||||
from utils.log import logger
|
||||
|
||||
@ -29,16 +31,22 @@ class Sign(Plugin):
|
||||
sign_service: SignServices,
|
||||
user_admin_service: UserAdminService,
|
||||
sign_system: SignSystem,
|
||||
player: PlayersService,
|
||||
cookies: CookiesService,
|
||||
):
|
||||
self.user_admin_service = user_admin_service
|
||||
self.sign_service = sign_service
|
||||
self.sign_system = sign_system
|
||||
self.genshin_helper = genshin_helper
|
||||
self.players_service = player
|
||||
self.cookies_service = cookies
|
||||
|
||||
async def _process_auto_sign(self, user_id: int, chat_id: int, method: str) -> str:
|
||||
try:
|
||||
await self.genshin_helper.get_genshin_client(user_id)
|
||||
except (PlayerNotFoundError, CookiesNotFoundError):
|
||||
player = await self.players_service.get_player(user_id)
|
||||
if player is None:
|
||||
return "未查询到账号信息,请先私聊派蒙绑定账号"
|
||||
cookie_model = await self.cookies_service.get(player.user_id, player.account_id, player.region)
|
||||
if cookie_model is None:
|
||||
return "未查询到账号信息,请先私聊派蒙绑定账号"
|
||||
user: SignUser = await self.sign_service.get_by_user_id(user_id)
|
||||
if user:
|
||||
@ -93,20 +101,20 @@ class Sign(Plugin):
|
||||
if filters.ChatType.GROUPS.filter(message):
|
||||
self.add_delete_message_job(message)
|
||||
try:
|
||||
client = await self.genshin_helper.get_genshin_client(user.id)
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
_, challenge = await self.sign_system.get_challenge(client.uid)
|
||||
if validate:
|
||||
_, challenge = await self.sign_system.get_challenge(client.uid)
|
||||
if challenge:
|
||||
sign_text = await self.sign_system.start_sign(client, challenge=challenge, validate=validate)
|
||||
async with self.genshin_helper.genshin(user.id) as client:
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
_, challenge = await self.sign_system.get_challenge(client.player_id)
|
||||
if validate:
|
||||
_, challenge = await self.sign_system.get_challenge(client.player_id)
|
||||
if challenge:
|
||||
sign_text = await self.sign_system.start_sign(client, challenge=challenge, validate=validate)
|
||||
else:
|
||||
reply_message = await message.reply_text("请求已经过期", allow_sending_without_reply=True)
|
||||
if filters.ChatType.GROUPS.filter(reply_message):
|
||||
self.add_delete_message_job(reply_message)
|
||||
return
|
||||
else:
|
||||
reply_message = await message.reply_text("请求已经过期", allow_sending_without_reply=True)
|
||||
if filters.ChatType.GROUPS.filter(reply_message):
|
||||
self.add_delete_message_job(reply_message)
|
||||
return
|
||||
else:
|
||||
sign_text = await self.sign_system.start_sign(client)
|
||||
sign_text = await self.sign_system.start_sign(client)
|
||||
reply_message = await message.reply_text(sign_text, allow_sending_without_reply=True)
|
||||
if filters.ChatType.GROUPS.filter(reply_message):
|
||||
self.add_delete_message_job(reply_message)
|
||||
|
@ -1,37 +1,38 @@
|
||||
import random
|
||||
from typing import Optional
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
from genshin import Client, GenshinException
|
||||
from genshin.models import GenshinUserStats
|
||||
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from simnet.errors import BadRequest as SimnetBadRequest
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from telegram.constants import ChatAction
|
||||
from telegram.ext import CallbackContext, filters
|
||||
from telegram.ext import filters
|
||||
from telegram.helpers import create_deep_linked_url
|
||||
|
||||
from core.plugin import Plugin, handler
|
||||
from core.services.cookies.error import TooManyRequestPublicCookies
|
||||
from core.services.template.models import RenderResult
|
||||
from core.services.template.services import TemplateService
|
||||
from plugins.tools.genshin import GenshinHelper, PlayerNotFoundError, CookiesNotFoundError
|
||||
from plugins.tools.genshin import PlayerNotFoundError, CookiesNotFoundError, GenshinHelper
|
||||
from utils.log import logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Update
|
||||
from telegram.ext import ContextTypes
|
||||
from simnet.models.genshin.chronicle.stats import GenshinUserStats
|
||||
from simnet import GenshinClient
|
||||
|
||||
__all__ = ("PlayerStatsPlugins",)
|
||||
|
||||
|
||||
class PlayerStatsPlugins(Plugin):
|
||||
"""玩家统计查询"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
template: TemplateService,
|
||||
helper: GenshinHelper,
|
||||
):
|
||||
def __init__(self, template: TemplateService, helper: GenshinHelper):
|
||||
self.template_service = template
|
||||
self.helper = helper
|
||||
|
||||
@handler.command("stats", block=False)
|
||||
@handler.message(filters.Regex("^玩家统计查询(.*)"), block=False)
|
||||
async def command_start(self, update: Update, context: CallbackContext) -> Optional[int]:
|
||||
async def command_start(self, update: "Update", context: "ContextTypes.DEFAULT_TYPE") -> Optional[int]:
|
||||
user = update.effective_user
|
||||
message = update.effective_message
|
||||
logger.info("用户 %s[%s] 查询游戏用户命令请求", user.full_name, user.id)
|
||||
@ -46,10 +47,11 @@ class PlayerStatsPlugins(Plugin):
|
||||
return
|
||||
try:
|
||||
try:
|
||||
client = await self.helper.get_genshin_client(user.id)
|
||||
async with self.helper.genshin(user.id) as client:
|
||||
render_result = await self.render(client, uid)
|
||||
except CookiesNotFoundError:
|
||||
client, uid = await self.helper.get_public_genshin_client(user.id)
|
||||
render_result = await self.render(client, uid)
|
||||
async with self.helper.public_genshin(user.id) as client:
|
||||
render_result = await self.render(client, uid)
|
||||
except PlayerNotFoundError:
|
||||
buttons = [[InlineKeyboardButton("点我绑定账号", url=create_deep_linked_url(context.bot.username, "set_cookie"))]]
|
||||
if filters.ChatType.GROUPS.filter(message):
|
||||
@ -61,8 +63,8 @@ class PlayerStatsPlugins(Plugin):
|
||||
else:
|
||||
await message.reply_text("未查询到您所绑定的账号信息,请先绑定账号", reply_markup=InlineKeyboardMarkup(buttons))
|
||||
return
|
||||
except GenshinException as exc:
|
||||
if exc.retcode == 1034 and uid:
|
||||
except SimnetBadRequest as exc:
|
||||
if exc.ret_code == 1034 and uid:
|
||||
await message.reply_text("出错了呜呜呜 ~ 请稍后重试")
|
||||
return
|
||||
raise exc
|
||||
@ -75,14 +77,13 @@ class PlayerStatsPlugins(Plugin):
|
||||
await message.reply_text("角色数据有误 估计是派蒙晕了")
|
||||
return
|
||||
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
||||
await render_result.reply_photo(message, filename=f"{client.uid}.png", allow_sending_without_reply=True)
|
||||
await render_result.reply_photo(message, filename=f"{client.player_id}.png", allow_sending_without_reply=True)
|
||||
|
||||
async def render(self, client: Client, uid: Optional[int] = None) -> RenderResult:
|
||||
async def render(self, client: "GenshinClient", uid: Optional[int] = None) -> RenderResult:
|
||||
if uid is None:
|
||||
uid = client.uid
|
||||
uid = client.player_id
|
||||
|
||||
user_info = await client.get_genshin_user(uid)
|
||||
logger.debug(user_info)
|
||||
|
||||
# 因为需要替换线上图片地址为本地地址,先克隆数据,避免修改原数据
|
||||
user_info = user_info.copy(deep=True)
|
||||
@ -122,7 +123,7 @@ class PlayerStatsPlugins(Plugin):
|
||||
full_page=True,
|
||||
)
|
||||
|
||||
async def cache_images(self, data: GenshinUserStats) -> None:
|
||||
async def cache_images(self, data: "GenshinUserStats") -> None:
|
||||
"""缓存所有图片到本地"""
|
||||
# TODO: 并发下载所有资源
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
from io import BytesIO
|
||||
|
||||
import genshin
|
||||
from aiofiles import open as async_open
|
||||
from genshin.models import GenshinBannerType
|
||||
from simnet import GenshinClient, Region
|
||||
from simnet.models.genshin.wish import BannerType
|
||||
from simnet.utils.player import recognize_genshin_game_biz, recognize_genshin_server
|
||||
from telegram import Document, InlineKeyboardButton, InlineKeyboardMarkup, Message, Update, User
|
||||
from telegram.constants import ChatAction
|
||||
from telegram.ext import CallbackContext, CommandHandler, ConversationHandler, MessageHandler, filters
|
||||
@ -27,9 +28,8 @@ from modules.gacha_log.error import (
|
||||
)
|
||||
from modules.gacha_log.helpers import from_url_get_authkey
|
||||
from modules.gacha_log.log import GachaLog
|
||||
from plugins.tools.genshin import PlayerNotFoundError, GenshinHelper
|
||||
from plugins.tools.genshin import GenshinHelper
|
||||
from plugins.tools.player_info import PlayerInfoSystem
|
||||
from utils.genshin import get_authkey_by_stoken
|
||||
from utils.log import logger
|
||||
|
||||
try:
|
||||
@ -41,6 +41,10 @@ except ImportError:
|
||||
INPUT_URL, INPUT_FILE, CONFIRM_DELETE = range(10100, 10103)
|
||||
|
||||
|
||||
class PlayerNotFoundError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class WishLogPlugin(Plugin.Conversation):
|
||||
"""抽卡记录导入/导出/分析"""
|
||||
|
||||
@ -50,8 +54,8 @@ class WishLogPlugin(Plugin.Conversation):
|
||||
players_service: PlayersService,
|
||||
assets: AssetsService,
|
||||
cookie_service: CookiesService,
|
||||
helper: GenshinHelper,
|
||||
player_info: PlayerInfoSystem,
|
||||
genshin_helper: GenshinHelper,
|
||||
):
|
||||
self.template_service = template_service
|
||||
self.players_service = players_service
|
||||
@ -59,8 +63,8 @@ class WishLogPlugin(Plugin.Conversation):
|
||||
self.cookie_service = cookie_service
|
||||
self.zh_dict = None
|
||||
self.gacha_log = GachaLog()
|
||||
self.helper = helper
|
||||
self.player_info = player_info
|
||||
self.genshin_helper = genshin_helper
|
||||
|
||||
async def initialize(self) -> None:
|
||||
await update_paimon_moe_zh(False)
|
||||
@ -78,12 +82,12 @@ class WishLogPlugin(Plugin.Conversation):
|
||||
"""
|
||||
try:
|
||||
logger.debug("尝试获取已绑定的原神账号")
|
||||
client = await self.helper.get_genshin_client(user.id, need_cookie=False)
|
||||
client = await self.genshin_helper.get_genshin_client(user.id)
|
||||
if authkey:
|
||||
new_num = await self.gacha_log.get_gacha_log_data(user.id, client, authkey)
|
||||
return "更新完成,本次没有新增数据" if new_num == 0 else f"更新完成,本次共新增{new_num}条抽卡记录"
|
||||
if data:
|
||||
new_num = await self.gacha_log.import_gacha_log_data(user.id, client, data, verify_uid)
|
||||
new_num = await self.gacha_log.import_gacha_log_data(user.id, client.player_id, data, verify_uid)
|
||||
return "更新完成,本次没有新增数据" if new_num == 0 else f"更新完成,本次共新增{new_num}条抽卡记录"
|
||||
except GachaLogNotFound:
|
||||
return "派蒙没有找到你的抽卡记录,快来私聊派蒙导入吧~"
|
||||
@ -169,14 +173,14 @@ class WishLogPlugin(Plugin.Conversation):
|
||||
(value for key, value in cookies.data.items() if key in ["ltuid", "login_uid"]), None
|
||||
):
|
||||
cookies.data["stuid"] = stuid
|
||||
client = genshin.Client(
|
||||
cookies=cookies.data,
|
||||
game=genshin.types.Game.GENSHIN,
|
||||
region=genshin.Region.CHINESE,
|
||||
lang="zh-cn",
|
||||
uid=player_info.player_id,
|
||||
)
|
||||
authkey = await get_authkey_by_stoken(client)
|
||||
async with GenshinClient(
|
||||
cookies=cookies.data, region=Region.CHINESE, lang="zh-cn", player_id=player_info.player_id
|
||||
) as client:
|
||||
authkey = await client.get_authkey_by_stoken(
|
||||
recognize_genshin_game_biz(client.player_id),
|
||||
recognize_genshin_server(client.player_id),
|
||||
"webview_gacha",
|
||||
)
|
||||
if not authkey:
|
||||
await message.reply_text(
|
||||
"<b>开始导入祈愿历史记录:请通过 https://paimon.moe/wish/import 获取抽卡记录链接后发送给我"
|
||||
@ -223,13 +227,15 @@ class WishLogPlugin(Plugin.Conversation):
|
||||
user = update.effective_user
|
||||
logger.info("用户 %s[%s] 删除抽卡记录命令请求", user.full_name, user.id)
|
||||
try:
|
||||
client = await self.helper.get_genshin_client(user.id, need_cookie=False)
|
||||
context.chat_data["uid"] = client.uid
|
||||
player_info = await self.players_service.get_player(user.id)
|
||||
if player_info is None:
|
||||
raise PlayerNotFoundError
|
||||
context.chat_data["uid"] = player_info.player_id
|
||||
except PlayerNotFoundError:
|
||||
logger.info("未查询到用户 %s[%s] 所绑定的账号信息", user.full_name, user.id)
|
||||
await message.reply_text("未查询到您所绑定的账号信息,请先绑定账号")
|
||||
return ConversationHandler.END
|
||||
_, status = await self.gacha_log.load_history_info(str(user.id), str(client.uid), only_status=True)
|
||||
_, status = await self.gacha_log.load_history_info(str(user.id), str(player_info.player_id), only_status=True)
|
||||
if not status:
|
||||
await message.reply_text("你还没有导入抽卡记录哦~")
|
||||
return ConversationHandler.END
|
||||
@ -251,6 +257,7 @@ class WishLogPlugin(Plugin.Conversation):
|
||||
@handler(CommandHandler, command="gacha_log_force_delete", block=False, admin=True)
|
||||
async def command_gacha_log_force_delete(self, update: Update, context: CallbackContext):
|
||||
message = update.effective_message
|
||||
user = update.effective_user
|
||||
args = self.get_args(context)
|
||||
if not args:
|
||||
await message.reply_text("请指定用户ID")
|
||||
@ -259,12 +266,14 @@ class WishLogPlugin(Plugin.Conversation):
|
||||
cid = int(args[0])
|
||||
if cid < 0:
|
||||
raise ValueError("Invalid cid")
|
||||
client = await self.helper.get_genshin_client(cid, need_cookie=False)
|
||||
_, status = await self.gacha_log.load_history_info(str(cid), str(client.uid), only_status=True)
|
||||
player_info = await self.players_service.get_player(user.id)
|
||||
if player_info is None:
|
||||
raise PlayerNotFoundError
|
||||
_, status = await self.gacha_log.load_history_info(str(cid), str(player_info.player_id), only_status=True)
|
||||
if not status:
|
||||
await message.reply_text("该用户还没有导入抽卡记录")
|
||||
return
|
||||
status = await self.gacha_log.remove_history_info(str(cid), str(client.uid))
|
||||
status = await self.gacha_log.remove_history_info(str(cid), str(player_info.player_id))
|
||||
await message.reply_text("抽卡记录已强制删除" if status else "抽卡记录删除失败")
|
||||
except GachaLogNotFound:
|
||||
await message.reply_text("该用户还没有导入抽卡记录")
|
||||
@ -280,9 +289,11 @@ class WishLogPlugin(Plugin.Conversation):
|
||||
user = update.effective_user
|
||||
logger.info("用户 %s[%s] 导出抽卡记录命令请求", user.full_name, user.id)
|
||||
try:
|
||||
client = await self.helper.get_genshin_client(user.id, need_cookie=False)
|
||||
player_info = await self.players_service.get_player(user.id)
|
||||
if player_info is None:
|
||||
raise PlayerNotFoundError
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
path = await self.gacha_log.gacha_log_to_uigf(str(user.id), str(client.uid))
|
||||
path = await self.gacha_log.gacha_log_to_uigf(str(user.id), str(player_info.player_id))
|
||||
await message.reply_chat_action(ChatAction.UPLOAD_DOCUMENT)
|
||||
await message.reply_document(document=open(path, "rb+"), caption="抽卡记录导出文件 - UIGF V2.2")
|
||||
except GachaLogNotFound:
|
||||
@ -304,24 +315,26 @@ class WishLogPlugin(Plugin.Conversation):
|
||||
async def command_start_analysis(self, update: Update, context: CallbackContext) -> None:
|
||||
message = update.effective_message
|
||||
user = update.effective_user
|
||||
pool_type = GenshinBannerType.CHARACTER1
|
||||
pool_type = BannerType.CHARACTER1
|
||||
if args := self.get_args(context):
|
||||
if "武器" in args:
|
||||
pool_type = GenshinBannerType.WEAPON
|
||||
pool_type = BannerType.WEAPON
|
||||
elif "常驻" in args:
|
||||
pool_type = GenshinBannerType.STANDARD
|
||||
pool_type = BannerType.STANDARD
|
||||
logger.info("用户 %s[%s] 抽卡记录命令请求 || 参数 %s", user.full_name, user.id, pool_type.name)
|
||||
try:
|
||||
client = await self.helper.get_genshin_client(user.id, need_cookie=False)
|
||||
player_info = await self.players_service.get_player(user.id)
|
||||
if player_info is None:
|
||||
raise PlayerNotFoundError
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
data = await self.gacha_log.get_analysis(user.id, client, pool_type, self.assets_service)
|
||||
data = await self.gacha_log.get_analysis(user.id, player_info.player_id, pool_type, self.assets_service)
|
||||
if isinstance(data, str):
|
||||
reply_message = await message.reply_text(data)
|
||||
if filters.ChatType.GROUPS.filter(message):
|
||||
self.add_delete_message_job(reply_message, delay=300)
|
||||
self.add_delete_message_job(message, delay=300)
|
||||
else:
|
||||
name_card = await self.player_info.get_name_card(client.uid, user)
|
||||
name_card = await self.player_info.get_name_card(player_info.player_id, user)
|
||||
await message.reply_chat_action(ChatAction.UPLOAD_PHOTO)
|
||||
data["name_card"] = name_card
|
||||
png_data = await self.template_service.render(
|
||||
@ -358,31 +371,35 @@ class WishLogPlugin(Plugin.Conversation):
|
||||
async def command_start_count(self, update: Update, context: CallbackContext) -> None:
|
||||
message = update.effective_message
|
||||
user = update.effective_user
|
||||
pool_type = GenshinBannerType.CHARACTER1
|
||||
pool_type = BannerType.CHARACTER1
|
||||
all_five = False
|
||||
if args := self.get_args(context):
|
||||
if "武器" in args:
|
||||
pool_type = GenshinBannerType.WEAPON
|
||||
pool_type = BannerType.WEAPON
|
||||
elif "常驻" in args:
|
||||
pool_type = GenshinBannerType.STANDARD
|
||||
pool_type = BannerType.STANDARD
|
||||
elif "仅五星" in args:
|
||||
all_five = True
|
||||
logger.info("用户 %s[%s] 抽卡统计命令请求 || 参数 %s || 仅五星 %s", user.full_name, user.id, pool_type.name, all_five)
|
||||
try:
|
||||
client = await self.helper.get_genshin_client(user.id, need_cookie=False)
|
||||
player_info = await self.players_service.get_player(user.id)
|
||||
if player_info is None:
|
||||
raise PlayerNotFoundError
|
||||
group = filters.ChatType.GROUPS.filter(message)
|
||||
await message.reply_chat_action(ChatAction.TYPING)
|
||||
if all_five:
|
||||
data = await self.gacha_log.get_all_five_analysis(user.id, client, self.assets_service)
|
||||
data = await self.gacha_log.get_all_five_analysis(user.id, player_info.player_id, self.assets_service)
|
||||
else:
|
||||
data = await self.gacha_log.get_pool_analysis(user.id, client, pool_type, self.assets_service, group)
|
||||
data = await self.gacha_log.get_pool_analysis(
|
||||
user.id, player_info.player_id, pool_type, self.assets_service, group
|
||||
)
|
||||
if isinstance(data, str):
|
||||
reply_message = await message.reply_text(data)
|
||||
if filters.ChatType.GROUPS.filter(message):
|
||||
self.add_delete_message_job(reply_message)
|
||||
self.add_delete_message_job(message)
|
||||
else:
|
||||
name_card = await self.player_info.get_name_card(client.uid, user)
|
||||
name_card = await self.player_info.get_name_card(player_info.player_id, user)
|
||||
document = False
|
||||
if data["hasMore"] and not group:
|
||||
document = True
|
||||
|
@ -5,8 +5,8 @@ from typing import Optional
|
||||
|
||||
import aiofiles
|
||||
from aiohttp import ClientError, ClientConnectorError
|
||||
from genshin import DataNotPublic, GenshinException, InvalidCookies, TooManyRequests
|
||||
from httpx import HTTPError, TimeoutException
|
||||
from simnet.errors import DataNotPublic, BadRequest as SIMNetBadRequest, InvalidCookies, TooManyRequests
|
||||
from telegram import ReplyKeyboardRemove, Update, InlineKeyboardMarkup, InlineKeyboardButton
|
||||
from telegram.constants import ParseMode
|
||||
from telegram.error import BadRequest, Forbidden, TelegramError, TimedOut, NetworkError
|
||||
@ -100,7 +100,7 @@ class ErrorHandler(Plugin):
|
||||
|
||||
@error_handler()
|
||||
async def process_genshin_exception(self, update: object, context: CallbackContext):
|
||||
if not isinstance(context.error, GenshinException) or not isinstance(update, Update):
|
||||
if not isinstance(context.error, SIMNetBadRequest) or not isinstance(update, Update):
|
||||
return
|
||||
exc = context.error
|
||||
notice: Optional[str] = None
|
||||
|
@ -1,13 +1,15 @@
|
||||
from typing import Tuple, Optional
|
||||
|
||||
from genshin import Region, GenshinException
|
||||
from simnet import Region
|
||||
from simnet.errors import BadRequest as SIMNetBadRequest
|
||||
|
||||
from core.dependence.redisdb import RedisDB
|
||||
from core.plugin import Plugin
|
||||
from core.services.cookies import CookiesService
|
||||
from core.services.players import PlayersService
|
||||
from modules.apihelper.client.components.verify import Verify
|
||||
from modules.apihelper.error import ResponseException, APIHelperException
|
||||
from plugins.tools.genshin import GenshinHelper, PlayerNotFoundError, CookiesNotFoundError
|
||||
from plugins.tools.genshin import PlayerNotFoundError, CookiesNotFoundError, GenshinHelper
|
||||
from utils.log import logger
|
||||
|
||||
__all__ = ("ChallengeSystemException", "ChallengeSystem")
|
||||
@ -25,11 +27,13 @@ class ChallengeSystem(Plugin):
|
||||
cookies_service: CookiesService,
|
||||
redis: RedisDB,
|
||||
genshin_helper: GenshinHelper,
|
||||
player: PlayersService,
|
||||
) -> None:
|
||||
self.cookies_service = cookies_service
|
||||
self.genshin_helper = genshin_helper
|
||||
self.cache = redis.client
|
||||
self.qname = "plugin:challenge:"
|
||||
self.players_service = player
|
||||
|
||||
async def get_challenge(self, uid: int) -> Tuple[Optional[str], Optional[str]]:
|
||||
data = await self.cache.get(f"{self.qname}{uid}")
|
||||
@ -56,12 +60,16 @@ class ChallengeSystem(Plugin):
|
||||
if need_verify:
|
||||
try:
|
||||
await client.get_genshin_notes()
|
||||
except GenshinException as exc:
|
||||
except SIMNetBadRequest as exc:
|
||||
if exc.retcode != 1034:
|
||||
raise exc
|
||||
else:
|
||||
raise ChallengeSystemException("账户正常,无需验证")
|
||||
verify = Verify(account_id=client.hoyolab_id, cookies=client.cookie_manager.cookies)
|
||||
finally:
|
||||
await client.shutdown()
|
||||
else:
|
||||
await client.shutdown()
|
||||
verify = Verify(cookies=client.cookies)
|
||||
try:
|
||||
data = await verify.create()
|
||||
challenge = data["challenge"]
|
||||
@ -74,26 +82,26 @@ class ChallengeSystem(Plugin):
|
||||
validate = await verify.ajax(referer="https://webstatic.mihoyo.com/", gt=gt, challenge=challenge)
|
||||
if validate:
|
||||
await verify.verify(challenge, validate)
|
||||
return client.uid, "ajax", "ajax"
|
||||
return client.player_id, "ajax", "ajax"
|
||||
except APIHelperException as exc:
|
||||
logger.warning("用户 %s ajax 验证失效 错误信息为 %s", user_id, str(exc))
|
||||
logger.warning("用户 %s ajax 验证失败 重新申请验证", user_id)
|
||||
return await self.create_challenge(user_id, need_verify, False)
|
||||
await self.set_challenge(client.uid, gt, challenge)
|
||||
return client.uid, gt, challenge
|
||||
await self.set_challenge(client.player_id, gt, challenge)
|
||||
return client.player_id, gt, challenge
|
||||
|
||||
async def pass_challenge(self, user_id: int, validate: str, challenge: Optional[str] = None) -> bool:
|
||||
try:
|
||||
client = await self.genshin_helper.get_genshin_client(user_id)
|
||||
except PlayerNotFoundError:
|
||||
player = await self.players_service.get_player(user_id)
|
||||
if player is None:
|
||||
raise ChallengeSystemException("用户未找到")
|
||||
if client.region != Region.CHINESE:
|
||||
if player.region != Region.CHINESE:
|
||||
raise ChallengeSystemException("非法用户")
|
||||
cookie_model = await self.cookies_service.get(player.user_id, player.account_id, player.region)
|
||||
if cookie_model is None:
|
||||
raise ChallengeSystemException("无需验证")
|
||||
if challenge is None:
|
||||
_, challenge = await self.get_challenge(client.uid)
|
||||
_, challenge = await self.get_challenge(player.player_id)
|
||||
if challenge is None:
|
||||
raise ChallengeSystemException("验证失效 请求已经过期")
|
||||
verify = Verify(account_id=client.hoyolab_id, cookies=client.cookie_manager.cookies)
|
||||
verify = Verify(cookies=cookie_model.data)
|
||||
try:
|
||||
await verify.verify(challenge=challenge, validate=validate)
|
||||
except ResponseException as exc:
|
||||
|
@ -1,46 +1,37 @@
|
||||
import asyncio
|
||||
import random
|
||||
from contextlib import asynccontextmanager
|
||||
from datetime import datetime, time, timedelta
|
||||
from typing import Optional, TYPE_CHECKING, Tuple, Union
|
||||
from typing import Optional
|
||||
from typing import TYPE_CHECKING, Union
|
||||
|
||||
import genshin
|
||||
from genshin.errors import GenshinException
|
||||
from genshin.models import BaseCharacter, CalculatorCharacterDetails
|
||||
from pydantic import ValidationError
|
||||
from simnet import GenshinClient, Region
|
||||
from simnet.errors import BadRequest as SimnetBadRequest
|
||||
from simnet.models.genshin.calculator import CalculatorCharacterDetails
|
||||
from simnet.models.genshin.chronicle.characters import Character
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlmodel import BigInteger, Column, DateTime, Field, Index, Integer, SQLModel, String, delete, func, select
|
||||
from telegram.ext import ContextTypes
|
||||
|
||||
from core.basemodel import RegionEnum
|
||||
from core.config import config
|
||||
from core.dependence.database import Database
|
||||
from core.dependence.redisdb import RedisDB
|
||||
from core.error import ServiceNotFoundError
|
||||
from core.plugin import Plugin
|
||||
from core.services.cookies.services import CookiesService, PublicCookiesService
|
||||
from core.services.devices import DevicesService
|
||||
from core.services.players.services import PlayersService
|
||||
from core.services.users.services import UserService
|
||||
from core.sqlmodel.session import AsyncSession
|
||||
from utils.const import REGION_MAP
|
||||
from utils.log import logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from sqlalchemy import Table
|
||||
from genshin import Client as GenshinClient
|
||||
|
||||
__all__ = ("GenshinHelper", "PlayerNotFoundError", "CookiesNotFoundError", "CharacterDetails")
|
||||
|
||||
|
||||
class PlayerNotFoundError(Exception):
|
||||
def __init__(self, user_id):
|
||||
super().__init__(f"User not found, user_id: {user_id}")
|
||||
|
||||
|
||||
class CookiesNotFoundError(Exception):
|
||||
def __init__(self, user_id):
|
||||
super().__init__(f"{user_id} cookies not found")
|
||||
|
||||
|
||||
class CharacterDetailsSQLModel(SQLModel, table=True):
|
||||
__tablename__ = "character_details"
|
||||
__table_args__ = (
|
||||
@ -164,132 +155,173 @@ class CharacterDetails(Plugin):
|
||||
return None
|
||||
|
||||
async def get_character_details(
|
||||
self, client: "GenshinClient", character: "Union[int,BaseCharacter]"
|
||||
self, client: "GenshinClient", character: "Union[int,Character]"
|
||||
) -> Optional["CalculatorCharacterDetails"]:
|
||||
"""缓存 character_details 并定时对其进行数据存储 当遇到 Too Many Requests 可以获取以前的数据
|
||||
:param client: genshin.py
|
||||
:param character:
|
||||
:return:
|
||||
"""
|
||||
uid = client.uid
|
||||
"""缓存 character_details 并定时对其进行数据存储 当遇到 Too Many Requests 可以获取以前的数据"""
|
||||
uid = client.player_id
|
||||
if isinstance(character, Character):
|
||||
character_id = character.id
|
||||
else:
|
||||
character_id = character
|
||||
if uid is not None:
|
||||
if isinstance(character, BaseCharacter):
|
||||
character_id = character.id
|
||||
else:
|
||||
character_id = character
|
||||
detail = await self.get_character_details_for_redis(uid, character_id)
|
||||
if detail is not None:
|
||||
return detail
|
||||
try:
|
||||
detail = await client.get_character_details(character)
|
||||
except GenshinException as exc:
|
||||
if "Too Many Requests" in exc.msg:
|
||||
detail = await client.get_character_details(character_id)
|
||||
except SimnetBadRequest as exc:
|
||||
if "Too Many Requests" in exc.message:
|
||||
return await self.get_character_details_for_mysql(uid, character_id)
|
||||
raise exc
|
||||
asyncio.create_task(self.set_character_details(uid, character_id, detail.json()))
|
||||
asyncio.create_task(self.set_character_details(uid, character_id, detail.json(by_alias=True)))
|
||||
return detail
|
||||
try:
|
||||
return await client.get_character_details(character)
|
||||
except GenshinException as exc:
|
||||
if "Too Many Requests" in exc.msg:
|
||||
return await client.get_character_details(character_id)
|
||||
except SimnetBadRequest as exc:
|
||||
if "Too Many Requests" in exc.message:
|
||||
logger.warning("Too Many Requests")
|
||||
else:
|
||||
raise exc
|
||||
return None
|
||||
|
||||
|
||||
class PlayerNotFoundError(Exception):
|
||||
def __init__(self, user_id):
|
||||
super().__init__(f"User not found, user_id: {user_id}")
|
||||
|
||||
|
||||
class CookiesNotFoundError(Exception):
|
||||
def __init__(self, user_id):
|
||||
super().__init__(f"{user_id} cookies not found")
|
||||
|
||||
|
||||
class GenshinHelper(Plugin):
|
||||
def __init__(
|
||||
self,
|
||||
cookies: CookiesService,
|
||||
public_cookies: PublicCookiesService,
|
||||
user: UserService,
|
||||
redis: RedisDB,
|
||||
player: PlayersService,
|
||||
devices: DevicesService,
|
||||
) -> None:
|
||||
self.cookies_service = cookies
|
||||
self.public_cookies_service = public_cookies
|
||||
self.user_service = user
|
||||
self.redis_db = redis
|
||||
self.players_service = player
|
||||
|
||||
if self.redis_db and config.genshin_ttl:
|
||||
self.genshin_cache = genshin.RedisCache(self.redis_db.client, ttl=config.genshin_ttl)
|
||||
else:
|
||||
self.genshin_cache = None
|
||||
|
||||
self.devices_service = devices
|
||||
if None in (temp := [self.user_service, self.cookies_service, self.players_service]):
|
||||
raise ServiceNotFoundError(*filter(lambda x: x is None, temp))
|
||||
|
||||
@staticmethod
|
||||
def region_server(uid: Union[int, str]) -> RegionEnum:
|
||||
if isinstance(uid, (int, str)):
|
||||
region = REGION_MAP.get(str(uid)[0])
|
||||
else:
|
||||
raise TypeError("UID variable type error")
|
||||
if region:
|
||||
return region
|
||||
raise ValueError(f"UID {uid} isn't associated with any region.")
|
||||
|
||||
async def get_genshin_client(
|
||||
self, user_id: int, region: Optional[RegionEnum] = None, need_cookie: bool = True
|
||||
) -> Optional[genshin.Client]:
|
||||
"""通过 user_id 和 region 获取私有的 `genshin.Client`"""
|
||||
@asynccontextmanager
|
||||
async def genshin(self, user_id: int, region: Optional[RegionEnum] = None) -> GenshinClient:
|
||||
player = await self.players_service.get_player(user_id, region)
|
||||
if player is None:
|
||||
raise PlayerNotFoundError(user_id)
|
||||
cookies = None
|
||||
if need_cookie:
|
||||
if player.account_id is None:
|
||||
raise CookiesNotFoundError(user_id)
|
||||
cookie_model = await self.cookies_service.get(player.user_id, player.account_id, player.region)
|
||||
if cookie_model is None:
|
||||
raise CookiesNotFoundError(user_id)
|
||||
cookies = cookie_model.data
|
||||
|
||||
uid = player.player_id
|
||||
if player.account_id is None:
|
||||
raise CookiesNotFoundError(user_id)
|
||||
cookie_model = await self.cookies_service.get(player.user_id, player.account_id, player.region)
|
||||
if cookie_model is None:
|
||||
raise CookiesNotFoundError(user_id)
|
||||
cookies = cookie_model.data
|
||||
|
||||
region = player.region
|
||||
if region == RegionEnum.HYPERION: # 国服
|
||||
game_region = genshin.types.Region.CHINESE
|
||||
game_region = Region.CHINESE
|
||||
elif region == RegionEnum.HOYOLAB: # 国际服
|
||||
game_region = genshin.types.Region.OVERSEAS
|
||||
game_region = Region.OVERSEAS
|
||||
else:
|
||||
raise TypeError("Region is not None")
|
||||
|
||||
client = genshin.Client(
|
||||
device_id: Optional[str] = None
|
||||
device_fp: Optional[str] = None
|
||||
devices = await self.devices_service.get(player.account_id)
|
||||
if devices:
|
||||
device_id = devices.device_id
|
||||
device_fp = devices.device_fp
|
||||
|
||||
async with GenshinClient(
|
||||
cookies,
|
||||
lang="zh-cn",
|
||||
game=genshin.types.Game.GENSHIN,
|
||||
region=game_region,
|
||||
uid=uid,
|
||||
hoyolab_id=player.account_id,
|
||||
account_id=player.account_id,
|
||||
player_id=player.player_id,
|
||||
lang="zh-cn",
|
||||
device_id=device_id,
|
||||
device_fp=device_fp,
|
||||
) as client:
|
||||
yield client
|
||||
|
||||
async def get_genshin_client(self, user_id: int, region: Optional[RegionEnum] = None) -> GenshinClient:
|
||||
player = await self.players_service.get_player(user_id, region)
|
||||
if player is None:
|
||||
raise PlayerNotFoundError(user_id)
|
||||
|
||||
if player.account_id is None:
|
||||
raise CookiesNotFoundError(user_id)
|
||||
cookie_model = await self.cookies_service.get(player.user_id, player.account_id, player.region)
|
||||
if cookie_model is None:
|
||||
raise CookiesNotFoundError(user_id)
|
||||
cookies = cookie_model.data
|
||||
|
||||
region = player.region
|
||||
if region == RegionEnum.HYPERION:
|
||||
game_region = Region.CHINESE
|
||||
elif region == RegionEnum.HOYOLAB:
|
||||
game_region = Region.OVERSEAS
|
||||
else:
|
||||
raise TypeError("Region is not None")
|
||||
|
||||
device_id: Optional[str] = None
|
||||
device_fp: Optional[str] = None
|
||||
devices = await self.devices_service.get(player.account_id)
|
||||
if devices:
|
||||
device_id = devices.device_id
|
||||
device_fp = devices.device_fp
|
||||
|
||||
return GenshinClient(
|
||||
cookies,
|
||||
region=game_region,
|
||||
account_id=player.account_id,
|
||||
player_id=player.player_id,
|
||||
lang="zh-cn",
|
||||
device_id=device_id,
|
||||
device_fp=device_fp,
|
||||
)
|
||||
|
||||
if self.genshin_cache is not None:
|
||||
client.cache = self.genshin_cache
|
||||
|
||||
return client
|
||||
|
||||
async def get_public_genshin_client(self, user_id: int) -> Tuple[genshin.Client, int]:
|
||||
"""通过 user_id 获取公共的 `genshin.Client`"""
|
||||
player = await self.players_service.get_player(user_id)
|
||||
@asynccontextmanager
|
||||
async def public_genshin(self, user_id: int, region: Optional[RegionEnum] = None) -> GenshinClient:
|
||||
player = await self.players_service.get_player(user_id, region)
|
||||
|
||||
region = player.region
|
||||
cookies = await self.public_cookies_service.get_cookies(user_id, region)
|
||||
|
||||
uid = player.player_id
|
||||
if region is RegionEnum.HYPERION:
|
||||
game_region = genshin.types.Region.CHINESE
|
||||
game_region = Region.CHINESE
|
||||
elif region is RegionEnum.HOYOLAB:
|
||||
game_region = genshin.types.Region.OVERSEAS
|
||||
game_region = Region.OVERSEAS
|
||||
else:
|
||||
raise TypeError("Region is not `RegionEnum.NULL`")
|
||||
|
||||
client = genshin.Client(
|
||||
cookies.data, region=game_region, uid=uid, game=genshin.types.Game.GENSHIN, lang="zh-cn"
|
||||
)
|
||||
device_id: Optional[str] = None
|
||||
device_fp: Optional[str] = None
|
||||
devices = await self.devices_service.get(cookies.account_id)
|
||||
if devices:
|
||||
device_id = devices.device_id
|
||||
device_fp = devices.device_fp
|
||||
|
||||
if self.genshin_cache is not None:
|
||||
client.cache = self.genshin_cache
|
||||
|
||||
return client, uid
|
||||
async with GenshinClient(
|
||||
cookies,
|
||||
region=game_region,
|
||||
account_id=player.account_id,
|
||||
player_id=uid,
|
||||
lang="zh-cn",
|
||||
device_id=device_id,
|
||||
device_fp=device_fp,
|
||||
) as client:
|
||||
try:
|
||||
yield client
|
||||
except SimnetBadRequest as exc:
|
||||
if exc.ret_code == 1034:
|
||||
await self.public_cookies_service.undo(user_id)
|
||||
raise exc
|
||||
|
@ -6,9 +6,10 @@ from enum import Enum
|
||||
from typing import Optional, Tuple, List, TYPE_CHECKING
|
||||
|
||||
from aiohttp import ClientConnectorError
|
||||
from genshin import Game, GenshinException, AlreadyClaimed, Client, InvalidCookies
|
||||
from genshin.utility import recognize_genshin_server
|
||||
from httpx import TimeoutException
|
||||
from simnet import Game
|
||||
from simnet.errors import BadRequest as SimnetBadRequest, AlreadyClaimed, InvalidCookies
|
||||
from simnet.utils.player import recognize_genshin_server
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from telegram.constants import ParseMode
|
||||
from telegram.error import Forbidden, BadRequest
|
||||
@ -21,11 +22,12 @@ from core.services.sign.models import SignStatusEnum
|
||||
from core.services.sign.services import SignServices
|
||||
from core.services.users.services import UserService
|
||||
from modules.apihelper.client.components.verify import Verify
|
||||
from plugins.tools.genshin import GenshinHelper, CookiesNotFoundError, PlayerNotFoundError
|
||||
from plugins.tools.genshin import PlayerNotFoundError, CookiesNotFoundError, GenshinHelper
|
||||
from plugins.tools.recognize import RecognizeSystem
|
||||
from utils.log import logger
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from simnet import GenshinClient
|
||||
from telegram.ext import ContextTypes
|
||||
|
||||
|
||||
@ -104,7 +106,7 @@ class SignSystem(Plugin):
|
||||
|
||||
async def start_sign(
|
||||
self,
|
||||
client: Client,
|
||||
client: "GenshinClient",
|
||||
challenge: Optional[str] = None,
|
||||
validate: Optional[str] = None,
|
||||
is_sleep: bool = False,
|
||||
@ -112,28 +114,28 @@ class SignSystem(Plugin):
|
||||
title: Optional[str] = "签到结果",
|
||||
) -> str:
|
||||
if is_sleep:
|
||||
if recognize_genshin_server(client.uid) in ("cn_gf01", "cn_qd01"):
|
||||
if recognize_genshin_server(client.player_id) in ("cn_gf01", "cn_qd01"):
|
||||
await asyncio.sleep(random.randint(10, 300)) # nosec
|
||||
else:
|
||||
await asyncio.sleep(random.randint(0, 3)) # nosec
|
||||
try:
|
||||
rewards = await client.get_monthly_rewards(game=Game.GENSHIN, lang="zh-cn")
|
||||
except GenshinException as error:
|
||||
logger.warning("UID[%s] 获取签到信息失败,API返回信息为 %s", client.uid, str(error))
|
||||
except SimnetBadRequest as error:
|
||||
logger.warning("UID[%s] 获取签到信息失败,API返回信息为 %s", client.player_id, str(error))
|
||||
if is_raise:
|
||||
raise error
|
||||
return f"获取签到信息失败,API返回信息为 {str(error)}"
|
||||
try:
|
||||
daily_reward_info = await client.get_reward_info(game=Game.GENSHIN, lang="zh-cn") # 获取签到信息失败
|
||||
except GenshinException as error:
|
||||
logger.warning("UID[%s] 获取签到状态失败,API返回信息为 %s", client.uid, str(error))
|
||||
except SimnetBadRequest as error:
|
||||
logger.warning("UID[%s] 获取签到状态失败,API返回信息为 %s", client.player_id, str(error))
|
||||
if is_raise:
|
||||
raise error
|
||||
return f"获取签到状态失败,API返回信息为 {str(error)}"
|
||||
if not daily_reward_info.signed_in:
|
||||
try:
|
||||
if validate:
|
||||
logger.info("UID[%s] 正在尝试通过验证码\nchallenge[%s]\nvalidate[%s]", client.uid, challenge, validate)
|
||||
logger.info("UID[%s] 正在尝试通过验证码\nchallenge[%s]\nvalidate[%s]", client.player_id, challenge, validate)
|
||||
request_daily_reward = await client.request_daily_reward(
|
||||
"sign",
|
||||
method="POST",
|
||||
@ -147,8 +149,8 @@ class SignSystem(Plugin):
|
||||
# 尝试通过 ajax 请求绕过签到
|
||||
gt = request_daily_reward.get("gt", "")
|
||||
challenge = request_daily_reward.get("challenge", "")
|
||||
logger.warning("UID[%s] 触发验证码\ngt[%s]\nchallenge[%s]", client.uid, gt, challenge)
|
||||
self.verify.account_id = client.hoyolab_id
|
||||
logger.warning("UID[%s] 触发验证码\ngt[%s]\nchallenge[%s]", client.player_id, gt, challenge)
|
||||
self.verify.account_id = client.account_id
|
||||
validate = await self.verify.ajax(
|
||||
referer=RecognizeSystem.REFERER,
|
||||
gt=gt,
|
||||
@ -166,16 +168,16 @@ class SignSystem(Plugin):
|
||||
)
|
||||
logger.debug("request_daily_reward 返回 %s", request_daily_reward)
|
||||
if request_daily_reward and request_daily_reward.get("success", 0) == 1:
|
||||
logger.warning("UID[%s] 触发验证码\nchallenge[%s]", client.uid, challenge)
|
||||
logger.warning("UID[%s] 触发验证码\nchallenge[%s]", client.player_id, challenge)
|
||||
raise NeedChallenge(
|
||||
uid=client.uid,
|
||||
uid=client.player_id,
|
||||
gt=request_daily_reward.get("gt", ""),
|
||||
challenge=request_daily_reward.get("challenge", ""),
|
||||
)
|
||||
elif config.pass_challenge_app_key:
|
||||
# 如果无法绕过 检查配置文件是否配置识别 API 尝试请求绕过
|
||||
# 注意 需要重新获取没有进行任何请求的 Challenge
|
||||
logger.info("UID[%s] 正在使用 recognize 重新请求签到", client.uid)
|
||||
logger.info("UID[%s] 正在使用 recognize 重新请求签到", client.player_id)
|
||||
_request_daily_reward = await client.request_daily_reward(
|
||||
"sign",
|
||||
method="POST",
|
||||
@ -186,8 +188,8 @@ class SignSystem(Plugin):
|
||||
if _request_daily_reward and _request_daily_reward.get("success", 0) == 1:
|
||||
_gt = _request_daily_reward.get("gt", "")
|
||||
_challenge = _request_daily_reward.get("challenge", "")
|
||||
logger.info("UID[%s] 创建验证码\ngt[%s]\nchallenge[%s]", client.uid, _gt, _challenge)
|
||||
_validate = await RecognizeSystem.recognize(_gt, _challenge, uid=client.uid)
|
||||
logger.info("UID[%s] 创建验证码\ngt[%s]\nchallenge[%s]", client.player_id, _gt, _challenge)
|
||||
_validate = await RecognizeSystem.recognize(_gt, _challenge, uid=client.player_id)
|
||||
if _validate:
|
||||
logger.success("recognize 通过验证成功\nchallenge[%s]\nvalidate[%s]", _challenge, _validate)
|
||||
request_daily_reward = await client.request_daily_reward(
|
||||
@ -199,55 +201,57 @@ class SignSystem(Plugin):
|
||||
validate=_validate,
|
||||
)
|
||||
if request_daily_reward and request_daily_reward.get("success", 0) == 1:
|
||||
logger.warning("UID[%s] 触发验证码\nchallenge[%s]", client.uid, _challenge)
|
||||
logger.warning("UID[%s] 触发验证码\nchallenge[%s]", client.player_id, _challenge)
|
||||
gt = request_daily_reward.get("gt", "")
|
||||
challenge = request_daily_reward.get("challenge", "")
|
||||
logger.success("UID[%s] 创建验证成功\ngt[%s]\nchallenge[%s]", client.uid, gt, challenge)
|
||||
logger.success(
|
||||
"UID[%s] 创建验证成功\ngt[%s]\nchallenge[%s]", client.player_id, gt, challenge
|
||||
)
|
||||
raise NeedChallenge(
|
||||
uid=client.uid,
|
||||
uid=client.player_id,
|
||||
gt=gt,
|
||||
challenge=challenge,
|
||||
)
|
||||
logger.success("UID[%s] 通过 recognize 签到成功", client.uid)
|
||||
logger.success("UID[%s] 通过 recognize 签到成功", client.player_id)
|
||||
else:
|
||||
request_daily_reward = await client.request_daily_reward(
|
||||
"sign", method="POST", game=Game.GENSHIN, lang="zh-cn"
|
||||
)
|
||||
gt = request_daily_reward.get("gt", "")
|
||||
challenge = request_daily_reward.get("challenge", "")
|
||||
logger.success("UID[%s] 创建验证成功\ngt[%s]\nchallenge[%s]", client.uid, gt, challenge)
|
||||
raise NeedChallenge(uid=client.uid, gt=gt, challenge=challenge)
|
||||
logger.success("UID[%s] 创建验证成功\ngt[%s]\nchallenge[%s]", client.player_id, gt, challenge)
|
||||
raise NeedChallenge(uid=client.player_id, gt=gt, challenge=challenge)
|
||||
else:
|
||||
request_daily_reward = await client.request_daily_reward(
|
||||
"sign", method="POST", game=Game.GENSHIN, lang="zh-cn"
|
||||
)
|
||||
gt = request_daily_reward.get("gt", "")
|
||||
challenge = request_daily_reward.get("challenge", "")
|
||||
logger.success("UID[%s] 创建验证成功\ngt[%s]\nchallenge[%s]", client.uid, gt, challenge)
|
||||
raise NeedChallenge(uid=client.uid, gt=gt, challenge=challenge)
|
||||
logger.success("UID[%s] 创建验证成功\ngt[%s]\nchallenge[%s]", client.player_id, gt, challenge)
|
||||
raise NeedChallenge(uid=client.player_id, gt=gt, challenge=challenge)
|
||||
else:
|
||||
logger.success("UID[%s] 签到成功", client.uid)
|
||||
logger.success("UID[%s] 签到成功", client.player_id)
|
||||
except TimeoutException as error:
|
||||
logger.warning("UID[%s] 签到请求超时", client.uid)
|
||||
logger.warning("UID[%s] 签到请求超时", client.player_id)
|
||||
if is_raise:
|
||||
raise error
|
||||
return "签到失败了呜呜呜 ~ 服务器连接超时 服务器熟啦 ~ "
|
||||
except AlreadyClaimed as error:
|
||||
logger.warning("UID[%s] 已经签到", client.uid)
|
||||
logger.warning("UID[%s] 已经签到", client.player_id)
|
||||
if is_raise:
|
||||
raise error
|
||||
result = "今天旅行者已经签到过了~"
|
||||
except GenshinException as error:
|
||||
logger.warning("UID %s 签到失败,API返回信息为 %s", client.uid, str(error))
|
||||
except SimnetBadRequest as error:
|
||||
logger.warning("UID %s 签到失败,API返回信息为 %s", client.player_id, str(error))
|
||||
if is_raise:
|
||||
raise error
|
||||
return f"获取签到状态失败,API返回信息为 {str(error)}"
|
||||
else:
|
||||
result = "OK"
|
||||
else:
|
||||
logger.info("UID[%s] 已经签到", client.uid)
|
||||
logger.info("UID[%s] 已经签到", client.player_id)
|
||||
result = "今天旅行者已经签到过了~"
|
||||
logger.info("UID[%s] 签到结果 %s", client.uid, result)
|
||||
logger.info("UID[%s] 签到结果 %s", client.player_id, result)
|
||||
reward = rewards[daily_reward_info.claimed_rewards - (1 if daily_reward_info.signed_in else 0)]
|
||||
today = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
|
||||
cn_timezone = datetime.timezone(datetime.timedelta(hours=8))
|
||||
@ -258,7 +262,7 @@ class SignSystem(Plugin):
|
||||
message = (
|
||||
f"#### {title} ####\n"
|
||||
f"时间:{today} (UTC+8)\n"
|
||||
f"UID: {client.uid}\n"
|
||||
f"UID: {client.player_id}\n"
|
||||
f"今日奖励: {reward.name} × {reward.amount}\n"
|
||||
f"本月漏签次数:{missed_days}\n"
|
||||
f"签到结果: {result}"
|
||||
@ -284,15 +288,15 @@ class SignSystem(Plugin):
|
||||
continue
|
||||
user_id = sign_db.user_id
|
||||
try:
|
||||
client = await self.genshin_helper.get_genshin_client(user_id)
|
||||
text = await self.start_sign(client, is_sleep=True, is_raise=True, title=title)
|
||||
async with self.genshin_helper.genshin(user_id) as client:
|
||||
text = await self.start_sign(client, is_sleep=True, is_raise=True, title=title)
|
||||
except InvalidCookies:
|
||||
text = "自动签到执行失败,Cookie无效"
|
||||
sign_db.status = SignStatusEnum.INVALID_COOKIES
|
||||
except AlreadyClaimed:
|
||||
text = "今天旅行者已经签到过了~"
|
||||
sign_db.status = SignStatusEnum.ALREADY_CLAIMED
|
||||
except GenshinException as exc:
|
||||
except SimnetBadRequest as exc:
|
||||
text = f"自动签到执行失败,API返回信息为 {str(exc)}"
|
||||
sign_db.status = SignStatusEnum.GENSHIN_EXCEPTION
|
||||
except ClientConnectorError:
|
||||
|
1426
poetry.lock
generated
1426
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -8,9 +8,8 @@ readme = "README.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
httpx = "^0.23.3"
|
||||
httpx = "^0.24.0"
|
||||
ujson = "^5.8.0"
|
||||
genshin = { git = "https://github.com/thesadru/genshin.py" }
|
||||
Jinja2 = "^3.1.2"
|
||||
python-telegram-bot = { version = "^20.1", extras = ["ext", "rate-limiter"] }
|
||||
sqlmodel = "^0.0.8"
|
||||
@ -45,6 +44,7 @@ cryptography = "^41.0.2"
|
||||
pillow = "^10.0.0"
|
||||
playwright = "^1.27.1"
|
||||
aiosqlite = { extras = ["sqlite"], version = "^0.19.0" }
|
||||
simnet = { git = "https://github.com/PaiGramTeam/SIMNet" }
|
||||
|
||||
[tool.poetry.extras]
|
||||
pyro = ["Pyrogram", "TgCrypto"]
|
||||
|
104
requirements.txt
104
requirements.txt
@ -1,106 +1,104 @@
|
||||
aiofiles==23.1.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
aiohttp==3.8.4 ; python_version >= "3.8" and python_version < "4.0"
|
||||
aiolimiter==1.0.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
aiolimiter==1.1.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
aiosignal==1.3.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
aiosqlite[sqlite]==0.19.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
alembic==1.10.3 ; python_version >= "3.8" and python_version < "4.0"
|
||||
anyio==3.6.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
alembic==1.11.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
anyio==3.7.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
appdirs==1.4.4 ; python_version >= "3.8" and python_version < "4.0"
|
||||
apscheduler==3.10.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
arko-wrapper==0.2.8 ; python_version >= "3.8" and python_version < "4.0"
|
||||
async-lru==2.0.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
async-lru==2.0.3 ; python_version >= "3.8" and python_version < "4.0"
|
||||
async-timeout==4.0.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
asyncmy==0.2.7 ; python_version >= "3.8" and python_version < "4.0"
|
||||
asyncmy==0.2.8 ; python_version >= "3.8" and python_version < "4.0"
|
||||
attrs==23.1.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
backports-zoneinfo==0.2.1 ; python_version >= "3.8" and python_version < "3.9"
|
||||
beautifulsoup4==4.12.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
black==23.3.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
cachetools==5.3.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
certifi==2022.12.7 ; python_version >= "3.8" and python_version < "4.0"
|
||||
black==23.7.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
cachetools==5.3.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
certifi==2023.5.7 ; python_version >= "3.8" and python_version < "4.0"
|
||||
cffi==1.15.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
charset-normalizer==3.1.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
click==8.1.3 ; python_version >= "3.8" and python_version < "4.0"
|
||||
colorama==0.4.6 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "win32" or python_version >= "3.8" and python_version < "4.0" and platform_system == "Windows"
|
||||
charset-normalizer==3.2.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
click==8.1.5 ; python_version >= "3.8" and python_version < "4.0"
|
||||
colorama==0.4.6 ; python_version >= "3.8" and python_version < "4.0" and (sys_platform == "win32" or platform_system == "Windows")
|
||||
colorlog==6.7.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
cryptography==40.0.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
cryptography==41.0.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
enkanetwork-py @ git+https://github.com/mrwan200/EnkaNetwork.py@master ; python_version >= "3.8" and python_version < "4.0"
|
||||
et-xmlfile==1.1.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
exceptiongroup==1.1.1 ; python_version >= "3.8" and python_version < "3.11"
|
||||
fakeredis==2.10.3 ; python_version >= "3.8" and python_version < "4.0"
|
||||
fastapi==0.95.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
exceptiongroup==1.1.2 ; python_version >= "3.8" and python_version < "3.11"
|
||||
fakeredis==2.16.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
fastapi==0.99.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
flaky==3.7.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
frozenlist==1.3.3 ; python_version >= "3.8" and python_version < "4.0"
|
||||
genshin @ git+https://github.com/thesadru/genshin.py@master ; python_version >= "3.8" and python_version < "4.0"
|
||||
frozenlist==1.4.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
gitdb==4.0.10 ; python_version >= "3.8" and python_version < "4.0"
|
||||
gitpython==3.1.31 ; python_version >= "3.8" and python_version < "4.0"
|
||||
gitpython==3.1.32 ; python_version >= "3.8" and python_version < "4.0"
|
||||
greenlet==1.1.3 ; python_version >= "3.8" and python_version < "4.0"
|
||||
h11==0.14.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
httpcore==0.16.3 ; python_version >= "3.8" and python_version < "4.0"
|
||||
httptools==0.5.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
httpx==0.23.3 ; python_version >= "3.8" and python_version < "4.0"
|
||||
httpcore==0.17.3 ; python_version >= "3.8" and python_version < "4.0"
|
||||
httptools==0.6.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
httpx==0.24.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
idna==3.4 ; python_version >= "3.8" and python_version < "4.0"
|
||||
importlib-metadata==6.5.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
importlib-resources==5.12.0 ; python_version >= "3.8" and python_version < "3.9"
|
||||
importlib-metadata==6.8.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
importlib-resources==6.0.0 ; python_version >= "3.8" and python_version < "3.9"
|
||||
iniconfig==2.0.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
jinja2==3.1.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
lxml==4.9.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
lxml==4.9.3 ; python_version >= "3.8" and python_version < "4.0"
|
||||
mako==1.2.4 ; python_version >= "3.8" and python_version < "4.0"
|
||||
markdown-it-py==2.2.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
markupsafe==2.1.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
markdown-it-py==3.0.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
markupsafe==2.1.3 ; python_version >= "3.8" and python_version < "4.0"
|
||||
mdurl==0.1.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
multidict==6.0.4 ; python_version >= "3.8" and python_version < "4.0"
|
||||
mypy-extensions==1.0.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
openpyxl==3.1.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
packaging==23.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pathspec==0.11.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pillow==9.5.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
platformdirs==3.2.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pillow==10.0.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
platformdirs==3.9.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
playwright==1.27.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pluggy==1.0.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pluggy==1.2.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pyaes==1.6.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pycparser==2.21 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pydantic==1.10.7 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pydantic==1.10.11 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pyee==8.1.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pygments==2.15.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pypng==0.20220715.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pyppeteer==1.0.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pyrogram==2.0.104 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pyrogram==2.0.106 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pysocks==1.7.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pytest-asyncio==0.21.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pytest==7.3.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pytest-asyncio==0.21.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pytest==7.4.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
python-dotenv==1.0.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
python-telegram-bot[ext,rate-limiter]==20.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pytz-deprecation-shim==0.1.0.post0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
python-telegram-bot[ext,rate-limiter]==20.4 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pytz==2023.3 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pyyaml==6.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pyyaml==6.0.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
qrcode==7.4.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
redis==4.5.4 ; python_version >= "3.8" and python_version < "4.0"
|
||||
rfc3986[idna2008]==1.5.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
rich==13.3.4 ; python_version >= "3.8" and python_version < "4.0"
|
||||
sentry-sdk==1.20.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
setuptools==67.7.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
redis==4.6.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
rich==13.4.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
sentry-sdk==1.28.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
setuptools==68.0.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
simnet @ git+https://github.com/PaiGramTeam/SIMNet@main ; python_version >= "3.8" and python_version < "4.0"
|
||||
six==1.16.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
smmap==5.0.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
sniffio==1.3.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
sortedcontainers==2.4.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
soupsieve==2.4.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
sqlalchemy2-stubs==0.0.2a34 ; python_version >= "3.8" and python_version < "4.0"
|
||||
sqlalchemy2-stubs==0.0.2a35 ; python_version >= "3.8" and python_version < "4.0"
|
||||
sqlalchemy==1.4.41 ; python_version >= "3.8" and python_version < "4.0"
|
||||
sqlmodel==0.0.8 ; python_version >= "3.8" and python_version < "4.0"
|
||||
starlette==0.26.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
starlette==0.27.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
tgcrypto==1.2.5 ; python_version >= "3.8" and python_version < "4.0"
|
||||
thefuzz==0.19.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
tomli==2.0.1 ; python_version >= "3.8" and python_version < "3.11"
|
||||
tornado==6.3 ; python_version >= "3.8" and python_version < "4.0"
|
||||
tornado==6.3.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
tqdm==4.65.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
typing-extensions==4.5.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
tzdata==2023.3 ; python_version >= "3.8" and python_version < "4.0"
|
||||
tzlocal==4.3 ; python_version >= "3.8" and python_version < "4.0"
|
||||
ujson==5.7.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
urllib3==1.26.15 ; python_version >= "3.8" and python_version < "4.0"
|
||||
uvicorn[standard]==0.21.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
uvloop==0.17.0 ; sys_platform != "win32" and sys_platform != "cygwin" and platform_python_implementation != "PyPy" and python_version >= "3.8" and python_version < "4.0"
|
||||
typing-extensions==4.7.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
tzdata==2023.3 ; python_version >= "3.8" and python_version < "4.0" and platform_system == "Windows"
|
||||
tzlocal==5.0.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
ujson==5.8.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
urllib3==1.26.16 ; python_version >= "3.8" and python_version < "4.0"
|
||||
uvicorn[standard]==0.22.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
uvloop==0.17.0 ; (sys_platform != "win32" and sys_platform != "cygwin") and platform_python_implementation != "PyPy" and python_version >= "3.8" and python_version < "4.0"
|
||||
watchfiles==0.19.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
websockets==10.4 ; python_version >= "3.8" and python_version < "4.0"
|
||||
yarl==1.8.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
zipp==3.15.0 ; python_version >= "3.8" and python_version < "4.0"
|
||||
yarl==1.9.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
zipp==3.16.2 ; python_version >= "3.8" and python_version < "4.0"
|
||||
|
@ -1,64 +0,0 @@
|
||||
from typing import Optional
|
||||
|
||||
from genshin import Client
|
||||
from genshin.client.routes import InternationalRoute # noqa F401
|
||||
from genshin.utility import recognize_genshin_server
|
||||
|
||||
from modules.apihelper.utility.devices import devices_methods
|
||||
from modules.apihelper.utility.helpers import hex_digest, get_ds
|
||||
|
||||
AUTHKEY_API = "https://api-takumi.mihoyo.com/binding/api/genAuthKey"
|
||||
HK4E_LOGIN_URL = InternationalRoute(
|
||||
overseas="https://sg-public-api.hoyoverse.com/common/badge/v1/login/account",
|
||||
chinese="https://api-takumi.mihoyo.com/common/badge/v1/login/account",
|
||||
)
|
||||
GACHA_HEADERS = {
|
||||
"User-Agent": "okhttp/4.8.0",
|
||||
"x-rpc-sys_version": "12",
|
||||
"x-rpc-channel": "mihoyo",
|
||||
"x-rpc-device_name": "",
|
||||
"x-rpc-device_model": "",
|
||||
"Referer": "https://app.mihoyo.com",
|
||||
"Host": "api-takumi.mihoyo.com",
|
||||
}
|
||||
|
||||
|
||||
def recognize_genshin_game_biz(game_uid: int) -> str:
|
||||
return "hk4e_cn" if game_uid < 600000000 else "hk4e_global"
|
||||
|
||||
|
||||
async def get_authkey_by_stoken(client: Client, auth_appid: str = "webview_gacha") -> Optional[str]:
|
||||
"""通过 stoken 获取 authkey"""
|
||||
headers = GACHA_HEADERS.copy()
|
||||
json = {
|
||||
"auth_appid": auth_appid,
|
||||
"game_biz": recognize_genshin_game_biz(client.uid),
|
||||
"game_uid": client.uid,
|
||||
"region": recognize_genshin_server(client.uid),
|
||||
}
|
||||
device_id = hex_digest(str(client.uid))
|
||||
device = f"Paimon Build {device_id[:5]}"
|
||||
await devices_methods.update_device_headers(client.hoyolab_id, headers)
|
||||
headers["x-rpc-device_name"] = device
|
||||
headers["x-rpc-device_model"] = device
|
||||
app_version, client_type, ds_sign = get_ds()
|
||||
headers["x-rpc-app_version"] = app_version
|
||||
headers["x-rpc-client_type"] = client_type
|
||||
headers["ds"] = ds_sign
|
||||
data = await client.cookie_manager.request(AUTHKEY_API, method="POST", json=json, headers=headers)
|
||||
return data.get("authkey")
|
||||
|
||||
|
||||
async def fetch_hk4e_token_by_cookie(client: Client) -> None:
|
||||
"""通过 cookie_token 获取 hk4e_token 保存到 client"""
|
||||
url = HK4E_LOGIN_URL.get_url(client.region)
|
||||
headers = {
|
||||
"Content-Type": "application/json;charset=UTF-8",
|
||||
}
|
||||
json = {
|
||||
"game_biz": recognize_genshin_game_biz(client.uid),
|
||||
"lang": "zh-cn",
|
||||
"uid": str(client.uid),
|
||||
"region": recognize_genshin_server(client.uid),
|
||||
}
|
||||
await client.cookie_manager.request(url, method="POST", json=json, headers=headers)
|
@ -1,3 +1,3 @@
|
||||
from utils.patch import aiohttp, genshin
|
||||
from utils.patch import aiohttp
|
||||
|
||||
__all__ = ["aiohttp", "genshin"]
|
||||
__all__ = ["aiohttp"]
|
||||
|
@ -1,358 +0,0 @@
|
||||
import asyncio
|
||||
import typing
|
||||
import warnings
|
||||
|
||||
import aiohttp.typedefs
|
||||
import genshin # pylint: disable=W0406
|
||||
import yarl
|
||||
from genshin import constants, types, utility
|
||||
from genshin.client import routes
|
||||
from genshin.utility import generate_dynamic_secret, ds
|
||||
|
||||
from modules.apihelper.utility.devices import devices_methods
|
||||
from modules.apihelper.utility.helpers import get_ds, get_ua, get_device_id, hex_digest
|
||||
from utils.patch.methods import patch, patchable
|
||||
|
||||
DEVICE_ID = get_device_id()
|
||||
UPDATE_CHARACTERS = False
|
||||
|
||||
|
||||
def get_account_mid_v2(cookies: typing.Dict[str, str]) -> typing.Optional[str]:
|
||||
return next(
|
||||
(value for name, value in cookies.items() if name == "account_mid_v2"),
|
||||
None,
|
||||
)
|
||||
|
||||
|
||||
@patch(genshin.client.components.calculator.CalculatorClient) # noqa
|
||||
class CalculatorClient:
|
||||
@patchable
|
||||
async def request_calculator(
|
||||
self,
|
||||
endpoint: str,
|
||||
*,
|
||||
method: str = "POST",
|
||||
lang: typing.Optional[str] = None,
|
||||
params: typing.Optional[typing.Mapping[str, typing.Any]] = None,
|
||||
data: typing.Optional[typing.Mapping[str, typing.Any]] = None,
|
||||
headers: typing.Optional[aiohttp.typedefs.LooseHeaders] = None,
|
||||
**kwargs: typing.Any,
|
||||
) -> typing.Mapping[str, typing.Any]:
|
||||
global UPDATE_CHARACTERS # pylint: disable=W0603
|
||||
params = dict(params or {})
|
||||
headers = dict(headers or {})
|
||||
|
||||
base_url = routes.CALCULATOR_URL.get_url(self.region)
|
||||
url = base_url / endpoint
|
||||
|
||||
if method == "GET":
|
||||
params["lang"] = lang or self.lang
|
||||
data = None
|
||||
else:
|
||||
data = dict(data or {})
|
||||
data["lang"] = lang or self.lang
|
||||
|
||||
if self.region == types.Region.CHINESE:
|
||||
headers["referer"] = str(routes.CALCULATOR_REFERER_URL.get_url())
|
||||
|
||||
update_task = (
|
||||
None
|
||||
if UPDATE_CHARACTERS
|
||||
else asyncio.create_task(utility.update_characters_any(lang or self.lang, lenient=True))
|
||||
)
|
||||
data = await self.request(url, method=method, params=params, data=data, headers=headers, **kwargs)
|
||||
|
||||
if update_task:
|
||||
try:
|
||||
await update_task
|
||||
UPDATE_CHARACTERS = True
|
||||
except Exception as e: # pylint: disable=W0703
|
||||
warnings.warn(f"Failed to update characters: {e!r}")
|
||||
|
||||
return data
|
||||
|
||||
@patchable
|
||||
async def get_character_details(
|
||||
self,
|
||||
character: genshin.types.IDOr[genshin.models.genshin.Character],
|
||||
*,
|
||||
uid: typing.Optional[int] = None,
|
||||
lang: typing.Optional[str] = None,
|
||||
):
|
||||
uid = uid or await self._get_uid(genshin.types.Game.GENSHIN)
|
||||
|
||||
data = await self.request_calculator(
|
||||
"sync/avatar/detail",
|
||||
method="GET",
|
||||
lang=lang,
|
||||
params=dict(
|
||||
avatar_id=int(character),
|
||||
uid=uid,
|
||||
region=genshin.utility.recognize_genshin_server(uid),
|
||||
),
|
||||
)
|
||||
if data.get("weapon") is None:
|
||||
weapon = {
|
||||
"id": character.weapon.id,
|
||||
"name": character.weapon.name,
|
||||
"icon": character.weapon.icon,
|
||||
"weapon_cat_id": character.weapon.type,
|
||||
"weapon_level": character.weapon.rarity,
|
||||
"max_level": 90,
|
||||
"level_current": character.weapon.level,
|
||||
}
|
||||
data["weapon"] = weapon
|
||||
return genshin.models.genshin.CalculatorCharacterDetails(**data)
|
||||
|
||||
|
||||
@patch(genshin.client.components.base.BaseClient) # noqa
|
||||
class BaseClient:
|
||||
@patchable
|
||||
async def request_hoyolab(
|
||||
self: "genshin.Client",
|
||||
url: aiohttp.typedefs.StrOrURL,
|
||||
*,
|
||||
lang: typing.Optional[str] = None,
|
||||
region: typing.Optional[types.Region] = None,
|
||||
method: typing.Optional[str] = None,
|
||||
params: typing.Optional[typing.Mapping[str, typing.Any]] = None,
|
||||
data: typing.Any = None,
|
||||
headers: typing.Optional[aiohttp.typedefs.LooseHeaders] = None,
|
||||
**kwargs: typing.Any,
|
||||
) -> typing.Mapping[str, typing.Any]:
|
||||
"""Make a request any hoyolab endpoint."""
|
||||
if lang is not None and lang not in constants.LANGS:
|
||||
raise ValueError(f"{lang} is not a valid language, must be one of: " + ", ".join(constants.LANGS))
|
||||
|
||||
lang = lang or self.lang
|
||||
region = region or self.region
|
||||
|
||||
url = routes.TAKUMI_URL.get_url(region).join(yarl.URL(url))
|
||||
|
||||
if region == types.Region.OVERSEAS:
|
||||
headers = {
|
||||
"x-rpc-app_version": "1.5.0",
|
||||
"x-rpc-client_type": "5",
|
||||
"x-rpc-language": lang,
|
||||
"ds": generate_dynamic_secret(),
|
||||
}
|
||||
elif region == types.Region.CHINESE:
|
||||
account_id = self.cookie_manager.user_id
|
||||
if account_id:
|
||||
device_id = hex_digest(str(account_id))
|
||||
else:
|
||||
account_mid_v2 = get_account_mid_v2(self.cookie_manager.cookies)
|
||||
if account_mid_v2:
|
||||
device_id = hex_digest(account_mid_v2)
|
||||
else:
|
||||
device_id = DEVICE_ID
|
||||
app_version, client_type, ds_sign = get_ds(new_ds=True, data=data, params=params)
|
||||
ua = get_ua(device="Paimon Build " + device_id[0:5], version=app_version)
|
||||
headers = {
|
||||
"User-Agent": ua,
|
||||
"X_Requested_With": "com.mihoyo.hoyolab",
|
||||
"Referer": "https://webstatic.mihoyo.com",
|
||||
"x-rpc-app_version": app_version,
|
||||
"x-rpc-client_type": client_type,
|
||||
"ds": ds_sign,
|
||||
}
|
||||
await devices_methods.update_device_headers(self.hoyolab_id, headers)
|
||||
else:
|
||||
raise TypeError(f"{region!r} is not a valid region.")
|
||||
|
||||
data = await self.request(url, method=method, params=params, data=data, headers=headers, **kwargs)
|
||||
return data
|
||||
|
||||
@patchable
|
||||
async def request(
|
||||
self: "genshin.Client",
|
||||
url: aiohttp.typedefs.StrOrURL,
|
||||
*,
|
||||
method: typing.Optional[str] = None,
|
||||
params: typing.Optional[typing.Mapping[str, typing.Any]] = None,
|
||||
data: typing.Any = None,
|
||||
headers: typing.Optional[aiohttp.typedefs.LooseHeaders] = None,
|
||||
cache: typing.Any = None,
|
||||
static_cache: typing.Any = None,
|
||||
**kwargs: typing.Any,
|
||||
) -> typing.Mapping[str, typing.Any]:
|
||||
"""Make a request and return a parsed json response."""
|
||||
if cache is not None:
|
||||
value = await self.cache.get(cache)
|
||||
if value is not None:
|
||||
return value
|
||||
elif static_cache is not None:
|
||||
value = await self.cache.get_static(static_cache)
|
||||
if value is not None:
|
||||
return value
|
||||
|
||||
# actual request
|
||||
|
||||
headers = dict(headers or {})
|
||||
headers.setdefault("User-Agent", self.USER_AGENT)
|
||||
await devices_methods.update_device_headers(self.hoyolab_id, headers)
|
||||
|
||||
if method is None:
|
||||
method = "POST" if data else "GET"
|
||||
|
||||
if "json" in kwargs:
|
||||
raise TypeError("Use data instead of json in request.")
|
||||
|
||||
await self._request_hook(method, url, params=params, data=data, headers=headers, **kwargs)
|
||||
|
||||
response = await self.cookie_manager.request(
|
||||
url,
|
||||
method=method,
|
||||
params=params,
|
||||
json=data,
|
||||
headers=headers,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
# cache
|
||||
|
||||
if cache is not None:
|
||||
await self.cache.set(cache, response)
|
||||
elif static_cache is not None:
|
||||
await self.cache.set_static(static_cache, response)
|
||||
|
||||
return response
|
||||
|
||||
@patchable
|
||||
async def request_bbs(
|
||||
self: "genshin.Client",
|
||||
url: aiohttp.typedefs.StrOrURL,
|
||||
*,
|
||||
lang: typing.Optional[str] = None,
|
||||
region: typing.Optional[types.Region] = None,
|
||||
method: typing.Optional[str] = None,
|
||||
params: typing.Optional[typing.Mapping[str, typing.Any]] = None,
|
||||
data: typing.Any = None,
|
||||
headers: typing.Optional[aiohttp.typedefs.LooseHeaders] = None,
|
||||
**kwargs: typing.Any,
|
||||
) -> typing.Mapping[str, typing.Any]:
|
||||
"""Make a request any bbs endpoint."""
|
||||
if lang is not None and lang not in constants.LANGS:
|
||||
raise ValueError(f"{lang} is not a valid language, must be one of: " + ", ".join(constants.LANGS))
|
||||
|
||||
lang = lang or self.lang
|
||||
region = region or self.region
|
||||
|
||||
url = routes.BBS_URL.get_url(region).join(yarl.URL(url))
|
||||
headers = dict(headers or {})
|
||||
|
||||
if self.region == types.Region.CHINESE:
|
||||
if self.region == types.Region.CHINESE:
|
||||
account_id = self.cookie_manager.user_id
|
||||
if account_id:
|
||||
device_id = hex_digest(str(account_id))
|
||||
else:
|
||||
account_mid_v2 = get_account_mid_v2(self.cookie_manager.cookies)
|
||||
if account_mid_v2:
|
||||
device_id = hex_digest(account_mid_v2)
|
||||
else:
|
||||
device_id = DEVICE_ID
|
||||
|
||||
app_version, _, ds_sign = get_ds()
|
||||
ua = get_ua(device="Paimon Build " + device_id[0:5], version=app_version)
|
||||
add_headers = {
|
||||
"User-Agent": ua,
|
||||
"Referer": "https://www.miyoushe.com/ys/",
|
||||
"x-rpc-app_version": app_version,
|
||||
"x-rpc-client_type": "4",
|
||||
"ds": ds_sign,
|
||||
}
|
||||
headers.update(add_headers)
|
||||
await devices_methods.update_device_headers(self.hoyolab_id, headers)
|
||||
elif self.region == types.Region.OVERSEAS:
|
||||
headers.update(ds.get_ds_headers(data=data, params=params, region=region, lang=lang or self.lang))
|
||||
headers["Referer"] = str(routes.BBS_REFERER_URL.get_url(self.region))
|
||||
else:
|
||||
raise TypeError(f"{region!r} is not a valid region.")
|
||||
|
||||
data = await self.request(url, method=method, params=params, data=data, headers=headers, **kwargs)
|
||||
return data
|
||||
|
||||
|
||||
@patch(genshin.client.components.daily.DailyRewardClient) # noqa
|
||||
class DailyRewardClient:
|
||||
@patchable
|
||||
async def request_daily_reward(
|
||||
self: "genshin.Client",
|
||||
endpoint: str,
|
||||
*,
|
||||
game: typing.Optional[types.Game] = None,
|
||||
method: str = "GET",
|
||||
lang: typing.Optional[str] = None,
|
||||
params: typing.Optional[typing.Mapping[str, typing.Any]] = None,
|
||||
headers: typing.Optional[aiohttp.typedefs.LooseHeaders] = None,
|
||||
**kwargs: typing.Any,
|
||||
) -> typing.Mapping[str, typing.Any]:
|
||||
"""Make a request towards the daily reward endpoint."""
|
||||
params = dict(params or {})
|
||||
headers = dict(headers or {})
|
||||
|
||||
if game is None:
|
||||
if self.default_game is None:
|
||||
raise RuntimeError("No default game set.")
|
||||
|
||||
game = self.default_game
|
||||
|
||||
base_url = routes.REWARD_URL.get_url(self.region, game)
|
||||
url = (base_url / endpoint).update_query(**base_url.query)
|
||||
|
||||
if self.region == types.Region.OVERSEAS:
|
||||
params["lang"] = lang or self.lang
|
||||
|
||||
elif self.region == types.Region.CHINESE:
|
||||
# TODO: Support cn honkai
|
||||
player_id = await self._get_uid(types.Game.GENSHIN)
|
||||
|
||||
params["uid"] = player_id
|
||||
params["region"] = utility.recognize_genshin_server(player_id)
|
||||
|
||||
account_id = self.cookie_manager.user_id
|
||||
if account_id:
|
||||
device_id = hex_digest(str(account_id))
|
||||
else:
|
||||
account_mid_v2 = get_account_mid_v2(self.cookie_manager.cookies)
|
||||
if account_mid_v2:
|
||||
device_id = hex_digest(account_mid_v2)
|
||||
else:
|
||||
device_id = DEVICE_ID
|
||||
if endpoint == "sign":
|
||||
app_version, client_type, ds_sign = get_ds()
|
||||
else:
|
||||
app_version, client_type, ds_sign = get_ds(new_ds=True, params=params)
|
||||
device = "Paimon Build " + device_id[0:5]
|
||||
ua = get_ua(device=device)
|
||||
headers["User-Agent"] = ua
|
||||
headers["X_Requested_With"] = "com.mihoyo.hoyolab"
|
||||
headers["Referer"] = (
|
||||
"https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?"
|
||||
"bbs_auth_required=true&act_id=e202009291139501&utm_source=bbs&utm_medium=mys&utm_campaign=icon"
|
||||
)
|
||||
headers["x-rpc-device_name"] = device
|
||||
headers["x-rpc-app_version"] = app_version
|
||||
headers["x-rpc-client_type"] = client_type
|
||||
headers["x-rpc-sys_version"] = "12"
|
||||
headers["x-rpc-platform"] = "android"
|
||||
headers["x-rpc-channel"] = "miyousheluodi"
|
||||
headers["x-rpc-device_model"] = device
|
||||
headers["ds"] = ds_sign
|
||||
|
||||
validate = kwargs.get("validate")
|
||||
challenge = kwargs.get("challenge")
|
||||
|
||||
if validate and challenge:
|
||||
headers["x-rpc-challenge"] = challenge
|
||||
headers["x-rpc-validate"] = validate
|
||||
headers["x-rpc-seccode"] = f"{validate}|jordan"
|
||||
await devices_methods.update_device_headers(self.hoyolab_id, headers)
|
||||
else:
|
||||
raise TypeError(f"{self.region!r} is not a valid region.")
|
||||
|
||||
kwargs.pop("challenge", None)
|
||||
kwargs.pop("validate", None)
|
||||
|
||||
return await self.request(url, method=method, params=params, headers=headers, **kwargs)
|
Loading…
Reference in New Issue
Block a user