添加自动签到相关功能

添加自动签到相关请求和定时任务 并没写插件 )
This commit is contained in:
洛水居室 2022-08-06 14:36:44 +08:00
parent 542a2a1fab
commit 9c208f7b4c
No known key found for this signature in database
GPG Key ID: C9DE87DA724B88FC
5 changed files with 192 additions and 0 deletions

11
apps/sign/__init__.py Normal file
View File

@ -0,0 +1,11 @@
from utils.apps.manager import listener_service
from utils.mysql import MySQL
from .repositories import SignRepository
from .services import SignServices
@listener_service()
def create_game_strategy_service(mysql: MySQL):
_repository = SignRepository(mysql)
_service = SignServices(_repository)
return _service

25
apps/sign/models.py Normal file
View File

@ -0,0 +1,25 @@
import enum
from datetime import datetime
from typing import Optional
from sqlalchemy import func
from sqlmodel import SQLModel, Field, Enum, Column, DateTime
class SignStatusEnum(int, enum.Enum):
STATUS_SUCCESS = 0 # 签到成功
INVALID_COOKIES = 1 # Cookie无效
ALREADY_CLAIMED = 2 # 已经获取奖励
GENSHIN_EXCEPTION = 3 # API异常
TIMEOUT_ERROR = 4 # 请求超时
BAD_REQUEST = 5 # 请求失败
FORBIDDEN = 6 # 这错误一般为通知失败 机器人被用户BAN
class Sign(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
user_id: int = Field()
chat_id: int = Field()
time_created: Optional[datetime] = Field(sa_column=Column(DateTime(timezone=True), server_default=func.now()))
time_updated: Optional[datetime] = Field(sa_column=Column(DateTime(timezone=True), onupdate=func.now()))
status: Optional[SignStatusEnum] = Field(sa_column=Column(Enum(SignStatusEnum)))

41
apps/sign/repositories.py Normal file
View File

@ -0,0 +1,41 @@
from typing import List, cast, Optional
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from utils.mysql import MySQL
from .models import Sign
class SignRepository:
def __init__(self, mysql: MySQL):
self.mysql = mysql
async def add(self, sign: Sign):
async with self.mysql.Session() as session:
session = cast(AsyncSession, session)
session.add(sign)
await session.commit()
async def update(self, sign: Sign):
async with self.mysql.Session() as session:
session = cast(AsyncSession, session)
session.add(sign)
await session.commit()
await session.refresh(sign)
async def get_by_user_id(self, user_id: int) -> Optional[Sign]:
async with self.mysql.Session() as session:
session = cast(AsyncSession, session)
statement = select(Sign).where(Sign.user_id == user_id)
results = await session.exec(statement)
if sign := results.first():
return sign[0]
return None
async def get_all(self) -> List[Sign]:
async with self.mysql.Session() as session:
query = select(Sign)
results = await session.exec(query)
signs = results.all()
return [sign[0] for sign in signs]

19
apps/sign/services.py Normal file
View File

@ -0,0 +1,19 @@
from .models import Sign
from .repositories import SignRepository
class SignServices:
def __init__(self, sign_repository: SignRepository) -> None:
self._repository: SignRepository = sign_repository
async def get_all(self):
return await self._repository.get_all()
async def add(self, sign: Sign):
return await self._repository.add(sign)
async def update(self, sign: Sign):
return await self._repository.update(sign)
async def get_by_user_id(self, user_id: int):
return await self._repository.get_by_user_id(user_id)

96
jobs/sign.py Normal file
View File

@ -0,0 +1,96 @@
import datetime
import time
from aiohttp import ClientConnectorError
from genshin import Game, GenshinException, AlreadyClaimed, InvalidCookies
from telegram.error import BadRequest, Forbidden
from telegram.ext import CallbackContext, JobQueue
from apps.cookies import CookiesService
from apps.sign.models import SignStatusEnum
from apps.sign.services import SignServices
from apps.user import UserService
from config import config
from logger import Log
from utils.apps.inject import inject
from utils.helpers import get_genshin_client
from utils.job.manager import listener_jobs_class
@listener_jobs_class()
class SignJob:
@inject
def __init__(self, sign_service: SignServices = None, user_service: UserService = None,
cookies_service: CookiesService = None):
self.sign_service = sign_service
self.cookies_service = cookies_service
self.user_service = user_service
@classmethod
def build_jobs(cls, job_queue: JobQueue):
sign = cls()
if config.DEBUG:
job_queue.run_once(sign.sign, 3, name="SignJobTest")
# 每天凌晨执行
job_queue.run_daily(sign.sign, datetime.time(hour=0, minute=0, second=0), name="SignJob")
async def sign(self, context: CallbackContext):
Log.info("正在执行自动签到")
sign_list = await self.sign_service.get_all()
for sign_db in sign_list:
if sign_db.status != SignStatusEnum.STATUS_SUCCESS:
continue
user_id = sign_db.user_id
try:
client = await get_genshin_client(user_id, self.user_service, self.cookies_service)
rewards = await client.get_monthly_rewards(game=Game.GENSHIN, lang="zh-cn")
daily_reward_info = await client.get_reward_info(game=Game.GENSHIN)
if not daily_reward_info.signed_in:
request_daily_reward = await client.request_daily_reward("sign", method="POST", game=Game.GENSHIN)
Log.info(f"UID {client.uid} 签到请求 {request_daily_reward}")
result = "OK"
else:
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))
now = datetime.datetime.now(cn_timezone)
missed_days = now.day - daily_reward_info.claimed_rewards
if not daily_reward_info.signed_in:
missed_days -= 1
text = f"########### 定时签到 ###########\n" \
f"#### {today} (UTC+8) ####\n" \
f"UID: {client.uid}\n" \
f"今日奖励: {reward.name} × {reward.amount}\n" \
f"本月漏签次数:{missed_days}\n" \
f"签到结果: {result}"
except InvalidCookies:
text = "自动签到执行失败Cookie无效"
sign_db.status = SignStatusEnum.INVALID_COOKIES
except AlreadyClaimed:
text = "今天旅行者已经签到过了~"
sign_db.status = SignStatusEnum.ALREADY_CLAIMED
except GenshinException as exc:
text = f"自动签到执行失败API返回信息为 {str(exc)}"
sign_db.status = SignStatusEnum.GENSHIN_EXCEPTION
except ClientConnectorError:
text = "签到失败了呜呜呜 ~ 服务器连接超时 服务器熟啦 ~ "
sign_db.status = SignStatusEnum.TIMEOUT_ERROR
except BaseException as exc:
Log.error(f"执行自动签到时发生错误", exc)
continue
try:
await context.bot.send_message(sign_db.chat_id, text)
except BadRequest as exc:
Log.error(f"执行自动签到时发生错误", exc)
sign_db.status = SignStatusEnum.BAD_REQUEST
except Forbidden as exc:
Log.error(f"执行自动签到时发生错误", exc)
sign_db.status = SignStatusEnum.FORBIDDEN
except BaseException as exc:
Log.error(f"执行自动签到时发生错误", exc)
continue
sign_db.time_updated = datetime.datetime.now()
await self.sign_service.update(sign_db)
Log.info("执行自动签到完成")