Create main.py
Browse files
main.py
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import uvicorn
|
| 2 |
+
from fastapi import FastAPI, Query
|
| 3 |
+
from genshin import Client
|
| 4 |
+
import asyncio
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
app = FastAPI()
|
| 8 |
+
|
| 9 |
+
cookies = {"ltuid_v2": os.getenv("ltuid_v2"), "ltoken_v2": os.getenv("ltoken_v2"),"ltmid_v2":os.getenv("ltmid_v2"),"cookie_token_v2":os.getenv("cookie_token_v2")}
|
| 10 |
+
client = Client(cookies)
|
| 11 |
+
|
| 12 |
+
# Helper function to format data
|
| 13 |
+
def format_user_data(user):
|
| 14 |
+
try:
|
| 15 |
+
# Info section
|
| 16 |
+
info = f"• Info •\n"
|
| 17 |
+
info += f"{getattr(user.stats, 'days_active', 'N/A')} Active Days\n"
|
| 18 |
+
info += f"{getattr(user.stats, 'achievements', 'N/A')} Achievements\n"
|
| 19 |
+
info += f"{len(user.characters) if hasattr(user, 'characters') and isinstance(user.characters, list) else 'N/A'} Characters\n"
|
| 20 |
+
info += f"{getattr(user.stats, 'unlocked_waypoints', 'N/A')} Waypoints\n"
|
| 21 |
+
info += f"{getattr(user.stats, 'unlocked_domains', 'N/A')} Domains\n"
|
| 22 |
+
info += f"{getattr(user.stats, 'dendroculi', 'N/A')} Dendroculus\n"
|
| 23 |
+
info += f"{getattr(user.stats, 'electroculi', 'N/A')} Electroculus\n"
|
| 24 |
+
info += f"{getattr(user.stats, 'anemoculi', 'N/A')} Anemoculus\n"
|
| 25 |
+
info += f"{getattr(user.stats, 'geoculi', 'N/A')} Geoculus\n"
|
| 26 |
+
info += f"Spiral Abyss {getattr(user.stats, 'spiral_abyss', 'N/A')}\n"
|
| 27 |
+
|
| 28 |
+
# Chests section
|
| 29 |
+
chests = f"• Chests •\n"
|
| 30 |
+
chests += f"{getattr(user.stats, 'remarkable_chests', 'N/A')} Remarkable\n"
|
| 31 |
+
chests += f"{getattr(user.stats, 'luxurious_chests', 'N/A')} Luxurious\n"
|
| 32 |
+
chests += f"{getattr(user.stats, 'precious_chests', 'N/A')} Precious\n"
|
| 33 |
+
chests += f"{getattr(user.stats, 'exquisite_chests', 'N/A')} Exquisite\n"
|
| 34 |
+
chests += f"{getattr(user.stats, 'common_chests', 'N/A')} Common\n"
|
| 35 |
+
|
| 36 |
+
# Exploration section
|
| 37 |
+
exploration = f"• Exploration •\n"
|
| 38 |
+
if hasattr(user, 'explorations') and isinstance(user.explorations, list):
|
| 39 |
+
for exploration_data in user.explorations:
|
| 40 |
+
percent = f"{getattr(exploration_data, 'raw_explored', 0) / 10.0:.1f}%"
|
| 41 |
+
exploration += f"{getattr(exploration_data, 'name', 'Unknown')} {percent}\n"
|
| 42 |
+
if hasattr(exploration_data, 'offerings') and isinstance(exploration_data.offerings, list):
|
| 43 |
+
for offering in exploration_data.offerings:
|
| 44 |
+
exploration += f" {getattr(offering, 'name', 'Unknown')} level {getattr(offering, 'level', 'N/A')}\n"
|
| 45 |
+
else:
|
| 46 |
+
exploration += "No exploration data available.\n"
|
| 47 |
+
|
| 48 |
+
# Teapot section
|
| 49 |
+
teapot = f"• Teapot •\n"
|
| 50 |
+
if hasattr(user.teapot, 'realms') and isinstance(user.teapot.realms, list) and len(user.teapot.realms) > 0:
|
| 51 |
+
teapot += f"{getattr(user.teapot.realms[0], 'name', 'Unknown')}\n"
|
| 52 |
+
teapot += f"Level {getattr(user.teapot, 'level', 'N/A')} ({getattr(user.teapot, 'comfort_name', 'Unknown')})\n"
|
| 53 |
+
teapot += f"Comfort {getattr(user.teapot, 'comfort', 'N/A')}\n"
|
| 54 |
+
teapot += f"Visits {len(user.teapot.visitors) if hasattr(user.teapot, 'visitors') and isinstance(user.teapot.visitors, list) else 'N/A'}\n"
|
| 55 |
+
teapot += f"Items {getattr(user.teapot, 'items', 'N/A')}\n"
|
| 56 |
+
|
| 57 |
+
return f"{info}\n{chests}\n{exploration}\n{teapot}"
|
| 58 |
+
except Exception as e:
|
| 59 |
+
# Log unexpected issues in the formatting process
|
| 60 |
+
return f"Error formatting user data: {e}"
|
| 61 |
+
|
| 62 |
+
@app.get("/user/{uid}")
|
| 63 |
+
async def get_user_info(uid: int):
|
| 64 |
+
try:
|
| 65 |
+
# Fetch user data from the client
|
| 66 |
+
user = await client.get_genshin_user(uid)
|
| 67 |
+
# Format user data
|
| 68 |
+
formatted_data = format_user_data(user)
|
| 69 |
+
return {"uid": uid, "data": formatted_data}
|
| 70 |
+
except Exception as e:
|
| 71 |
+
# Log and return any errors encountered during API call or formatting
|
| 72 |
+
return {"error": str(e)}
|
| 73 |
+
|
| 74 |
+
async def fetch_spiral_abyss_data(uid: int, previous: bool = False):
|
| 75 |
+
"""Fetches Spiral Abyss data using the genshin API."""
|
| 76 |
+
return await client.get_spiral_abyss(uid, previous=previous)
|
| 77 |
+
|
| 78 |
+
def format_abyss_data(data):
|
| 79 |
+
"""Formats the Spiral Abyss data into the desired format."""
|
| 80 |
+
|
| 81 |
+
def format_rank(rank):
|
| 82 |
+
"""Formats a rank entry with its value and character name."""
|
| 83 |
+
return f"{rank[0].value} ({rank[0].name})" if rank else "N/A"
|
| 84 |
+
|
| 85 |
+
return {
|
| 86 |
+
"Season": data.season,
|
| 87 |
+
"Start Time": data.start_time.isoformat(),
|
| 88 |
+
"End Time": data.end_time.isoformat(),
|
| 89 |
+
"Total Battles": data.total_battles,
|
| 90 |
+
"Total Wins": data.total_wins,
|
| 91 |
+
"Max Floor": data.max_floor,
|
| 92 |
+
"Total Stars": data.total_stars,
|
| 93 |
+
"Ranks": {
|
| 94 |
+
"Most Played": [f"{char.name} ({char.value})" for char in data.ranks.most_played],
|
| 95 |
+
"Most Kills": format_rank(data.ranks.most_kills),
|
| 96 |
+
"Strongest Strike": format_rank(data.ranks.strongest_strike),
|
| 97 |
+
"Most Damage Taken": format_rank(data.ranks.most_damage_taken),
|
| 98 |
+
"Most Bursts Used": format_rank(data.ranks.most_bursts_used),
|
| 99 |
+
"Most Skills Used": format_rank(data.ranks.most_skills_used),
|
| 100 |
+
},
|
| 101 |
+
"Floors": [
|
| 102 |
+
{
|
| 103 |
+
"Floor": floor.floor,
|
| 104 |
+
"Unlocked": floor.unlocked,
|
| 105 |
+
"Stars": f"{floor.stars}/{floor.max_stars}",
|
| 106 |
+
"Chambers": [
|
| 107 |
+
{
|
| 108 |
+
"Chamber": chamber.chamber,
|
| 109 |
+
"Stars": f"{chamber.stars}/{chamber.max_stars}",
|
| 110 |
+
}
|
| 111 |
+
for chamber in floor.chambers
|
| 112 |
+
],
|
| 113 |
+
}
|
| 114 |
+
for floor in data.floors
|
| 115 |
+
],
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
@app.get("/spiral-abyss/")
|
| 119 |
+
async def get_spiral_abyss(
|
| 120 |
+
id: int = Query(...),
|
| 121 |
+
previous: bool = Query(False)
|
| 122 |
+
):
|
| 123 |
+
"""
|
| 124 |
+
Fetch and return Spiral Abyss data for the given user ID.
|
| 125 |
+
|
| 126 |
+
Query parameters:
|
| 127 |
+
- `id`: The user ID to fetch data for.
|
| 128 |
+
- `previous`: Whether to fetch the previous season's data (default: False).
|
| 129 |
+
"""
|
| 130 |
+
try:
|
| 131 |
+
data = await fetch_spiral_abyss_data(id, previous)
|
| 132 |
+
formatted_data = format_abyss_data(data)
|
| 133 |
+
return formatted_data
|
| 134 |
+
except Exception as e:
|
| 135 |
+
return {"error": str(e)}
|
| 136 |
+
# Run FastAPI app
|
| 137 |
+
if __name__ == "__main__":
|
| 138 |
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|