""" Fetch updated card images for the 20 fixed left-handed players, upload to AWS S3, and update player image URLs """ import asyncio import datetime import boto3 import aiohttp from io import BytesIO from db_calls import db_get, db_patch, url_get, DB_URL from exceptions import logger # AWS Configuration AWS_BUCKET_NAME = 'paper-dynasty' AWS_REGION = 'us-east-1' S3_BASE_URL = f'https://{AWS_BUCKET_NAME}.s3.{AWS_REGION}.amazonaws.com' CARDSET_ID = 27 # Initialize S3 client s3_client = boto3.client('s3', region_name=AWS_REGION) # List of player IDs that were fixed FIXED_PLAYER_IDS = [ 13015, 13017, 13020, 13030, 13032, 13034, 13037, 13045, 13047, 13048, 13053, 13058, 13062, 13068, 13070, 13071, 13077, 13082, 13084, 13090 ] async def fetch_card_image(session, card_url: str, timeout: int = 6) -> bytes: """Fetch card image from URL and return raw bytes.""" try: async with session.get(card_url, timeout=timeout) as r: if r.status == 200: return await r.read() else: error_text = await r.text() raise ValueError(f'Status {r.status}: {error_text}') except Exception as e: raise ValueError(f'Failed to fetch card: {str(e)}') def upload_to_s3(image_bytes: bytes, s3_key: str, content_type: str = 'image/png') -> str: """Upload image bytes to S3 and return the URL.""" try: s3_client.put_object( Bucket=AWS_BUCKET_NAME, Key=s3_key, Body=image_bytes, ContentType=content_type, CacheControl='public, max-age=31536000' # 1 year cache ) s3_url = f'{S3_BASE_URL}/{s3_key}' return s3_url except Exception as e: raise ValueError(f'Failed to upload to S3: {str(e)}') async def process_player(session, player_id: int, release_date: str): """Fetch card, upload to S3, and update player URL.""" try: print(f"\nProcessing player {player_id}...") # Fetch current player data player_data = await db_get('players', object_id=player_id) player_name = player_data.get('p_name', 'Unknown') print(f" Name: {player_name}") # Build card URL (API endpoint) card_api_url = f'{DB_URL}/v2/players/{player_id}/battingcard?d={release_date}' # Fetch the card image print(f" Fetching card image...") image_bytes = await fetch_card_image(session, card_api_url) print(f" ✅ Fetched {len(image_bytes)} bytes") # Build S3 key (without query parameters!) s3_key = f'cards/cardset-{CARDSET_ID:03d}/player-{player_id}/battingcard.png' # Upload to S3 print(f" Uploading to S3...") s3_url_base = upload_to_s3(image_bytes, s3_key) # Add cache-busting query parameter to the URL s3_url = f'{s3_url_base}?d={release_date}' print(f" ✅ Uploaded to S3") # Update player record with S3 URL print(f" Updating player image URL...") await db_patch('players', object_id=player_id, params=[('image', s3_url)]) print(f" ✅ Updated player record") return {'success': True, 'player_id': player_id, 'name': player_name, 's3_url': s3_url} except Exception as e: print(f" ❌ Error: {str(e)}") return {'success': False, 'player_id': player_id, 'error': str(e)} async def main(): # Use timestamp to bust cache completely import time timestamp = int(time.time()) release_date = f'2025-11-25-{timestamp}' print(f"{'='*60}") print(f"Uploading cards to S3 for 20 left-handed players") print(f"Release date: {release_date}") print(f"{'='*60}") successes = [] errors = [] async with aiohttp.ClientSession() as session: for player_id in FIXED_PLAYER_IDS: result = await process_player(session, player_id, release_date) if result['success']: successes.append(result) else: errors.append(result) print(f"\n{'='*60}") print(f"SUMMARY") print(f"{'='*60}") print(f"Successes: {len(successes)}") print(f"Errors: {len(errors)}") print(f"Total: {len(FIXED_PLAYER_IDS)}") if errors: print(f"\nErrors:") for err in errors: print(f" Player {err['player_id']}: {err.get('error', 'Unknown error')}") if successes: print(f"\nFirst S3 URL: {successes[0]['s3_url']}") print(f"{'='*60}") if __name__ == '__main__': asyncio.run(main())