| |
| import httpx |
| from typing import Dict, Any |
|
|
| ACT_ID = "e202102251931481" |
|
|
| HOME_URL = "https://sg-hk4e-api.hoyolab.com/event/sol/home" |
| INFO_URL = "https://sg-hk4e-api.hoyolab.com/event/sol/info" |
| SIGN_URL = "https://sg-hk4e-api.hoyolab.com/event/sol/sign" |
| ROLE_URL = "https://api-os-takumi.hoyoverse.com/binding/api/getUserGameRolesByCookie" |
|
|
| class GSDailyApp: |
| def __init__(self): |
| self.client: httpx.AsyncClient | None = None |
|
|
| async def start(self): |
| self.client = httpx.AsyncClient(timeout=15) |
|
|
| async def stop(self): |
| if self.client: |
| await self.client.aclose() |
|
|
| def _headers(self, cookie: str): |
| return { |
| "Cookie": cookie, |
| "User-Agent": "Mozilla/5.0", |
| "Accept": "application/json" |
| } |
|
|
| async def _get_home(self, cookie: str): |
| r = await self.client.get( |
| HOME_URL, |
| headers=self._headers(cookie), |
| params={"act_id": ACT_ID} |
| ) |
| return r.json() |
|
|
| async def _get_info(self, cookie: str): |
| r = await self.client.get( |
| INFO_URL, |
| headers=self._headers(cookie), |
| params={"act_id": ACT_ID} |
| ) |
| return r.json() |
|
|
| async def _sign(self, cookie: str): |
| r = await self.client.post( |
| SIGN_URL, |
| headers=self._headers(cookie), |
| json={"act_id": ACT_ID} |
| ) |
| return r.json() |
|
|
| async def _get_role(self, cookie: str): |
| r = await self.client.get( |
| ROLE_URL, |
| headers=self._headers(cookie), |
| params={"game_biz": "hk4e_global"} |
| ) |
| return r.json() |
|
|
| async def run_daily_and_capture( |
| self, |
| cookie_string: str, |
| discord_id: str, |
| server_input: str |
| ) -> Dict[str, Any]: |
|
|
| try: |
| home_data = await self._get_home(cookie_string) |
| if home_data.get("retcode") != 0: |
| return {"ok": False, "error": home_data.get("message", "Home API lỗi")} |
|
|
| awards = home_data.get("data", {}).get("awards", []) |
| total_days_month = len(awards) |
|
|
| info_data = await self._get_info(cookie_string) |
| if info_data.get("retcode") != 0: |
| return {"ok": False, "error": info_data.get("message", "Info API lỗi")} |
|
|
| info = info_data.get("data", {}) |
| total_signed = info.get("total_sign_day", 0) |
| is_signed = info.get("is_sign", False) |
|
|
| claimed = False |
| risk_code = 0 |
| |
| if not is_signed: |
| sign_data = await self._sign(cookie_string) |
| risk_code = sign_data.get("risk_code", 0) |
|
|
| if sign_data.get("retcode") == 0: |
| claimed = True |
| total_signed += 1 |
| elif sign_data.get("retcode") == -5003: |
| claimed = False |
| else: |
| return {"ok": False, "error": sign_data.get("message", "Sign API lỗi")} |
|
|
| today_index = max(total_signed - 1, 0) |
|
|
| today_reward = ( |
| awards[today_index] if today_index < len(awards) else None |
| ) |
|
|
| tomorrow_reward = ( |
| awards[total_signed] if total_signed < len(awards) else None |
| ) |
|
|
| role_data = await self._get_role(cookie_string) |
|
|
| if role_data.get("retcode") != 0: |
| return {"ok": False, "error": "Không lấy được danh sách tài khoản"} |
|
|
| roles = role_data.get("data", {}).get("list", []) |
| if not roles: |
| return {"ok": False, "error": "Cookie không có tài khoản Genshin"} |
|
|
| region_map = { |
| "asia": "os_asia", |
| "america": "os_usa", |
| "usa": "os_usa", |
| "na": "os_usa", |
| "europe": "os_euro", |
| "eu": "os_euro", |
| "tw": "os_cht", |
| "hk": "os_cht" |
| } |
|
|
| target_region = region_map.get(server_input.lower()) |
| if not target_region: |
| return {"ok": False, "error": "Server không hợp lệ"} |
|
|
| selected_role = None |
| for r in roles: |
| if r.get("region") == target_region: |
| selected_role = r |
| break |
|
|
| if not selected_role: |
| return {"ok": False, "error": f"Không tìm thấy tài khoản ở server {server_input}"} |
|
|
| uid = selected_role.get("game_uid") |
| nickname = selected_role.get("nickname") |
| level = selected_role.get("level") |
| region = selected_role.get("region") |
|
|
| server_name_map = { |
| "os_asia": "Asia", |
| "os_euro": "EU", |
| "os_usa": "NA", |
| "os_cht": "TW/HK" |
| } |
|
|
| server_name = server_name_map.get(region, region) |
|
|
| missing_days = max(total_days_month - total_signed, 0) |
|
|
| return { |
| "ok": True, |
| "claimed": claimed, |
| "discord_id": discord_id, |
|
|
| "nickname": nickname, |
| "uid": uid, |
| "server": server_name, |
| "adventure_rank": level, |
|
|
| "signed_days": total_signed, |
| "total_days_month": total_days_month, |
| "missing_days": missing_days, |
|
|
| "today_reward": { |
| "name": today_reward.get("name"), |
| "count": today_reward.get("cnt"), |
| "icon": today_reward.get("icon") |
| } if today_reward else None, |
|
|
| "tomorrow_reward": { |
| "name": tomorrow_reward.get("name"), |
| "count": tomorrow_reward.get("cnt"), |
| "icon": tomorrow_reward.get("icon") |
| } if tomorrow_reward else None, |
|
|
| "risk_code": risk_code |
| } |
|
|
| except Exception as e: |
| return {"ok": False, "error": f"Internal error: {str(e)}"} |