Migrated all major card creation workflows to pd-cards CLI: live-series: - update: Full FanGraphs/BBRef card generation with CLI options - status: Show cardset status from database retrosheet: - process: Historical Retrosheet data processing - arms: Generate outfield arm ratings from play-by-play - validate: Check for position anomalies in cardsets - defense: Fetch defensive stats from Baseball Reference scouting: - batters: Generate batting scouting reports - pitchers: Generate pitching scouting reports - all: Generate all reports at once upload: - s3: Upload card images to AWS S3 - check: Validate cards without uploading - refresh: Re-generate and re-upload card images Updated CLAUDE.md with comprehensive CLI documentation. Legacy scripts remain available but CLI is now the primary interface. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
223 lines
6.9 KiB
Python
223 lines
6.9 KiB
Python
"""
|
|
Card image upload commands.
|
|
|
|
Commands for uploading card images to AWS S3.
|
|
"""
|
|
|
|
import asyncio
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
import typer
|
|
from rich.console import Console
|
|
|
|
app = typer.Typer(no_args_is_help=True)
|
|
console = Console()
|
|
|
|
|
|
@app.command()
|
|
def s3(
|
|
cardset: str = typer.Option(..., "--cardset", "-c", help="Cardset name to upload"),
|
|
start_id: Optional[int] = typer.Option(None, "--start-id", help="Player ID to start from (for resuming)"),
|
|
limit: Optional[int] = typer.Option(None, "--limit", "-l", help="Limit number of cards to process"),
|
|
html: bool = typer.Option(False, "--html", help="Upload HTML preview cards instead of PNG"),
|
|
skip_batters: bool = typer.Option(False, "--skip-batters", help="Skip batting cards"),
|
|
skip_pitchers: bool = typer.Option(False, "--skip-pitchers", help="Skip pitching cards"),
|
|
upload: bool = typer.Option(True, "--upload/--no-upload", help="Upload to S3"),
|
|
update_urls: bool = typer.Option(True, "--update-urls/--no-update-urls", help="Update player URLs in database"),
|
|
dry_run: bool = typer.Option(False, "--dry-run", "-n", help="Preview without uploading"),
|
|
):
|
|
"""
|
|
Upload card images to AWS S3.
|
|
|
|
Fetches card images from Paper Dynasty API and uploads to S3 bucket.
|
|
|
|
Example:
|
|
pd-cards upload s3 --cardset "2005 Live" --limit 10
|
|
"""
|
|
console.print()
|
|
console.print("=" * 70)
|
|
console.print(f"[bold]S3 UPLOAD - {cardset}[/bold]")
|
|
console.print("=" * 70)
|
|
|
|
console.print(f"Cardset: {cardset}")
|
|
if start_id:
|
|
console.print(f"Starting from player ID: {start_id}")
|
|
if limit:
|
|
console.print(f"Limit: {limit} cards")
|
|
if html:
|
|
console.print("Mode: HTML preview cards")
|
|
if skip_batters:
|
|
console.print("Skipping: Batting cards")
|
|
if skip_pitchers:
|
|
console.print("Skipping: Pitching cards")
|
|
console.print(f"Upload to S3: {upload and not dry_run}")
|
|
console.print(f"Update URLs: {update_urls and not dry_run}")
|
|
console.print()
|
|
|
|
if dry_run:
|
|
console.print("[yellow]DRY RUN - no uploads will be made[/yellow]")
|
|
console.print()
|
|
console.print("[green]Validation passed - ready to run[/green]")
|
|
raise typer.Exit(0)
|
|
|
|
try:
|
|
import sys
|
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
|
|
|
import check_cards_and_upload as ccu
|
|
|
|
# Configure the module's globals
|
|
ccu.CARDSET_NAME = cardset
|
|
ccu.START_ID = start_id
|
|
ccu.TEST_COUNT = limit if limit else 9999
|
|
ccu.HTML_CARDS = html
|
|
ccu.SKIP_BATS = skip_batters
|
|
ccu.SKIP_ARMS = skip_pitchers
|
|
ccu.UPLOAD_TO_S3 = upload
|
|
ccu.UPDATE_PLAYER_URLS = update_urls
|
|
|
|
# Re-initialize S3 client if uploading
|
|
if upload:
|
|
import boto3
|
|
ccu.s3_client = boto3.client('s3', region_name=ccu.AWS_REGION)
|
|
else:
|
|
ccu.s3_client = None
|
|
|
|
console.print("[bold]Starting S3 upload...[/bold]")
|
|
console.print()
|
|
|
|
asyncio.run(ccu.main([]))
|
|
|
|
console.print()
|
|
console.print("=" * 70)
|
|
console.print(f"[bold green]✓ S3 UPLOAD COMPLETE[/bold green]")
|
|
console.print("=" * 70)
|
|
|
|
except ImportError as e:
|
|
console.print(f"[red]Error importing modules: {e}[/red]")
|
|
raise typer.Exit(1)
|
|
except Exception as e:
|
|
console.print(f"[red]Error: {e}[/red]")
|
|
import traceback
|
|
traceback.print_exc()
|
|
raise typer.Exit(1)
|
|
|
|
|
|
@app.command()
|
|
def refresh(
|
|
cardset: str = typer.Option(..., "--cardset", "-c", help="Cardset name"),
|
|
limit: Optional[int] = typer.Option(None, "--limit", "-l", help="Limit number of cards"),
|
|
dry_run: bool = typer.Option(False, "--dry-run", "-n", help="Preview without refreshing"),
|
|
):
|
|
"""
|
|
Refresh card images for a cardset.
|
|
|
|
Re-generates and re-uploads card images.
|
|
|
|
Example:
|
|
pd-cards upload refresh --cardset "2005 Live" --limit 10
|
|
"""
|
|
console.print()
|
|
console.print("=" * 70)
|
|
console.print(f"[bold]CARD REFRESH - {cardset}[/bold]")
|
|
console.print("=" * 70)
|
|
|
|
console.print(f"Cardset: {cardset}")
|
|
if limit:
|
|
console.print(f"Limit: {limit} cards")
|
|
|
|
if dry_run:
|
|
console.print("[yellow]DRY RUN - no changes will be made[/yellow]")
|
|
console.print()
|
|
console.print("[green]Validation passed - ready to run[/green]")
|
|
raise typer.Exit(0)
|
|
|
|
try:
|
|
import sys
|
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
|
|
|
import refresh_cards as rc
|
|
|
|
# Configure the module
|
|
rc.CARDSET_NAME = cardset
|
|
rc.TEST_COUNT = limit if limit else 9999
|
|
|
|
console.print("[bold]Starting card refresh...[/bold]")
|
|
console.print()
|
|
|
|
asyncio.run(rc.main([]))
|
|
|
|
console.print()
|
|
console.print("=" * 70)
|
|
console.print(f"[bold green]✓ CARD REFRESH COMPLETE[/bold green]")
|
|
console.print("=" * 70)
|
|
|
|
except ImportError as e:
|
|
console.print(f"[red]Error importing modules: {e}[/red]")
|
|
console.print("Try: python refresh_cards.py")
|
|
raise typer.Exit(1)
|
|
except Exception as e:
|
|
console.print(f"[red]Error: {e}[/red]")
|
|
import traceback
|
|
traceback.print_exc()
|
|
raise typer.Exit(1)
|
|
|
|
|
|
@app.command()
|
|
def check(
|
|
cardset: str = typer.Option(..., "--cardset", "-c", help="Cardset name"),
|
|
limit: Optional[int] = typer.Option(None, "--limit", "-l", help="Limit number of cards to check"),
|
|
output_dir: Path = typer.Option(Path("data-output"), "--output", "-o", help="Output directory"),
|
|
):
|
|
"""
|
|
Check and validate card images without uploading.
|
|
|
|
Downloads card images and saves locally for review.
|
|
|
|
Example:
|
|
pd-cards upload check --cardset "2005 Live" --limit 10
|
|
"""
|
|
console.print()
|
|
console.print("=" * 70)
|
|
console.print(f"[bold]CARD CHECK - {cardset}[/bold]")
|
|
console.print("=" * 70)
|
|
|
|
console.print(f"Cardset: {cardset}")
|
|
if limit:
|
|
console.print(f"Limit: {limit} cards")
|
|
console.print(f"Output: {output_dir}")
|
|
console.print()
|
|
|
|
try:
|
|
import sys
|
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
|
|
|
import check_cards_and_upload as ccu
|
|
|
|
# Configure for check-only mode
|
|
ccu.CARDSET_NAME = cardset
|
|
ccu.START_ID = None
|
|
ccu.TEST_COUNT = limit if limit else 9999
|
|
ccu.HTML_CARDS = False
|
|
ccu.UPLOAD_TO_S3 = False
|
|
ccu.UPDATE_PLAYER_URLS = False
|
|
ccu.s3_client = None
|
|
|
|
console.print("[bold]Starting card check...[/bold]")
|
|
console.print()
|
|
|
|
asyncio.run(ccu.main([]))
|
|
|
|
console.print()
|
|
console.print("[green]✓ Card check complete[/green]")
|
|
|
|
except ImportError as e:
|
|
console.print(f"[red]Error importing modules: {e}[/red]")
|
|
raise typer.Exit(1)
|
|
except Exception as e:
|
|
console.print(f"[red]Error: {e}[/red]")
|
|
import traceback
|
|
traceback.print_exc()
|
|
raise typer.Exit(1)
|