SIMNet/simnet/client/components/daily.py

253 lines
9.1 KiB
Python
Raw Normal View History

2023-05-05 14:15:40 +00:00
"""Daily reward component."""
2024-03-29 13:48:07 +00:00
2023-05-05 14:15:40 +00:00
import asyncio
from typing import Optional, Dict, Any, List
from httpx import QueryParams
2023-05-05 14:15:40 +00:00
from simnet.client.base import BaseClient
from simnet.client.routes import REWARD_URL
from simnet.errors import GeetestTriggered
2023-05-05 14:15:40 +00:00
from simnet.models.lab.daily import DailyRewardInfo, DailyReward, ClaimedDailyReward
2023-12-27 07:09:24 +00:00
from simnet.utils.enums import Game, Region
from simnet.utils.player import recognize_genshin_server, recognize_starrail_server
2023-05-05 14:15:40 +00:00
__all__ = ("DailyRewardClient",)
class DailyRewardClient(BaseClient):
"""A client for interacting with the daily reward system."""
async def request_daily_reward(
self,
endpoint: str,
*,
method: str = "GET",
challenge: Optional[str] = None,
validate: Optional[str] = None,
game: Optional[Game] = None,
lang: Optional[str] = None,
params: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
"""
Makes a request to the daily reward endpoint.
Args:
endpoint (str): The endpoint to request.
method (str): The HTTP method to use. Defaults to "GET".
challenge (str): A challenge string for validating the request. Defaults to None.
validate (str): A validation string for validating the request. Defaults to None.
game (Game): The game to request data for. Defaults to None.
lang (str): The language to use. Defaults to None.
params (Dict[str, Any]): Any parameters to include in the request.
Returns:
A dictionary containing the response data.
"""
headers: Dict[str, str] = {}
params = QueryParams(params)
base_url = REWARD_URL.get_url(self.region, self.game or game)
params = params.merge(base_url.params)
2023-07-19 05:02:22 +00:00
params = params.set("lang", lang or self.lang)
if challenge is not None:
headers["x-rpc-challenge"] = challenge
if validate is not None:
headers["x-rpc-validate"] = validate
headers["x-rpc-seccode"] = f"{validate}|jordan"
2023-05-05 14:15:40 +00:00
if self.region == Region.CHINESE:
headers["x-rpc-device_name"] = "Chrome 20 2023"
headers["x-rpc-channel"] = "chrome"
headers["x-rpc-device_model"] = "Chrome 2023"
headers["x-rpc-sys_version"] = "13"
headers["x-rpc-platform"] = "android"
if self.game == Game.GENSHIN:
2023-12-01 03:09:32 +00:00
headers["x-rpc-signgame"] = "hk4e"
headers["referer"] = (
2023-12-01 03:09:32 +00:00
"https://act.mihoyo.com/bbs/event/signin/hk4e/index.html?"
"bbs_auth_required=true&act_id=e202311201442471&"
"bbs_auth_required=true&bbs_presentation_style=fullscreen&"
"utm_source=bbs&utm_medium=mys&utm_campaign=icon"
)
params = params.set("uid", self.player_id)
params = params.set("region", recognize_genshin_server(self.player_id))
if self.game == Game.STARRAIL:
headers["referer"] = (
"https://webstatic.mihoyo.com/bbs/event/signin/hkrpg/index.html?"
"bbs_auth_required=true&act_id=e202304121516551&"
"bbs_auth_required=true&bbs_presentation_style=fullscreen&"
"utm_source=bbs&utm_medium=mys&utm_campaign=icon"
)
params = params.set("uid", self.player_id)
params = params.set("region", recognize_starrail_server(self.player_id))
url = base_url / endpoint
2023-05-05 14:15:40 +00:00
return await self.request_lab(
url,
method,
params=params,
headers=headers,
lang=lang,
2023-05-05 14:15:40 +00:00
)
async def get_reward_info(
self,
*,
game: Optional[Game] = None,
lang: Optional[str] = None,
) -> DailyRewardInfo:
"""Gets the daily reward info for the current user.
Args:
game (Game): The game to request data for. Defaults to None.
lang (str): The language to use. Defaults to None.
Returns:
A DailyRewardInfo object containing information about the user's daily reward status.
"""
data = await self.request_daily_reward("info", game=game, lang=lang)
return DailyRewardInfo(data["is_sign"], data["total_sign_day"])
async def get_monthly_rewards(
self,
*,
game: Optional[Game] = None,
lang: Optional[str] = None,
) -> List[DailyReward]:
"""Gets a list of all available rewards for the current month.
Args:
game (Game): The game to request data for. Defaults to None.
lang (str): The language to use. Defaults to None.
Returns:
A list of DailyReward objects representing the available rewards for the current month.
"""
data = await self.request_daily_reward(
"home",
game=game or self.game,
2023-05-05 14:15:40 +00:00
lang=lang,
)
return [DailyReward(**i) for i in data["awards"]]
async def _get_claimed_rewards_page(
self,
page: int,
*,
game: Optional[Game] = None,
lang: Optional[str] = None,
) -> List[ClaimedDailyReward]:
"""Gets a single page of claimed rewards for the current user.
Args:
page (int): The page number to retrieve.
game (Game): The game to request data for. Defaults to None.
lang (str): The language to use. Defaults to None.
Returns:
A list of ClaimedDailyReward objects representing the claimed rewards for the current user on the specified
page.
"""
data = await self.request_daily_reward(
"award", params=dict(current_page=page), game=game or self.game, lang=lang
2023-05-05 14:15:40 +00:00
)
return [ClaimedDailyReward(**i) for i in data["list"]]
async def claimed_rewards(
self,
*,
limit: Optional[int] = None,
game: Optional[Game] = None,
lang: Optional[str] = None,
) -> List[ClaimedDailyReward]:
"""Gets all claimed rewards for the current user.
Args:
limit (int): The maximum number of rewards to return. Defaults to None.
game (Game): The game to request data for. Defaults to None.
lang (str): The language to use. Defaults to None.
Returns:
A list of ClaimedDailyReward objects representing the claimed rewards for the current user.
"""
result = []
index = 0
page = 1
while True:
if page >= 10:
break
2023-05-12 03:24:06 +00:00
fetched_items = await self._get_claimed_rewards_page(page, game=game or self.game, lang=lang)
2023-05-05 14:15:40 +00:00
if not fetched_items:
break
# Calculate how many items should be added
items_to_add = (
2023-05-12 03:24:06 +00:00
limit - index if limit is not None and limit - index < len(fetched_items) else len(fetched_items)
2023-05-05 14:15:40 +00:00
)
result.extend(fetched_items[:items_to_add])
index += items_to_add
if limit is not None and index >= limit:
break
page += 1
return result
async def claim_daily_reward(
self,
*,
challenge: Optional[str] = None,
validate: Optional[str] = None,
game: Optional[Game] = None,
lang: Optional[str] = None,
reward: bool = True,
) -> Optional[DailyReward]:
"""
Signs into lab and claims the daily reward.
Args:
challenge (str): A challenge string for validating the request. Defaults to None.
validate (str): A validation string for validating the request. Defaults to None.
game (Game): The game to claim the reward for. Defaults to None.
lang (str): The language to use. Defaults to None.
reward (bool): Whether to return the claimed reward. Defaults to True.
Returns:
If `reward` is True, a DailyReward object representing the claimed reward. Otherwise, None.
"""
daily_reward = await self.request_daily_reward(
2023-05-05 14:15:40 +00:00
"sign",
method="POST",
game=game or self.game,
2023-05-05 14:15:40 +00:00
lang=lang,
challenge=challenge,
validate=validate,
)
if self.region == Region.CHINESE and daily_reward.get("success", 0) == 1:
gt = daily_reward.get("gt", "")
challenge = daily_reward.get("challenge", "")
raise GeetestTriggered(gt, challenge)
if self.region == Region.OVERSEAS:
gt_result = daily_reward.get("gt_result")
if gt_result is not None and gt_result["success"] != 0:
gt = gt_result.get("gt", "")
challenge = gt_result.get("challenge", "")
raise GeetestTriggered(gt, challenge)
2023-05-05 14:15:40 +00:00
if not reward:
return None
info, rewards = await asyncio.gather(
self.get_reward_info(game=game or self.game, lang=lang),
self.get_monthly_rewards(game=game or self.game, lang=lang),
2023-05-05 14:15:40 +00:00
)
return rewards[info.claimed_rewards - 1]