""" NationStates High-Value Trading Card Tracker (CLI) =================================================== Runs a full scan pipeline using the NationStates API directly. 1. Scans cards by ID range for Legendary/Epic (Low ID filter) 2. Checks if flagged nations are dead (CTE filter) 3. Matches against historical names 4. Checks live market prices 5. Generates dashboard.html COMPLIANCE: This script NEVER executes automated trades. All purchases are manual via generated URL links. Rate limit: 1.2s between every API request. Usage: python tracker.py [--max-id 10000] [--price-checks 30] """ import sys import os import time import sqlite3 from datetime import datetime # Add script directory to path for imports SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, SCRIPT_DIR) from core import ( init_db, scan_low_id_cards, scan_cte_cards, scan_historical_cards, check_target_prices, SEASON, RATE_LIMIT_SECONDS, THRESHOLDS ) DB_PATH = os.path.join(SCRIPT_DIR, "cards.db") DASHBOARD_PATH = os.path.join(SCRIPT_DIR, "dashboard.html") # Defaults (can be overridden via command line) DEFAULT_MAX_ID = 10000 DEFAULT_PRICE_CHECKS = 30 # ========================================== # CLI CALLBACKS # ========================================== def scan_callback(status, card_id, card): if status == "found": print(f" ★ ID:{card_id} — {card['name']} ({card['rarity']}) MV:{card['market_value']}") else: name = card["name"] if card else "not found" rarity = card["rarity"] if card else "" if card: print(f" · ID:{card_id} — {name} ({rarity}) skip") else: print(f" · ID:{card_id} — not found") def cte_callback(status, card_id, name): if status == "cte": print(f" 💀 {name} (ID:{card_id}) — DEAD") else: print(f" ✓ {name} (ID:{card_id}) — alive") # ========================================== # DASHBOARD GENERATION # ========================================== def generate_dashboard(alerts): """Generate HTML dashboard.""" print("\n[HTML] Generating dashboard...") conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute("SELECT COUNT(*) FROM cards") total_cards = c.fetchone()[0] c.execute("SELECT COUNT(*) FROM targets") total_targets = c.fetchone()[0] c.execute(""" SELECT card_id, name, rarity, flag_reason, lowest_ask, last_checked, card_url FROM targets ORDER BY CASE rarity WHEN 'legendary' THEN 1 WHEN 'epic' THEN 2 ELSE 3 END, lowest_ask ASC """) all_targets = c.fetchall() conn.close() now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") rarity_colors = { "legendary": "#FFD700", "epic": "#FF9800", "ultra-rare": "#9C27B0", "rare": "#2196F3", "uncommon": "#4CAF50", "common": "#8B8B8B" } alerts_html = "" if alerts: alerts_html = f'

🚨 {len(alerts)} Undervalued Cards!

' for a in alerts: color = rarity_colors.get(a["rarity"], "#fff") alerts_html += ( f'
{a["rarity"].upper()} ' f'{a["name"]} (ID:{a["card_id"]})
' f'Reason: {a["reason"]}
' f'Ask: {a["ask"]:.2f} (threshold: {a["threshold"]})
' f'🛒 View / Buy
' ) alerts_html += "
" else: alerts_html = '
✅ No undervalued cards below threshold.
' table_rows = "" for row in all_targets: card_id, name, rarity, flag_reason, lowest_ask, last_checked, card_url = row color = rarity_colors.get(rarity, "#fff") ask_display = f"{lowest_ask:.2f}" if lowest_ask is not None else "—" checked_display = last_checked[:16] if last_checked else "—" table_rows += ( f'{card_id}{name}' f'{rarity}' f'{flag_reason}{ask_display}' f'{checked_display}' f'View' ) html = f""" NS Card Tracker

🏆 NS High-Value Card Tracker

Generated: {now} | Season {SEASON} | API-only (no dumps)

{total_cards}
Cards Scanned
{total_targets}
Targets
{len(alerts)}
Undervalued
{alerts_html}

📋 All Targets

{table_rows}
IDNameRarityReasonAskCheckedLink
⚠️ Read-only tool. No automated trades. Rate limit: {RATE_LIMIT_SECONDS}s/request.
""" with open(DASHBOARD_PATH, "w", encoding="utf-8") as f: f.write(html) print(f"[HTML] Saved: {DASHBOARD_PATH}") # ========================================== # MAIN # ========================================== def main(): max_id = DEFAULT_MAX_ID price_checks = DEFAULT_PRICE_CHECKS for i, arg in enumerate(sys.argv[1:]): if arg == "--max-id" and i + 2 <= len(sys.argv[1:]): max_id = int(sys.argv[i + 2]) if arg == "--price-checks" and i + 2 <= len(sys.argv[1:]): price_checks = int(sys.argv[i + 2]) print("=" * 50) print(" NS High-Value Card Tracker (API-Only)") print(" No dump files needed. No automated trades.") print(f" Scan range: 1–{max_id} | Price checks: {price_checks}") print("=" * 50) start = time.time() init_db(DB_PATH) # Step 1: Low ID scan print(f"\n[SCAN] Scanning cards 1–{max_id} for Legendary/Epic...") found = scan_low_id_cards(DB_PATH, max_id, callback=scan_callback) print(f"[SCAN] Done. Found {len(found)} Legendary/Epic cards.") # Step 2: CTE check print(f"\n[CTE] Checking cards for dead nations...") cte = scan_cte_cards(DB_PATH, callback=cte_callback) print(f"[CTE] Found {len(cte)} dead nation cards.") # Step 3: Historical check print(f"\n[HIST] Checking against historical names...") hist = scan_historical_cards(DB_PATH) print(f"[HIST] Found {len(hist)} historical name matches.") # Step 4: Price check print(f"\n[PRICE] Checking live prices for up to {price_checks} targets...") alerts, errors = check_target_prices(DB_PATH, price_checks) if errors: print(f" ⚠️ {errors} API errors during price check") if alerts: print(f"\n🚨 {len(alerts)} UNDERVALUED CARDS:") for a in alerts: print(f" {a['name']} (ID:{a['card_id']}) {a['rarity']} — Ask:{a['ask']:.2f} < {a['threshold']}") print(f" {a['url']}") else: print("\n✅ No undervalued cards below threshold.") # Step 5: Dashboard generate_dashboard(alerts) elapsed = time.time() - start print(f"\n{'=' * 50}") print(f" Done in {elapsed:.0f}s. Open dashboard.html to view.") print(f"{'=' * 50}") if __name__ == "__main__": main()