PamGram/plugins/starrail/redeem/redeem.py

189 lines
8.0 KiB
Python
Raw Normal View History

2024-04-14 03:44:24 +00:00
import asyncio
import contextlib
2024-04-14 03:44:24 +00:00
import time
from asyncio import sleep
from typing import List, Tuple
2024-04-14 03:44:24 +00:00
from simnet import Region
from telegram import Update, Message
from telegram.error import BadRequest, Forbidden
2024-04-14 03:44:24 +00:00
from telegram.ext import CallbackContext
from telegram.ext import filters
from core.plugin import Plugin, handler
from gram_core.basemodel import RegionEnum
from gram_core.services.cookies import CookiesService
from gram_core.services.cookies.models import CookiesStatusEnum
2024-04-14 03:44:24 +00:00
from gram_core.services.users.services import UserAdminService
from plugins.starrail.redeem.runner import RedeemRunner, RedeemResult, RedeemQueueFull
from plugins.tools.genshin import GenshinHelper
from utils.log import logger
REDEEM_TEXT = """#### 兑换结果 ####
时间{} (UTC+8)
UID: {}
兑换码{}
兑换结果{}"""
REDEEM_ALL_TEXT = """#### 批量兑换 ####
兑换码{}
正在兑换中请稍等
{} / {}"""
REDEEM_ALL_FAIL_TEXT = """#### 批量兑换 ####
兑换码{}
兑换成功{}
兑换失败{}"""
2024-04-14 03:44:24 +00:00
class Redeem(Plugin):
"""兑换码兑换"""
def __init__(
self,
genshin_helper: GenshinHelper,
user_admin_service: UserAdminService,
cookies_service: CookiesService,
2024-04-14 03:44:24 +00:00
):
self.genshin_helper = genshin_helper
self.user_admin_service = user_admin_service
self.max_code_in_pri_message = 5
self.max_code_in_pub_message = 3
self.redeem_runner = RedeemRunner(genshin_helper)
self.cookies_service = cookies_service
2024-04-14 03:44:24 +00:00
async def _callback(self, data: "RedeemResult") -> None:
code = data.code
uid = data.uid if data.uid else "未知"
msg = data.error if data.error else "成功"
today = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
text = REDEEM_TEXT.format(today, uid, code, msg)
reply_message = None
try:
reply_message = await data.message.edit_text(text)
except BadRequest:
try:
reply_message = await data.message.reply_text(text)
except BadRequest:
pass
if reply_message and filters.ChatType.GROUPS.filter(reply_message):
self.add_delete_message_job(reply_message)
async def redeem_one_code(self, update: Update, user_id: int, uid: int, code: str, chinese: bool):
2024-04-14 03:44:24 +00:00
if not code:
return
message = update.effective_message
reply_message = await message.reply_text("正在兑换中,请稍等")
task_data = RedeemResult(user_id=user_id, code=code, uid=uid, message=reply_message)
if chinese:
task_data.error = "此服务器暂不支持进行兑换哦~"
await self._callback(task_data)
return
2024-04-14 03:44:24 +00:00
priority = 1 if await self.user_admin_service.is_admin(user_id) else 2
try:
await self.redeem_runner.run(task_data, self._callback, priority)
except RedeemQueueFull:
await reply_message.edit_text("兑换队列已满,请稍后再试")
if filters.ChatType.GROUPS.filter(reply_message):
self.add_delete_message_job(reply_message)
async def redeem_codes(self, update: Update, user_id: int, codes: List[str]):
uid, offset = self.get_real_uid_or_offset(update)
async with self.genshin_helper.genshin(user_id, player_id=uid, offset=offset) as client:
chinese = client.region == Region.CHINESE
2024-04-14 03:44:24 +00:00
uid = client.player_id
tasks = []
for code in codes:
tasks.append(self.redeem_one_code(update, user_id, uid, code, chinese))
2024-04-14 03:44:24 +00:00
await asyncio.gather(*tasks)
@handler.command(command="redeem", cookie=True, block=False)
@handler.message(filters=filters.Regex("^兑换码兑换(.*)"), cookie=True, block=False)
async def command_start(self, update: Update, context: CallbackContext) -> None:
user_id = await self.get_real_user_id(update)
message = update.effective_message
limit = self.max_code_in_pri_message
if filters.ChatType.GROUPS.filter(message):
self.add_delete_message_job(message)
limit = self.max_code_in_pub_message
codes = [i for i in self.get_args(context) if not i.startswith("@")][:limit]
2024-04-14 03:44:24 +00:00
self.log_user(update, logger.info, "兑换码兑换命令请求 codes[%s]", codes)
if not codes:
return
await self.redeem_codes(update, user_id, codes)
@handler.command(command="start", filters=filters.Regex(r" redeem_(.*)"), block=False)
async def start_redeem(self, update: Update, context: CallbackContext) -> None:
user = update.effective_user
args = self.get_args(context)
codes = [i for i in args[0].split("_")[1:] if i][: self.max_code_in_pri_message]
logger.info("用户 %s[%s] 通过start命令 进入兑换码兑换流程 codes[%s]", user.full_name, user.id, codes)
await self.redeem_codes(update, user.id, codes)
async def _job_callback(self, data: "RedeemResult") -> None:
if data.error:
logger.warning("执行自动兑换兑换码时发生错误 user_id[%s] message[%s]", data.user_id, data.error)
data.count[1] += 1
return
data.count[0] += 1
user_id = data.user_id
code = data.code
uid = data.uid if data.uid else "未知"
msg = "成功"
today = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
text = REDEEM_TEXT.format(today, uid, code, msg)
try:
await self.application.bot.send_message(user_id, text)
except BadRequest as exc:
logger.warning("执行自动兑换兑换码时发生错误 user_id[%s] Message[%s]", user_id, exc.message)
except Forbidden as exc:
logger.warning("执行自动兑换兑换码时发生错误 user_id[%s] message[%s]", user_id, exc.message)
except Exception as exc:
logger.warning("执行自动兑换兑换码时发生错误 user_id[%s]", user_id, exc_info=exc)
async def job_redeem_one_code(self, user_id: int, code: str, count: List[int]):
task_data = RedeemResult(user_id=user_id, code=code, count=count)
priority = 1 if await self.user_admin_service.is_admin(user_id) else 2
try:
await self.redeem_runner.run(task_data, self._job_callback, priority, True)
except RedeemQueueFull:
await sleep(5)
await self.job_redeem_one_code(user_id, code, count)
async def do_redeem_job(self, message: "Message", code: str) -> Tuple[int, int]:
count = [0, 0]
task_list = await self.cookies_service.get_all(
region=RegionEnum.HOYOLAB, status=CookiesStatusEnum.STATUS_SUCCESS
)
task_len = len(task_list)
for idx, task_db in enumerate(task_list):
user_id = task_db.user_id
try:
await self.job_redeem_one_code(user_id, code, count)
except Exception as exc:
logger.warning("执行自动兑换兑换码时发生错误 user_id[%s]", user_id, exc_info=exc)
if idx % 10 == 0:
text = REDEEM_ALL_TEXT.format(code, idx, task_len)
with contextlib.suppress(Exception):
await message.edit_text(text)
return count[0], count[1]
@handler.command(command="redeem_all", admin=True, block=False)
async def redeem_all_command_start(self, update: Update, context: CallbackContext) -> None:
message = update.effective_message
codes = [i for i in self.get_args(context) if i]
self.log_user(update, logger.info, "兑换码批量兑换命令请求 codes[%s]", codes)
if not codes:
await message.reply_text("请输入兑换码")
return
code = codes[0]
reply = await message.reply_text("开始运行批量兑换任务,请等待...")
success, failed = await self.do_redeem_job(reply, code)
text = REDEEM_ALL_FAIL_TEXT.format(code, success, failed)
await message.reply_text(text)
self.add_delete_message_job(reply, delay=1)