PaiGram/plugins/tools/cloud_game.py
2024-12-10 14:21:21 +08:00

176 lines
8.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import time
from contextlib import asynccontextmanager
from typing import Optional, List, TYPE_CHECKING
from simnet.errors import BadRequest as SimnetBadRequest, InvalidCookies, AlreadyClaimed, TimedOut as SimnetTimedOut
from simnet.models.cloud_game.base import CloudGameWallet
from sqlalchemy.orm.exc import StaleDataError
from telegram.constants import ParseMode
from telegram.error import BadRequest, Forbidden
from gram_core.basemodel import RegionEnum
from gram_core.plugin import Plugin
from gram_core.services.task.models import TaskStatusEnum
from gram_core.services.task.services import TaskCardServices
from plugins.tools.genshin import GenshinHelper, CookiesUpdateRequestError, PlayerNotFoundError, CookiesNotFoundError
from plugins.tools.sign import SignJobType
from utils.log import logger
if TYPE_CHECKING:
from simnet import GenshinClient
from telegram.ext import ContextTypes
class CloudGameHelper(Plugin):
def __init__(self, genshin_helper: GenshinHelper, sign_service: TaskCardServices):
self.genshin_helper = genshin_helper
self.sign_service = sign_service
@asynccontextmanager
async def client( # skipcq: PY-R1000 #
self, user_id: int, region: Optional[RegionEnum] = None, player_id: int = None, offset: int = 0
) -> "GenshinClient":
async with self.genshin_helper.genshin(user_id, region, player_id, offset) as client:
client: "GenshinClient"
try:
yield client
except InvalidCookies as exc:
stoken = client.cookies.get("stoken")
combo_token = None
if stoken is not None:
try:
game_token = await client.get_game_token_by_stoken()
logger.success("用户 %s 获取 game_token 成功", user_id)
login_cookie = await client.login_game_by_game_token(game_token)
logger.success("用户 %s 刷新 combo_token 成功", user_id)
combo_token = login_cookie.combo_token
except Exception as _exc:
logger.error("用户 %s 刷新 combo_token 失败", user_id, exc_info=_exc)
if combo_token:
raise CookiesUpdateRequestError({client.cloud_game_combo_token_key: combo_token})
raise exc
@staticmethod
async def clear_notification(client: "GenshinClient"):
no = await client.get_cloud_game_notifications()
data_list = no.get("list")
if not data_list:
return
for data in data_list:
n_id = data.get("id")
if not n_id:
continue
await client.ask_cloud_game_notifications(n_id)
@staticmethod
async def get_wallet(client: "GenshinClient") -> CloudGameWallet:
await client.check_cloud_game_token()
return await client.get_cloud_game_wallet()
async def start_sign(
self,
client: "GenshinClient",
is_raise: bool = False,
title: Optional[str] = "云游戏签到结果",
) -> str:
try:
wallet = await self.get_wallet(client)
except InvalidCookies as error:
logger.warning("UID[%s] 获取云游戏钱包信息失败API返回信息为 %s", client.player_id, str(error))
raise 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:
await self.clear_notification(client)
except Exception:
logger.warning("UID[%s] 清空云游戏通知失败", client.player_id)
have_free_time = wallet.free_time.free_time
limit_time = wallet.free_time.free_time_limit
if have_free_time == limit_time:
logger.success("UID[%s] 云游戏签到超出免费时长上限", client.player_id)
result = "超出免费时长上限"
else:
logger.success("UID[%s] 云游戏签到成功", client.player_id)
result = "OK"
today = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
message = (
f"#### {title} ####\n"
f"时间:{today} (UTC+8)\n"
f"Account: {client.account_id}\n"
f"免费时长:{have_free_time} 分钟\n"
f"签到结果: {result}"
)
return message
async def do_sign_job(self, context: "ContextTypes.DEFAULT_TYPE", job_type: SignJobType): # skipcq: PY-R1000 #
include_status: List[TaskStatusEnum] = [
TaskStatusEnum.STATUS_SUCCESS,
TaskStatusEnum.ALREADY_CLAIMED,
TaskStatusEnum.TIMEOUT_ERROR,
TaskStatusEnum.NEED_CHALLENGE,
TaskStatusEnum.GENSHIN_EXCEPTION,
]
if job_type == SignJobType.START:
title = "自动签到"
elif job_type == SignJobType.REDO:
title = "自动重新签到"
include_status.remove(TaskStatusEnum.STATUS_SUCCESS)
else:
raise ValueError
sign_list = await self.sign_service.get_all()
for sign_db in sign_list:
if sign_db.status not in include_status:
continue
user_id = sign_db.user_id
try:
async with self.client(user_id) as client:
text = await self.start_sign(client, is_raise=True, title=title)
except InvalidCookies:
text = "云游戏自动签到执行失败Cookie无效"
sign_db.status = TaskStatusEnum.INVALID_COOKIES
except AlreadyClaimed:
text = "今天旅行者云游戏已经签到过了~"
sign_db.status = TaskStatusEnum.ALREADY_CLAIMED
except SimnetBadRequest as exc:
text = f"云游戏自动签到执行失败API返回信息为 {str(exc)}"
sign_db.status = TaskStatusEnum.GENSHIN_EXCEPTION
except SimnetTimedOut:
text = "云游戏签到失败了呜呜呜 ~ 服务器连接超时 服务器熟啦 ~ "
sign_db.status = TaskStatusEnum.TIMEOUT_ERROR
except PlayerNotFoundError:
logger.info("用户 user_id[%s] 玩家不存在 关闭并移除云游戏自动签到", user_id)
await self.sign_service.remove(sign_db)
continue
except CookiesNotFoundError:
logger.info("用户 user_id[%s] cookie 不存在 关闭并移除云游戏自动签到", user_id)
await self.sign_service.remove(sign_db)
continue
except Exception as exc:
logger.error("执行云游戏自动签到时发生错误 user_id[%s]", user_id, exc_info=exc)
text = "签到失败了呜呜呜 ~ 执行云游戏自动签到时发生错误"
else:
sign_db.status = TaskStatusEnum.STATUS_SUCCESS
if sign_db.chat_id < 0:
text = f'<a href="tg://user?id={sign_db.user_id}">NOTICE {sign_db.user_id}</a>\n\n{text}'
try:
await context.bot.send_message(sign_db.chat_id, text, parse_mode=ParseMode.HTML)
except BadRequest as exc:
logger.error("执行云游戏自动签到时发生错误 user_id[%s] Message[%s]", user_id, exc.message)
sign_db.status = TaskStatusEnum.BAD_REQUEST
except Forbidden as exc:
logger.error("执行云游戏自动签到时发生错误 user_id[%s] message[%s]", user_id, exc.message)
sign_db.status = TaskStatusEnum.FORBIDDEN
except Exception as exc:
logger.error("执行云游戏自动签到时发生错误 user_id[%s]", user_id, exc_info=exc)
continue
else:
if sign_db.status not in include_status:
sign_db.status = TaskStatusEnum.STATUS_SUCCESS
try:
await self.sign_service.update(sign_db)
except StaleDataError:
logger.warning("用户 user_id[%s] 云游戏自动签到数据过期,跳过更新数据", user_id)