File size: 17,643 Bytes
5dcf7d0 07b1df4 3371607 f764335 5dcf7d0 4581b9c 5dcf7d0 0f25724 8d7afe4 616d8b2 5dcf7d0 3371607 fb8f91f 2454d1f b6f52d4 fb8f91f 697c68e 3371607 1245b1b 3371607 5dcf7d0 2b8e58c 5dcf7d0 f0d0df4 2b8e58c 4d0d752 2b8e58c 4d0d752 b4a1659 4d0d752 1d83294 b4a1659 2b8e58c 5dcf7d0 2b8e58c 1d83294 bbd2b34 2b8e58c 5dcf7d0 d001f2c 5dcf7d0 616d8b2 d001f2c 5dcf7d0 145bc51 5dcf7d0 3371607 5dcf7d0 2b8e58c 4d0d752 2b8e58c 4d0d752 2b8e58c 5dcf7d0 2b8e58c 5dcf7d0 2b8e58c 3371607 5dcf7d0 3371607 5dcf7d0 9cf4bdf 5dcf7d0 9cf4bdf 5dcf7d0 3371607 b6a9752 373e6ff 56b8e2d dd53bc5 56b8e2d dd53bc5 0f25724 7af2f44 30edefa 5dcf7d0 616d8b2 5dcf7d0 616d8b2 5dcf7d0 3371607 5dcf7d0 616d8b2 5dcf7d0 616d8b2 5dcf7d0 7af2f44 5dcf7d0 a5a20d5 7af2f44 a5a20d5 7af2f44 a5a20d5 7af2f44 a5a20d5 92764d6 a5a20d5 92764d6 a5a20d5 7af2f44 a5a20d5 7af2f44 a5a20d5 92764d6 a5a20d5 92764d6 a5a20d5 e1317b6 a5a20d5 e1317b6 755ba90 e1317b6 a5a20d5 7af2f44 a5a20d5 e1317b6 a5a20d5 7af2f44 a5a20d5 7af2f44 b6f52d4 2ed695d b6f52d4 697c68e 5dcf7d0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 |
import asyncio
from zenka import zenka, ZZZError, CacheConfig, Lang
import os
from enum import Enum
from enkacard import encbanner
from enkanetwork import EnkaNetworkAPI
from starrailcard.src.api import enka
import concurrent.futures
import requests
import traceback
from fastapi import FastAPI,Query
from io import BytesIO
from fastapi.responses import JSONResponse
import enkacard
import starrailcard
import enkanetwork
import uvicorn
import cloudinary
import cloudinary.uploader
from cloudinary.utils import cloudinary_url
import pydantic
from pydantic import BaseModel
import genshin
from packaging import version
# Check Pydantic version
pydantic_version = version.parse(pydantic.__version__)
if pydantic_version.major >= 2:
# Use Pydantic v2-compatible imports or replacements
print("Running with Pydantic v2")
# Add any required adjustments for Pydantic v2 here
else:
# Use Pydantic v1-compatible imports or replacements
print("Running with Pydantic v1")
# No changes needed for older code compatible with v1
app = FastAPI()
# Cloudinary configuration
cloudinary.config(
cloud_name=os.getenv("cloudname"),
api_key=os.getenv("key"),
api_secret=os.getenv("secret"),
secure=True
)
# Genshin Impact card creation
async def genshin_card(id, designtype,character_id=None, character_art_url=None):
# Use the provided character ID and character art URL from user input, if available
character_art = {str(character_id): character_art_url} if character_id and character_art_url else None
async with encbanner.ENC(uid=str(id), character_art=character_art) as encard:
return await encard.creat(template=(2 if str(designtype) == "2" else 1))
# Star Rail card creation with optional character ID and cookies
async def starrail_card(id, designtype, character_id=None, character_art_url=None, ltmid_v2=None, ltoken_v2=None, ltuid_v2=None):
character_art = {str(character_id): character_art_url} if character_id and character_art_url else None
# Use cookies if provided
if ltmid_v2 and ltoken_v2 and ltuid_v2:
cookie = {
"ltmid_v2": ltmid_v2,
"ltoken_v2": ltoken_v2,
"ltuid_v2": ltuid_v2
}
async with starrailcard.HoYoCard(cookie=cookie,seeleland=True, remove_logo=True, character_art=character_art,boost_speed = True) as card:
return await card.create(id,force_update = True, style=(2 if str(designtype) == "2" else 1))
else:
# Fallback to the existing process
async with starrailcard.Card(seeleland=True, remove_logo=True, character_art=character_art,boost_speed = True,enka=True) as card:
return await card.create(id,force_update = True, style=(2 if str(designtype) == "2" else 1))
# Star Rail profile creation
async def starrail_profile(id):
async with starrailcard.Card(remove_logo=True, seeleland=True,boost_speed = True,enka=True) as card:
return await card.create_profile(id,force_update = True, style=2)
# Genshin profile creation
async def genshinprofile(id):
async with encbanner.ENC(uid=id) as encard:
return await encard.profile(card=True)
# Route for Genshin Impact
@app.get("/genshin/{id}")
async def genshin_characters(id: int, design: str = "1", character_id: int = None, character_art_url: str = None):
try:
result = await genshin_card(id, design, character_id, character_art_url)
characters = process_images(result, id)
return JSONResponse(content={'response': characters})
except enkanetwork.exception.VaildateUIDError:
return JSONResponse(content={'error': 'Invalid UID. Please check your UID.'}, status_code=400)
except enkacard.enc_error.ENCardError:
return JSONResponse(content={'error': 'Enable display of the showcase in the game or add characters there.'}, status_code=400)
except Exception as e:
return JSONResponse(content={'error': 'UNKNOWN ERR: ' + str(e)}, status_code=500)
# Route for Star Rail with optional character ID
@app.get("/starrail/{id}")
async def starrail_characters(
id: int,
design: str = "1",
character_id: int = None,
character_art_url: str = None,
ltmid_v2: str = None,
ltoken_v2: str = None,
ltuid_v2: str = None
):
try:
# Call starrail_card with cookies if provided
result = await starrail_card(id, design, character_id, character_art_url, ltmid_v2, ltoken_v2, ltuid_v2)
characters = process_images(result, id)
return JSONResponse(content={'response': characters})
except Exception as e:
return JSONResponse(content={'error': 'UNKNOWN ERR: ' + str(e)}, status_code=500)
# Route for Star Rail profile
@app.get("/starrail/profile/{id}")
async def starrail_profile_route(id: int):
try:
result = await starrail_profile(id)
profile_data = process_profile(result)
return JSONResponse(content={'response': profile_data})
except Exception as e:
return JSONResponse(content={'error': 'UNKNOWN ERR: ' + str(e)}, status_code=500)
# Route for Genshin profile
@app.get("/genshin/profile/{id}")
async def genshin_profile_route(id: int):
try:
result = await genshinprofile(id)
profile_data = process_profile(result)
return JSONResponse(content={'response': profile_data})
except Exception as e:
return JSONResponse(content={'error': 'UNKNOWN ERR: ' + str(e)}, status_code=500)
@app.get("/")
def root():
return "خدتك عليه"
@app.get("/ايه")
def root():
return "خدتك عليه"
@app.get("/update")
async def update():
try:
# Update assets using EnkaNetworkAPI and ApiEnkaNetwork
async def update_assets() -> None:
async with EnkaNetworkAPI() as client:
await client.update_assets()
await enka.ApiEnkaNetwork().update_assets()
await asyncio.create_task(update_assets())
return JSONResponse(content={'response': 'Assets updated successfully'})
except Exception as e:
error_details = traceback.format_exc()
return JSONResponse(
content={'error': f'UNKNOWN ERR: {str(e)}', 'details': error_details},
status_code=500
)
@app.get("/updatezzz")
async def maiin():
try:
async with zenka.Client() as client:
await client.update_asset()
return JSONResponse(content={'response': 'Assets updated successfully'})
except ZZZError as e:
error_details = traceback.format_exc()
return JSONResponse(
content={'error': f'UNKNOWN ERR: {str(e)}', 'details': error_details},
status_code=500
)
# Helper function to upload the image to Cloudinary
def upload_image(data, character_id, player_id):
try:
# Set the public_id to include the character ID and the given player ID
public_id = f"{character_id}_{player_id}"
# Upload image to Cloudinary with the specified public_id
upload_result = cloudinary.uploader.upload(data, folder="card_images", public_id=public_id, invalidate=True)
# Get the secure URL of the uploaded image
return upload_result["secure_url"]
except Exception as e:
raise Exception(f"Cloudinary upload error: {str(e)}")
# Helper function to upload the image to Cloudinary without player or character ID
def upload_imagee(data):
try:
# Upload image to Cloudinary without specifying a public_id
upload_result = cloudinary.uploader.upload(data, folder="card_images", invalidate=True)
# Get the secure URL of the uploaded image
return upload_result["secure_url"]
except Exception as e:
raise Exception(f"Cloudinary upload error: {str(e)}")
# Process individual image card
def process_image(dt, player_id):
with BytesIO() as byte_io:
dt.card.save(byte_io, "PNG")
byte_io.seek(0)
# Upload the image using the character's ID and player ID
image_url = upload_image(byte_io, dt.id, player_id)
return {
"name": dt.name,
"id": dt.id,
"url": image_url
}
# Process the profile image
def process_profile(profile_card):
with BytesIO() as byte_io:
profile_card.card.save(byte_io, "PNG")
byte_io.seek(0)
# Upload the image without using the character or player ID
image_url = upload_imagee(byte_io)
return {
"url": image_url,
}
from io import BytesIO
def process_profilee(profile_card):
# Ensure profile_card contains an image
if not profile_card.cards or not isinstance(profile_card.cards, list):
raise ValueError("Invalid profile_card: 'cards' is missing or not a list.")
profile_image = profile_card.cards[0].card # Extract the PIL image from the first card
with BytesIO() as byte_io:
profile_image.save(byte_io, "PNG") # Save the image as PNG
byte_io.seek(0)
image_url = upload_imagee(byte_io) # Upload the image
return {
"url": image_url,
}
# Process all the images returned
def process_images(result, player_id):
characters = []
with concurrent.futures.ThreadPoolExecutor() as executor:
futures = [executor.submit(process_image, dt, player_id) for dt in result.card]
for future in concurrent.futures.as_completed(futures):
try:
characters.append(future.result())
except Exception as e:
print(f"Error processing image: {e}")
return characters
def process_imagess(result, player_id):
characters = []
with concurrent.futures.ThreadPoolExecutor() as executor:
futures = [executor.submit(process_image, dt, player_id) for dt in result.cards]
for future in concurrent.futures.as_completed(futures):
try:
characters.append(future.result())
except Exception as e:
print(f"Error processing image: {e}")
return characters
# ZZZ Card and Profile creation functions
async def zenless_card(uid, character_id=None, character_art=None):
config = zenka.Config(
asset_save=True,
hide_uid=False,
)
try:
# Simplified to match your example exactly
async with zenka.Client(
lang=Lang.EN,
config=config,
character_art=character_art,
character_id=character_id
) as client:
data = await client.card(uid)
return data
except ZZZError as e:
raise Exception(f"Zenless Zone Zero Error: Code:{e.code} Message: {e.text}")
except Exception as e:
# Add more detailed error information
import traceback
error_details = traceback.format_exc()
raise Exception(f"Zenless Zone Zero Error: {str(e)}\n{error_details}")
async def zenless_profile(uid):
config = zenka.Config(
asset_save=True,
hide_uid=False,
)
try:
# Simplified to match your example exactly
async with zenka.Client(
lang=Lang.EN,
config=config
) as client:
data = await client.profile(uid)
return data
except ZZZError as e:
raise Exception(f"Zenless Zone Zero Error: Code:{e.code} Message: {e.text}")
except Exception as e:
# Add more detailed error information
import traceback
error_details = traceback.format_exc()
raise Exception(f"Zenless Zone Zero Error: {str(e)}\n{error_details}")
# Add these routes to your FastAPI app
@app.get("/zenless/{uid}")
async def zenless_characters(uid: int, character_id: str = None, character_art_url: str = None):
try:
# Process character_id from string to list if provided
char_id = None
if character_id:
char_id = [int(id) if id.isdigit() else id for id in character_id.split(',')]
# Process character_art from URL to dict if provided
char_art = None
if character_id and character_art_url:
# Create a dictionary mapping character IDs to art URLs
char_ids = char_id if isinstance(char_id, list) else []
# The key in the dictionary must be a string
if char_ids:
char_art = {char_ids[0]: character_art_url}
result = await zenless_card(uid, char_id, char_art)
characters = process_imagess(result, uid)
return JSONResponse(content={'response': characters})
except Exception as e:
return JSONResponse(content={'error': 'UNKNOWN ERR: ' + str(e)}, status_code=500)
async def zenless_card(uid, character_id=None, character_art=None):
config = zenka.Config(
asset_save=True,
hide_uid=False, # Fixed typo from Falde to False
)
try:
# Make sure character_art is properly formatted as a dictionary
async with zenka.Client(
lang=Lang.EN,
config=config,
character_art=character_art, # This should be a dict like {"1121": "https://example.com/image.webp"}
character_id=character_id # This should be a list like [1151, "1121"]
) as client:
data = await client.card(uid)
return data
except ZZZError as e:
raise Exception(f"Zenless Zone Zero Error: Code:{e.code} Message: {e.text}")
except Exception as e:
import traceback
error_details = traceback.format_exc()
raise Exception(f"Zenless Zone Zero Error: {str(e)}\n{error_details}")
@app.get("/zenless/profile/{uid}")
async def zenless_profile_route(uid: int):
try:
result = await zenless_profile(uid)
profile_data = process_profilee(result)
return JSONResponse(content={'response': profile_data})
except Exception as e:
return JSONResponse(content={'error': 'UNKNOWN ERR: ' + str(e)}, status_code=500)
@app.get("/check_train_score")
async def check_train_score(ltoken_v2: str, ltuid_v2: str):
"""
Check if the Star Rail training score is at maximum (500).
Parameters:
- ltoken_v2: Your ltoken_v2 cookie value
- ltuid_v2: Your ltuid_v2 cookie value as an integer
Returns:
- "yes" if train score is 500
- "no" if train score is less than 500
"""
try:
# Convert ltuid_v2 to int if it's passed as a string
ltuid_v2_int = int(ltuid_v2)
# Set up cookies for authentication
cookies = {
"ltoken_v2": ltoken_v2,
"ltuid_v2": ltuid_v2_int
}
# Initialize genshin client
client = genshin.Client(cookies)
# Fetch Star Rail notes data
data = await client.get_starrail_notes()
# Check train score
if data.current_train_score >= 500:
return "yes"
else:
return "no"
except genshin.errors.InvalidCookies:
raise HTTPException(status_code=401, detail="Invalid cookies provided")
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error checking train score: {str(e)}")
class GameOptions(str, Enum):
STARRAIL = "hsr"
GENSHIN = "genshin"
HONKAI = "hi3rd"
ZZZ = "zenless"
class RewardInfo(BaseModel):
name: str
amount: int
icon: str = None
@app.get("/claim_daily_reward", response_model=dict)
async def claim_daily_reward(
ltoken_v2: str,
ltuid_v2: str,
game: GameOptions = Query(..., description="Game to claim rewards for")
):
"""
Claim daily reward for selected Hoyoverse game.
Parameters:
- ltoken_v2: Your ltoken_v2 cookie value
- ltuid_v2: Your ltuid_v2 cookie value as an integer
- game: Game to claim rewards for (hsr, genshin, hi3rd, zenless)
Returns:
- Claim result information including reward details
"""
try:
# Convert ltuid_v2 to int if it's passed as a string
ltuid_v2_int = int(ltuid_v2)
# Set up cookies for authentication
cookies = {
"ltoken_v2": ltoken_v2,
"ltuid_v2": ltuid_v2_int
}
# Initialize genshin client
client = genshin.Client(cookies)
# Map the game option to genshin library enum
game_map = {
GameOptions.STARRAIL: genshin.Game.STARRAIL,
GameOptions.GENSHIN: genshin.Game.GENSHIN,
GameOptions.HONKAI: genshin.Game.HONKAI,
GameOptions.ZZZ: genshin.Game.ZZZ
}
selected_game = game_map[game]
# Claim daily reward
result = await client.claim_daily_reward(game=selected_game)
# Parse reward information
reward = {
"name": getattr(result, "name", "Unknown"),
"amount": getattr(result, "amount", 0),
"icon": getattr(result, "icon", None)
}
return {
"success": True,
"message": f"Successfully claimed daily reward for {game}",
"reward": reward
}
except genshin.errors.InvalidCookies:
raise HTTPException(status_code=401, detail="Invalid cookies provided")
except genshin.errors.AlreadyClaimed:
return {
"success": False,
"message": f"Daily reward for {game} already claimed today"
}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error claiming daily reward: {str(e)}")
if __name__ == "__main__":
uvicorn.run("main:app", host="0.0.0.0", port=7860, workers=8, timeout_keep_alive=60000) |