diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9d2c59c --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +# General +__pycache__/ +*.py[cod] +*$py.class +*.swp +*.swo +*.tmp +*.log +.DS_Store +Thumbs.db + +# Virtual Environment +venv/ +.venv/ +env/ +.env + +# Build and Distribution +build/ +dist/ +*.spec +# Exception: We want to keep our custom spec file +!UmamusumeCardManager.spec +*.exe +*.zip +*.pkg + +# Database +# Ignore the running database, but keep the seed/template +database/*.db +!database/umamusume_seed.db + +# VS Code +.vscode/ + +# Project Specific +# We are allowing .txt and .html now (removing previous blocks) +# If there are specific large generated files, add them here. diff --git a/UmamusumeCardManager.spec b/UmamusumeCardManager.spec new file mode 100644 index 0000000..e18f0c4 --- /dev/null +++ b/UmamusumeCardManager.spec @@ -0,0 +1,38 @@ +# -*- mode: python ; coding: utf-8 -*- + + +a = Analysis( + ['main.py'], + pathex=[], + binaries=[], + datas=[('images', 'images'), ('database/umamusume_seed.db', 'database'), ('version.py', '.'), ('updater', 'updater')], + hiddenimports=['requests'], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + noarchive=False, + optimize=0, +) +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.datas, + [], + name='UmamusumeCardManager', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=False, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) diff --git a/build.py b/build.py new file mode 100644 index 0000000..0ba0985 --- /dev/null +++ b/build.py @@ -0,0 +1,37 @@ +import subprocess +import sys +import os + +def main(): + print("šŸš€ Starting Build Process...\n") + + # Get python interpreter + python_exe = sys.executable + + # 1. Prepare Release Database + print("--------------------------------") + print("Step 1/2: Preparing Database") + print("--------------------------------") + script_path = os.path.join("scripts", "prepare_release_db.py") + ret = subprocess.call([python_exe, script_path]) + if ret != 0: + print("āŒ Error: Database preparation failed.") + sys.exit(1) + + print("\n") + + # 2. Run PyInstaller + print("--------------------------------") + print("Step 2/2: Building Executable") + print("--------------------------------") + # We use 'pyinstaller' as a command. If it's not in path, we might need to assume it's a module + # Try running as module first for safety: python -m PyInstaller + ret = subprocess.call([python_exe, "-m", "PyInstaller", "UmamusumeCardManager.spec", "--noconfirm"]) + if ret != 0: + print("āŒ Error: PyInstaller build failed.") + sys.exit(1) + + print("\nāœ… Build Complete! Executable is in in 'dist' folder.") + +if __name__ == "__main__": + main() diff --git a/check_paths.py b/check_paths.py new file mode 100644 index 0000000..a32ae14 --- /dev/null +++ b/check_paths.py @@ -0,0 +1,20 @@ + +import sqlite3 +import os + +DB_PATH = r"y:\Keith\umamusuma card application\database\umamusume.db" +print(f"Checking DB at: {DB_PATH}") + +try: + conn = sqlite3.connect(DB_PATH) + cur = conn.cursor() + cur.execute("SELECT card_id, name, image_path FROM support_cards LIMIT 5") + rows = cur.fetchall() + + print("\nSample Card Data:") + for row in rows: + print(f"ID: {row[0]}, Name: {row[1]}, Path: {row[2]}") + + conn.close() +except Exception as e: + print(f"Error: {e}") diff --git a/database/umamusume_seed.db b/database/umamusume_seed.db new file mode 100644 index 0000000..7d3adf6 Binary files /dev/null and b/database/umamusume_seed.db differ diff --git a/db/db_init.py b/db/db_init.py new file mode 100644 index 0000000..beeff4d --- /dev/null +++ b/db/db_init.py @@ -0,0 +1,154 @@ +""" +Database initialization module +Creates the SQLite database schema for Umamusume support cards +""" + +import sqlite3 +import os + +DB_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "database", "umamusume.db") + +def get_conn(): + """Get database connection""" + os.makedirs(os.path.dirname(DB_PATH), exist_ok=True) + return sqlite3.connect(DB_PATH) + +def init_db(reset=False): + """ + Initialize the database with schema + + Args: + reset: If True, drops all existing tables first + """ + conn = get_conn() + cur = conn.cursor() + + if reset: + print("Resetting database...") + cur.execute("DROP TABLE IF EXISTS deck_slots") + cur.execute("DROP TABLE IF EXISTS user_decks") + cur.execute("DROP TABLE IF EXISTS event_skills") + cur.execute("DROP TABLE IF EXISTS support_events") + cur.execute("DROP TABLE IF EXISTS support_hints") + cur.execute("DROP TABLE IF EXISTS support_effects") + cur.execute("DROP TABLE IF EXISTS owned_cards") + cur.execute("DROP TABLE IF EXISTS support_cards") + + # Support Cards - main card info + cur.execute(""" + CREATE TABLE IF NOT EXISTS support_cards ( + card_id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + rarity TEXT, + card_type TEXT, + max_level INTEGER DEFAULT 50, + gametora_url TEXT UNIQUE, + image_path TEXT + ) + """) + + # Effects by level - stores effect values at each level + cur.execute(""" + CREATE TABLE IF NOT EXISTS support_effects ( + effect_id INTEGER PRIMARY KEY AUTOINCREMENT, + card_id INTEGER, + level INTEGER, + effect_name TEXT, + effect_value TEXT, + FOREIGN KEY (card_id) REFERENCES support_cards(card_id) + ) + """) + + # Support Hints - training skills that can be learned + cur.execute(""" + CREATE TABLE IF NOT EXISTS support_hints ( + hint_id INTEGER PRIMARY KEY AUTOINCREMENT, + card_id INTEGER, + hint_name TEXT, + hint_description TEXT, + FOREIGN KEY (card_id) REFERENCES support_cards(card_id) + ) + """) + + # Training Events + cur.execute(""" + CREATE TABLE IF NOT EXISTS support_events ( + event_id INTEGER PRIMARY KEY AUTOINCREMENT, + card_id INTEGER, + event_name TEXT, + event_type TEXT, + FOREIGN KEY (card_id) REFERENCES support_cards(card_id) + ) + """) + + # Event Skills + cur.execute(""" + CREATE TABLE IF NOT EXISTS event_skills ( + skill_id INTEGER PRIMARY KEY AUTOINCREMENT, + event_id INTEGER, + skill_name TEXT, + FOREIGN KEY (event_id) REFERENCES support_events(event_id) + ) + """) + + # User's owned cards - which cards the user personally owns + cur.execute(""" + CREATE TABLE IF NOT EXISTS owned_cards ( + owned_id INTEGER PRIMARY KEY AUTOINCREMENT, + card_id INTEGER UNIQUE, + level INTEGER DEFAULT 50, + limit_break INTEGER DEFAULT 0, + owned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (card_id) REFERENCES support_cards(card_id) + ) + """) + + # User's saved decks + cur.execute(""" + CREATE TABLE IF NOT EXISTS user_decks ( + deck_id INTEGER PRIMARY KEY AUTOINCREMENT, + deck_name TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + """) + + # Cards in each deck (6 slots max) + cur.execute(""" + CREATE TABLE IF NOT EXISTS deck_slots ( + slot_id INTEGER PRIMARY KEY AUTOINCREMENT, + deck_id INTEGER, + card_id INTEGER, + slot_position INTEGER, + level INTEGER DEFAULT 50, + FOREIGN KEY (deck_id) REFERENCES user_decks(deck_id), + FOREIGN KEY (card_id) REFERENCES support_cards(card_id) + ) + """) + + # Create indexes for better query performance + cur.execute("CREATE INDEX IF NOT EXISTS idx_effects_card_level ON support_effects(card_id, level)") + cur.execute("CREATE INDEX IF NOT EXISTS idx_hints_card ON support_hints(card_id)") + cur.execute("CREATE INDEX IF NOT EXISTS idx_events_card ON support_events(card_id)") + cur.execute("CREATE INDEX IF NOT EXISTS idx_cards_type ON support_cards(card_type)") + cur.execute("CREATE INDEX IF NOT EXISTS idx_cards_rarity ON support_cards(rarity)") + cur.execute("CREATE INDEX IF NOT EXISTS idx_owned_card ON owned_cards(card_id)") + cur.execute("CREATE INDEX IF NOT EXISTS idx_deck_slots ON deck_slots(deck_id)") + + conn.commit() + conn.close() + print("Database initialized successfully!") + +def migrate_add_image_path(): + """Add image_path column if it doesn't exist""" + conn = get_conn() + cur = conn.cursor() + try: + cur.execute("ALTER TABLE support_cards ADD COLUMN image_path TEXT") + conn.commit() + print("Added image_path column") + except sqlite3.OperationalError: + pass # Column already exists + conn.close() + +if __name__ == "__main__": + init_db(reset=True) diff --git a/db/db_queries.py b/db/db_queries.py new file mode 100644 index 0000000..03f5b37 --- /dev/null +++ b/db/db_queries.py @@ -0,0 +1,702 @@ +""" +Database query functions for Umamusume support cards +""" + +import sqlite3 +import os +import sys + +import shutil + +if getattr(sys, 'frozen', False): + # In frozen state (exe), we need to ensure the database is in a writable location + # sys.executable points to the .exe file + base_dir = os.path.dirname(sys.executable) + db_dir = os.path.join(base_dir, "database") + DB_PATH = os.path.join(db_dir, "umamusume.db") + + # Function to check if DB is effectively empty + def is_db_empty(path): + try: + conn = sqlite3.connect(path) + cur = conn.cursor() + cur.execute("SELECT COUNT(*) FROM support_cards") + count = cur.fetchone()[0] + conn.close() + return count == 0 + except: + return True + + # Check state: Missing OR Empty + should_copy_seed = False + if not os.path.exists(DB_PATH): + should_copy_seed = True + elif is_db_empty(DB_PATH): + # exists but empty - overwrite it + should_copy_seed = True + + if should_copy_seed: + try: + # Ensure directory exists + os.makedirs(db_dir, exist_ok=True) + + # Check for bundled seed database + bundled_seed_path = os.path.join(sys._MEIPASS, "database", "umamusume_seed.db") + + if os.path.exists(bundled_seed_path): + # Copy seed database to user location (overwrite if exists) + shutil.copy2(bundled_seed_path, DB_PATH) + # Else: will be initialized by get_conn -> init_database + + except Exception as e: + pass +else: + DB_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "database", "umamusume.db") + +# Add VERSION import +if not getattr(sys, 'frozen', False): + sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +try: + from version import VERSION +except ImportError: + VERSION = "2.1.0" # Fallback + +def get_conn(): + """Get database connection""" + # Initialize if missing + if not os.path.exists(DB_PATH): + init_database() + + # Check for updates and migrate if needed + check_for_updates() + + return sqlite3.connect(DB_PATH) + +def check_for_updates(): + """Check if database version matches app version, sync if outdated""" + if getattr(sys, 'frozen', False): + bundled_seed_path = os.path.join(sys._MEIPASS, "database", "umamusume_seed.db") + if not os.path.exists(bundled_seed_path): + return + + try: + conn = sqlite3.connect(DB_PATH) + cur = conn.cursor() + + # Check for metadata table + cur.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='system_metadata'") + if not cur.fetchone(): + # No metadata, likely old version. Create it. + cur.execute("CREATE TABLE IF NOT EXISTS system_metadata (key TEXT PRIMARY KEY, value TEXT)") + cur.execute("INSERT OR REPLACE INTO system_metadata (key, value) VALUES (?, ?)", ('app_version', "0.0.0")) + conn.commit() + db_version = "0.0.0" + else: + cur.execute("SELECT value FROM system_metadata WHERE key='app_version'") + row = cur.fetchone() + db_version = row[0] if row else "0.0.0" + + conn.close() + + # Compare versions (simple string compare works for semver if zero-padded, but valid enough here) + # Or just check inequality. If different, try to update. + if db_version != VERSION: + sync_from_seed(bundled_seed_path) + + except Exception as e: + print(f"Update check failed: {e}") + +def sync_from_seed(seed_path): + """Merge new data from seed into user database""" + print(f"Syncing database from {seed_path}...") + try: + conn = sqlite3.connect(DB_PATH) + cur = conn.cursor() + + # Attach seed database + cur.execute("ATTACH DATABASE ? AS seed", (seed_path,)) + + # 1. Insert New Cards (match by gametora_url) + # We assume gametora_url is unique and stable + cur.execute(""" + INSERT INTO main.support_cards (name, rarity, card_type, max_level, gametora_url, image_path) + SELECT name, rarity, card_type, max_level, gametora_url, image_path + FROM seed.support_cards + WHERE gametora_url NOT IN (SELECT gametora_url FROM main.support_cards) + """) + + # 2. Sync Child Tables + # Since effects/hints/events don't have stable IDs, we wipe and re-import them for ALL cards. + # But we must map seed_card_id to main_card_id. + + # First, ensure we don't break foreign keys temporarily + cur.execute("PRAGMA foreign_keys = OFF") + + tables_to_sync = ['support_effects', 'support_hints', 'support_events', 'event_skills'] + for table in tables_to_sync: + cur.execute(f"DELETE FROM main.{table}") + + # Migrate Support Effects + # Map: seed.card_id -> gametora_url -> main.card_id + cur.execute(""" + INSERT INTO main.support_effects (card_id, level, effect_name, effect_value) + SELECT m.card_id, s.level, s.effect_name, s.effect_value + FROM seed.support_effects s + JOIN seed.support_cards sc ON s.card_id = sc.card_id + JOIN main.support_cards m ON sc.gametora_url = m.gametora_url + """) + + # Migrate Support Hints + cur.execute(""" + INSERT INTO main.support_hints (card_id, hint_name, hint_description) + SELECT m.card_id, s.hint_name, s.hint_description + FROM seed.support_hints s + JOIN seed.support_cards sc ON s.card_id = sc.card_id + JOIN main.support_cards m ON sc.gametora_url = m.gametora_url + """) + + # Migrate Support Events + # We need to preserve event_id mapping for event_skills? + # Actually no, we deleted event_skills too. + # But we need to insert events first to get new IDs, then insert skills linking to those new IDs? + # That's tricky in SQL. + # Easier: Insert events, then resolving event_id is hard without a map. + # Alternative: Just copy the tables matching on card_id if we assume card_ids are consistent? + # If user has same cards as seed, IDs might be consistent. + # But if we added a card in the middle, IDs shift. + # Let's assume we can just drop event/skills for now or try to match them. + # The logic below is complex for events+skills because of the 2-level hierarchy. + + # Strategy for Events/Skills: + # Since we just deleted them, we can re-insert. + # But main.event_id will be auto-incremented. + # We need to insert event, get ID, then insert skill? No, bulk insert. + # We can't easily map seed.event_id to main.event_id in bulk SQL across DBs easily without a temp table. + + # Simplified Approach for Events/Skills: + # Iterate in Python? Slower but safer. + pass # Placeholder for python logic below + + # Update Version + cur.execute("INSERT OR REPLACE INTO system_metadata (key, value) VALUES (?, ?)", ('app_version', VERSION)) + + conn.commit() + + # Python Logic for Events/Skills + # Fetch all events from seed with their card's gametora_url + cur.execute(""" + SELECT sc.gametora_url, se.event_name, se.event_type, se.event_id + FROM seed.support_events se + JOIN seed.support_cards sc ON se.card_id = sc.card_id + """) + seed_events = cur.fetchall() + + # Prepare Skill map: seed_event_id -> list of (skill_name) + cur.execute("SELECT event_id, skill_name FROM seed.event_skills") + seed_skills = {} + for ev_id, sk_name in cur.fetchall(): + if ev_id not in seed_skills: seed_skills[ev_id] = [] + seed_skills[ev_id].append(sk_name) + + # Main Card Map: gametora_url -> main_card_id + cur.execute("SELECT gametora_url, card_id FROM main.support_cards") + url_to_main_id = dict(cur.fetchall()) + + for url, ev_name, ev_type, seed_ev_id in seed_events: + if url in url_to_main_id: + main_card_id = url_to_main_id[url] + # Insert Event + cur.execute("INSERT INTO main.support_events (card_id, event_name, event_type) VALUES (?, ?, ?)", + (main_card_id, ev_name, ev_type)) + new_event_id = cur.lastrowid + + # Insert Skills + if seed_ev_id in seed_skills: + for sk_name in seed_skills[seed_ev_id]: + cur.execute("INSERT INTO main.event_skills (event_id, skill_name) VALUES (?, ?)", + (new_event_id, sk_name)) + + cur.execute("PRAGMA foreign_keys = ON") + conn.commit() + conn.close() + print(f"Database sync complete. Updated to version {VERSION}") + + except Exception as e: + print(f"Sync failed: {e}") + +def init_database(): + """Initialize fresh database with schema""" + # Ensure directory exists + os.makedirs(os.path.dirname(DB_PATH), exist_ok=True) + + conn = sqlite3.connect(DB_PATH) + cur = conn.cursor() + + # Create tables + cur.execute(""" + CREATE TABLE IF NOT EXISTS support_cards ( + card_id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + rarity TEXT, + card_type TEXT, + max_level INTEGER DEFAULT 50, + gametora_url TEXT UNIQUE, + image_path TEXT + ) + """) + + cur.execute(""" + CREATE TABLE IF NOT EXISTS support_effects ( + effect_id INTEGER PRIMARY KEY AUTOINCREMENT, + card_id INTEGER, + level INTEGER, + effect_name TEXT, + effect_value TEXT, + FOREIGN KEY (card_id) REFERENCES support_cards(card_id) + ) + """) + + cur.execute(""" + CREATE TABLE IF NOT EXISTS support_hints ( + hint_id INTEGER PRIMARY KEY AUTOINCREMENT, + card_id INTEGER, + hint_name TEXT, + hint_description TEXT, + FOREIGN KEY (card_id) REFERENCES support_cards(card_id) + ) + """) + + cur.execute(""" + CREATE TABLE IF NOT EXISTS support_events ( + event_id INTEGER PRIMARY KEY AUTOINCREMENT, + card_id INTEGER, + event_name TEXT, + event_type TEXT, + FOREIGN KEY (card_id) REFERENCES support_cards(card_id) + ) + """) + + cur.execute(""" + CREATE TABLE IF NOT EXISTS event_skills ( + skill_id INTEGER PRIMARY KEY AUTOINCREMENT, + event_id INTEGER, + skill_name TEXT, + FOREIGN KEY (event_id) REFERENCES support_events(event_id) + ) + """) + + # User tables + cur.execute(""" + CREATE TABLE IF NOT EXISTS owned_cards ( + owned_id INTEGER PRIMARY KEY AUTOINCREMENT, + card_id INTEGER UNIQUE, + level INTEGER DEFAULT 50, + limit_break INTEGER DEFAULT 0, + FOREIGN KEY (card_id) REFERENCES support_cards(card_id) + ) + """) + + cur.execute(""" + CREATE TABLE IF NOT EXISTS user_decks ( + deck_id INTEGER PRIMARY KEY AUTOINCREMENT, + deck_name TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + """) + + cur.execute(""" + CREATE TABLE IF NOT EXISTS deck_slots ( + slot_id INTEGER PRIMARY KEY AUTOINCREMENT, + deck_id INTEGER, + card_id INTEGER, + slot_position INTEGER, + level INTEGER DEFAULT 50, + FOREIGN KEY (deck_id) REFERENCES user_decks(deck_id), + FOREIGN KEY (card_id) REFERENCES support_cards(card_id) + ) + """) + + # Create indexes for performance + cur.execute("CREATE INDEX IF NOT EXISTS idx_effects_card_level ON support_effects(card_id, level)") + cur.execute("CREATE INDEX IF NOT EXISTS idx_hints_card ON support_hints(card_id)") + cur.execute("CREATE INDEX IF NOT EXISTS idx_events_card ON support_events(card_id)") + + conn.commit() + conn.close() + +# ============================================ +# Card Queries +# ============================================ + +def get_all_cards(rarity_filter=None, type_filter=None, search_term=None, owned_only=False): + """ + Get all support cards with optional filtering + """ + conn = get_conn() + cur = conn.cursor() + + query = """ + SELECT sc.card_id, sc.name, sc.rarity, sc.card_type, sc.max_level, sc.image_path, + CASE WHEN oc.card_id IS NOT NULL THEN 1 ELSE 0 END as is_owned, + oc.level as owned_level + FROM support_cards sc + LEFT JOIN owned_cards oc ON sc.card_id = oc.card_id + WHERE 1=1 + """ + params = [] + + if rarity_filter: + query += " AND sc.rarity = ?" + params.append(rarity_filter) + + if type_filter: + query += " AND sc.card_type = ?" + params.append(type_filter) + + if search_term: + query += " AND sc.name LIKE ?" + params.append(f"%{search_term}%") + + if owned_only: + query += " AND oc.card_id IS NOT NULL" + + query += " ORDER BY sc.rarity DESC, sc.name" + + cur.execute(query, params) + rows = cur.fetchall() + conn.close() + return rows + +def get_card_by_id(card_id): + """Get a single card by ID""" + conn = get_conn() + cur = conn.cursor() + cur.execute(""" + SELECT sc.card_id, sc.name, sc.rarity, sc.card_type, sc.max_level, sc.gametora_url, sc.image_path, + CASE WHEN oc.card_id IS NOT NULL THEN 1 ELSE 0 END as is_owned, + oc.level as owned_level + FROM support_cards sc + LEFT JOIN owned_cards oc ON sc.card_id = oc.card_id + WHERE sc.card_id = ? + """, (card_id,)) + row = cur.fetchone() + conn.close() + return row + +def get_card_count(): + """Get total number of cards in database""" + conn = get_conn() + cur = conn.cursor() + cur.execute("SELECT COUNT(*) FROM support_cards") + count = cur.fetchone()[0] + conn.close() + return count + +# ============================================ +# Effect Queries +# ============================================ + +def get_effects_at_level(card_id, level): + """Get all effects for a card at a specific level""" + conn = get_conn() + cur = conn.cursor() + cur.execute(""" + SELECT effect_name, effect_value + FROM support_effects + WHERE card_id = ? AND level = ? + ORDER BY effect_name + """, (card_id, level)) + rows = cur.fetchall() + conn.close() + return rows + +def get_all_effects(card_id): + """Get all effects for a card at all levels""" + conn = get_conn() + cur = conn.cursor() + cur.execute(""" + SELECT level, effect_name, effect_value + FROM support_effects + WHERE card_id = ? + ORDER BY level, effect_name + """, (card_id,)) + rows = cur.fetchall() + conn.close() + return rows + +def get_unique_effect_names(card_id): + """Get list of unique effect names for a card""" + conn = get_conn() + cur = conn.cursor() + cur.execute(""" + SELECT DISTINCT effect_name + FROM support_effects + WHERE card_id = ? + ORDER BY effect_name + """, (card_id,)) + rows = [r[0] for r in cur.fetchall()] + conn.close() + return rows + +# ============================================ +# Hint Queries +# ============================================ + +def get_hints(card_id): + """Get all hints for a card""" + conn = get_conn() + cur = conn.cursor() + cur.execute(""" + SELECT hint_name, hint_description + FROM support_hints + WHERE card_id = ? + ORDER BY hint_name + """, (card_id,)) + rows = cur.fetchall() + conn.close() + return rows + +# ============================================ +# Event Queries +# ============================================ + +def get_events(card_id): + """Get all events for a card""" + conn = get_conn() + cur = conn.cursor() + cur.execute(""" + SELECT event_id, event_name, event_type + FROM support_events + WHERE card_id = ? + ORDER BY event_name + """, (card_id,)) + rows = cur.fetchall() + conn.close() + return rows + +def get_all_event_skills(card_id): + """Get all events and their skills for a card""" + conn = get_conn() + cur = conn.cursor() + cur.execute(""" + SELECT se.event_name, es.skill_name + FROM support_events se + LEFT JOIN event_skills es ON se.event_id = es.event_id + WHERE se.card_id = ? + ORDER BY se.event_name, es.skill_name + """, (card_id,)) + + result = {} + for event_name, skill_name in cur.fetchall(): + if event_name not in result: + result[event_name] = [] + if skill_name: + result[event_name].append(skill_name) + + conn.close() + return result + +# ============================================ +# Owned Cards (Collection) Queries +# ============================================ + +def is_card_owned(card_id): + """Check if a card is owned""" + conn = get_conn() + cur = conn.cursor() + cur.execute("SELECT 1 FROM owned_cards WHERE card_id = ?", (card_id,)) + result = cur.fetchone() is not None + conn.close() + return result + +def set_card_owned(card_id, owned=True, level=50): + """Set a card as owned or not owned""" + conn = get_conn() + cur = conn.cursor() + + if owned: + cur.execute(""" + INSERT OR REPLACE INTO owned_cards (card_id, level) + VALUES (?, ?) + """, (card_id, level)) + else: + cur.execute("DELETE FROM owned_cards WHERE card_id = ?", (card_id,)) + + conn.commit() + conn.close() + +def update_owned_card_level(card_id, level): + """Update the level of an owned card""" + conn = get_conn() + cur = conn.cursor() + cur.execute("UPDATE owned_cards SET level = ? WHERE card_id = ?", (level, card_id)) + conn.commit() + conn.close() + +def get_owned_cards(): + """Get all owned cards""" + conn = get_conn() + cur = conn.cursor() + cur.execute(""" + SELECT sc.card_id, sc.name, sc.rarity, sc.card_type, oc.level, sc.image_path + FROM owned_cards oc + JOIN support_cards sc ON oc.card_id = sc.card_id + ORDER BY sc.rarity DESC, sc.name + """) + rows = cur.fetchall() + conn.close() + return rows + +def get_owned_count(): + """Get count of owned cards""" + conn = get_conn() + cur = conn.cursor() + cur.execute("SELECT COUNT(*) FROM owned_cards") + count = cur.fetchone()[0] + conn.close() + return count + +# ============================================ +# Deck Queries +# ============================================ + +def create_deck(name): + """Create a new deck""" + conn = get_conn() + cur = conn.cursor() + cur.execute("INSERT INTO user_decks (deck_name) VALUES (?)", (name,)) + deck_id = cur.lastrowid + conn.commit() + conn.close() + return deck_id + +def get_all_decks(): + """Get all saved decks""" + conn = get_conn() + cur = conn.cursor() + cur.execute("SELECT deck_id, deck_name, created_at FROM user_decks ORDER BY created_at DESC") + rows = cur.fetchall() + conn.close() + return rows + +def delete_deck(deck_id): + """Delete a deck and its slots""" + conn = get_conn() + cur = conn.cursor() + cur.execute("DELETE FROM deck_slots WHERE deck_id = ?", (deck_id,)) + cur.execute("DELETE FROM user_decks WHERE deck_id = ?", (deck_id,)) + conn.commit() + conn.close() + +def add_card_to_deck(deck_id, card_id, slot_position, level=50): + """Add a card to a deck slot""" + conn = get_conn() + cur = conn.cursor() + # Remove existing card in that slot + cur.execute("DELETE FROM deck_slots WHERE deck_id = ? AND slot_position = ?", (deck_id, slot_position)) + # Add new card + cur.execute(""" + INSERT INTO deck_slots (deck_id, card_id, slot_position, level) + VALUES (?, ?, ?, ?) + """, (deck_id, card_id, slot_position, level)) + conn.commit() + conn.close() + +def remove_card_from_deck(deck_id, slot_position): + """Remove a card from a deck slot""" + conn = get_conn() + cur = conn.cursor() + cur.execute("DELETE FROM deck_slots WHERE deck_id = ? AND slot_position = ?", (deck_id, slot_position)) + conn.commit() + conn.close() + +def get_deck_cards(deck_id): + """Get all cards in a deck with their effects""" + conn = get_conn() + cur = conn.cursor() + cur.execute(""" + SELECT ds.slot_position, ds.level, sc.card_id, sc.name, sc.rarity, sc.card_type, sc.image_path + FROM deck_slots ds + JOIN support_cards sc ON ds.card_id = sc.card_id + WHERE ds.deck_id = ? + ORDER BY ds.slot_position + """, (deck_id,)) + rows = cur.fetchall() + conn.close() + return rows + +def get_deck_combined_effects(deck_id): + """ + Get combined effects for all cards in a deck + Returns dict: {effect_name: {'total': value, 'breakdown': [(card_name, value), ...]}} + """ + conn = get_conn() + cur = conn.cursor() + + # Get cards in deck with their levels + cur.execute(""" + SELECT ds.card_id, ds.level, sc.name + FROM deck_slots ds + JOIN support_cards sc ON ds.card_id = sc.card_id + WHERE ds.deck_id = ? + """, (deck_id,)) + deck_cards = cur.fetchall() + + combined = {} + + for card_id, level, card_name in deck_cards: + # Get effects for this card at this level + cur.execute(""" + SELECT effect_name, effect_value + FROM support_effects + WHERE card_id = ? AND level = ? + """, (card_id, level)) + + for effect_name, effect_value in cur.fetchall(): + if effect_name not in combined: + combined[effect_name] = {'total': 0, 'breakdown': []} + + # Parse value (remove % and convert to number) + try: + num_value = float(effect_value.replace('%', '').replace('+', '')) + except: + num_value = 0 + + combined[effect_name]['total'] += num_value + combined[effect_name]['breakdown'].append((card_name, effect_value)) + + conn.close() + return combined + +# ============================================ +# Statistics +# ============================================ + +def get_database_stats(): + """Get statistics about the database""" + conn = get_conn() + cur = conn.cursor() + + stats = {} + + cur.execute("SELECT COUNT(*) FROM support_cards") + stats['total_cards'] = cur.fetchone()[0] + + cur.execute("SELECT rarity, COUNT(*) FROM support_cards GROUP BY rarity") + stats['by_rarity'] = dict(cur.fetchall()) + + cur.execute("SELECT card_type, COUNT(*) FROM support_cards GROUP BY card_type") + stats['by_type'] = dict(cur.fetchall()) + + cur.execute("SELECT COUNT(*) FROM support_effects") + stats['total_effects'] = cur.fetchone()[0] + + cur.execute("SELECT COUNT(*) FROM owned_cards") + stats['owned_cards'] = cur.fetchone()[0] + + cur.execute("SELECT COUNT(*) FROM user_decks") + stats['saved_decks'] = cur.fetchone()[0] + + conn.close() + return stats diff --git a/gui/card_view.py b/gui/card_view.py new file mode 100644 index 0000000..b2d02f8 --- /dev/null +++ b/gui/card_view.py @@ -0,0 +1,559 @@ +""" +Card List View - Browse and search support cards with ownership management +""" + +import tkinter as tk +from tkinter import ttk +import sys +import os +from PIL import Image, ImageTk + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from db.db_queries import get_all_cards, get_card_by_id, get_effects_at_level, set_card_owned, is_card_owned, update_owned_card_level +from utils import resolve_image_path +from gui.theme import ( + BG_DARK, BG_MEDIUM, BG_LIGHT, BG_HIGHLIGHT, + ACCENT_PRIMARY, ACCENT_SECONDARY, ACCENT_SUCCESS, + TEXT_PRIMARY, TEXT_SECONDARY, TEXT_MUTED, + FONT_HEADER, FONT_SUBHEADER, FONT_BODY, FONT_BODY_BOLD, FONT_SMALL, FONT_MONO, + RARITY_COLORS, TYPE_COLORS, TYPE_ICONS, + create_styled_button, create_styled_text, create_card_frame, + get_rarity_color, get_type_color, get_type_icon, + EFFECT_DESCRIPTIONS, Tooltip +) + + +class CardListFrame(ttk.Frame): + """Frame containing card list with search/filter, ownership, and details panel""" + + def __init__(self, parent, on_card_selected_callback=None): + super().__init__(parent) + self.on_card_selected = on_card_selected_callback + self.cards = [] + self.current_card_id = None + self.card_image = None # Keep reference to prevent garbage collection + self.icon_cache = {} # Cache for list icons + + # Create main layout + self.create_widgets() + self.load_cards() + + def create_widgets(self): + """Create the card list interface""" + # Main horizontal layout + main_pane = ttk.PanedWindow(self, orient=tk.HORIZONTAL) + main_pane.pack(fill=tk.BOTH, expand=True) + + # Left panel - Card list with filters + left_frame = ttk.Frame(main_pane, width=420) + main_pane.add(left_frame, weight=1) + + # Right panel - Card details + self.details_frame = ttk.Frame(main_pane) + main_pane.add(self.details_frame, weight=2) + + # === Left Panel Contents === + + # Initialize filter variables FIRST (before search trace can trigger filter_cards) + self.rarity_var = tk.StringVar(value="All") + self.type_var = tk.StringVar(value="All") + self.owned_only_var = tk.BooleanVar(value=False) + + # Search bar with modern styling + search_frame = tk.Frame(left_frame, bg=BG_DARK) + search_frame.pack(fill=tk.X, padx=10, pady=10) + + search_icon = tk.Label(search_frame, text="šŸ”", font=FONT_BODY, bg=BG_DARK, fg=TEXT_MUTED) + search_icon.pack(side=tk.LEFT, padx=(0, 5)) + + self.search_var = tk.StringVar() + self.search_entry = ttk.Entry(search_frame, textvariable=self.search_var, width=35) + self.search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True) + + # Set placeholder BEFORE adding the trace (so it doesn't trigger filter) + self.search_entry.insert(0, "Search cards...") + self.search_entry.config(foreground=TEXT_MUTED) + self.search_entry.bind('', self._on_search_focus_in) + self.search_entry.bind('', self._on_search_focus_out) + + # NOW add the trace (after placeholder is set) + self.search_var.trace('w', lambda *args: self.filter_cards()) + + # Filter dropdowns + filter_frame = tk.Frame(left_frame, bg=BG_DARK) + filter_frame.pack(fill=tk.X, padx=10, pady=(0, 10)) + + # Rarity filter + tk.Label(filter_frame, text="Rarity:", font=FONT_SMALL, bg=BG_DARK, fg=TEXT_MUTED).pack(side=tk.LEFT) + rarity_combo = ttk.Combobox(filter_frame, textvariable=self.rarity_var, + values=["All", "SSR", "SR", "R"], width=7, state='readonly') + rarity_combo.pack(side=tk.LEFT, padx=(5, 15)) + rarity_combo.bind('<>', lambda e: self.filter_cards()) + + # Type filter + tk.Label(filter_frame, text="Type:", font=FONT_SMALL, bg=BG_DARK, fg=TEXT_MUTED).pack(side=tk.LEFT) + type_combo = ttk.Combobox(filter_frame, textvariable=self.type_var, + values=["All", "Speed", "Stamina", "Power", "Guts", "Wisdom", "Friend", "Group"], + width=10, state='readonly') + type_combo.pack(side=tk.LEFT, padx=5) + type_combo.bind('<>', lambda e: self.filter_cards()) + + # Owned only filter + owned_check = ttk.Checkbutton(filter_frame, text="Owned Only", + variable=self.owned_only_var, command=self.filter_cards) + owned_check.pack(side=tk.LEFT, padx=15) + + # Reset Button + ttk.Button(filter_frame, text="Reset", command=self.reset_filters, + style='Small.TButton', width=7).pack(side=tk.LEFT, padx=5) + + # Shortcuts + self.bind_all('', lambda e: self.search_entry.focus_set()) + + # Card count label + self.count_label = tk.Label(left_frame, text="0 cards", font=FONT_SMALL, + bg=BG_DARK, fg=ACCENT_PRIMARY) + self.count_label.pack(pady=5) + + # Card list (Treeview) + list_frame = tk.Frame(left_frame, bg=BG_DARK) + list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10)) + + self.tree = ttk.Treeview(list_frame, columns=('owned', 'name', 'rarity', 'type'), + show='tree headings', selectmode='browse', + style="CardList.Treeview") + + self.tree.heading('#0', text='') + self.tree.column('#0', width=45, anchor='center') + + self.tree.heading('owned', text='ā˜…', command=lambda: self.sort_column('owned', False)) + self.tree.heading('name', text='Name', anchor='w', command=lambda: self.sort_column('name', False)) + self.tree.heading('rarity', text='Rarity', command=lambda: self.sort_column('rarity', False)) + self.tree.heading('type', text='Type', command=lambda: self.sort_column('type', False)) + + self.tree.column('owned', width=30, anchor='center') + self.tree.column('name', width=180, minwidth=150) + self.tree.column('rarity', width=55, anchor='center') + self.tree.column('type', width=90, anchor='center') + + scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.tree.yview) + self.tree.configure(yscrollcommand=scrollbar.set) + + self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + scrollbar.pack(side=tk.RIGHT, fill=tk.Y) + + self.tree.bind('<>', self.on_select) + + # Tag for owned cards + self.tree.tag_configure('owned', background='#1a3a2e') + + # === Right Panel Contents (Details) === + self.create_details_panel() + + def create_details_panel(self): + """Create the card details panel""" + # Container with card-like appearance + details_container = tk.Frame(self.details_frame, bg=BG_DARK) + details_container.pack(fill=tk.BOTH, expand=True, padx=15, pady=10) + + # Image area with card frame + image_frame = create_card_frame(details_container, padx=10, pady=10) + image_frame.pack(pady=10) + + self.image_label = tk.Label(image_frame, text="", bg=BG_MEDIUM) + self.image_label.pack(padx=5, pady=5) + + # Header with card name + self.detail_name = tk.Label(details_container, text="Select a card", + font=FONT_HEADER, bg=BG_DARK, fg=ACCENT_PRIMARY) + self.detail_name.pack(pady=(10, 5)) + + self.detail_info = tk.Label(details_container, text="", + font=FONT_SMALL, bg=BG_DARK, fg=TEXT_MUTED) + self.detail_info.pack() + + # Owned checkbox with emphasis + owned_frame = tk.Frame(details_container, bg=BG_DARK) + owned_frame.pack(pady=15) + + self.owned_var = tk.BooleanVar(value=False) + self.owned_checkbox = ttk.Checkbutton(owned_frame, text="✨ I Own This Card", + variable=self.owned_var, + command=self.toggle_owned, + style='Large.TCheckbutton') + self.owned_checkbox.pack(side=tk.LEFT) + + # Level selector with button-based control (no slider) + level_frame = tk.Frame(details_container, bg=BG_DARK) + level_frame.pack(fill=tk.X, padx=30, pady=10) + + tk.Label(level_frame, text="Card Level:", font=FONT_BODY, + bg=BG_DARK, fg=TEXT_SECONDARY).pack(side=tk.LEFT) + + # Level display with increment/decrement + level_ctrl = tk.Frame(level_frame, bg=BG_DARK) + level_ctrl.pack(side=tk.LEFT, padx=15) + + self.level_var = tk.IntVar(value=50) + self.max_level = 50 + self.valid_levels = [30, 35, 40, 45, 50] # Default SSR + + # Decrement button + dec_btn = tk.Button(level_ctrl, text="āˆ’", font=FONT_HEADER, + bg=BG_LIGHT, fg=TEXT_PRIMARY, bd=0, width=2, + activebackground=BG_HIGHLIGHT, cursor='hand2', + command=self.decrement_level) + dec_btn.pack(side=tk.LEFT) + + self.level_label = tk.Label(level_ctrl, text="50", width=4, font=FONT_HEADER, + bg=BG_MEDIUM, fg=ACCENT_PRIMARY, padx=10) + self.level_label.pack(side=tk.LEFT, padx=2) + + # Increment button + inc_btn = tk.Button(level_ctrl, text="+", font=FONT_HEADER, + bg=BG_LIGHT, fg=TEXT_PRIMARY, bd=0, width=2, + activebackground=BG_HIGHLIGHT, cursor='hand2', + command=self.increment_level) + inc_btn.pack(side=tk.LEFT) + + # Quick level buttons container + self.level_btn_frame = tk.Frame(level_frame, bg=BG_DARK) + self.level_btn_frame.pack(side=tk.LEFT, padx=20) + + self.level_buttons = {} + # Initial population + self.update_level_buttons('SSR', 50) + + # Effects display header + effects_header = tk.Frame(details_container, bg=BG_DARK) + effects_header.pack(fill=tk.X, padx=20, pady=(20, 10)) + + tk.Label(effects_header, text="šŸ“Š Effects at Current Level", + font=FONT_SUBHEADER, bg=BG_DARK, fg=TEXT_PRIMARY).pack(side=tk.LEFT) + + # Effects text area with modern styling + effects_frame = create_card_frame(details_container) + effects_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=(0, 15)) + + self.effects_text = create_styled_text(effects_frame, height=10) + self.effects_text.pack(fill=tk.BOTH, expand=True, padx=2, pady=2) + self.effects_text.config(state=tk.DISABLED) + + def load_cards(self): + """Load all cards from database""" + self.cards = get_all_cards() + self.populate_tree(self.cards) + + def reset_filters(self): + """Reset all filters to default""" + self.search_var.set("") + self.rarity_var.set("All") + self.type_var.set("All") + self.owned_only_var.set(False) + # Reset placeholder + self.search_entry.delete(0, tk.END) + self.search_entry.insert(0, "Search cards...") + self.search_entry.config(foreground=TEXT_MUTED) + self.filter_cards() + + def _on_search_focus_in(self, event): + """Clear placeholder on focus""" + if self.search_entry.get() == "Search cards...": + self.search_entry.delete(0, tk.END) + self.search_entry.config(foreground=TEXT_PRIMARY) + + def _on_search_focus_out(self, event): + """Show placeholder if empty""" + if not self.search_entry.get(): + self.search_entry.insert(0, "Search cards...") + self.search_entry.config(foreground=TEXT_MUTED) + + def filter_cards(self): + """Filter cards based on search and dropdown values""" + rarity = self.rarity_var.get() if self.rarity_var.get() != "All" else None + card_type = self.type_var.get() if self.type_var.get() != "All" else None + # Ignore placeholder text + search_text = self.search_var.get().strip() + search = search_text if search_text and search_text != "Search cards..." else None + owned_only = self.owned_only_var.get() + + self.cards = get_all_cards(rarity_filter=rarity, type_filter=card_type, + search_term=search, owned_only=owned_only) + self.populate_tree(self.cards) + + def sort_column(self, col, reverse): + """Sort treeview by column""" + l = [(self.tree.set(k, col), k) for k in self.tree.get_children('')] + + # Custom sort logic + if col == 'owned': + # Sort by star/empty + l.sort(key=lambda t: t[0] if t[0] else "", reverse=reverse) + elif col == 'rarity': + # Sort by rarity rank (SSR > SR > R) + rarity_map = {'SSR': 3, 'SR': 2, 'R': 1} + l.sort(key=lambda t: rarity_map.get(t[0], 0), reverse=reverse) + else: + # Default string sort + l.sort(reverse=reverse) + + # Rearrange items + for index, (val, k) in enumerate(l): + self.tree.move(k, '', index) + + # Reverse sort next time + self.tree.heading(col, command=lambda: self.sort_column(col, not reverse)) + + def populate_tree(self, cards): + """Populate treeview with cards""" + self.tree.delete(*self.tree.get_children()) + + for card in cards: + card_id, name, rarity, card_type, max_level, image_path, is_owned, owned_level = card + type_icon = get_type_icon(card_type) + owned_mark = "ā˜…" if is_owned else "" + tag = 'owned' if is_owned else '' + + # Show level for owned cards + display_name = name + if is_owned and owned_level: + display_name = f"{name} (Lv{owned_level})" + + # Load Icon + img = self.icon_cache.get(card_id) + if not img: + resolved_path = resolve_image_path(image_path) + if resolved_path and os.path.exists(resolved_path): + try: + pil_img = Image.open(resolved_path) + pil_img.thumbnail((32, 32), Image.Resampling.LANCZOS) + img = ImageTk.PhotoImage(pil_img) + self.icon_cache[card_id] = img + except: + pass + + if img: + self.tree.insert('', tk.END, iid=card_id, text='', image=img, + values=(owned_mark, display_name, rarity, f"{type_icon} {card_type}"), + tags=(tag,)) + else: + self.tree.insert('', tk.END, iid=card_id, text='', + values=(owned_mark, display_name, rarity, f"{type_icon} {card_type}"), + tags=(tag,)) + + self.count_label.config(text=f"✨ {len(cards)} cards") + + def on_select(self, event): + """Handle card selection""" + selection = self.tree.selection() + if not selection: + return + + card_id = int(selection[0]) + card = get_card_by_id(card_id) + + if card: + card_id, name, rarity, card_type, max_level, url, image_path, is_owned, owned_level = card + + # Update owned checkbox + self.owned_var.set(bool(is_owned)) + + # Load card image if available + self.load_card_image(image_path) + + # Use owned level if owned, otherwise max level or default 50 + initial_level = owned_level if is_owned and owned_level else max_level + + # Update level controls + self.max_level = max_level + self.update_level_buttons(rarity, max_level) + + # Snap initial level to valid levels + if initial_level not in self.valid_levels: + # Find closest or default to max + initial_level = max_level + + self.level_var.set(initial_level) + self.level_label.config(text=str(initial_level)) + + # Update details display with colors + type_icon = get_type_icon(card_type) + type_color = get_type_color(card_type) + rarity_color = get_rarity_color(rarity) + + self.detail_name.config(text=f"{type_icon} {name}", fg=ACCENT_PRIMARY) + self.detail_info.config(text=f"{rarity} │ {card_type} │ Max Level: {max_level}") + + # Load effects + self.current_card_id = card_id + self.update_effects_display() + + # Notify parent window + if self.on_card_selected: + self.on_card_selected(card_id, name) + + def load_card_image(self, image_path): + """Load and display card image""" + resolved_path = resolve_image_path(image_path) + + if resolved_path and os.path.exists(resolved_path): + try: + img = Image.open(resolved_path) + img.thumbnail((130, 130)) # Slightly larger + self.card_image = ImageTk.PhotoImage(img) + self.image_label.config(image=self.card_image) + except Exception as e: + self.image_label.config(image='', text="[Image not found]") + else: + self.image_label.config(image='', text="") + + def toggle_owned(self): + """Toggle owned status for current card""" + if self.current_card_id: + owned = self.owned_var.get() + level = int(self.level_var.get()) + set_card_owned(self.current_card_id, owned, level) + self.filter_cards() # Refresh list to update owned markers + + def update_level_buttons(self, rarity, max_level): + """Update quick level buttons based on rarity/max level""" + # Determine valid levels + if max_level == 50: # SSR + self.valid_levels = [30, 35, 40, 45, 50] + elif max_level == 45: # SR + self.valid_levels = [25, 30, 35, 40, 45] + else: # R (max 40) + self.valid_levels = [20, 25, 30, 35, 40] + + # Clear existing buttons + for widget in self.level_btn_frame.winfo_children(): + widget.destroy() + self.level_buttons = {} + + # Create new buttons + for lvl in self.valid_levels: + btn = create_styled_button(self.level_btn_frame, text=f"Lv{lvl}", + command=lambda l=lvl: self.set_level(l), + style_type='default') + btn.config(width=5, padx=6, pady=3, font=FONT_SMALL) + btn.pack(side=tk.LEFT, padx=2) + self.level_buttons[lvl] = btn + + def set_level(self, level): + """Set level from quick button""" + self.level_var.set(level) + self.level_label.config(text=str(level)) + self.update_effects_display() + + # Save level if owned + if self.current_card_id and self.owned_var.get(): + update_owned_card_level(self.current_card_id, level) + self.update_tree_item_level(self.current_card_id, level) + + def increment_level(self): + """Increase level to next valid step""" + current = self.level_var.get() + # Find next level in valid_levels + for lvl in self.valid_levels: + if lvl > current: + self.set_level(lvl) + return + + def decrement_level(self): + """Decrease level to previous valid step""" + current = self.level_var.get() + # Find previous level in valid_levels + for lvl in reversed(self.valid_levels): + if lvl < current: + self.set_level(lvl) + return + + def update_tree_item_level(self, card_id, level): + """Update visible name in tree without full reload""" + if self.tree.exists(card_id): + current_values = self.tree.item(card_id, 'values') + if current_values: + # current_values is a tuple: (owned_mark, name, rarity, type) + # We need to strip existing " (LvXX)" from name if present + name = current_values[1] + base_name = name.split(" (Lv")[0] + new_name = f"{base_name} (Lv{level})" + + # Make new values tuple preserving other columns + new_values = (current_values[0], new_name, current_values[2], current_values[3]) + self.tree.item(card_id, values=new_values) + + def update_effects_display(self): + """Update the effects display for current card and level""" + if not self.current_card_id: + return + + level = int(self.level_var.get()) + effects = get_effects_at_level(self.current_card_id, level) + + self.effects_text.config(state=tk.NORMAL) + self.effects_text.delete('1.0', tk.END) + + # Configure tags for styling + self.effects_text.tag_configure('header', font=FONT_SUBHEADER, foreground=ACCENT_PRIMARY) + self.effects_text.tag_configure('highlight', foreground=ACCENT_SUCCESS) + self.effects_text.tag_configure('effect_name', foreground=TEXT_SECONDARY) + self.effects_text.tag_configure('effect_value', foreground=TEXT_PRIMARY) + self.effects_text.tag_configure('effect_tooltip', underline=False) + + if effects: + self.effects_text.insert(tk.END, f"━━━ Level {level} ━━━\n\n", 'header') + for name, value in effects: + # Highlight high values + prefix = "" + if '%' in str(value): + try: + num = int(str(value).replace('%', '').replace('+', '')) + if num >= 20: + prefix = "ā˜… " + except: + pass + if prefix: + self.effects_text.insert(tk.END, prefix, 'highlight') + + # Insert effect name with tooltip tag + tag_name = f"tooltip_{name.replace(' ', '_')}" + self.effects_text.insert(tk.END, f"{name}: ", ('effect_name', tag_name)) + + # Bind tooltip events + self.effects_text.tag_bind(tag_name, "", lambda e, n=name: self.show_effect_tooltip(e, n)) + self.effects_text.tag_bind(tag_name, "", self.hide_effect_tooltip) + + self.effects_text.insert(tk.END, f"{value}\n", 'effect_value') + else: + self.effects_text.insert(tk.END, f"No effects data for Level {level}\n\n") + self.effects_text.insert(tk.END, "Available levels: 1, 25, 40, 50\n", 'effect_name') + + self.effects_text.config(state=tk.DISABLED) + + def show_effect_tooltip(self, event, effect_name): + """Show tooltip for effect""" + if effect_name in EFFECT_DESCRIPTIONS: + text = EFFECT_DESCRIPTIONS[effect_name] + x = event.x_root + 15 + y = event.y_root + 10 + + # Close existing if any + self.hide_effect_tooltip(None) + + self.tooltip_window = tk.Toplevel(self) + self.tooltip_window.wm_overrideredirect(True) + self.tooltip_window.wm_geometry(f"+{x}+{y}") + + label = tk.Label(self.tooltip_window, text=text, justify=tk.LEFT, + background=BG_LIGHT, foreground=TEXT_PRIMARY, + relief=tk.SOLID, borderwidth=1, font=FONT_SMALL, + padx=10, pady=5, wraplength=250) + label.pack() + + def hide_effect_tooltip(self, event): + """Hide tooltip""" + if hasattr(self, 'tooltip_window') and self.tooltip_window: + self.tooltip_window.destroy() + self.tooltip_window = None diff --git a/gui/deck_builder.py b/gui/deck_builder.py new file mode 100644 index 0000000..5d41160 --- /dev/null +++ b/gui/deck_builder.py @@ -0,0 +1,547 @@ +""" +Deck Builder Frame +Build decks with 6 cards and view combined effects with breakdown +""" + +import tkinter as tk +from tkinter import ttk, messagebox +import sys +import os +from PIL import Image, ImageTk + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from db.db_queries import ( + get_all_cards, get_all_decks, create_deck, delete_deck, + add_card_to_deck, remove_card_from_deck, get_deck_cards, + get_effects_at_level +) +from utils import resolve_image_path +from gui.theme import ( + BG_DARK, BG_DARKEST, BG_MEDIUM, BG_LIGHT, BG_HIGHLIGHT, + ACCENT_PRIMARY, ACCENT_SECONDARY, ACCENT_SUCCESS, ACCENT_ERROR, + TEXT_PRIMARY, TEXT_SECONDARY, TEXT_MUTED, + FONT_HEADER, FONT_SUBHEADER, FONT_BODY, FONT_BODY_BOLD, FONT_SMALL, FONT_TINY, + TYPE_COLORS, get_type_color, get_type_icon, + create_styled_button, create_styled_text, create_card_frame +) + + +class CardSlot(tk.Frame): + """Visual component for a single card slot""" + def __init__(self, parent, index, remove_callback, level_callback): + super().__init__(parent, bg=BG_MEDIUM, highlightthickness=2, highlightbackground=BG_LIGHT) + self.index = index + self.remove_callback = remove_callback + self.level_callback = level_callback + self.image_ref = None # Keep reference to prevent GC + + self.setup_ui() + + def setup_ui(self): + # Configure grid weight + self.columnconfigure(1, weight=1) + + # Slot number indicator + slot_label = tk.Label(self, text=f"#{self.index + 1}", font=FONT_TINY, + bg=BG_LIGHT, fg=TEXT_MUTED, padx=4, pady=2) + slot_label.place(x=2, y=2) + + # Image Area (Left) + self.image_label = tk.Label(self, bg=BG_MEDIUM, text="šŸ“­", fg=TEXT_MUTED, + font=('Segoe UI', 20)) + self.image_label.grid(row=0, column=0, rowspan=3, padx=8, pady=8) + + # Details Area (Right) + self.name_label = tk.Label(self, text="Empty Slot", bg=BG_MEDIUM, fg=TEXT_MUTED, + font=FONT_BODY_BOLD, anchor='w', wraplength=130) + self.name_label.grid(row=0, column=1, sticky='w', padx=8, pady=(10, 0)) + + self.meta_label = tk.Label(self, text="", bg=BG_MEDIUM, fg=TEXT_MUTED, + font=FONT_SMALL, anchor='w') + self.meta_label.grid(row=1, column=1, sticky='w', padx=8) + + # Controls (Bottom Right) + ctrl_frame = tk.Frame(self, bg=BG_MEDIUM) + ctrl_frame.grid(row=2, column=1, sticky='ew', padx=8, pady=8) + + # Level Selector + tk.Label(ctrl_frame, text="Lv:", bg=BG_MEDIUM, fg=TEXT_MUTED, + font=FONT_SMALL).pack(side=tk.LEFT) + + self.level_var = tk.StringVar(value="50") + self.level_combo = ttk.Combobox(ctrl_frame, textvariable=self.level_var, + values=[], width=4, state='readonly') + self.level_combo.pack(side=tk.LEFT, padx=4) + self.level_combo.bind('<>', self._on_level_change) + + # Remove Button + self.remove_btn = tk.Button(ctrl_frame, text="āœ•", bg=BG_LIGHT, fg=ACCENT_ERROR, + bd=0, font=FONT_BODY_BOLD, width=2, + activebackground=ACCENT_ERROR, activeforeground=TEXT_PRIMARY, + cursor='hand2', + command=lambda: self.remove_callback(self.index)) + self.remove_btn.pack(side=tk.RIGHT) + + # Hide controls initially + self.toggle_controls(False) + + def toggle_controls(self, visible): + state = 'normal' if visible else 'disabled' + self.level_combo.config(state='readonly' if visible else 'disabled') + if not visible: + self.remove_btn.pack_forget() + else: + self.remove_btn.pack(side=tk.RIGHT) + + def set_card(self, card_data): + """Set card data: (id, name, rarity, type, image_path, level)""" + if not card_data: + self.reset() + return + + card_id, name, rarity, card_type, image_path, level = card_data + + # Calculate valid levels based on rarity + if rarity == 'SSR': + valid_levels = [50, 45, 40, 35, 30] + max_lvl = 50 + elif rarity == 'SR': + valid_levels = [45, 40, 35, 30, 25] + max_lvl = 45 + else: # R + valid_levels = [40, 35, 30, 25, 20] + max_lvl = 40 + + self.level_combo['values'] = [str(l) for l in valid_levels] + + # Snap level to valid value if not present (e.g. old data) + if level not in valid_levels: + level = max_lvl + + # Update styling based on type + color = get_type_color(card_type) + type_icon = get_type_icon(card_type) + + self.name_label.config(text=name, fg=TEXT_PRIMARY) + self.meta_label.config(text=f"{type_icon} {rarity} │ {card_type}", fg=color) + self.level_var.set(str(level)) + + # Update border color based on rarity + rarity_borders = {'SSR': '#ffd700', 'SR': '#c0c0c0', 'R': '#cd853f'} + self.config(highlightbackground=rarity_borders.get(rarity, BG_LIGHT)) + + # Load Image + self._load_image(image_path) + + self.toggle_controls(True) + + def reset(self): + self.name_label.config(text="Empty Slot", fg=TEXT_MUTED) + self.meta_label.config(text="Click a card to add") + self.image_label.config(image='', text="šŸ“­", font=('Segoe UI', 20)) + self.config(highlightbackground=BG_LIGHT) + self.image_ref = None + self.toggle_controls(False) + + def _load_image(self, path): + resolved_path = resolve_image_path(path) + if resolved_path and os.path.exists(resolved_path): + try: + pil_img = Image.open(resolved_path) + pil_img.thumbnail((65, 65), Image.Resampling.LANCZOS) + self.image_ref = ImageTk.PhotoImage(pil_img) + self.image_label.config(image=self.image_ref, text='') + except Exception as e: + print(f"Failed to load image: {e}") + self.image_label.config(image='', text="āš ļø") + else: + self.image_label.config(image='', text="šŸ–¼ļø") + + def _on_level_change(self, event): + self.level_callback(self.index, int(self.level_var.get())) + + +class DeckBuilderFrame(ttk.Frame): + """Deck builder with combined effects breakdown""" + + def __init__(self, parent): + super().__init__(parent) + self.current_deck_id = None + self.deck_slots = [None] * 6 # 6 card slots + self.setup_ui() + self.refresh_decks() + + def setup_ui(self): + # Main container with split view + main_split = ttk.PanedWindow(self, orient=tk.HORIZONTAL) + main_split.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) + + # === Left Panel: Card Browser === + left_panel = ttk.Frame(main_split) + main_split.add(left_panel, weight=1) + + # Header + header = tk.Frame(left_panel, bg=BG_DARK) + header.pack(fill=tk.X, pady=(0, 10)) + tk.Label(header, text="šŸ“‹ Available Cards", font=FONT_SUBHEADER, + bg=BG_DARK, fg=TEXT_PRIMARY).pack(side=tk.LEFT) + + # Filters + filter_frame = tk.Frame(left_panel, bg=BG_DARK) + filter_frame.pack(fill=tk.X, pady=(0, 8)) + + # Filters - Initialize vars FIRST + self.type_var = tk.StringVar(value="All") + self.owned_only_var = tk.BooleanVar(value=False) + self.search_var = tk.StringVar() + + # Search Entry + self.search_entry = ttk.Entry(filter_frame, textvariable=self.search_var, width=18) + self.search_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 8)) + + # Placeholder behavior (before trace) + self.search_entry.insert(0, "Search...") + self.search_entry.config(foreground=TEXT_MUTED) + self.search_entry.bind('', self._on_search_focus_in) + self.search_entry.bind('', self._on_search_focus_out) + + # Add trace AFTER placeholder is set + self.search_var.trace('w', lambda *args: self.filter_cards()) + + types = ["All", "Speed", "Stamina", "Power", "Guts", "Wisdom", "Friend", "Group"] + type_combo = ttk.Combobox(filter_frame, textvariable=self.type_var, + values=types, width=9, state='readonly') + type_combo.pack(side=tk.LEFT) + type_combo.bind('<>', lambda e: self.filter_cards()) + + ttk.Checkbutton(filter_frame, text="Owned", variable=self.owned_only_var, + command=self.filter_cards).pack(side=tk.LEFT, padx=8) + + # Card List + list_frame = tk.Frame(left_panel, bg=BG_DARK) + list_frame.pack(fill=tk.BOTH, expand=True) + + self.card_tree = ttk.Treeview(list_frame, columns=('name', 'rarity', 'type'), + show='tree headings', style="DeckList.Treeview") + self.card_tree.heading('#0', text='') + self.card_tree.column('#0', width=45, anchor='center') + + self.card_tree.heading('name', text='Name') + self.card_tree.heading('rarity', text='Rarity') + self.card_tree.heading('type', text='Type') + self.card_tree.column('name', width=130) + self.card_tree.column('rarity', width=45, anchor='center') + self.card_tree.column('type', width=65, anchor='center') + + scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.card_tree.yview) + self.card_tree.configure(yscrollcommand=scrollbar.set) + + self.card_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + scrollbar.pack(side=tk.RIGHT, fill=tk.Y) + + # Double-click to add + self.card_tree.bind('', lambda e: self.add_selected_to_deck()) + + # Add Button + add_btn = create_styled_button(left_panel, text="āž• Add to Deck", + command=self.add_selected_to_deck, + style_type='accent') + add_btn.pack(fill=tk.X, pady=10) + + # === Right Panel: Deck & Stats === + right_panel = ttk.Frame(main_split) + main_split.add(right_panel, weight=2) + + # Deck Controls + deck_ctrl = tk.Frame(right_panel, bg=BG_DARK) + deck_ctrl.pack(fill=tk.X, pady=(0, 15)) + + tk.Label(deck_ctrl, text="šŸŽ“ Current Deck:", font=FONT_BODY, + bg=BG_DARK, fg=TEXT_SECONDARY).pack(side=tk.LEFT) + self.deck_combo = ttk.Combobox(deck_ctrl, width=25, state='readonly') + self.deck_combo.pack(side=tk.LEFT, padx=10) + self.deck_combo.bind('<>', self.on_deck_selected) + + ttk.Button(deck_ctrl, text="+ New", command=self.create_new_deck, + style='Small.TButton').pack(side=tk.LEFT, padx=5) + ttk.Button(deck_ctrl, text="šŸ—‘ļø Delete", command=self.delete_current_deck, + style='Small.TButton').pack(side=tk.LEFT) + + # Card count indicator + self.deck_count_label = tk.Label(deck_ctrl, text="0/6 cards", + font=FONT_SMALL, bg=BG_DARK, fg=ACCENT_PRIMARY) + self.deck_count_label.pack(side=tk.LEFT, padx=15) + + # Deck Grid (3x2) + self.slots_frame = tk.Frame(right_panel, bg=BG_DARK) + self.slots_frame.pack(fill=tk.X) + + self.card_slots = [] + for i in range(6): + slot = CardSlot(self.slots_frame, i, self.remove_from_slot, self.on_slot_level_changed) + r, c = divmod(i, 3) + slot.grid(row=r, column=c, padx=6, pady=6, sticky='nsew') + self.slots_frame.columnconfigure(c, weight=1) + self.card_slots.append(slot) + + # Stats / Effects Area + effects_header = tk.Frame(right_panel, bg=BG_DARK) + effects_header.pack(fill=tk.X, pady=(20, 10)) + tk.Label(effects_header, text="šŸ“Š Combined Effects Breakdown", + font=FONT_SUBHEADER, bg=BG_DARK, fg=TEXT_PRIMARY).pack(side=tk.LEFT) + + effects_frame = create_card_frame(right_panel) + effects_frame.pack(fill=tk.BOTH, expand=True) + + self.effects_tree = ttk.Treeview(effects_frame, + columns=('effect', 'total', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6'), + show='headings', height=8) + + self.effects_tree.heading('effect', text='Effect') + self.effects_tree.heading('total', text='TOTAL') + self.effects_tree.column('effect', width=140) + self.effects_tree.column('total', width=60, anchor='center') + + for i in range(1, 7): + self.effects_tree.heading(f'c{i}', text=f'#{i}') + self.effects_tree.column(f'c{i}', width=45, anchor='center') + + vsb = ttk.Scrollbar(effects_frame, orient=tk.VERTICAL, command=self.effects_tree.yview) + self.effects_tree.configure(yscrollcommand=vsb.set) + + self.effects_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=2, pady=2) + vsb.pack(side=tk.RIGHT, fill=tk.Y, pady=2) + + # Unique Effects Area + unique_header = tk.Frame(right_panel, bg=BG_DARK) + unique_header.pack(fill=tk.X, pady=(15, 8)) + tk.Label(unique_header, text="✨ Unique Effects", font=FONT_BODY_BOLD, + bg=BG_DARK, fg=ACCENT_SECONDARY).pack(side=tk.LEFT) + + unique_frame = create_card_frame(right_panel) + unique_frame.pack(fill=tk.X) + + self.unique_text = create_styled_text(unique_frame, height=5) + self.unique_text.pack(fill=tk.BOTH, expand=True, padx=2, pady=2) + self.unique_text.config(state=tk.DISABLED) + + self.icon_cache = {} + self.filter_cards() + + + # Helper methods for placeholder + def _on_search_focus_in(self, event): + """Clear placeholder on focus""" + if self.search_entry.get() == "Search...": + self.search_entry.delete(0, tk.END) + self.search_entry.config(foreground=TEXT_PRIMARY) + + def _on_search_focus_out(self, event): + """Show placeholder if empty""" + if not self.search_entry.get(): + self.search_entry.insert(0, "Search...") + self.search_entry.config(foreground=TEXT_MUTED) + + # --- Logic Methods --- + + def filter_cards(self): + for item in self.card_tree.get_children(): + self.card_tree.delete(item) + + type_filter = self.type_var.get() if self.type_var.get() != "All" else None + + # Ignore placeholder + search_text = self.search_var.get() + search = search_text if search_text and search_text != "Search..." else None + + owned_only = self.owned_only_var.get() + + cards = get_all_cards(type_filter=type_filter, search_term=search, owned_only=owned_only) + + for card in cards: + card_id, name, rarity, card_type, max_level, image_path, is_owned, owned_level = card + + # Load Icon + img = self.icon_cache.get(card_id) + resolved_path = resolve_image_path(image_path) + + if not img and resolved_path and os.path.exists(resolved_path): + try: + pil_img = Image.open(resolved_path) + pil_img.thumbnail((32, 32), Image.Resampling.LANCZOS) + img = ImageTk.PhotoImage(pil_img) + self.icon_cache[card_id] = img + except: + pass + + type_icon = get_type_icon(card_type) + if img: + self.card_tree.insert('', tk.END, text='', image=img, + values=(name, rarity, f"{type_icon}"), iid=str(card_id)) + else: + self.card_tree.insert('', tk.END, text='?', + values=(name, rarity, f"{type_icon}"), iid=str(card_id)) + + def refresh_decks(self): + decks = get_all_decks() + self.deck_combo['values'] = [f"{d[0]}: {d[1]}" for d in decks] + if decks and not self.current_deck_id: + self.deck_combo.current(0) + self.on_deck_selected(None) + + def on_deck_selected(self, event): + selection = self.deck_combo.get() + if selection: + self.current_deck_id = int(selection.split(':')[0]) + self.load_deck() + + def load_deck(self): + if not self.current_deck_id: + return + + # Reset visual slots + for s in self.card_slots: + s.reset() + self.deck_slots = [None] * 6 + + # Load from DB + deck_cards = get_deck_cards(self.current_deck_id) + + for card in deck_cards: + slot_pos, level, card_id, name, rarity, card_type, image_path = card + if 0 <= slot_pos < 6: + self.deck_slots[slot_pos] = card_id + self.card_slots[slot_pos].set_card((card_id, name, rarity, card_type, image_path, level)) + + self.update_deck_count() + self.update_effects_breakdown() + + def create_new_deck(self): + name = tk.simpledialog.askstring("New Deck", "Enter deck name:") + if name: + deck_id = create_deck(name) + self.current_deck_id = deck_id + self.refresh_decks() + self.deck_combo.set(f"{deck_id}: {name}") + self.load_deck() + + def delete_current_deck(self): + if self.current_deck_id: + if messagebox.askyesno("Delete Deck", "Are you sure you want to delete this deck?"): + delete_deck(self.current_deck_id) + self.current_deck_id = None + self.deck_combo.set('') + self.refresh_decks() + self.load_deck() + + def add_selected_to_deck(self): + if not self.current_deck_id: + messagebox.showwarning("No Deck", "Select or create a deck first.") + return + + selection = self.card_tree.selection() + if not selection: + return + card_id = int(selection[0]) + + # Check for duplicates + if card_id in self.deck_slots: + messagebox.showinfo("Duplicate Card", "This card is already in the deck.") + return + + # Find empty slot + for i in range(6): + if self.deck_slots[i] is None: + add_card_to_deck(self.current_deck_id, card_id, i, 50) + self.load_deck() + return + + messagebox.showinfo("Deck Full", "Remove a card first to add a new one.") + + def remove_from_slot(self, index): + if self.current_deck_id and self.deck_slots[index]: + remove_card_from_deck(self.current_deck_id, index) + self.deck_slots[index] = None + self.card_slots[index].reset() + self.update_deck_count() + self.update_effects_breakdown() + + def update_deck_count(self): + """Update the X/6 cards display""" + count = sum(1 for slot in self.deck_slots if slot is not None) + self.deck_count_label.config(text=f"{count}/6 cards") + + def on_slot_level_changed(self, index, new_level): + if self.current_deck_id and self.deck_slots[index]: + card_id = self.deck_slots[index] + add_card_to_deck(self.current_deck_id, card_id, index, new_level) + self.update_effects_breakdown() + + def update_effects_breakdown(self): + for item in self.effects_tree.get_children(): + self.effects_tree.delete(item) + + # Clear Unique Text + self.unique_text.config(state=tk.NORMAL) + self.unique_text.delete('1.0', tk.END) + + if not self.current_deck_id: + self.unique_text.insert(tk.END, "No deck selected") + self.unique_text.config(state=tk.DISABLED) + return + + # Prepare data for calculation + card_info = [] + for i in range(6): + if self.deck_slots[i]: + level = int(self.card_slots[i].level_var.get()) + card_info.append((self.deck_slots[i], level)) + else: + card_info.append(None) + + # Gather effects + all_effects = {} + unique_effects_list = [] + + for i, info in enumerate(card_info): + if info: + card_id, level = info + card_name = self.card_slots[i].name_label.cget("text") + + effects = get_effects_at_level(card_id, level) + for name, value in effects: + if name == "Unique Effect": + unique_effects_list.append(f"• {card_name}: {value}") + continue + + if name not in all_effects: + all_effects[name] = [''] * 6 + all_effects[name][i] = value + + # Configure tags + self.unique_text.tag_configure('card_name', foreground=ACCENT_PRIMARY) + + # Fill Unique Effects + if unique_effects_list: + self.unique_text.insert(tk.END, "\n".join(unique_effects_list)) + else: + self.unique_text.insert(tk.END, "No unique effects in this deck", 'card_name') + self.unique_text.config(state=tk.DISABLED) + + # Sum totals + for effect_name, values in sorted(all_effects.items()): + total = 0 + is_percent = False + for v in values: + if v: + if '%' in str(v): is_percent = True + try: + total += float(str(v).replace('%','').replace('+','')) + except: pass + + total_str = f"{total:.0f}%" if is_percent else (f"+{total:.0f}" if total > 0 else str(int(total))) + row_vals = [effect_name, total_str] + values + self.effects_tree.insert('', tk.END, values=row_vals) + +import tkinter.simpledialog diff --git a/gui/deck_view.py b/gui/deck_view.py new file mode 100644 index 0000000..6d7fb1f --- /dev/null +++ b/gui/deck_view.py @@ -0,0 +1,23 @@ +import tkinter as tk +from db.db_queries import get_deck_bonus + +class DeckView(tk.Toplevel): + def __init__(self, parent): + super().__init__(parent) + self.title("Deck Builder") + self.geometry("500x400") + + self.deck_id = 1 # Default deck + + tk.Button(self, text="Calculate Deck Bonuses", command=self.calculate).pack(pady=10) + self.output = tk.Text(self, height=20) + self.output.pack(fill=tk.BOTH, expand=True) + + def calculate(self): + self.output.delete("1.0", tk.END) + bonuses = get_deck_bonus(self.deck_id) + if not bonuses: + self.output.insert(tk.END, "No bonuses found for this deck.\n") + return + for bonus, total in bonuses: + self.output.insert(tk.END, f"{bonus}: +{total}\n") diff --git a/gui/effects_view.py b/gui/effects_view.py new file mode 100644 index 0000000..b36576e --- /dev/null +++ b/gui/effects_view.py @@ -0,0 +1,298 @@ +""" +Effects View - Display support effects at all levels with interactive slider +""" + +import tkinter as tk +from tkinter import ttk, messagebox +import sys +import os + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from db.db_queries import get_all_effects, get_effects_at_level, get_unique_effect_names, get_card_by_id +from gui.theme import ( + BG_DARK, BG_MEDIUM, BG_LIGHT, BG_HIGHLIGHT, + ACCENT_PRIMARY, ACCENT_SECONDARY, ACCENT_SUCCESS, ACCENT_TERTIARY, + TEXT_PRIMARY, TEXT_SECONDARY, TEXT_MUTED, + FONT_HEADER, FONT_SUBHEADER, FONT_BODY, FONT_BODY_BOLD, FONT_SMALL, FONT_MONO, + create_styled_button, create_styled_text, create_card_frame, + EFFECT_DESCRIPTIONS +) + + +class EffectsFrame(ttk.Frame): + """Frame for viewing support effects at different levels""" + + def __init__(self, parent): + super().__init__(parent) + self.current_card_id = None + self.current_card_name = None + self.max_level = 50 + + self.create_widgets() + + def create_widgets(self): + """Create the effects view interface""" + # Header + header_frame = tk.Frame(self, bg=BG_DARK) + header_frame.pack(fill=tk.X, padx=20, pady=15) + + self.card_label = tk.Label(header_frame, text="šŸ“Š Select a card from the Card List tab", + font=FONT_HEADER, bg=BG_DARK, fg=ACCENT_PRIMARY) + self.card_label.pack(side=tk.LEFT) + + # Legend Button + legend_btn = create_styled_button(header_frame, text="ā“ Legend", + command=self.show_legend, style_type='default') + legend_btn.config(font=FONT_SMALL, padx=10, pady=4) + legend_btn.pack(side=tk.RIGHT) + + # Level control frame + control_frame = tk.Frame(self, bg=BG_MEDIUM, padx=15, pady=12) + control_frame.pack(fill=tk.X, padx=20) + + # Level label + tk.Label(control_frame, text="Level:", font=FONT_BODY, + bg=BG_MEDIUM, fg=TEXT_SECONDARY).pack(side=tk.LEFT) + + # Level display with increment/decrement buttons + level_ctrl = tk.Frame(control_frame, bg=BG_MEDIUM) + level_ctrl.pack(side=tk.LEFT, padx=15) + + # Decrement button + dec_btn = tk.Button(level_ctrl, text="āˆ’", font=FONT_HEADER, + bg=BG_LIGHT, fg=TEXT_PRIMARY, bd=0, width=2, + activebackground=BG_HIGHLIGHT, cursor='hand2', + command=self.decrement_level) + dec_btn.pack(side=tk.LEFT) + + self.level_var = tk.IntVar(value=50) + self.level_display = tk.Label(level_ctrl, text="50", width=4, font=FONT_HEADER, + bg=BG_LIGHT, fg=ACCENT_PRIMARY, padx=10) + self.level_display.pack(side=tk.LEFT, padx=2) + + # Increment button + inc_btn = tk.Button(level_ctrl, text="+", font=FONT_HEADER, + bg=BG_LIGHT, fg=TEXT_PRIMARY, bd=0, width=2, + activebackground=BG_HIGHLIGHT, cursor='hand2', + command=self.increment_level) + inc_btn.pack(side=tk.LEFT) + + # Quick level buttons + button_frame = tk.Frame(control_frame, bg=BG_MEDIUM) + button_frame.pack(side=tk.LEFT, padx=25) + + quick_levels = [1, 25, 40, 50] + for lvl in quick_levels: + btn = create_styled_button(button_frame, text=f"Lv{lvl}", + command=lambda l=lvl: self.set_level(l), + style_type='default') + btn.config(width=5, font=FONT_SMALL, padx=6, pady=3) + btn.pack(side=tk.LEFT, padx=3) + + # Main content area + content_frame = tk.Frame(self, bg=BG_DARK) + content_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=15) + + # Left: Current level effects + left_frame = ttk.LabelFrame(content_frame, text=" Current Level Effects ", padding=12) + left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 10)) + + self.current_effects = create_styled_text(left_frame, height=15) + self.current_effects.pack(fill=tk.BOTH, expand=True) + self.current_effects.config(state=tk.DISABLED) + + # Right: Effect progression table + right_frame = ttk.LabelFrame(content_frame, text=" Effect Progression ", padding=12) + right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True) + + # Treeview for effect table + columns = ('effect', 'lv1', 'lv25', 'lv40', 'lv50') + self.effects_tree = ttk.Treeview(right_frame, columns=columns, show='headings', height=12) + + self.effects_tree.heading('effect', text='Effect', anchor='w') + self.effects_tree.column('effect', width=140, minwidth=120) + + for col in columns[1:]: + level = col.replace('lv', 'Lv ') + self.effects_tree.heading(col, text=level) + self.effects_tree.column(col, width=65, anchor='center') + + scrollbar = ttk.Scrollbar(right_frame, orient=tk.VERTICAL, command=self.effects_tree.yview) + self.effects_tree.configure(yscrollcommand=scrollbar.set) + + self.effects_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + scrollbar.pack(side=tk.RIGHT, fill=tk.Y) + + def show_legend(self): + """Show effect explanations""" + legend = { + "Friendship Bonus": "Increases stats gained when training with this support card during Friendship Training (orange aura).", + "Motivation Bonus": "Increases stats gained based on your Uma's motivation level.", + "Specialty Rate": "Increases the chance of this card appearing in its specialty training.", + "Training Bonus": "Flat percentage increase to stats gained in training where this card is present.", + "Initial Bond": "Starting gauge value for this card.", + "Race Bonus": "Increases stats gained from racing.", + "Fan Count Bonus": "Increases fans gained from racing.", + "Skill Pt Bonus": "Bonus skill points gained when training with this card.", + "Hint Lv": "Starting level of skills taught by this card's hints.", + "Hint Rate": "Increases chance of getting a hint event." + } + + text = "šŸ“– Effect Explanations:\n\n" + for name, desc in legend.items(): + text += f"• {name}:\n {desc}\n\n" + + messagebox.showinfo("Effect Legend", text) + + def set_card(self, card_id): + """Load a card's effects""" + self.current_card_id = card_id + + # Get card info for max level + card = get_card_by_id(card_id) + if card: + self.current_card_name = card[1] + self.max_level = card[4] + if self.level_var.get() > self.max_level: + self.level_var.set(self.max_level) + self.level_display.config(text=str(self.max_level)) + + self.card_label.config(text=f"šŸ“Š {self.current_card_name}") + + # Update displays + self.update_current_effects() + self.update_progression_table() + + def set_level(self, level): + """Set level from quick button""" + if level <= self.max_level: + self.level_var.set(level) + self.level_display.config(text=str(level)) + self.update_current_effects() + + def increment_level(self): + """Increase level by 1""" + current = self.level_var.get() + if current < self.max_level: + self.set_level(current + 1) + + def decrement_level(self): + """Decrease level by 1""" + current = self.level_var.get() + if current > 1: + self.set_level(current - 1) + + def update_current_effects(self): + """Update the current level effects display""" + self.current_effects.config(state=tk.NORMAL) + self.current_effects.delete('1.0', tk.END) + + # Configure tags + self.current_effects.tag_configure('header', font=FONT_SUBHEADER, foreground=ACCENT_PRIMARY) + self.current_effects.tag_configure('highlight', foreground=ACCENT_SUCCESS) + self.current_effects.tag_configure('effect_name', foreground=TEXT_SECONDARY) + self.current_effects.tag_configure('effect_value', foreground=TEXT_PRIMARY, font=FONT_BODY_BOLD) + self.current_effects.tag_configure('effect_tooltip', underline=False) + + if not self.current_card_id: + self.current_effects.insert(tk.END, "No card selected\n\n", 'effect_name') + self.current_effects.insert(tk.END, "Select a card from the Card List tab to view its effects.", 'effect_name') + self.current_effects.config(state=tk.DISABLED) + return + + level = self.level_var.get() + effects = get_effects_at_level(self.current_card_id, level) + + self.current_effects.insert(tk.END, f"━━━ Level {level} ━━━\n\n", 'header') + + if effects: + for name, value in effects: + # Highlight high values + prefix = "" + if '%' in str(value): + try: + num = int(str(value).replace('%', '').replace('+', '')) + if num >= 20: + prefix = "ā˜… " + except: + pass + + if prefix: + self.current_effects.insert(tk.END, prefix, 'highlight') + + # Insert effect name with tooltip tag + tag_name = f"tooltip_{name.replace(' ', '_')}" + self.current_effects.insert(tk.END, f"{name}: ", ('effect_name', tag_name)) + + # Bind tooltip events + self.current_effects.tag_bind(tag_name, "", lambda e, n=name: self.show_effect_tooltip(e, n)) + self.current_effects.tag_bind(tag_name, "", self.hide_effect_tooltip) + + self.current_effects.insert(tk.END, f"{value}\n", 'effect_value') + else: + self.current_effects.insert(tk.END, "No effect data available for this level.\n\n", 'effect_name') + self.current_effects.insert(tk.END, "Try selecting: Lv 1, 25, 40, or 50", 'effect_name') + + self.current_effects.config(state=tk.DISABLED) + + def show_effect_tooltip(self, event, effect_name): + """Show tooltip for effect""" + if effect_name in EFFECT_DESCRIPTIONS: + text = EFFECT_DESCRIPTIONS[effect_name] + x = event.x_root + 15 + y = event.y_root + 10 + + # Close existing if any + self.hide_effect_tooltip(None) + + self.tooltip_window = tk.Toplevel(self) + self.tooltip_window.wm_overrideredirect(True) + self.tooltip_window.wm_geometry(f"+{x}+{y}") + + label = tk.Label(self.tooltip_window, text=text, justify=tk.LEFT, + background=BG_LIGHT, foreground=TEXT_PRIMARY, + relief=tk.SOLID, borderwidth=1, font=FONT_SMALL, + padx=10, pady=5, wraplength=250) + label.pack() + + def hide_effect_tooltip(self, event): + """Hide tooltip""" + if hasattr(self, 'tooltip_window') and self.tooltip_window: + self.tooltip_window.destroy() + self.tooltip_window = None + + def update_progression_table(self): + """Update the effect progression table""" + self.effects_tree.delete(*self.effects_tree.get_children()) + + if not self.current_card_id: + return + + # Get all effects + all_effects = get_all_effects(self.current_card_id) + + # Organize by effect name + effect_by_level = {} + for level, effect_name, effect_value in all_effects: + if effect_name not in effect_by_level: + effect_by_level[effect_name] = {} + effect_by_level[effect_name][level] = effect_value + + # Key levels for the table + key_levels = [1, 25, 40, 50] + + # Add rows + for effect_name, levels in sorted(effect_by_level.items()): + row = [effect_name] + for lvl in key_levels: + # Find closest level we have data for + value = levels.get(lvl, '') + if not value: + # Try to find nearest + for l in sorted(levels.keys()): + if l <= lvl: + value = levels[l] + row.append(value) + + self.effects_tree.insert('', tk.END, values=row) diff --git a/gui/hints_skills_view.py b/gui/hints_skills_view.py new file mode 100644 index 0000000..796f990 --- /dev/null +++ b/gui/hints_skills_view.py @@ -0,0 +1,180 @@ +""" +Hints and Skills View - Display support hints and event skills +""" + +import tkinter as tk +from tkinter import ttk +import sys +import os + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from db.db_queries import get_hints, get_events, get_all_event_skills, get_card_by_id +from gui.theme import ( + BG_DARK, BG_MEDIUM, BG_LIGHT, + ACCENT_PRIMARY, ACCENT_SECONDARY, ACCENT_TERTIARY, ACCENT_SUCCESS, + TEXT_PRIMARY, TEXT_SECONDARY, TEXT_MUTED, + FONT_HEADER, FONT_SUBHEADER, FONT_BODY, FONT_BODY_BOLD, FONT_SMALL, + create_styled_text, create_card_frame +) + + +class HintsSkillsFrame(ttk.Frame): + """Frame for viewing support hints and event skills""" + + def __init__(self, parent): + super().__init__(parent) + self.current_card_id = None + self.current_card_name = None + + self.create_widgets() + + def create_widgets(self): + """Create the hints and skills interface""" + # Header + header_frame = tk.Frame(self, bg=BG_DARK) + header_frame.pack(fill=tk.X, padx=20, pady=15) + + self.card_label = tk.Label(header_frame, + text="šŸ’” Select a card from the Card List tab", + font=FONT_HEADER, bg=BG_DARK, fg=ACCENT_PRIMARY) + self.card_label.pack(side=tk.LEFT) + + # Main content with two columns + content_frame = tk.Frame(self, bg=BG_DARK) + content_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=(0, 15)) + + # Left column: Hints + left_container = tk.Frame(content_frame, bg=BG_DARK) + left_container.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 10)) + + hints_header = tk.Frame(left_container, bg=BG_DARK) + hints_header.pack(fill=tk.X, pady=(0, 8)) + tk.Label(hints_header, text="šŸŽÆ Training Hints", font=FONT_SUBHEADER, + bg=BG_DARK, fg=TEXT_PRIMARY).pack(side=tk.LEFT) + + hints_frame = create_card_frame(left_container) + hints_frame.pack(fill=tk.BOTH, expand=True) + + self.hints_text = create_styled_text(hints_frame, height=18) + self.hints_text.pack(fill=tk.BOTH, expand=True, padx=2, pady=2) + self.hints_text.config(state=tk.DISABLED) + + # Configure tags for hints + self.hints_text.tag_configure('header', font=FONT_SUBHEADER, foreground=ACCENT_PRIMARY) + self.hints_text.tag_configure('skill', foreground=ACCENT_TERTIARY, font=FONT_BODY_BOLD) + self.hints_text.tag_configure('desc', foreground=TEXT_MUTED) + self.hints_text.tag_configure('number', foreground=ACCENT_SECONDARY) + + # Right column: Events and Skills + right_container = tk.Frame(content_frame, bg=BG_DARK) + right_container.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True) + + events_header = tk.Frame(right_container, bg=BG_DARK) + events_header.pack(fill=tk.X, pady=(0, 8)) + tk.Label(events_header, text="šŸ“… Training Events & Skills", font=FONT_SUBHEADER, + bg=BG_DARK, fg=TEXT_PRIMARY).pack(side=tk.LEFT) + + events_frame = create_card_frame(right_container) + events_frame.pack(fill=tk.BOTH, expand=True) + + tree_container = tk.Frame(events_frame, bg=BG_MEDIUM) + tree_container.pack(fill=tk.BOTH, expand=True, padx=2, pady=2) + + # Treeview for events + self.events_tree = ttk.Treeview(tree_container, columns=('event', 'skills'), show='tree headings') + self.events_tree.heading('#0', text='') + self.events_tree.heading('event', text='Event/Skill') + self.events_tree.heading('skills', text='Details') + + self.events_tree.column('#0', width=35) + self.events_tree.column('event', width=240) + self.events_tree.column('skills', width=180) + + scrollbar = ttk.Scrollbar(tree_container, orient=tk.VERTICAL, command=self.events_tree.yview) + self.events_tree.configure(yscrollcommand=scrollbar.set) + + self.events_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + scrollbar.pack(side=tk.RIGHT, fill=tk.Y) + + # Summary section at bottom + summary_frame = tk.Frame(self, bg=BG_MEDIUM, padx=15, pady=10) + summary_frame.pack(fill=tk.X, padx=20, pady=(0, 10)) + + self.summary_label = tk.Label(summary_frame, text="", font=FONT_SMALL, + bg=BG_MEDIUM, fg=TEXT_SECONDARY) + self.summary_label.pack() + + def set_card(self, card_id): + """Load a card's hints and skills""" + self.current_card_id = card_id + + # Get card info + card = get_card_by_id(card_id) + if card: + self.current_card_name = card[1] + self.card_label.config(text=f"šŸ’” {self.current_card_name}") + + self.update_hints_display() + self.update_events_display() + + def update_hints_display(self): + """Update the hints display""" + self.hints_text.config(state=tk.NORMAL) + self.hints_text.delete('1.0', tk.END) + + if not self.current_card_id: + self.hints_text.insert(tk.END, "No card selected\n\n", 'desc') + self.hints_text.insert(tk.END, "Select a card from the Card List tab to view its hints.", 'desc') + self.hints_text.config(state=tk.DISABLED) + return + + hints = get_hints(self.current_card_id) + + self.hints_text.insert(tk.END, "Training Skills this card can teach:\n\n", 'header') + + if hints: + for i, (hint_name, hint_desc) in enumerate(hints, 1): + self.hints_text.insert(tk.END, f" {i}. ", 'number') + self.hints_text.insert(tk.END, f"{hint_name}\n", 'skill') + if hint_desc: + self.hints_text.insert(tk.END, f" {hint_desc}\n", 'desc') + self.hints_text.insert(tk.END, "\n") + else: + self.hints_text.insert(tk.END, " No hints/skills data available.\n\n", 'desc') + self.hints_text.insert(tk.END, " This may mean:\n", 'desc') + self.hints_text.insert(tk.END, " • Card hasn't been scraped yet\n", 'desc') + self.hints_text.insert(tk.END, " • Card has no trainable skills\n", 'desc') + + self.hints_text.config(state=tk.DISABLED) + + def update_events_display(self): + """Update the events tree display""" + self.events_tree.delete(*self.events_tree.get_children()) + + if not self.current_card_id: + return + + events = get_events(self.current_card_id) + events_with_skills = get_all_event_skills(self.current_card_id) + + # Add events as parent nodes + for event_id, event_name, event_type in events: + skills = events_with_skills.get(event_name, []) + skill_count = f"{len(skills)} skills" if skills else "No skills" + + event_node = self.events_tree.insert('', tk.END, text='šŸ“…', + values=(event_name, skill_count)) + + # Add skills as children + for skill in skills: + self.events_tree.insert(event_node, tk.END, text='⭐', + values=(skill, '')) + + # Update summary + hint_count = len(get_hints(self.current_card_id)) + event_count = len(events) + + self.summary_label.config( + text=f"šŸ“Š Summary: {hint_count} hints │ {event_count} events" + ) diff --git a/gui/main_window.py b/gui/main_window.py new file mode 100644 index 0000000..335b213 --- /dev/null +++ b/gui/main_window.py @@ -0,0 +1,239 @@ +""" +Main Window for Umamusume Support Card Manager +Tabbed interface for card browsing, effects, deck builder, and hints +""" + +import tkinter as tk +from tkinter import ttk +import sys +import os + +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from db.db_queries import get_database_stats, get_owned_count +from gui.card_view import CardListFrame +from gui.effects_view import EffectsFrame +from gui.hints_skills_view import HintsSkillsFrame +from gui.deck_builder import DeckBuilderFrame +from gui.update_dialog import show_update_dialog +from gui.theme import ( + configure_styles, create_styled_button, + BG_DARK, BG_MEDIUM, BG_LIGHT, BG_HIGHLIGHT, + ACCENT_PRIMARY, ACCENT_SECONDARY, ACCENT_TERTIARY, + TEXT_PRIMARY, TEXT_SECONDARY, TEXT_MUTED, + FONT_TITLE, FONT_HEADER, FONT_BODY, FONT_SMALL +) +from utils import resolve_image_path +from version import VERSION + + +class MainWindow: + """Main application window with tabbed interface""" + + def __init__(self): + self.root = tk.Tk() + self.root.title("Umamusume Support Card Manager") + self.root.geometry("1350x800") + self.root.minsize(1350, 800) + + # Set icon + try: + icon_path = resolve_image_path("1_Special Week.png") + if icon_path and os.path.exists(icon_path): + icon_img = tk.PhotoImage(file=icon_path) + self.root.iconphoto(True, icon_img) + except Exception as e: + print(f"Failed to set icon: {e}") + + # Configure all styles using centralized theme + configure_styles(self.root) + + # Create main container + main_container = ttk.Frame(self.root) + main_container.pack(fill=tk.BOTH, expand=True) + + # Header with stats + self.create_header(main_container) + + # Status bar - Create BEFORE notebook to anchor it to bottom + self.create_status_bar(main_container) + + # Tabbed notebook + self.notebook = ttk.Notebook(main_container) + self.notebook.pack(fill=tk.BOTH, expand=True, padx=15, pady=8) + + # Create tabs + self.create_tabs() + + def create_header(self, parent): + """Create header with database statistics and update button""" + # Header container with subtle bottom border effect + header_outer = tk.Frame(parent, bg=BG_DARK) + header_outer.pack(fill=tk.X) + + header_frame = tk.Frame(header_outer, bg=BG_DARK) + header_frame.pack(fill=tk.X, padx=20, pady=15) + + # Left side: Title and version + title_frame = tk.Frame(header_frame, bg=BG_DARK) + title_frame.pack(side=tk.LEFT) + + # App icon and title + title_label = tk.Label( + title_frame, + text="šŸ‡ Umamusume Support Card Manager", + font=FONT_TITLE, + bg=BG_DARK, + fg=ACCENT_PRIMARY + ) + title_label.pack(side=tk.LEFT) + + # Version badge + version_frame = tk.Frame(title_frame, bg=ACCENT_SECONDARY, padx=8, pady=2) + version_frame.pack(side=tk.LEFT, padx=12) + version_label = tk.Label( + version_frame, + text=f"v{VERSION}", + font=FONT_SMALL, + bg=ACCENT_SECONDARY, + fg=TEXT_PRIMARY + ) + version_label.pack() + + # Right side: Update button and stats + right_frame = tk.Frame(header_frame, bg=BG_DARK) + right_frame.pack(side=tk.RIGHT) + + # Update button with modern styling + self.update_button = create_styled_button( + right_frame, + text="šŸ”„ Check for Updates", + command=self.show_update_dialog, + style_type='default' + ) + self.update_button.pack(side=tk.RIGHT, padx=(15, 0)) + + # Stats panel with card-like appearance + stats_frame = tk.Frame(right_frame, bg=BG_MEDIUM, padx=15, pady=8) + stats_frame.pack(side=tk.RIGHT) + + stats = get_database_stats() + owned = get_owned_count() + + # Build stats text with better formatting + stats_parts = [ + f"šŸ“Š {stats.get('total_cards', 0)} Cards", + f"✨ {owned} Owned", + f"šŸ† {stats.get('by_rarity', {}).get('SSR', 0)} SSR", + f"⭐ {stats.get('by_rarity', {}).get('SR', 0)} SR", + f"ā— {stats.get('by_rarity', {}).get('R', 0)} R" + ] + stats_text = " │ ".join(stats_parts) + + self.stats_label = tk.Label( + stats_frame, + text=stats_text, + font=FONT_SMALL, + bg=BG_MEDIUM, + fg=TEXT_SECONDARY + ) + self.stats_label.pack() + + # Subtle separator line + separator = tk.Frame(header_outer, bg=BG_LIGHT, height=1) + separator.pack(fill=tk.X, padx=15) + + def create_tabs(self): + """Create all tab frames""" + # Card List Tab + self.card_frame = CardListFrame(self.notebook, on_card_selected_callback=self.on_card_selected) + self.notebook.add(self.card_frame, text=" šŸ“‹ Card List ") + + # Effects Tab + self.effects_frame = EffectsFrame(self.notebook) + self.notebook.add(self.effects_frame, text=" šŸ“Š Effects ") + + # Deck Builder Tab + self.deck_frame = DeckBuilderFrame(self.notebook) + self.notebook.add(self.deck_frame, text=" šŸŽ“ Deck Builder ") + + # Hints & Skills Tab + self.hints_frame = HintsSkillsFrame(self.notebook) + self.notebook.add(self.hints_frame, text=" šŸ’” Hints & Skills ") + + def create_status_bar(self, parent): + """Create status bar at bottom""" + status_outer = tk.Frame(parent, bg=BG_MEDIUM) + status_outer.pack(fill=tk.X, side=tk.BOTTOM) + + status_frame = tk.Frame(status_outer, bg=BG_MEDIUM) + status_frame.pack(fill=tk.X, padx=15, pady=8) + + self.status_label = tk.Label( + status_frame, + text="āœ“ Ready", + font=FONT_SMALL, + bg=BG_MEDIUM, + fg=TEXT_MUTED + ) + self.status_label.pack(side=tk.LEFT) + + tk.Label( + status_frame, + text="Data from gametora.com", + font=FONT_SMALL, + bg=BG_MEDIUM, + fg=TEXT_MUTED + ).pack(side=tk.RIGHT) + + tk.Label( + status_frame, + text="Made by Kiyreload │ ", + font=FONT_SMALL, + bg=BG_MEDIUM, + fg=ACCENT_TERTIARY + ).pack(side=tk.RIGHT) + + def on_card_selected(self, card_id, card_name): + """Handle card selection from card list""" + # Update other tabs with selected card + if hasattr(self, 'effects_frame'): + self.effects_frame.set_card(card_id) + if hasattr(self, 'hints_frame'): + self.hints_frame.set_card(card_id) + + self.status_label.config(text=f"šŸ“Œ Selected: {card_name}") + + def refresh_stats(self): + """Refresh the statistics display""" + stats = get_database_stats() + owned = get_owned_count() + + stats_parts = [ + f"šŸ“Š {stats.get('total_cards', 0)} Cards", + f"✨ {owned} Owned", + f"šŸ† {stats.get('by_rarity', {}).get('SSR', 0)} SSR", + f"⭐ {stats.get('by_rarity', {}).get('SR', 0)} SR", + f"ā— {stats.get('by_rarity', {}).get('R', 0)} R" + ] + stats_text = " │ ".join(stats_parts) + + self.stats_label.config(text=stats_text) + + def show_update_dialog(self): + """Show the update dialog""" + show_update_dialog(self.root) + + def run(self): + """Start the application""" + self.root.mainloop() + + +def main(): + """Entry point for GUI""" + app = MainWindow() + app.run() + + +if __name__ == "__main__": + main() diff --git a/gui/theme.py b/gui/theme.py new file mode 100644 index 0000000..6ea14aa --- /dev/null +++ b/gui/theme.py @@ -0,0 +1,461 @@ +""" +Centralized Theme Module for Umamusume Support Card Manager +Modern glassmorphism-inspired dark theme with consistent styling +""" + +import tkinter as tk +from tkinter import ttk + +# ═══════════════════════════════════════════════════════════════════════════════ +# COLOR PALETTE +# ═══════════════════════════════════════════════════════════════════════════════ + +# Primary backgrounds (rich purplish-blues with depth) +BG_DARKEST = '#0d0d1a' # Deepest background +BG_DARK = '#151528' # Main application background +BG_MEDIUM = '#1e1e3f' # Card/panel backgrounds +BG_LIGHT = '#2a2a5a' # Elevated elements, hover states +BG_HIGHLIGHT = '#3d3d7a' # Active/selected backgrounds + +# Accents (vibrant but refined) +ACCENT_PRIMARY = '#ff6b9d' # Pink accent (main action color) +ACCENT_SECONDARY = '#7c5cff' # Purple accent (secondary actions) +ACCENT_TERTIARY = '#5ce1e6' # Cyan accent (info/highlights) +ACCENT_SUCCESS = '#4ade80' # Green for success states +ACCENT_WARNING = '#fbbf24' # Amber for warnings +ACCENT_ERROR = '#ff6b6b' # Red for errors + +# Text colors +TEXT_PRIMARY = '#ffffff' # Primary text (headings, important) +TEXT_SECONDARY = '#e0e0f0' # Secondary text (body text) +TEXT_MUTED = '#9090b0' # Muted text (labels, hints) +TEXT_DISABLED = '#606080' # Disabled text + +# Rarity colors (enhanced with glow effect potential) +RARITY_SSR = '#ffd700' # Gold +RARITY_SR = '#c0c0c0' # Silver +RARITY_R = '#cd853f' # Bronze (warmer) + +RARITY_COLORS = { + 'SSR': RARITY_SSR, + 'SR': RARITY_SR, + 'R': RARITY_R +} + +# Type colors (for card types) +TYPE_COLORS = { + 'Speed': '#3b82f6', # Blue + 'Stamina': '#f97316', # Orange + 'Power': '#eab308', # Yellow + 'Guts': '#ef4444', # Red + 'Wisdom': '#22c55e', # Green + 'Friend': '#a855f7', # Purple + 'Group': '#f59e0b' # Amber +} + +# Type icons +TYPE_ICONS = { + 'Speed': 'šŸƒ', + 'Stamina': 'šŸ’š', + 'Power': 'šŸ’Ŗ', + 'Guts': 'šŸ”„', + 'Wisdom': '🧠', + 'Friend': 'šŸ’œ', + 'Group': 'šŸ‘„' +} + +# ═══════════════════════════════════════════════════════════════════════════════ +# FONTS +# ═══════════════════════════════════════════════════════════════════════════════ + +FONT_FAMILY = 'Segoe UI' +FONT_FAMILY_MONO = 'Consolas' + +FONT_TITLE = (FONT_FAMILY, 18, 'bold') +FONT_HEADER = (FONT_FAMILY, 14, 'bold') +FONT_SUBHEADER = (FONT_FAMILY, 12, 'bold') +FONT_BODY = (FONT_FAMILY, 11) +FONT_BODY_BOLD = (FONT_FAMILY, 11, 'bold') +FONT_SMALL = (FONT_FAMILY, 10) +FONT_TINY = (FONT_FAMILY, 9) +FONT_MONO = (FONT_FAMILY_MONO, 11) +FONT_MONO_SMALL = (FONT_FAMILY_MONO, 10) + +# ═══════════════════════════════════════════════════════════════════════════════ +# STYLE CONFIGURATION +# ═══════════════════════════════════════════════════════════════════════════════ + +def configure_styles(root: tk.Tk): + """Configure all ttk styles for the application""" + style = ttk.Style() + + # Use clam theme as base for better customization + style.theme_use('clam') + + # ───────────────────────────────────────────────────────────────────────── + # General Frame and Label styles + # ───────────────────────────────────────────────────────────────────────── + style.configure('TFrame', background=BG_DARK) + style.configure('TLabel', background=BG_DARK, foreground=TEXT_SECONDARY, font=FONT_BODY) + style.configure('TLabelframe', background=BG_DARK, foreground=TEXT_SECONDARY) + style.configure('TLabelframe.Label', background=BG_DARK, foreground=ACCENT_PRIMARY, font=FONT_SUBHEADER) + + # Header styles + style.configure('Title.TLabel', font=FONT_TITLE, foreground=TEXT_PRIMARY, background=BG_DARK) + style.configure('Header.TLabel', font=FONT_HEADER, foreground=ACCENT_PRIMARY, background=BG_DARK) + style.configure('Subheader.TLabel', font=FONT_SUBHEADER, foreground=TEXT_PRIMARY, background=BG_DARK) + style.configure('Subtitle.TLabel', font=FONT_SMALL, foreground=TEXT_MUTED, background=BG_DARK) + style.configure('Stats.TLabel', font=FONT_SMALL, foreground=TEXT_SECONDARY, background=BG_MEDIUM, padding=8) + style.configure('Accent.TLabel', font=FONT_BODY, foreground=ACCENT_PRIMARY, background=BG_DARK) + + # ───────────────────────────────────────────────────────────────────────── + # Button styles + # ───────────────────────────────────────────────────────────────────────── + style.configure('TButton', + padding=(12, 6), + font=FONT_BODY, + background=BG_LIGHT, + foreground=TEXT_PRIMARY) + style.map('TButton', + background=[('active', BG_HIGHLIGHT), ('pressed', ACCENT_PRIMARY)], + foreground=[('active', TEXT_PRIMARY), ('pressed', TEXT_PRIMARY)]) + + style.configure('Accent.TButton', + padding=(12, 6), + font=FONT_BODY_BOLD, + background=ACCENT_PRIMARY, + foreground=TEXT_PRIMARY) + style.map('Accent.TButton', + background=[('active', '#ff8ab5'), ('pressed', '#e55a88')]) + + style.configure('Small.TButton', + padding=(8, 4), + font=FONT_SMALL) + + # ───────────────────────────────────────────────────────────────────────── + # Checkbutton styles + # ───────────────────────────────────────────────────────────────────────── + style.configure('TCheckbutton', + background=BG_DARK, + foreground=TEXT_SECONDARY, + font=FONT_BODY) + style.map('TCheckbutton', + background=[('active', BG_DARK)], + foreground=[('active', TEXT_PRIMARY)]) + + style.configure('Large.TCheckbutton', + font=FONT_BODY_BOLD, + background=BG_DARK, + foreground=TEXT_PRIMARY) + + # ───────────────────────────────────────────────────────────────────────── + # Entry and Combobox styles + # ───────────────────────────────────────────────────────────────────────── + style.configure('TEntry', + fieldbackground=BG_MEDIUM, + foreground=TEXT_PRIMARY, + insertcolor=TEXT_PRIMARY, + padding=6) + + style.configure('TCombobox', + fieldbackground=BG_MEDIUM, + background=BG_LIGHT, + foreground=TEXT_PRIMARY, + arrowcolor=TEXT_MUTED, + padding=4) + style.map('TCombobox', + fieldbackground=[('readonly', BG_MEDIUM)], + selectbackground=[('readonly', BG_HIGHLIGHT)]) + + # ───────────────────────────────────────────────────────────────────────── + # Notebook (Tab) styles + # ───────────────────────────────────────────────────────────────────────── + style.configure('TNotebook', + background=BG_DARK, + borderwidth=0) + style.configure('TNotebook.Tab', + padding=(20, 10), + font=FONT_BODY_BOLD, + background=BG_MEDIUM, + foreground=TEXT_MUTED) + style.map('TNotebook.Tab', + background=[('selected', BG_LIGHT), ('active', BG_HIGHLIGHT)], + foreground=[('selected', ACCENT_PRIMARY), ('active', TEXT_PRIMARY)], + expand=[('selected', (0, 0, 0, 2))]) + + # ───────────────────────────────────────────────────────────────────────── + # Treeview styles + # ───────────────────────────────────────────────────────────────────────── + style.configure('Treeview', + background=BG_MEDIUM, + foreground=TEXT_SECONDARY, + fieldbackground=BG_MEDIUM, + font=FONT_BODY, + rowheight=28) + style.configure('Treeview.Heading', + font=FONT_BODY_BOLD, + background=BG_LIGHT, + foreground=TEXT_PRIMARY, + padding=6) + style.map('Treeview', + background=[('selected', ACCENT_PRIMARY)], + foreground=[('selected', TEXT_PRIMARY)]) + style.map('Treeview.Heading', + background=[('active', BG_HIGHLIGHT)]) + + # Card list with larger rows for thumbnails + style.configure('CardList.Treeview', + background=BG_MEDIUM, + foreground=TEXT_SECONDARY, + fieldbackground=BG_MEDIUM, + font=FONT_BODY, + rowheight=40) + + # Deck list style + style.configure('DeckList.Treeview', + background=BG_MEDIUM, + foreground=TEXT_SECONDARY, + fieldbackground=BG_MEDIUM, + font=FONT_BODY, + rowheight=40) + style.map('DeckList.Treeview', + background=[('selected', ACCENT_PRIMARY)]) + + # ───────────────────────────────────────────────────────────────────────── + # Scale (Slider) styles + # ───────────────────────────────────────────────────────────────────────── + style.configure('TScale', + background=BG_DARK, + troughcolor=BG_MEDIUM, + sliderthickness=18) + style.configure('Horizontal.TScale', + background=BG_DARK) + + # ───────────────────────────────────────────────────────────────────────── + # Progressbar styles + # ───────────────────────────────────────────────────────────────────────── + style.configure('TProgressbar', + background=ACCENT_PRIMARY, + troughcolor=BG_MEDIUM, + borderwidth=0, + thickness=8) + + # ───────────────────────────────────────────────────────────────────────── + # Scrollbar styles + # ───────────────────────────────────────────────────────────────────────── + style.configure('TScrollbar', + background=BG_LIGHT, + troughcolor=BG_MEDIUM, + borderwidth=0, + arrowsize=14) + style.map('TScrollbar', + background=[('active', BG_HIGHLIGHT), ('pressed', ACCENT_PRIMARY)]) + + # ───────────────────────────────────────────────────────────────────────── + # PanedWindow styles + # ───────────────────────────────────────────────────────────────────────── + style.configure('TPanedwindow', background=BG_DARK) + + # Set root background + root.configure(bg=BG_DARK) + + +# ═══════════════════════════════════════════════════════════════════════════════ +# WIDGET HELPER FUNCTIONS +# ═══════════════════════════════════════════════════════════════════════════════ + +def create_styled_button(parent, text, command=None, style_type='default', **kwargs): + """Create a styled tk.Button with modern appearance""" + bg_colors = { + 'default': BG_LIGHT, + 'accent': ACCENT_PRIMARY, + 'secondary': ACCENT_SECONDARY, + 'success': ACCENT_SUCCESS, + 'warning': ACCENT_WARNING, + 'danger': ACCENT_ERROR + } + hover_colors = { + 'default': BG_HIGHLIGHT, + 'accent': '#ff8ab5', + 'secondary': '#9580ff', + 'success': '#6ee7a0', + 'warning': '#fcd34d', + 'danger': '#ff8a8a' + } + + bg = bg_colors.get(style_type, BG_LIGHT) + hover_bg = hover_colors.get(style_type, BG_HIGHLIGHT) + + btn = tk.Button( + parent, + text=text, + command=command, + bg=bg, + fg=TEXT_PRIMARY, + font=FONT_BODY_BOLD if style_type == 'accent' else FONT_BODY, + activebackground=hover_bg, + activeforeground=TEXT_PRIMARY, + bd=0, + padx=16, + pady=8, + cursor='hand2', + relief=tk.FLAT, + **kwargs + ) + + # Add hover effect + def on_enter(e): + btn.configure(bg=hover_bg) + def on_leave(e): + btn.configure(bg=bg) + + btn.bind('', on_enter) + btn.bind('', on_leave) + + return btn + + +def create_styled_text(parent, height=10, **kwargs): + """Create a styled tk.Text widget with modern appearance""" + text = tk.Text( + parent, + bg=BG_MEDIUM, + fg=TEXT_SECONDARY, + font=FONT_MONO, + insertbackground=TEXT_PRIMARY, + selectbackground=ACCENT_PRIMARY, + selectforeground=TEXT_PRIMARY, + relief=tk.FLAT, + padx=12, + pady=12, + height=height, + wrap=tk.WORD, + **kwargs + ) + return text + + +def create_card_frame(parent, **kwargs): + """Create a styled frame that looks like a card""" + frame = tk.Frame( + parent, + bg=BG_MEDIUM, + highlightthickness=1, + highlightbackground=BG_LIGHT, + **kwargs + ) + return frame + + +def get_rarity_color(rarity): + """Get the color for a card rarity""" + return RARITY_COLORS.get(rarity, TEXT_SECONDARY) + + +def get_type_color(card_type): + """Get the color for a card type""" + return TYPE_COLORS.get(card_type, TEXT_SECONDARY) + + +def get_type_icon(card_type): + """Get the emoji icon for a card type""" + return TYPE_ICONS.get(card_type, '') + +# ═══════════════════════════════════════════════════════════════════════════════ +# TOOLTIPS & HELPERS +# ═══════════════════════════════════════════════════════════════════════════════ + +EFFECT_DESCRIPTIONS = { + "Friendship Bonus": "Increases stats gained when training with this support card during Friendship Training (orange aura).", + "Motivation Bonus": "Increases stats gained based on your Uma's motivation level.", + "Specialty Rate": "Increases the chance of this card appearing in its specialty training.", + "Training Bonus": "Flat percentage increase to stats gained in training where this card is present.", + "Initial Bond": "Starting gauge value for this card.", + "Race Bonus": "Increases stats gained from racing.", + "Fan Count Bonus": "Increases fans gained from racing.", + "Skill Pt Bonus": "Bonus skill points gained when training with this card.", + "Hint Lv": "Starting level of skills taught by this card's hints.", + "Hint Rate": "Increases chance of getting a hint event.", + "Minigame Fail Rate": "Reduces chance of failing training.", + "Energy Usage": "Reduces energy consumed during training.", + "Current Energy": "Increases starting energy in scenario.", + "Vitality": "Increases vitality gain from events.", + "Stamina": "Increases stamina gain from training.", + "Speed": "Increases speed gain from training.", + "Power": "Increases power gain from training.", + "Guts": "Increases guts gain from training.", + "Wisdom": "Increases wisdom gain from training.", + "Logic": "Custom logic effect.", + "Starting Stats": "Increases initial stats at start of scenario." +} + +class Tooltip: + """ + Creates a tooltip for a given widget as the mouse hovers above it. + """ + def __init__(self, widget, text): + self.widget = widget + self.text = text + self.tip_window = None + self.id = None + self.x = self.y = 0 + self._id1 = self.widget.bind("", self.enter) + self._id2 = self.widget.bind("", self.leave) + self._id3 = self.widget.bind("", self.leave) + + def enter(self, event=None): + self.schedule() + + def leave(self, event=None): + self.unschedule() + self.hidetip() + + def schedule(self): + self.unschedule() + self.id = self.widget.after(500, self.showtip) + + def unschedule(self): + id = self.id + self.id = None + if id: + self.widget.after_cancel(id) + + def showtip(self, event=None): + x = y = 0 + try: + x, y, cx, cy = self.widget.bbox("insert") + except: + pass + x += self.widget.winfo_rootx() + 25 + y += self.widget.winfo_rooty() + 20 + + # Creates a toplevel window + self.tip_window = tk.Toplevel(self.widget) + + # Leaves only the label and removes the app window + self.tip_window.wm_overrideredirect(True) + self.tip_window.wm_geometry(f"+{x}+{y}") + + label = tk.Label( + self.tip_window, + text=self.text, + justify=tk.LEFT, + background=BG_LIGHT, + foreground=TEXT_PRIMARY, + relief=tk.SOLID, + borderwidth=1, + font=FONT_SMALL, + padx=10, + pady=5 + ) + label.pack(ipadx=1) + + def hidetip(self): + tw = self.tip_window + self.tip_window = None + if tw: + tw.destroy() + +def create_tooltip(widget, text): + """Create a tooltip for a widget""" + return Tooltip(widget, text) diff --git a/gui/update_dialog.py b/gui/update_dialog.py new file mode 100644 index 0000000..00be9f4 --- /dev/null +++ b/gui/update_dialog.py @@ -0,0 +1,344 @@ +""" +Update Dialog for UmamusumeCardManager +Provides a modal dialog for the update process. +""" + +import tkinter as tk +from tkinter import ttk, messagebox, scrolledtext +import threading +import webbrowser +from typing import Optional, Callable + +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from updater.update_checker import check_for_updates, download_update, apply_update, get_current_version +from gui.theme import ( + BG_DARK, BG_DARKEST, BG_MEDIUM, BG_LIGHT, BG_HIGHLIGHT, + ACCENT_PRIMARY, ACCENT_SECONDARY, ACCENT_SUCCESS, ACCENT_ERROR, + TEXT_PRIMARY, TEXT_SECONDARY, TEXT_MUTED, + FONT_HEADER, FONT_SUBHEADER, FONT_BODY, FONT_BODY_BOLD, FONT_SMALL, + create_styled_button +) + + +class UpdateDialog: + """Modal dialog for checking and applying updates.""" + + def __init__(self, parent: tk.Tk, on_close_callback: Optional[Callable] = None): + self.parent = parent + self.on_close_callback = on_close_callback + self.update_info = None + self.download_thread = None + self.is_downloading = False + + # Create the dialog window + self.dialog = tk.Toplevel(parent) + self.dialog.title("Check for Updates") + self.dialog.geometry("520x600") + self.dialog.resizable(True, True) + self.dialog.minsize(480, 500) + self.dialog.transient(parent) + self.dialog.grab_set() + + # Center on parent + self.center_on_parent() + + self.dialog.configure(bg=BG_DARK) + + # Set up the UI + self.setup_ui() + + # Start checking for updates + self.check_for_updates() + + def center_on_parent(self): + """Center the dialog on the parent window.""" + self.dialog.update_idletasks() + parent_x = self.parent.winfo_x() + parent_y = self.parent.winfo_y() + parent_w = self.parent.winfo_width() + parent_h = self.parent.winfo_height() + + dialog_w = 520 + dialog_h = 600 + + x = parent_x + (parent_w - dialog_w) // 2 + y = parent_y + (parent_h - dialog_h) // 2 + + self.dialog.geometry(f"{dialog_w}x{dialog_h}+{x}+{y}") + + def setup_ui(self): + """Set up the dialog UI.""" + # Button frame (Create first to pack at bottom) + self.button_frame = tk.Frame(self.dialog, bg=BG_DARK, pady=20, padx=20) + self.button_frame.pack(side=tk.BOTTOM, fill=tk.X) + + # Close button + self.close_button = create_styled_button( + self.button_frame, + text="Close", + command=self.close, + style_type='default' + ) + self.close_button.pack(side=tk.RIGHT) + + # Update button (hidden initially) + self.update_button = create_styled_button( + self.button_frame, + text="ā¬‡ļø Download & Install", + command=self.start_download, + style_type='accent' + ) + # We don't pack it yet + + # Main container + main_frame = tk.Frame(self.dialog, bg=BG_DARK, padx=25, pady=20) + main_frame.pack(fill=tk.BOTH, expand=True) + + # Title + self.title_label = tk.Label( + main_frame, + text="šŸ”„ Checking for Updates...", + font=FONT_HEADER, + bg=BG_DARK, + fg=ACCENT_PRIMARY + ) + self.title_label.pack(pady=(0, 10)) + + # Status message + self.status_label = tk.Label( + main_frame, + text="Connecting to GitHub...", + font=FONT_BODY, + bg=BG_DARK, + fg=TEXT_MUTED, + wraplength=460 + ) + self.status_label.pack(pady=(0, 10)) + + # Version info frame + self.version_frame = tk.Frame(main_frame, bg=BG_MEDIUM, padx=15, pady=10) + self.version_frame.pack(fill=tk.X, pady=(0, 15)) + + self.current_version_label = tk.Label( + self.version_frame, + text=f"Current Version: v{get_current_version()}", + font=FONT_BODY, + bg=BG_MEDIUM, + fg=TEXT_SECONDARY + ) + self.current_version_label.pack(anchor='w') + + self.new_version_label = tk.Label( + self.version_frame, + text="Latest Version: Checking...", + font=FONT_BODY, + bg=BG_MEDIUM, + fg=TEXT_SECONDARY + ) + self.new_version_label.pack(anchor='w') + + # Release Notes Area + self.notes_label = tk.Label( + main_frame, + text="What's New:", + font=FONT_BODY_BOLD, + bg=BG_DARK, + fg=TEXT_PRIMARY + ) + self.notes_label.pack(anchor='w', pady=(0, 5)) + + # Text box for release notes + self.notes_text = scrolledtext.ScrolledText( + main_frame, + height=10, + bg=BG_MEDIUM, + fg=TEXT_SECONDARY, + font=FONT_SMALL, + borderwidth=0, + highlightthickness=0, + padx=10, + pady=10 + ) + self.notes_text.pack(fill=tk.BOTH, expand=True, pady=(0, 15)) + self.notes_text.insert(tk.END, "Checking for release notes...") + self.notes_text.config(state=tk.DISABLED) + + # Progress bar (hidden initially) + self.progress_frame = tk.Frame(main_frame, bg=BG_DARK) + self.progress_frame.pack(fill=tk.X, pady=(0, 10)) + + self.progress_label = tk.Label( + self.progress_frame, + text="", + font=FONT_SMALL, + bg=BG_DARK, + fg=TEXT_MUTED + ) + self.progress_label.pack(anchor='w', pady=(0, 5)) + + self.progress_bar = ttk.Progressbar( + self.progress_frame, + mode='indeterminate', + length=460 + ) + self.progress_bar.pack(fill=tk.X) + self.progress_bar.start(10) + + def check_for_updates(self): + """Check for updates in a background thread.""" + def check(): + self.update_info = check_for_updates() + self.dialog.after(0, self.update_check_complete) + + thread = threading.Thread(target=check, daemon=True) + thread.start() + + def update_check_complete(self): + """Called when the update check is complete.""" + self.progress_bar.stop() + self.progress_frame.pack_forget() # Hide progress bar when check is done + + # Enable text box to update it + self.notes_text.config(state=tk.NORMAL) + self.notes_text.delete(1.0, tk.END) + + if self.update_info: + # Update available! + self.title_label.config(text="šŸŽ‰ Update Available!") + self.status_label.config( + text="A new version is available.", + fg=ACCENT_SUCCESS + ) + self.new_version_label.config( + text=f"Latest Version: {self.update_info['new_version']}", + fg=ACCENT_SUCCESS + ) + + # Show Release Notes + notes = self.update_info.get('release_notes', 'No release notes available.') + self.notes_text.insert(tk.END, notes) + + # Show update button + self.update_button.pack(side=tk.RIGHT, padx=(0, 10)) + else: + # Up to date or error + self.title_label.config(text="āœ… You're Up to Date!") + self.status_label.config( + text=f"You are running the latest version.", + fg=TEXT_SECONDARY + ) + self.new_version_label.config( + text=f"Latest Version: v{get_current_version()}", + fg=ACCENT_SUCCESS + ) + self.notes_text.insert(tk.END, "You are using the latest version of Umamusume Support Card Manager.\n\nEnjoy!") + + self.notes_text.config(state=tk.DISABLED) + + def start_download(self): + """Start downloading the update.""" + if self.is_downloading or not self.update_info: + return + + self.is_downloading = True + self.update_button.config(state=tk.DISABLED, text="Downloading...") + self.close_button.config(state=tk.DISABLED) + + self.title_label.config(text="ā¬‡ļø Downloading Update...") + self.status_label.config(text="Please wait...", fg=TEXT_MUTED) + + # Configure progress bar for determinate mode + self.progress_frame.pack(fill=tk.X, pady=(0, 10)) # Show progress frame again + self.progress_bar.config(mode='determinate', maximum=100) + self.progress_bar.pack(fill=tk.X) + self.progress_bar['value'] = 0 + + def download(): + def progress_callback(downloaded, total): + if total > 0: + percent = int((downloaded / total) * 100) + mb_downloaded = downloaded / (1024 * 1024) + mb_total = total / (1024 * 1024) + self.dialog.after(0, lambda: self.update_progress(percent, mb_downloaded, mb_total)) + + download_path = download_update(self.update_info['download_url'], progress_callback) + self.dialog.after(0, lambda: self.download_complete(download_path)) + + self.download_thread = threading.Thread(target=download, daemon=True) + self.download_thread.start() + + def update_progress(self, percent: int, downloaded_mb: float, total_mb: float): + """Update the progress bar.""" + self.progress_bar['value'] = percent + self.progress_label.config(text=f"Downloaded: {downloaded_mb:.1f} MB / {total_mb:.1f} MB ({percent}%)") + + def download_complete(self, download_path: Optional[str]): + """Called when the download is complete.""" + self.is_downloading = False + + if download_path: + self.title_label.config(text="āœ… Download Complete!") + self.status_label.config( + text="Update ready to install.", + fg=ACCENT_SUCCESS + ) + + # Change button to install + self.update_button.config( + state=tk.NORMAL, + text="šŸ”„ Install & Restart", + command=lambda: self.install_update(download_path) + ) + self.close_button.config(state=tk.NORMAL) + else: + self.title_label.config(text="āŒ Download Failed") + self.status_label.config( + text="Failed not download update.", + fg=ACCENT_ERROR + ) + self.update_button.config(state=tk.NORMAL, text="ā¬‡ļø Retry Download") + self.close_button.config(state=tk.NORMAL) + + def install_update(self, download_path: str): + """Install the downloaded update.""" + self.title_label.config(text="šŸ”„ Installing Update...") + self.status_label.config(text="Applying update...", fg=TEXT_MUTED) + self.update_button.config(state=tk.DISABLED) + self.close_button.config(state=tk.DISABLED) + + if apply_update(download_path): + # Exit the application - the updater script will restart it + self.dialog.after(1000, lambda: self.parent.quit()) + else: + messagebox.showinfo( + "Manual Update Required", + f"The update was downloaded but cannot be applied automatically.\n\n" + f"Downloaded file location:\n{download_path}\n\n" + f"Please replace the current executable manually.", + parent=self.dialog + ) + self.close() + + + def close(self): + """Close the dialog.""" + if self.on_close_callback: + self.on_close_callback() + self.dialog.destroy() + + +def show_update_dialog(parent: tk.Tk, on_close_callback: Optional[Callable] = None) -> UpdateDialog: + """ + Show the update dialog. + + Args: + parent: The parent Tk window + on_close_callback: Optional callback when dialog is closed + + Returns: + The UpdateDialog instance + """ + return UpdateDialog(parent, on_close_callback) diff --git a/images/1000_Chrono Genesis.png b/images/1000_Chrono Genesis.png new file mode 100644 index 0000000..b84b9e5 Binary files /dev/null and b/images/1000_Chrono Genesis.png differ diff --git a/images/1001_Calstone Light O.png b/images/1001_Calstone Light O.png new file mode 100644 index 0000000..be45675 Binary files /dev/null and b/images/1001_Calstone Light O.png differ diff --git a/images/1002_Durandal.png b/images/1002_Durandal.png new file mode 100644 index 0000000..e5b83f8 Binary files /dev/null and b/images/1002_Durandal.png differ diff --git a/images/1003_Dantsu Flame.png b/images/1003_Dantsu Flame.png new file mode 100644 index 0000000..1fc9903 Binary files /dev/null and b/images/1003_Dantsu Flame.png differ diff --git a/images/1004_Daiichi Ruby.png b/images/1004_Daiichi Ruby.png new file mode 100644 index 0000000..f43c5f6 Binary files /dev/null and b/images/1004_Daiichi Ruby.png differ diff --git a/images/1005_Fuji Kiseki.png b/images/1005_Fuji Kiseki.png new file mode 100644 index 0000000..17f8384 Binary files /dev/null and b/images/1005_Fuji Kiseki.png differ diff --git a/images/1006_Eishin Flash.png b/images/1006_Eishin Flash.png new file mode 100644 index 0000000..d5141a2 Binary files /dev/null and b/images/1006_Eishin Flash.png differ diff --git a/images/1007_Tosen Jordan.png b/images/1007_Tosen Jordan.png new file mode 100644 index 0000000..cbaf13e Binary files /dev/null and b/images/1007_Tosen Jordan.png differ diff --git a/images/1008_Curren Bouquetd'or.png b/images/1008_Curren Bouquetd'or.png new file mode 100644 index 0000000..c358f50 Binary files /dev/null and b/images/1008_Curren Bouquetd'or.png differ diff --git a/images/1009_Tokai Teio.png b/images/1009_Tokai Teio.png new file mode 100644 index 0000000..ec0061e Binary files /dev/null and b/images/1009_Tokai Teio.png differ diff --git a/images/100_Royce and Royce.png b/images/100_Royce and Royce.png new file mode 100644 index 0000000..7349c94 Binary files /dev/null and b/images/100_Royce and Royce.png differ diff --git a/images/1010_Kiyoko Hoshina.png b/images/1010_Kiyoko Hoshina.png new file mode 100644 index 0000000..3268852 Binary files /dev/null and b/images/1010_Kiyoko Hoshina.png differ diff --git a/images/1011_Mihono Bourbon.png b/images/1011_Mihono Bourbon.png new file mode 100644 index 0000000..cf8d4eb Binary files /dev/null and b/images/1011_Mihono Bourbon.png differ diff --git a/images/1012_Gold Ship.png b/images/1012_Gold Ship.png new file mode 100644 index 0000000..57cafe6 Binary files /dev/null and b/images/1012_Gold Ship.png differ diff --git a/images/1013_Fenomeno.png b/images/1013_Fenomeno.png new file mode 100644 index 0000000..5f42e52 Binary files /dev/null and b/images/1013_Fenomeno.png differ diff --git a/images/1014_Orfevre.png b/images/1014_Orfevre.png new file mode 100644 index 0000000..dd7e220 Binary files /dev/null and b/images/1014_Orfevre.png differ diff --git a/images/1015_Inari One.png b/images/1015_Inari One.png new file mode 100644 index 0000000..97a10d2 Binary files /dev/null and b/images/1015_Inari One.png differ diff --git a/images/1016_Air Groove.png b/images/1016_Air Groove.png new file mode 100644 index 0000000..8bb619a Binary files /dev/null and b/images/1016_Air Groove.png differ diff --git a/images/1017_Fine Motion.png b/images/1017_Fine Motion.png new file mode 100644 index 0000000..9e86311 Binary files /dev/null and b/images/1017_Fine Motion.png differ diff --git a/images/1018_Bubble Gum Fellow.png b/images/1018_Bubble Gum Fellow.png new file mode 100644 index 0000000..9b30e2d Binary files /dev/null and b/images/1018_Bubble Gum Fellow.png differ diff --git a/images/101_Duramente.png b/images/101_Duramente.png new file mode 100644 index 0000000..cc8be96 Binary files /dev/null and b/images/101_Duramente.png differ diff --git a/images/102_North Flight.png b/images/102_North Flight.png new file mode 100644 index 0000000..9c5277d Binary files /dev/null and b/images/102_North Flight.png differ diff --git a/images/103_Orfevre.png b/images/103_Orfevre.png new file mode 100644 index 0000000..6400fdb Binary files /dev/null and b/images/103_Orfevre.png differ diff --git a/images/104_Ryoka Tsurugi.png b/images/104_Ryoka Tsurugi.png new file mode 100644 index 0000000..9de474f Binary files /dev/null and b/images/104_Ryoka Tsurugi.png differ diff --git a/images/105_Cheval Grand.png b/images/105_Cheval Grand.png new file mode 100644 index 0000000..ef8332f Binary files /dev/null and b/images/105_Cheval Grand.png differ diff --git a/images/106_Neo Universe.png b/images/106_Neo Universe.png new file mode 100644 index 0000000..db80584 Binary files /dev/null and b/images/106_Neo Universe.png differ diff --git a/images/107_Hishi Miracle.png b/images/107_Hishi Miracle.png new file mode 100644 index 0000000..3043da7 Binary files /dev/null and b/images/107_Hishi Miracle.png differ diff --git a/images/108_Dantsu Flame.png b/images/108_Dantsu Flame.png new file mode 100644 index 0000000..94f8f5b Binary files /dev/null and b/images/108_Dantsu Flame.png differ diff --git a/images/109_Yayoi Akikawa.png b/images/109_Yayoi Akikawa.png new file mode 100644 index 0000000..3ca6061 Binary files /dev/null and b/images/109_Yayoi Akikawa.png differ diff --git a/images/10_Mejiro McQueen.png b/images/10_Mejiro McQueen.png new file mode 100644 index 0000000..aa961d1 Binary files /dev/null and b/images/10_Mejiro McQueen.png differ diff --git a/images/110_Espoir City.png b/images/110_Espoir City.png new file mode 100644 index 0000000..0f7f6ee Binary files /dev/null and b/images/110_Espoir City.png differ diff --git a/images/111_Bubble Gum Fellow.png b/images/111_Bubble Gum Fellow.png new file mode 100644 index 0000000..faffb08 Binary files /dev/null and b/images/111_Bubble Gum Fellow.png differ diff --git a/images/112_Gentildonna.png b/images/112_Gentildonna.png new file mode 100644 index 0000000..a9a937e Binary files /dev/null and b/images/112_Gentildonna.png differ diff --git a/images/113_Rhein Kraft.png b/images/113_Rhein Kraft.png new file mode 100644 index 0000000..6f9c93d Binary files /dev/null and b/images/113_Rhein Kraft.png differ diff --git a/images/114_Cesario.png b/images/114_Cesario.png new file mode 100644 index 0000000..f8f827e Binary files /dev/null and b/images/114_Cesario.png differ diff --git a/images/115_Blast Onepiece.png b/images/115_Blast Onepiece.png new file mode 100644 index 0000000..a4e6eab Binary files /dev/null and b/images/115_Blast Onepiece.png differ diff --git a/images/116_No Reason.png b/images/116_No Reason.png new file mode 100644 index 0000000..0fad8dc Binary files /dev/null and b/images/116_No Reason.png differ diff --git a/images/117_Buena Vista.png b/images/117_Buena Vista.png new file mode 100644 index 0000000..22dbbfa Binary files /dev/null and b/images/117_Buena Vista.png differ diff --git a/images/118_Dream Journey.png b/images/118_Dream Journey.png new file mode 100644 index 0000000..7cb8d6f Binary files /dev/null and b/images/118_Dream Journey.png differ diff --git a/images/119_Daring Tact.png b/images/119_Daring Tact.png new file mode 100644 index 0000000..c9c32ba Binary files /dev/null and b/images/119_Daring Tact.png differ diff --git a/images/11_El Condor Pasa.png b/images/11_El Condor Pasa.png new file mode 100644 index 0000000..f481e93 Binary files /dev/null and b/images/11_El Condor Pasa.png differ diff --git a/images/120_Daring Heart.png b/images/120_Daring Heart.png new file mode 100644 index 0000000..b7ffc71 Binary files /dev/null and b/images/120_Daring Heart.png differ diff --git a/images/121_Almond Eye.png b/images/121_Almond Eye.png new file mode 100644 index 0000000..b2c67a2 Binary files /dev/null and b/images/121_Almond Eye.png differ diff --git a/images/122_Lucky Lilac.png b/images/122_Lucky Lilac.png new file mode 100644 index 0000000..71a44d0 Binary files /dev/null and b/images/122_Lucky Lilac.png differ diff --git a/images/123_Gran Alegria.png b/images/123_Gran Alegria.png new file mode 100644 index 0000000..132de05 Binary files /dev/null and b/images/123_Gran Alegria.png differ diff --git a/images/124_Transcend.png b/images/124_Transcend.png new file mode 100644 index 0000000..c8b9414 Binary files /dev/null and b/images/124_Transcend.png differ diff --git a/images/125_Curren Bouquetd'or.png b/images/125_Curren Bouquetd'or.png new file mode 100644 index 0000000..232c7b1 Binary files /dev/null and b/images/125_Curren Bouquetd'or.png differ diff --git a/images/126_Air Messiah.png b/images/126_Air Messiah.png new file mode 100644 index 0000000..e3deed3 Binary files /dev/null and b/images/126_Air Messiah.png differ diff --git a/images/127_Tucker Bryne.png b/images/127_Tucker Bryne.png new file mode 100644 index 0000000..56cb1f7 Binary files /dev/null and b/images/127_Tucker Bryne.png differ diff --git a/images/128_Fusaichi Pandora.png b/images/128_Fusaichi Pandora.png new file mode 100644 index 0000000..2a97f3b Binary files /dev/null and b/images/128_Fusaichi Pandora.png differ diff --git a/images/129_Win Variation.png b/images/129_Win Variation.png new file mode 100644 index 0000000..22cbe5a Binary files /dev/null and b/images/129_Win Variation.png differ diff --git a/images/12_TM Opera O.png b/images/12_TM Opera O.png new file mode 100644 index 0000000..6d0e2cf Binary files /dev/null and b/images/12_TM Opera O.png differ diff --git a/images/130_Stay Gold.png b/images/130_Stay Gold.png new file mode 100644 index 0000000..b915fb9 Binary files /dev/null and b/images/130_Stay Gold.png differ diff --git a/images/131_Admire Groove.png b/images/131_Admire Groove.png new file mode 100644 index 0000000..ca047f6 Binary files /dev/null and b/images/131_Admire Groove.png differ diff --git a/images/132_Chrono Genesis.png b/images/132_Chrono Genesis.png new file mode 100644 index 0000000..00d3dfc Binary files /dev/null and b/images/132_Chrono Genesis.png differ diff --git a/images/133_Calstone Light O.png b/images/133_Calstone Light O.png new file mode 100644 index 0000000..8d2889c Binary files /dev/null and b/images/133_Calstone Light O.png differ diff --git a/images/134_Durandal.png b/images/134_Durandal.png new file mode 100644 index 0000000..880fe53 Binary files /dev/null and b/images/134_Durandal.png differ diff --git a/images/135_Sakura Chitose O.png b/images/135_Sakura Chitose O.png new file mode 100644 index 0000000..f0a0e2c Binary files /dev/null and b/images/135_Sakura Chitose O.png differ diff --git a/images/136_Kiyoko Hoshina.png b/images/136_Kiyoko Hoshina.png new file mode 100644 index 0000000..b45ae5e Binary files /dev/null and b/images/136_Kiyoko Hoshina.png differ diff --git a/images/137_Fenomeno.png b/images/137_Fenomeno.png new file mode 100644 index 0000000..7ceacf8 Binary files /dev/null and b/images/137_Fenomeno.png differ diff --git a/images/138_Fuji Kiseki.png b/images/138_Fuji Kiseki.png new file mode 100644 index 0000000..f49efa3 Binary files /dev/null and b/images/138_Fuji Kiseki.png differ diff --git a/images/139_Daiwa Scarlet.png b/images/139_Daiwa Scarlet.png new file mode 100644 index 0000000..6fd5a71 Binary files /dev/null and b/images/139_Daiwa Scarlet.png differ diff --git a/images/13_Symboli Rudolf.png b/images/13_Symboli Rudolf.png new file mode 100644 index 0000000..be72ccf Binary files /dev/null and b/images/13_Symboli Rudolf.png differ diff --git a/images/140_Hishi Amazon.png b/images/140_Hishi Amazon.png new file mode 100644 index 0000000..c8d3863 Binary files /dev/null and b/images/140_Hishi Amazon.png differ diff --git a/images/141_Air Groove.png b/images/141_Air Groove.png new file mode 100644 index 0000000..0bbee00 Binary files /dev/null and b/images/141_Air Groove.png differ diff --git a/images/142_Agnes Digital.png b/images/142_Agnes Digital.png new file mode 100644 index 0000000..975ef83 Binary files /dev/null and b/images/142_Agnes Digital.png differ diff --git a/images/143_Biwa Hayahide.png b/images/143_Biwa Hayahide.png new file mode 100644 index 0000000..721324a Binary files /dev/null and b/images/143_Biwa Hayahide.png differ diff --git a/images/144_Mayano Top Gun.png b/images/144_Mayano Top Gun.png new file mode 100644 index 0000000..4d11ceb Binary files /dev/null and b/images/144_Mayano Top Gun.png differ diff --git a/images/145_Manhattan Cafe.png b/images/145_Manhattan Cafe.png new file mode 100644 index 0000000..fea8bb6 Binary files /dev/null and b/images/145_Manhattan Cafe.png differ diff --git a/images/146_Mihono Bourbon.png b/images/146_Mihono Bourbon.png new file mode 100644 index 0000000..7dc5720 Binary files /dev/null and b/images/146_Mihono Bourbon.png differ diff --git a/images/147_Mejiro Ryan.png b/images/147_Mejiro Ryan.png new file mode 100644 index 0000000..6ae179b Binary files /dev/null and b/images/147_Mejiro Ryan.png differ diff --git a/images/148_Yukino Bijin.png b/images/148_Yukino Bijin.png new file mode 100644 index 0000000..bd099ae Binary files /dev/null and b/images/148_Yukino Bijin.png differ diff --git a/images/149_Agnes Tachyon.png b/images/149_Agnes Tachyon.png new file mode 100644 index 0000000..1868d13 Binary files /dev/null and b/images/149_Agnes Tachyon.png differ diff --git a/images/14_Seiun Sky.png b/images/14_Seiun Sky.png new file mode 100644 index 0000000..8784dff Binary files /dev/null and b/images/14_Seiun Sky.png differ diff --git a/images/150_Eishin Flash.png b/images/150_Eishin Flash.png new file mode 100644 index 0000000..e54398c Binary files /dev/null and b/images/150_Eishin Flash.png differ diff --git a/images/151_Narita Taishin.png b/images/151_Narita Taishin.png new file mode 100644 index 0000000..bc965cc Binary files /dev/null and b/images/151_Narita Taishin.png differ diff --git a/images/152_Marvelous Sunday.png b/images/152_Marvelous Sunday.png new file mode 100644 index 0000000..fbe41b5 Binary files /dev/null and b/images/152_Marvelous Sunday.png differ diff --git a/images/153_Matikanefukukitaru.png b/images/153_Matikanefukukitaru.png new file mode 100644 index 0000000..e29ac31 Binary files /dev/null and b/images/153_Matikanefukukitaru.png differ diff --git a/images/154_Meisho Doto.png b/images/154_Meisho Doto.png new file mode 100644 index 0000000..0264e80 Binary files /dev/null and b/images/154_Meisho Doto.png differ diff --git a/images/155_Mejiro Dober.png b/images/155_Mejiro Dober.png new file mode 100644 index 0000000..05b5bc4 Binary files /dev/null and b/images/155_Mejiro Dober.png differ diff --git a/images/156_Nice Nature.png b/images/156_Nice Nature.png new file mode 100644 index 0000000..1a85d82 Binary files /dev/null and b/images/156_Nice Nature.png differ diff --git a/images/157_King Halo.png b/images/157_King Halo.png new file mode 100644 index 0000000..5f0ddf5 Binary files /dev/null and b/images/157_King Halo.png differ diff --git a/images/158_Aoi Kiryuin.png b/images/158_Aoi Kiryuin.png new file mode 100644 index 0000000..e2c12cd Binary files /dev/null and b/images/158_Aoi Kiryuin.png differ diff --git a/images/159_Tamamo Cross.png b/images/159_Tamamo Cross.png new file mode 100644 index 0000000..31fa49c Binary files /dev/null and b/images/159_Tamamo Cross.png differ diff --git a/images/15_Rice Shower.png b/images/15_Rice Shower.png new file mode 100644 index 0000000..0dd6372 Binary files /dev/null and b/images/15_Rice Shower.png differ diff --git a/images/160_Sweep Tosho.png b/images/160_Sweep Tosho.png new file mode 100644 index 0000000..d4e0680 Binary files /dev/null and b/images/160_Sweep Tosho.png differ diff --git a/images/161_Daitaku Helios.png b/images/161_Daitaku Helios.png new file mode 100644 index 0000000..5d3cfdf Binary files /dev/null and b/images/161_Daitaku Helios.png differ diff --git a/images/162_Ikuno Dictus.png b/images/162_Ikuno Dictus.png new file mode 100644 index 0000000..004d835 Binary files /dev/null and b/images/162_Ikuno Dictus.png differ diff --git a/images/163_Nice Nature.png b/images/163_Nice Nature.png new file mode 100644 index 0000000..ed7b605 Binary files /dev/null and b/images/163_Nice Nature.png differ diff --git a/images/164_Nishino Flower.png b/images/164_Nishino Flower.png new file mode 100644 index 0000000..d0cb28d Binary files /dev/null and b/images/164_Nishino Flower.png differ diff --git a/images/165_Zenno Rob Roy.png b/images/165_Zenno Rob Roy.png new file mode 100644 index 0000000..1a11c93 Binary files /dev/null and b/images/165_Zenno Rob Roy.png differ diff --git a/images/166_Seeking the Pearl.png b/images/166_Seeking the Pearl.png new file mode 100644 index 0000000..114e67c Binary files /dev/null and b/images/166_Seeking the Pearl.png differ diff --git a/images/167_Ines Fujin.png b/images/167_Ines Fujin.png new file mode 100644 index 0000000..d82f00b Binary files /dev/null and b/images/167_Ines Fujin.png differ diff --git a/images/168_Shinko Windy.png b/images/168_Shinko Windy.png new file mode 100644 index 0000000..99601ef Binary files /dev/null and b/images/168_Shinko Windy.png differ diff --git a/images/169_Inari One.png b/images/169_Inari One.png new file mode 100644 index 0000000..d89bfb2 Binary files /dev/null and b/images/169_Inari One.png differ diff --git a/images/16_Winning Ticket.png b/images/16_Winning Ticket.png new file mode 100644 index 0000000..d9ea2eb Binary files /dev/null and b/images/16_Winning Ticket.png differ diff --git a/images/170_El Condor Pasa.png b/images/170_El Condor Pasa.png new file mode 100644 index 0000000..3f2e2ac Binary files /dev/null and b/images/170_El Condor Pasa.png differ diff --git a/images/171_Mejiro Ardan.png b/images/171_Mejiro Ardan.png new file mode 100644 index 0000000..df5678d Binary files /dev/null and b/images/171_Mejiro Ardan.png differ diff --git a/images/172_Tosen Jordan.png b/images/172_Tosen Jordan.png new file mode 100644 index 0000000..617e0ed Binary files /dev/null and b/images/172_Tosen Jordan.png differ diff --git a/images/173_Mejiro Palmer.png b/images/173_Mejiro Palmer.png new file mode 100644 index 0000000..4cb5dfe Binary files /dev/null and b/images/173_Mejiro Palmer.png differ diff --git a/images/174_Fine Motion.png b/images/174_Fine Motion.png new file mode 100644 index 0000000..1df4908 Binary files /dev/null and b/images/174_Fine Motion.png differ diff --git a/images/175_Sirius Symboli.png b/images/175_Sirius Symboli.png new file mode 100644 index 0000000..a442dcd Binary files /dev/null and b/images/175_Sirius Symboli.png differ diff --git a/images/176_Vodka.png b/images/176_Vodka.png new file mode 100644 index 0000000..304d0cd Binary files /dev/null and b/images/176_Vodka.png differ diff --git a/images/177_Mejiro Ryan.png b/images/177_Mejiro Ryan.png new file mode 100644 index 0000000..65d3ac3 Binary files /dev/null and b/images/177_Mejiro Ryan.png differ diff --git a/images/178_Admire Vega.png b/images/178_Admire Vega.png new file mode 100644 index 0000000..fe1345f Binary files /dev/null and b/images/178_Admire Vega.png differ diff --git a/images/179_Sakura Bakushin O.png b/images/179_Sakura Bakushin O.png new file mode 100644 index 0000000..2a87e59 Binary files /dev/null and b/images/179_Sakura Bakushin O.png differ diff --git a/images/17_Gold City.png b/images/17_Gold City.png new file mode 100644 index 0000000..556f7bd Binary files /dev/null and b/images/17_Gold City.png differ diff --git a/images/180_Special Week.png b/images/180_Special Week.png new file mode 100644 index 0000000..ce55e65 Binary files /dev/null and b/images/180_Special Week.png differ diff --git a/images/181_Curren Chan.png b/images/181_Curren Chan.png new file mode 100644 index 0000000..fd0c725 Binary files /dev/null and b/images/181_Curren Chan.png differ diff --git a/images/182_Smart Falcon.png b/images/182_Smart Falcon.png new file mode 100644 index 0000000..3bdb189 Binary files /dev/null and b/images/182_Smart Falcon.png differ diff --git a/images/183_Sweep Tosho.png b/images/183_Sweep Tosho.png new file mode 100644 index 0000000..11aa56d Binary files /dev/null and b/images/183_Sweep Tosho.png differ diff --git a/images/184_Tokai Teio.png b/images/184_Tokai Teio.png new file mode 100644 index 0000000..d340861 Binary files /dev/null and b/images/184_Tokai Teio.png differ diff --git a/images/185_Oguri Cap.png b/images/185_Oguri Cap.png new file mode 100644 index 0000000..a74d619 Binary files /dev/null and b/images/185_Oguri Cap.png differ diff --git a/images/186_Gold City.png b/images/186_Gold City.png new file mode 100644 index 0000000..35c9eae Binary files /dev/null and b/images/186_Gold City.png differ diff --git a/images/187_Seiun Sky.png b/images/187_Seiun Sky.png new file mode 100644 index 0000000..b4935d0 Binary files /dev/null and b/images/187_Seiun Sky.png differ diff --git a/images/188_K.S.Miracle.png b/images/188_K.S.Miracle.png new file mode 100644 index 0000000..6453236 Binary files /dev/null and b/images/188_K.S.Miracle.png differ diff --git a/images/189_Tsurumaru Tsuyoshi.png b/images/189_Tsurumaru Tsuyoshi.png new file mode 100644 index 0000000..323f1b6 Binary files /dev/null and b/images/189_Tsurumaru Tsuyoshi.png differ diff --git a/images/18_Sakura Bakushin O.png b/images/18_Sakura Bakushin O.png new file mode 100644 index 0000000..7ce37b8 Binary files /dev/null and b/images/18_Sakura Bakushin O.png differ diff --git a/images/190_Narita Top Road.png b/images/190_Narita Top Road.png new file mode 100644 index 0000000..91b3da8 Binary files /dev/null and b/images/190_Narita Top Road.png differ diff --git a/images/191_TM Opera O.png b/images/191_TM Opera O.png new file mode 100644 index 0000000..1eb8800 Binary files /dev/null and b/images/191_TM Opera O.png differ diff --git a/images/192_Aston Machan.png b/images/192_Aston Machan.png new file mode 100644 index 0000000..2b2e82d Binary files /dev/null and b/images/192_Aston Machan.png differ diff --git a/images/193_Jungle Pocket.png b/images/193_Jungle Pocket.png new file mode 100644 index 0000000..b231f00 Binary files /dev/null and b/images/193_Jungle Pocket.png differ diff --git a/images/194_Mejiro Dober.png b/images/194_Mejiro Dober.png new file mode 100644 index 0000000..9a1b003 Binary files /dev/null and b/images/194_Mejiro Dober.png differ diff --git a/images/195_Symboli Rudolf.png b/images/195_Symboli Rudolf.png new file mode 100644 index 0000000..473179d Binary files /dev/null and b/images/195_Symboli Rudolf.png differ diff --git a/images/196_Agnes Tachyon.png b/images/196_Agnes Tachyon.png new file mode 100644 index 0000000..2addadd Binary files /dev/null and b/images/196_Agnes Tachyon.png differ diff --git a/images/197_Hishi Akebono.png b/images/197_Hishi Akebono.png new file mode 100644 index 0000000..b4277fd Binary files /dev/null and b/images/197_Hishi Akebono.png differ diff --git a/images/198_Gold Ship.png b/images/198_Gold Ship.png new file mode 100644 index 0000000..56bd06a Binary files /dev/null and b/images/198_Gold Ship.png differ diff --git a/images/199_Maruzensky.png b/images/199_Maruzensky.png new file mode 100644 index 0000000..c55a3cb Binary files /dev/null and b/images/199_Maruzensky.png differ diff --git a/images/19_Super Creek.png b/images/19_Super Creek.png new file mode 100644 index 0000000..a8053ce Binary files /dev/null and b/images/19_Super Creek.png differ diff --git a/images/1_Special Week.png b/images/1_Special Week.png new file mode 100644 index 0000000..ff2e4f5 Binary files /dev/null and b/images/1_Special Week.png differ diff --git a/images/200_Silence Suzuka.png b/images/200_Silence Suzuka.png new file mode 100644 index 0000000..eb3e46f Binary files /dev/null and b/images/200_Silence Suzuka.png differ diff --git a/images/201_Copano Rickey.png b/images/201_Copano Rickey.png new file mode 100644 index 0000000..a8206c9 Binary files /dev/null and b/images/201_Copano Rickey.png differ diff --git a/images/202_Grass Wonder.png b/images/202_Grass Wonder.png new file mode 100644 index 0000000..35e2b61 Binary files /dev/null and b/images/202_Grass Wonder.png differ diff --git a/images/203_Kitasan Black.png b/images/203_Kitasan Black.png new file mode 100644 index 0000000..57dfd16 Binary files /dev/null and b/images/203_Kitasan Black.png differ diff --git a/images/204_Taiki Shuttle.png b/images/204_Taiki Shuttle.png new file mode 100644 index 0000000..1b03ad5 Binary files /dev/null and b/images/204_Taiki Shuttle.png differ diff --git a/images/205_Nice Nature.png b/images/205_Nice Nature.png new file mode 100644 index 0000000..c46ee39 Binary files /dev/null and b/images/205_Nice Nature.png differ diff --git a/images/206_Matikanetannhauser.png b/images/206_Matikanetannhauser.png new file mode 100644 index 0000000..cfa6312 Binary files /dev/null and b/images/206_Matikanetannhauser.png differ diff --git a/images/207_Verxina.png b/images/207_Verxina.png new file mode 100644 index 0000000..c4ce1db Binary files /dev/null and b/images/207_Verxina.png differ diff --git a/images/208_Royce and Royce.png b/images/208_Royce and Royce.png new file mode 100644 index 0000000..0bf7803 Binary files /dev/null and b/images/208_Royce and Royce.png differ diff --git a/images/209_Tanino Gimlet.png b/images/209_Tanino Gimlet.png new file mode 100644 index 0000000..e6a9b44 Binary files /dev/null and b/images/209_Tanino Gimlet.png differ diff --git a/images/20_Haru Urara.png b/images/20_Haru Urara.png new file mode 100644 index 0000000..7a2893a Binary files /dev/null and b/images/20_Haru Urara.png differ diff --git a/images/210_Tosen Jordan.png b/images/210_Tosen Jordan.png new file mode 100644 index 0000000..c70a091 Binary files /dev/null and b/images/210_Tosen Jordan.png differ diff --git a/images/211_Yaeno Muteki.png b/images/211_Yaeno Muteki.png new file mode 100644 index 0000000..dcf70aa Binary files /dev/null and b/images/211_Yaeno Muteki.png differ diff --git a/images/212_Tap Dance City.png b/images/212_Tap Dance City.png new file mode 100644 index 0000000..416e225 Binary files /dev/null and b/images/212_Tap Dance City.png differ diff --git a/images/213_Air Shakur.png b/images/213_Air Shakur.png new file mode 100644 index 0000000..d699c83 Binary files /dev/null and b/images/213_Air Shakur.png differ diff --git a/images/214_Dantsu Flame.png b/images/214_Dantsu Flame.png new file mode 100644 index 0000000..fc4a372 Binary files /dev/null and b/images/214_Dantsu Flame.png differ diff --git a/images/215_Matikanefukukitaru.png b/images/215_Matikanefukukitaru.png new file mode 100644 index 0000000..77a659f Binary files /dev/null and b/images/215_Matikanefukukitaru.png differ diff --git a/images/216_Marvelous Sunday.png b/images/216_Marvelous Sunday.png new file mode 100644 index 0000000..a0a994d Binary files /dev/null and b/images/216_Marvelous Sunday.png differ diff --git a/images/217_Sakura Laurel.png b/images/217_Sakura Laurel.png new file mode 100644 index 0000000..bdbb7ad Binary files /dev/null and b/images/217_Sakura Laurel.png differ diff --git a/images/218_North Flight.png b/images/218_North Flight.png new file mode 100644 index 0000000..5e3f1c9 Binary files /dev/null and b/images/218_North Flight.png differ diff --git a/images/219_Bubble Gum Fellow.png b/images/219_Bubble Gum Fellow.png new file mode 100644 index 0000000..8ba6567 Binary files /dev/null and b/images/219_Bubble Gum Fellow.png differ diff --git a/images/21_Tazuna Hayakawa.png b/images/21_Tazuna Hayakawa.png new file mode 100644 index 0000000..7209d59 Binary files /dev/null and b/images/21_Tazuna Hayakawa.png differ diff --git a/images/220_Mejiro Ramonu.png b/images/220_Mejiro Ramonu.png new file mode 100644 index 0000000..1541f5f Binary files /dev/null and b/images/220_Mejiro Ramonu.png differ diff --git a/images/221_Lucky Lilac.png b/images/221_Lucky Lilac.png new file mode 100644 index 0000000..288a269 Binary files /dev/null and b/images/221_Lucky Lilac.png differ diff --git a/images/222_Mejiro McQueen.png b/images/222_Mejiro McQueen.png new file mode 100644 index 0000000..98f3e24 Binary files /dev/null and b/images/222_Mejiro McQueen.png differ diff --git a/images/223_Rice Shower.png b/images/223_Rice Shower.png new file mode 100644 index 0000000..5db4c3d Binary files /dev/null and b/images/223_Rice Shower.png differ diff --git a/images/224_Daring Heart.png b/images/224_Daring Heart.png new file mode 100644 index 0000000..474b0e3 Binary files /dev/null and b/images/224_Daring Heart.png differ diff --git a/images/225_Curren Bouquetd'or.png b/images/225_Curren Bouquetd'or.png new file mode 100644 index 0000000..7a2a387 Binary files /dev/null and b/images/225_Curren Bouquetd'or.png differ diff --git a/images/226_Kawakami Princess.png b/images/226_Kawakami Princess.png new file mode 100644 index 0000000..42494a4 Binary files /dev/null and b/images/226_Kawakami Princess.png differ diff --git a/images/227_Biko Pegasus.png b/images/227_Biko Pegasus.png new file mode 100644 index 0000000..d8b191c Binary files /dev/null and b/images/227_Biko Pegasus.png differ diff --git a/images/228_Sakura Chitose O.png b/images/228_Sakura Chitose O.png new file mode 100644 index 0000000..f07d472 Binary files /dev/null and b/images/228_Sakura Chitose O.png differ diff --git a/images/229_Hokko Tarumae.png b/images/229_Hokko Tarumae.png new file mode 100644 index 0000000..db4590d Binary files /dev/null and b/images/229_Hokko Tarumae.png differ diff --git a/images/22_Aoi Kiryuin.png b/images/22_Aoi Kiryuin.png new file mode 100644 index 0000000..4150d1d Binary files /dev/null and b/images/22_Aoi Kiryuin.png differ diff --git a/images/230_Mejiro Dober.png b/images/230_Mejiro Dober.png new file mode 100644 index 0000000..afff1f9 Binary files /dev/null and b/images/230_Mejiro Dober.png differ diff --git a/images/231_Special Week.png b/images/231_Special Week.png new file mode 100644 index 0000000..d930b71 Binary files /dev/null and b/images/231_Special Week.png differ diff --git a/images/232_Silence Suzuka.png b/images/232_Silence Suzuka.png new file mode 100644 index 0000000..81735fb Binary files /dev/null and b/images/232_Silence Suzuka.png differ diff --git a/images/233_Tokai Teio.png b/images/233_Tokai Teio.png new file mode 100644 index 0000000..fa976b1 Binary files /dev/null and b/images/233_Tokai Teio.png differ diff --git a/images/234_Gold Ship.png b/images/234_Gold Ship.png new file mode 100644 index 0000000..23ec7e5 Binary files /dev/null and b/images/234_Gold Ship.png differ diff --git a/images/235_Vodka.png b/images/235_Vodka.png new file mode 100644 index 0000000..ecb37c8 Binary files /dev/null and b/images/235_Vodka.png differ diff --git a/images/236_Grass Wonder.png b/images/236_Grass Wonder.png new file mode 100644 index 0000000..4f1bdd3 Binary files /dev/null and b/images/236_Grass Wonder.png differ diff --git a/images/237_El Condor Pasa.png b/images/237_El Condor Pasa.png new file mode 100644 index 0000000..160d3fe Binary files /dev/null and b/images/237_El Condor Pasa.png differ diff --git a/images/238_Seiun Sky.png b/images/238_Seiun Sky.png new file mode 100644 index 0000000..291c0cf Binary files /dev/null and b/images/238_Seiun Sky.png differ diff --git a/images/239_Tamamo Cross.png b/images/239_Tamamo Cross.png new file mode 100644 index 0000000..b7f8ce9 Binary files /dev/null and b/images/239_Tamamo Cross.png differ diff --git a/images/23_Daiwa Scarlet.png b/images/23_Daiwa Scarlet.png new file mode 100644 index 0000000..b300ea4 Binary files /dev/null and b/images/23_Daiwa Scarlet.png differ diff --git a/images/240_Fine Motion.png b/images/240_Fine Motion.png new file mode 100644 index 0000000..5433a0a Binary files /dev/null and b/images/240_Fine Motion.png differ diff --git a/images/241_Ines Fujin.png b/images/241_Ines Fujin.png new file mode 100644 index 0000000..d9f3f5a Binary files /dev/null and b/images/241_Ines Fujin.png differ diff --git a/images/242_Winning Ticket.png b/images/242_Winning Ticket.png new file mode 100644 index 0000000..78fbf80 Binary files /dev/null and b/images/242_Winning Ticket.png differ diff --git a/images/243_Air Shakur.png b/images/243_Air Shakur.png new file mode 100644 index 0000000..5fa175c Binary files /dev/null and b/images/243_Air Shakur.png differ diff --git a/images/244_Gold City.png b/images/244_Gold City.png new file mode 100644 index 0000000..9c050b2 Binary files /dev/null and b/images/244_Gold City.png differ diff --git a/images/245_Sakura Bakushin O.png b/images/245_Sakura Bakushin O.png new file mode 100644 index 0000000..46bd80d Binary files /dev/null and b/images/245_Sakura Bakushin O.png differ diff --git a/images/246_Super Creek.png b/images/246_Super Creek.png new file mode 100644 index 0000000..044ac81 Binary files /dev/null and b/images/246_Super Creek.png differ diff --git a/images/247_Smart Falcon.png b/images/247_Smart Falcon.png new file mode 100644 index 0000000..9534f32 Binary files /dev/null and b/images/247_Smart Falcon.png differ diff --git a/images/248_Nishino Flower.png b/images/248_Nishino Flower.png new file mode 100644 index 0000000..44289aa Binary files /dev/null and b/images/248_Nishino Flower.png differ diff --git a/images/249_Haru Urara.png b/images/249_Haru Urara.png new file mode 100644 index 0000000..409e8e5 Binary files /dev/null and b/images/249_Haru Urara.png differ diff --git a/images/24_Hishi Amazon.png b/images/24_Hishi Amazon.png new file mode 100644 index 0000000..3794684 Binary files /dev/null and b/images/24_Hishi Amazon.png differ diff --git a/images/250_Biko Pegasus.png b/images/250_Biko Pegasus.png new file mode 100644 index 0000000..f6afc0f Binary files /dev/null and b/images/250_Biko Pegasus.png differ diff --git a/images/251_Tazuna Hayakawa.png b/images/251_Tazuna Hayakawa.png new file mode 100644 index 0000000..989eb7b Binary files /dev/null and b/images/251_Tazuna Hayakawa.png differ diff --git a/images/252_Mejiro McQueen.png b/images/252_Mejiro McQueen.png new file mode 100644 index 0000000..f54da81 Binary files /dev/null and b/images/252_Mejiro McQueen.png differ diff --git a/images/253_Rice Shower.png b/images/253_Rice Shower.png new file mode 100644 index 0000000..bfebc32 Binary files /dev/null and b/images/253_Rice Shower.png differ diff --git a/images/254_Oguri Cap.png b/images/254_Oguri Cap.png new file mode 100644 index 0000000..fd58980 Binary files /dev/null and b/images/254_Oguri Cap.png differ diff --git a/images/255_Special Week.png b/images/255_Special Week.png new file mode 100644 index 0000000..eecc8a1 Binary files /dev/null and b/images/255_Special Week.png differ diff --git a/images/256_Twin Turbo.png b/images/256_Twin Turbo.png new file mode 100644 index 0000000..f712373 Binary files /dev/null and b/images/256_Twin Turbo.png differ diff --git a/images/257_Mejiro Palmer.png b/images/257_Mejiro Palmer.png new file mode 100644 index 0000000..69cb1c4 Binary files /dev/null and b/images/257_Mejiro Palmer.png differ diff --git a/images/258_Kitasan Black.png b/images/258_Kitasan Black.png new file mode 100644 index 0000000..2297ea4 Binary files /dev/null and b/images/258_Kitasan Black.png differ diff --git a/images/259_Satono Diamond.png b/images/259_Satono Diamond.png new file mode 100644 index 0000000..a75cb74 Binary files /dev/null and b/images/259_Satono Diamond.png differ diff --git a/images/25_Air Groove.png b/images/25_Air Groove.png new file mode 100644 index 0000000..9c9f2fc Binary files /dev/null and b/images/25_Air Groove.png differ diff --git a/images/260_Matikanetannhauser.png b/images/260_Matikanetannhauser.png new file mode 100644 index 0000000..6979056 Binary files /dev/null and b/images/260_Matikanetannhauser.png differ diff --git a/images/261_Yukino Bijin.png b/images/261_Yukino Bijin.png new file mode 100644 index 0000000..c130da9 Binary files /dev/null and b/images/261_Yukino Bijin.png differ diff --git a/images/262_Yaeno Muteki.png b/images/262_Yaeno Muteki.png new file mode 100644 index 0000000..7cbab4d Binary files /dev/null and b/images/262_Yaeno Muteki.png differ diff --git a/images/263_Winning Ticket.png b/images/263_Winning Ticket.png new file mode 100644 index 0000000..cdb7c98 Binary files /dev/null and b/images/263_Winning Ticket.png differ diff --git a/images/264_Rice Shower.png b/images/264_Rice Shower.png new file mode 100644 index 0000000..e9d37c9 Binary files /dev/null and b/images/264_Rice Shower.png differ diff --git a/images/265_Riko Kashimoto.png b/images/265_Riko Kashimoto.png new file mode 100644 index 0000000..3abbfb8 Binary files /dev/null and b/images/265_Riko Kashimoto.png differ diff --git a/images/266_Symboli Rudolf.png b/images/266_Symboli Rudolf.png new file mode 100644 index 0000000..8a85880 Binary files /dev/null and b/images/266_Symboli Rudolf.png differ diff --git a/images/267_Sakura Chiyono O.png b/images/267_Sakura Chiyono O.png new file mode 100644 index 0000000..140709a Binary files /dev/null and b/images/267_Sakura Chiyono O.png differ diff --git a/images/268_Kawakami Princess.png b/images/268_Kawakami Princess.png new file mode 100644 index 0000000..dc55627 Binary files /dev/null and b/images/268_Kawakami Princess.png differ diff --git a/images/269_Hishi Akebono.png b/images/269_Hishi Akebono.png new file mode 100644 index 0000000..9e95ede Binary files /dev/null and b/images/269_Hishi Akebono.png differ diff --git a/images/26_Agnes Digital.png b/images/26_Agnes Digital.png new file mode 100644 index 0000000..de04cab Binary files /dev/null and b/images/26_Agnes Digital.png differ diff --git a/images/270_Mejiro Dober.png b/images/270_Mejiro Dober.png new file mode 100644 index 0000000..f9658cb Binary files /dev/null and b/images/270_Mejiro Dober.png differ diff --git a/images/271_Bamboo Memory.png b/images/271_Bamboo Memory.png new file mode 100644 index 0000000..c4e41bc Binary files /dev/null and b/images/271_Bamboo Memory.png differ diff --git a/images/272_Nakayama Festa.png b/images/272_Nakayama Festa.png new file mode 100644 index 0000000..a5a5c45 Binary files /dev/null and b/images/272_Nakayama Festa.png differ diff --git a/images/273_Narita Brian.png b/images/273_Narita Brian.png new file mode 100644 index 0000000..55dc919 Binary files /dev/null and b/images/273_Narita Brian.png differ diff --git a/images/274_Sweep Tosho.png b/images/274_Sweep Tosho.png new file mode 100644 index 0000000..6a197b9 Binary files /dev/null and b/images/274_Sweep Tosho.png differ diff --git a/images/275_Winning Ticket.png b/images/275_Winning Ticket.png new file mode 100644 index 0000000..7486f90 Binary files /dev/null and b/images/275_Winning Ticket.png differ diff --git a/images/276_Daiwa Scarlet.png b/images/276_Daiwa Scarlet.png new file mode 100644 index 0000000..073415f Binary files /dev/null and b/images/276_Daiwa Scarlet.png differ diff --git a/images/277_Mejiro Ryan.png b/images/277_Mejiro Ryan.png new file mode 100644 index 0000000..77964e4 Binary files /dev/null and b/images/277_Mejiro Ryan.png differ diff --git a/images/278_Light Hello.png b/images/278_Light Hello.png new file mode 100644 index 0000000..c6e700b Binary files /dev/null and b/images/278_Light Hello.png differ diff --git a/images/279_Taiki Shuttle.png b/images/279_Taiki Shuttle.png new file mode 100644 index 0000000..8e3cd30 Binary files /dev/null and b/images/279_Taiki Shuttle.png differ diff --git a/images/27_Tamamo Cross.png b/images/27_Tamamo Cross.png new file mode 100644 index 0000000..83f0bfa Binary files /dev/null and b/images/27_Tamamo Cross.png differ diff --git a/images/280_Nice Nature.png b/images/280_Nice Nature.png new file mode 100644 index 0000000..4675b8e Binary files /dev/null and b/images/280_Nice Nature.png differ diff --git a/images/281_Seiun Sky.png b/images/281_Seiun Sky.png new file mode 100644 index 0000000..c31b5d0 Binary files /dev/null and b/images/281_Seiun Sky.png differ diff --git a/images/282_King Halo.png b/images/282_King Halo.png new file mode 100644 index 0000000..b4b4253 Binary files /dev/null and b/images/282_King Halo.png differ diff --git a/images/283_Gold Ship.png b/images/283_Gold Ship.png new file mode 100644 index 0000000..f115641 Binary files /dev/null and b/images/283_Gold Ship.png differ diff --git a/images/284_Tokai Teio.png b/images/284_Tokai Teio.png new file mode 100644 index 0000000..428aec0 Binary files /dev/null and b/images/284_Tokai Teio.png differ diff --git a/images/285_Mihono Bourbon.png b/images/285_Mihono Bourbon.png new file mode 100644 index 0000000..b587e70 Binary files /dev/null and b/images/285_Mihono Bourbon.png differ diff --git a/images/286_Twin Turbo.png b/images/286_Twin Turbo.png new file mode 100644 index 0000000..e059b44 Binary files /dev/null and b/images/286_Twin Turbo.png differ diff --git a/images/287_Biwa Hayahide.png b/images/287_Biwa Hayahide.png new file mode 100644 index 0000000..8816fbf Binary files /dev/null and b/images/287_Biwa Hayahide.png differ diff --git a/images/288_Silence Suzuka.png b/images/288_Silence Suzuka.png new file mode 100644 index 0000000..a9e391b Binary files /dev/null and b/images/288_Silence Suzuka.png differ diff --git a/images/289_Ikuno Dictus.png b/images/289_Ikuno Dictus.png new file mode 100644 index 0000000..b8d3562 Binary files /dev/null and b/images/289_Ikuno Dictus.png differ diff --git a/images/28_Fine Motion.png b/images/28_Fine Motion.png new file mode 100644 index 0000000..b97b813 Binary files /dev/null and b/images/28_Fine Motion.png differ diff --git a/images/290_Tamamo Cross.png b/images/290_Tamamo Cross.png new file mode 100644 index 0000000..f60006c Binary files /dev/null and b/images/290_Tamamo Cross.png differ diff --git a/images/291_Zenno Rob Roy.png b/images/291_Zenno Rob Roy.png new file mode 100644 index 0000000..100b654 Binary files /dev/null and b/images/291_Zenno Rob Roy.png differ diff --git a/images/292_Mihono Bourbon.png b/images/292_Mihono Bourbon.png new file mode 100644 index 0000000..a4a05d6 Binary files /dev/null and b/images/292_Mihono Bourbon.png differ diff --git a/images/293_The Throne's Assemblage.png b/images/293_The Throne's Assemblage.png new file mode 100644 index 0000000..c0f1bbf Binary files /dev/null and b/images/293_The Throne's Assemblage.png differ diff --git a/images/294_Curren Chan.png b/images/294_Curren Chan.png new file mode 100644 index 0000000..170ab70 Binary files /dev/null and b/images/294_Curren Chan.png differ diff --git a/images/295_Narita Brian.png b/images/295_Narita Brian.png new file mode 100644 index 0000000..4a5c74b Binary files /dev/null and b/images/295_Narita Brian.png differ diff --git a/images/296_Yukino Bijin.png b/images/296_Yukino Bijin.png new file mode 100644 index 0000000..5423f03 Binary files /dev/null and b/images/296_Yukino Bijin.png differ diff --git a/images/297_Daitaku Helios.png b/images/297_Daitaku Helios.png new file mode 100644 index 0000000..d65b577 Binary files /dev/null and b/images/297_Daitaku Helios.png differ diff --git a/images/298_Mayano Top Gun.png b/images/298_Mayano Top Gun.png new file mode 100644 index 0000000..3db1271 Binary files /dev/null and b/images/298_Mayano Top Gun.png differ diff --git a/images/299_Narita Taishin.png b/images/299_Narita Taishin.png new file mode 100644 index 0000000..705c376 Binary files /dev/null and b/images/299_Narita Taishin.png differ diff --git a/images/29_Biwa Hayahide.png b/images/29_Biwa Hayahide.png new file mode 100644 index 0000000..04735dc Binary files /dev/null and b/images/29_Biwa Hayahide.png differ diff --git a/images/2_Silence Suzuka.png b/images/2_Silence Suzuka.png new file mode 100644 index 0000000..158d515 Binary files /dev/null and b/images/2_Silence Suzuka.png differ diff --git a/images/2_Special Week.png b/images/2_Special Week.png new file mode 100644 index 0000000..ff2e4f5 Binary files /dev/null and b/images/2_Special Week.png differ diff --git a/images/300_Marvelous Sunday.png b/images/300_Marvelous Sunday.png new file mode 100644 index 0000000..9b9ff13 Binary files /dev/null and b/images/300_Marvelous Sunday.png differ diff --git a/images/301_Manhattan Cafe.png b/images/301_Manhattan Cafe.png new file mode 100644 index 0000000..462158d Binary files /dev/null and b/images/301_Manhattan Cafe.png differ diff --git a/images/302_Silence Suzuka.png b/images/302_Silence Suzuka.png new file mode 100644 index 0000000..c5d0d9f Binary files /dev/null and b/images/302_Silence Suzuka.png differ diff --git a/images/303_Admire Vega.png b/images/303_Admire Vega.png new file mode 100644 index 0000000..5193c89 Binary files /dev/null and b/images/303_Admire Vega.png differ diff --git a/images/304_Matikanefukukitaru.png b/images/304_Matikanefukukitaru.png new file mode 100644 index 0000000..c55b770 Binary files /dev/null and b/images/304_Matikanefukukitaru.png differ diff --git a/images/305_Meisho Doto.png b/images/305_Meisho Doto.png new file mode 100644 index 0000000..446f68c Binary files /dev/null and b/images/305_Meisho Doto.png differ diff --git a/images/306_Sasami Anshinzawa.png b/images/306_Sasami Anshinzawa.png new file mode 100644 index 0000000..898ccab Binary files /dev/null and b/images/306_Sasami Anshinzawa.png differ diff --git a/images/307_Team Sirius.png b/images/307_Team Sirius.png new file mode 100644 index 0000000..27222d0 Binary files /dev/null and b/images/307_Team Sirius.png differ diff --git a/images/308_Nishino Flower.png b/images/308_Nishino Flower.png new file mode 100644 index 0000000..d28db83 Binary files /dev/null and b/images/308_Nishino Flower.png differ diff --git a/images/309_Sakura Bakushin O.png b/images/309_Sakura Bakushin O.png new file mode 100644 index 0000000..ef376f2 Binary files /dev/null and b/images/309_Sakura Bakushin O.png differ diff --git a/images/30_Mayano Top Gun.png b/images/30_Mayano Top Gun.png new file mode 100644 index 0000000..cb14660 Binary files /dev/null and b/images/30_Mayano Top Gun.png differ diff --git a/images/310_Tosen Jordan.png b/images/310_Tosen Jordan.png new file mode 100644 index 0000000..5fda73d Binary files /dev/null and b/images/310_Tosen Jordan.png differ diff --git a/images/311_Agnes Digital.png b/images/311_Agnes Digital.png new file mode 100644 index 0000000..36c25c7 Binary files /dev/null and b/images/311_Agnes Digital.png differ diff --git a/images/312_Narita Top Road.png b/images/312_Narita Top Road.png new file mode 100644 index 0000000..f493b5f Binary files /dev/null and b/images/312_Narita Top Road.png differ diff --git a/images/313_Mejiro Bright.png b/images/313_Mejiro Bright.png new file mode 100644 index 0000000..db7571f Binary files /dev/null and b/images/313_Mejiro Bright.png differ diff --git a/images/314_Satono Diamond.png b/images/314_Satono Diamond.png new file mode 100644 index 0000000..1f47725 Binary files /dev/null and b/images/314_Satono Diamond.png differ diff --git a/images/315_Marvelous Sunday.png b/images/315_Marvelous Sunday.png new file mode 100644 index 0000000..388b857 Binary files /dev/null and b/images/315_Marvelous Sunday.png differ diff --git a/images/316_Symboli Rudolf.png b/images/316_Symboli Rudolf.png new file mode 100644 index 0000000..58da87c Binary files /dev/null and b/images/316_Symboli Rudolf.png differ diff --git a/images/317_Sirius Symboli.png b/images/317_Sirius Symboli.png new file mode 100644 index 0000000..0e30af6 Binary files /dev/null and b/images/317_Sirius Symboli.png differ diff --git a/images/318_Air Shakur.png b/images/318_Air Shakur.png new file mode 100644 index 0000000..7b74fa3 Binary files /dev/null and b/images/318_Air Shakur.png differ diff --git a/images/319_Daiwa Scarlet.png b/images/319_Daiwa Scarlet.png new file mode 100644 index 0000000..4d45df1 Binary files /dev/null and b/images/319_Daiwa Scarlet.png differ diff --git a/images/31_Manhattan Cafe.png b/images/31_Manhattan Cafe.png new file mode 100644 index 0000000..15e6778 Binary files /dev/null and b/images/31_Manhattan Cafe.png differ diff --git a/images/320_Bamboo Memory.png b/images/320_Bamboo Memory.png new file mode 100644 index 0000000..23886ed Binary files /dev/null and b/images/320_Bamboo Memory.png differ diff --git a/images/321_Seeking the Pearl.png b/images/321_Seeking the Pearl.png new file mode 100644 index 0000000..353c65f Binary files /dev/null and b/images/321_Seeking the Pearl.png differ diff --git a/images/322_Kawakami Princess.png b/images/322_Kawakami Princess.png new file mode 100644 index 0000000..8eb2178 Binary files /dev/null and b/images/322_Kawakami Princess.png differ diff --git a/images/323_Mr. C.B..png b/images/323_Mr. C.B..png new file mode 100644 index 0000000..56aaa5a Binary files /dev/null and b/images/323_Mr. C.B..png differ diff --git a/images/324_Haru Urara.png b/images/324_Haru Urara.png new file mode 100644 index 0000000..fad432a Binary files /dev/null and b/images/324_Haru Urara.png differ diff --git a/images/325_Ikuno Dictus.png b/images/325_Ikuno Dictus.png new file mode 100644 index 0000000..771d713 Binary files /dev/null and b/images/325_Ikuno Dictus.png differ diff --git a/images/326_Rice Shower.png b/images/326_Rice Shower.png new file mode 100644 index 0000000..f36bd52 Binary files /dev/null and b/images/326_Rice Shower.png differ diff --git a/images/327_Agnes Tachyon.png b/images/327_Agnes Tachyon.png new file mode 100644 index 0000000..58e8df2 Binary files /dev/null and b/images/327_Agnes Tachyon.png differ diff --git a/images/328_El Condor Pasa.png b/images/328_El Condor Pasa.png new file mode 100644 index 0000000..8f0fe7c Binary files /dev/null and b/images/328_El Condor Pasa.png differ diff --git a/images/329_Matikanetannhauser.png b/images/329_Matikanetannhauser.png new file mode 100644 index 0000000..237136b Binary files /dev/null and b/images/329_Matikanetannhauser.png differ diff --git a/images/32_Mihono Bourbon.png b/images/32_Mihono Bourbon.png new file mode 100644 index 0000000..9f18f54 Binary files /dev/null and b/images/32_Mihono Bourbon.png differ diff --git a/images/330_Zenno Rob Roy.png b/images/330_Zenno Rob Roy.png new file mode 100644 index 0000000..a1ebc0e Binary files /dev/null and b/images/330_Zenno Rob Roy.png differ diff --git a/images/331_Special Week.png b/images/331_Special Week.png new file mode 100644 index 0000000..3b3184b Binary files /dev/null and b/images/331_Special Week.png differ diff --git a/images/332_Air Groove.png b/images/332_Air Groove.png new file mode 100644 index 0000000..4aaf146 Binary files /dev/null and b/images/332_Air Groove.png differ diff --git a/images/333_Maruzensky.png b/images/333_Maruzensky.png new file mode 100644 index 0000000..062e8ce Binary files /dev/null and b/images/333_Maruzensky.png differ diff --git a/images/334_Nakayama Festa.png b/images/334_Nakayama Festa.png new file mode 100644 index 0000000..6469e64 Binary files /dev/null and b/images/334_Nakayama Festa.png differ diff --git a/images/335_Sakura Chiyono O.png b/images/335_Sakura Chiyono O.png new file mode 100644 index 0000000..d9de5bc Binary files /dev/null and b/images/335_Sakura Chiyono O.png differ diff --git a/images/336_Manhattan Cafe.png b/images/336_Manhattan Cafe.png new file mode 100644 index 0000000..4d4d622 Binary files /dev/null and b/images/336_Manhattan Cafe.png differ diff --git a/images/337_Tokai Teio.png b/images/337_Tokai Teio.png new file mode 100644 index 0000000..13e442e Binary files /dev/null and b/images/337_Tokai Teio.png differ diff --git a/images/338_Twin Turbo.png b/images/338_Twin Turbo.png new file mode 100644 index 0000000..1aec1bd Binary files /dev/null and b/images/338_Twin Turbo.png differ diff --git a/images/339_Biwa Hayahide.png b/images/339_Biwa Hayahide.png new file mode 100644 index 0000000..4ab5134 Binary files /dev/null and b/images/339_Biwa Hayahide.png differ diff --git a/images/33_Mejiro Ryan.png b/images/33_Mejiro Ryan.png new file mode 100644 index 0000000..56bd62e Binary files /dev/null and b/images/33_Mejiro Ryan.png differ diff --git a/images/340_Daiichi Ruby.png b/images/340_Daiichi Ruby.png new file mode 100644 index 0000000..b247bd8 Binary files /dev/null and b/images/340_Daiichi Ruby.png differ diff --git a/images/341_Mejiro Palmer.png b/images/341_Mejiro Palmer.png new file mode 100644 index 0000000..b2b8b5c Binary files /dev/null and b/images/341_Mejiro Palmer.png differ diff --git a/images/342_Daitaku Helios.png b/images/342_Daitaku Helios.png new file mode 100644 index 0000000..de7685d Binary files /dev/null and b/images/342_Daitaku Helios.png differ diff --git a/images/343_Shinko Windy.png b/images/343_Shinko Windy.png new file mode 100644 index 0000000..7238867 Binary files /dev/null and b/images/343_Shinko Windy.png differ diff --git a/images/344_Symboli Kris S.png b/images/344_Symboli Kris S.png new file mode 100644 index 0000000..032d869 Binary files /dev/null and b/images/344_Symboli Kris S.png differ diff --git a/images/345_Mejiro Ardan.png b/images/345_Mejiro Ardan.png new file mode 100644 index 0000000..3073e18 Binary files /dev/null and b/images/345_Mejiro Ardan.png differ diff --git a/images/346_Yaeno Muteki.png b/images/346_Yaeno Muteki.png new file mode 100644 index 0000000..a8f3c9c Binary files /dev/null and b/images/346_Yaeno Muteki.png differ diff --git a/images/347_Mihono Bourbon.png b/images/347_Mihono Bourbon.png new file mode 100644 index 0000000..1da6c6b Binary files /dev/null and b/images/347_Mihono Bourbon.png differ diff --git a/images/348_Eishin Flash.png b/images/348_Eishin Flash.png new file mode 100644 index 0000000..7623979 Binary files /dev/null and b/images/348_Eishin Flash.png differ diff --git a/images/349_Narita Brian.png b/images/349_Narita Brian.png new file mode 100644 index 0000000..37d9aea Binary files /dev/null and b/images/349_Narita Brian.png differ diff --git a/images/34_Yukino Bijin.png b/images/34_Yukino Bijin.png new file mode 100644 index 0000000..41d4bc2 Binary files /dev/null and b/images/34_Yukino Bijin.png differ diff --git a/images/350_Air Groove.png b/images/350_Air Groove.png new file mode 100644 index 0000000..d801cd1 Binary files /dev/null and b/images/350_Air Groove.png differ diff --git a/images/351_Sakura Laurel.png b/images/351_Sakura Laurel.png new file mode 100644 index 0000000..c92885b Binary files /dev/null and b/images/351_Sakura Laurel.png differ diff --git a/images/352_Yamanin Zephyr.png b/images/352_Yamanin Zephyr.png new file mode 100644 index 0000000..73824af Binary files /dev/null and b/images/352_Yamanin Zephyr.png differ diff --git a/images/353_Special Week.png b/images/353_Special Week.png new file mode 100644 index 0000000..c47bfec Binary files /dev/null and b/images/353_Special Week.png differ diff --git a/images/354_Sweep Tosho.png b/images/354_Sweep Tosho.png new file mode 100644 index 0000000..857b65e Binary files /dev/null and b/images/354_Sweep Tosho.png differ diff --git a/images/355_Grass Wonder.png b/images/355_Grass Wonder.png new file mode 100644 index 0000000..4cb54dc Binary files /dev/null and b/images/355_Grass Wonder.png differ diff --git a/images/356_K.S.Miracle.png b/images/356_K.S.Miracle.png new file mode 100644 index 0000000..c793d83 Binary files /dev/null and b/images/356_K.S.Miracle.png differ diff --git a/images/357_Marvelous Sunday.png b/images/357_Marvelous Sunday.png new file mode 100644 index 0000000..13b3519 Binary files /dev/null and b/images/357_Marvelous Sunday.png differ diff --git a/images/358_Biko Pegasus.png b/images/358_Biko Pegasus.png new file mode 100644 index 0000000..aadca5b Binary files /dev/null and b/images/358_Biko Pegasus.png differ diff --git a/images/359_Hishi Akebono.png b/images/359_Hishi Akebono.png new file mode 100644 index 0000000..a96c647 Binary files /dev/null and b/images/359_Hishi Akebono.png differ diff --git a/images/35_Ines Fujin.png b/images/35_Ines Fujin.png new file mode 100644 index 0000000..da13a55 Binary files /dev/null and b/images/35_Ines Fujin.png differ diff --git a/images/360_Mejiro Ramonu.png b/images/360_Mejiro Ramonu.png new file mode 100644 index 0000000..fe8b868 Binary files /dev/null and b/images/360_Mejiro Ramonu.png differ diff --git a/images/361_Katsuragi Ace.png b/images/361_Katsuragi Ace.png new file mode 100644 index 0000000..d9e64b7 Binary files /dev/null and b/images/361_Katsuragi Ace.png differ diff --git a/images/362_Symboli Kris S.png b/images/362_Symboli Kris S.png new file mode 100644 index 0000000..4d70702 Binary files /dev/null and b/images/362_Symboli Kris S.png differ diff --git a/images/363_Ancestors & Guides.png b/images/363_Ancestors & Guides.png new file mode 100644 index 0000000..7da24e0 Binary files /dev/null and b/images/363_Ancestors & Guides.png differ diff --git a/images/364_Nice Nature.png b/images/364_Nice Nature.png new file mode 100644 index 0000000..54ff312 Binary files /dev/null and b/images/364_Nice Nature.png differ diff --git a/images/365_Mejiro McQueen.png b/images/365_Mejiro McQueen.png new file mode 100644 index 0000000..bb713e2 Binary files /dev/null and b/images/365_Mejiro McQueen.png differ diff --git a/images/366_Tokai Teio.png b/images/366_Tokai Teio.png new file mode 100644 index 0000000..69f9c77 Binary files /dev/null and b/images/366_Tokai Teio.png differ diff --git a/images/367_Mihono Bourbon.png b/images/367_Mihono Bourbon.png new file mode 100644 index 0000000..2e2711f Binary files /dev/null and b/images/367_Mihono Bourbon.png differ diff --git a/images/368_Sakura Laurel.png b/images/368_Sakura Laurel.png new file mode 100644 index 0000000..76b162d Binary files /dev/null and b/images/368_Sakura Laurel.png differ diff --git a/images/369_Ikuno Dictus.png b/images/369_Ikuno Dictus.png new file mode 100644 index 0000000..f419609 Binary files /dev/null and b/images/369_Ikuno Dictus.png differ diff --git a/images/36_Agnes Tachyon.png b/images/36_Agnes Tachyon.png new file mode 100644 index 0000000..b5f3905 Binary files /dev/null and b/images/36_Agnes Tachyon.png differ diff --git a/images/370_Tanino Gimlet.png b/images/370_Tanino Gimlet.png new file mode 100644 index 0000000..8af9c0e Binary files /dev/null and b/images/370_Tanino Gimlet.png differ diff --git a/images/371_Oguri Cap.png b/images/371_Oguri Cap.png new file mode 100644 index 0000000..d4f768f Binary files /dev/null and b/images/371_Oguri Cap.png differ diff --git a/images/372_Jungle Pocket.png b/images/372_Jungle Pocket.png new file mode 100644 index 0000000..5c3d6b3 Binary files /dev/null and b/images/372_Jungle Pocket.png differ diff --git a/images/373_Daiwa Scarlet.png b/images/373_Daiwa Scarlet.png new file mode 100644 index 0000000..9025caf Binary files /dev/null and b/images/373_Daiwa Scarlet.png differ diff --git a/images/374_Aston Machan.png b/images/374_Aston Machan.png new file mode 100644 index 0000000..f0527f7 Binary files /dev/null and b/images/374_Aston Machan.png differ diff --git a/images/375_Vodka.png b/images/375_Vodka.png new file mode 100644 index 0000000..c8cbb93 Binary files /dev/null and b/images/375_Vodka.png differ diff --git a/images/376_Mayano Top Gun.png b/images/376_Mayano Top Gun.png new file mode 100644 index 0000000..a11ed26 Binary files /dev/null and b/images/376_Mayano Top Gun.png differ diff --git a/images/377_TM Opera O.png b/images/377_TM Opera O.png new file mode 100644 index 0000000..0dbf8a3 Binary files /dev/null and b/images/377_TM Opera O.png differ diff --git a/images/378_Gold City.png b/images/378_Gold City.png new file mode 100644 index 0000000..958e33a Binary files /dev/null and b/images/378_Gold City.png differ diff --git a/images/379_Mejiro Palmer.png b/images/379_Mejiro Palmer.png new file mode 100644 index 0000000..fd7b40d Binary files /dev/null and b/images/379_Mejiro Palmer.png differ diff --git a/images/37_Air Shakur.png b/images/37_Air Shakur.png new file mode 100644 index 0000000..a425fbc Binary files /dev/null and b/images/37_Air Shakur.png differ diff --git a/images/380_Daitaku Helios.png b/images/380_Daitaku Helios.png new file mode 100644 index 0000000..55a4306 Binary files /dev/null and b/images/380_Daitaku Helios.png differ diff --git a/images/381_Wonder Acute.png b/images/381_Wonder Acute.png new file mode 100644 index 0000000..08662b9 Binary files /dev/null and b/images/381_Wonder Acute.png differ diff --git a/images/382_Manhattan Cafe.png b/images/382_Manhattan Cafe.png new file mode 100644 index 0000000..89d3a1a Binary files /dev/null and b/images/382_Manhattan Cafe.png differ diff --git a/images/383_Jungle Pocket.png b/images/383_Jungle Pocket.png new file mode 100644 index 0000000..f4d2c7b Binary files /dev/null and b/images/383_Jungle Pocket.png differ diff --git a/images/384_Air Groove.png b/images/384_Air Groove.png new file mode 100644 index 0000000..5ac449e Binary files /dev/null and b/images/384_Air Groove.png differ diff --git a/images/385_Mei Satake.png b/images/385_Mei Satake.png new file mode 100644 index 0000000..538e229 Binary files /dev/null and b/images/385_Mei Satake.png differ diff --git a/images/386_El Condor Pasa.png b/images/386_El Condor Pasa.png new file mode 100644 index 0000000..4e2e17d Binary files /dev/null and b/images/386_El Condor Pasa.png differ diff --git a/images/387_Admire Vega.png b/images/387_Admire Vega.png new file mode 100644 index 0000000..992e417 Binary files /dev/null and b/images/387_Admire Vega.png differ diff --git a/images/388_Nakayama Festa.png b/images/388_Nakayama Festa.png new file mode 100644 index 0000000..98b17a6 Binary files /dev/null and b/images/388_Nakayama Festa.png differ diff --git a/images/389_Hishi Amazon.png b/images/389_Hishi Amazon.png new file mode 100644 index 0000000..8b40955 Binary files /dev/null and b/images/389_Hishi Amazon.png differ diff --git a/images/38_Eishin Flash.png b/images/38_Eishin Flash.png new file mode 100644 index 0000000..9d7f915 Binary files /dev/null and b/images/38_Eishin Flash.png differ diff --git a/images/390_Tanino Gimlet.png b/images/390_Tanino Gimlet.png new file mode 100644 index 0000000..c21b70b Binary files /dev/null and b/images/390_Tanino Gimlet.png differ diff --git a/images/391_Tap Dance City.png b/images/391_Tap Dance City.png new file mode 100644 index 0000000..3c76e60 Binary files /dev/null and b/images/391_Tap Dance City.png differ diff --git a/images/392_Fine Motion.png b/images/392_Fine Motion.png new file mode 100644 index 0000000..e085023 Binary files /dev/null and b/images/392_Fine Motion.png differ diff --git a/images/393_Gold Ship.png b/images/393_Gold Ship.png new file mode 100644 index 0000000..e58f591 Binary files /dev/null and b/images/393_Gold Ship.png differ diff --git a/images/394_Tsurumaru Tsuyoshi.png b/images/394_Tsurumaru Tsuyoshi.png new file mode 100644 index 0000000..33c6965 Binary files /dev/null and b/images/394_Tsurumaru Tsuyoshi.png differ diff --git a/images/395_King Halo.png b/images/395_King Halo.png new file mode 100644 index 0000000..6f4fe79 Binary files /dev/null and b/images/395_King Halo.png differ diff --git a/images/396_Haru Urara.png b/images/396_Haru Urara.png new file mode 100644 index 0000000..99f46bd Binary files /dev/null and b/images/396_Haru Urara.png differ diff --git a/images/397_Mejiro McQueen.png b/images/397_Mejiro McQueen.png new file mode 100644 index 0000000..ca30369 Binary files /dev/null and b/images/397_Mejiro McQueen.png differ diff --git a/images/398_Sounds of Earth.png b/images/398_Sounds of Earth.png new file mode 100644 index 0000000..c8f8e96 Binary files /dev/null and b/images/398_Sounds of Earth.png differ diff --git a/images/399_Mejiro Dober.png b/images/399_Mejiro Dober.png new file mode 100644 index 0000000..cb0d0af Binary files /dev/null and b/images/399_Mejiro Dober.png differ diff --git a/images/39_Smart Falcon.png b/images/39_Smart Falcon.png new file mode 100644 index 0000000..79ec244 Binary files /dev/null and b/images/39_Smart Falcon.png differ diff --git a/images/3_Tokai Teio.png b/images/3_Tokai Teio.png new file mode 100644 index 0000000..bf45409 Binary files /dev/null and b/images/3_Tokai Teio.png differ diff --git a/images/400_Mejiro Ramonu.png b/images/400_Mejiro Ramonu.png new file mode 100644 index 0000000..1b733f3 Binary files /dev/null and b/images/400_Mejiro Ramonu.png differ diff --git a/images/401_Mejiro Ryan.png b/images/401_Mejiro Ryan.png new file mode 100644 index 0000000..72f9159 Binary files /dev/null and b/images/401_Mejiro Ryan.png differ diff --git a/images/402_Vivlos.png b/images/402_Vivlos.png new file mode 100644 index 0000000..48b56fe Binary files /dev/null and b/images/402_Vivlos.png differ diff --git a/images/403_Duramente.png b/images/403_Duramente.png new file mode 100644 index 0000000..77ab87b Binary files /dev/null and b/images/403_Duramente.png differ diff --git a/images/404_Satono Diamond.png b/images/404_Satono Diamond.png new file mode 100644 index 0000000..5961bdd Binary files /dev/null and b/images/404_Satono Diamond.png differ diff --git a/images/405_Carvers of History.png b/images/405_Carvers of History.png new file mode 100644 index 0000000..2cd16e3 Binary files /dev/null and b/images/405_Carvers of History.png differ diff --git a/images/406_Twin Turbo.png b/images/406_Twin Turbo.png new file mode 100644 index 0000000..d2f4405 Binary files /dev/null and b/images/406_Twin Turbo.png differ diff --git a/images/407_Hokko Tarumae.png b/images/407_Hokko Tarumae.png new file mode 100644 index 0000000..2b0f8b0 Binary files /dev/null and b/images/407_Hokko Tarumae.png differ diff --git a/images/408_Winning Ticket.png b/images/408_Winning Ticket.png new file mode 100644 index 0000000..26e5ab2 Binary files /dev/null and b/images/408_Winning Ticket.png differ diff --git a/images/409_Sakura Bakushin O.png b/images/409_Sakura Bakushin O.png new file mode 100644 index 0000000..a9845d2 Binary files /dev/null and b/images/409_Sakura Bakushin O.png differ diff --git a/images/40_Narita Taishin.png b/images/40_Narita Taishin.png new file mode 100644 index 0000000..3eb209f Binary files /dev/null and b/images/40_Narita Taishin.png differ diff --git a/images/410_North Flight.png b/images/410_North Flight.png new file mode 100644 index 0000000..1fc26cd Binary files /dev/null and b/images/410_North Flight.png differ diff --git a/images/411_Gentildonna.png b/images/411_Gentildonna.png new file mode 100644 index 0000000..86318f0 Binary files /dev/null and b/images/411_Gentildonna.png differ diff --git a/images/412_Orfevre.png b/images/412_Orfevre.png new file mode 100644 index 0000000..b21420e Binary files /dev/null and b/images/412_Orfevre.png differ diff --git a/images/413_Ryoka Tsurugi.png b/images/413_Ryoka Tsurugi.png new file mode 100644 index 0000000..9550ba4 Binary files /dev/null and b/images/413_Ryoka Tsurugi.png differ diff --git a/images/414_Kitasan Black.png b/images/414_Kitasan Black.png new file mode 100644 index 0000000..8df8136 Binary files /dev/null and b/images/414_Kitasan Black.png differ diff --git a/images/415_Duramente.png b/images/415_Duramente.png new file mode 100644 index 0000000..1b401f0 Binary files /dev/null and b/images/415_Duramente.png differ diff --git a/images/416_Sounds of Earth.png b/images/416_Sounds of Earth.png new file mode 100644 index 0000000..71eefed Binary files /dev/null and b/images/416_Sounds of Earth.png differ diff --git a/images/417_Vivlos.png b/images/417_Vivlos.png new file mode 100644 index 0000000..6cb25e0 Binary files /dev/null and b/images/417_Vivlos.png differ diff --git a/images/418_Cheval Grand.png b/images/418_Cheval Grand.png new file mode 100644 index 0000000..fd38bf7 Binary files /dev/null and b/images/418_Cheval Grand.png differ diff --git a/images/419_Rhein Kraft.png b/images/419_Rhein Kraft.png new file mode 100644 index 0000000..86fd53f Binary files /dev/null and b/images/419_Rhein Kraft.png differ diff --git a/images/41_Nishino Flower.png b/images/41_Nishino Flower.png new file mode 100644 index 0000000..fa34c70 Binary files /dev/null and b/images/41_Nishino Flower.png differ diff --git a/images/420_K.S.Miracle.png b/images/420_K.S.Miracle.png new file mode 100644 index 0000000..55eb1b5 Binary files /dev/null and b/images/420_K.S.Miracle.png differ diff --git a/images/421_Yamanin Zephyr.png b/images/421_Yamanin Zephyr.png new file mode 100644 index 0000000..8861763 Binary files /dev/null and b/images/421_Yamanin Zephyr.png differ diff --git a/images/422_Bamboo Memory.png b/images/422_Bamboo Memory.png new file mode 100644 index 0000000..f279c34 Binary files /dev/null and b/images/422_Bamboo Memory.png differ diff --git a/images/423_Neo Universe.png b/images/423_Neo Universe.png new file mode 100644 index 0000000..831f717 Binary files /dev/null and b/images/423_Neo Universe.png differ diff --git a/images/424_Hishi Miracle.png b/images/424_Hishi Miracle.png new file mode 100644 index 0000000..d6a4fe7 Binary files /dev/null and b/images/424_Hishi Miracle.png differ diff --git a/images/425_No Reason.png b/images/425_No Reason.png new file mode 100644 index 0000000..b64cbe7 Binary files /dev/null and b/images/425_No Reason.png differ diff --git a/images/426_Narita Taishin.png b/images/426_Narita Taishin.png new file mode 100644 index 0000000..ed942d1 Binary files /dev/null and b/images/426_Narita Taishin.png differ diff --git a/images/427_Vodka.png b/images/427_Vodka.png new file mode 100644 index 0000000..00a87a1 Binary files /dev/null and b/images/427_Vodka.png differ diff --git a/images/428_Jungle Pocket.png b/images/428_Jungle Pocket.png new file mode 100644 index 0000000..5157759 Binary files /dev/null and b/images/428_Jungle Pocket.png differ diff --git a/images/429_Seiun Sky.png b/images/429_Seiun Sky.png new file mode 100644 index 0000000..16cbff6 Binary files /dev/null and b/images/429_Seiun Sky.png differ diff --git a/images/42_Biko Pegasus.png b/images/42_Biko Pegasus.png new file mode 100644 index 0000000..bcf6a2a Binary files /dev/null and b/images/42_Biko Pegasus.png differ diff --git a/images/430_Verxina.png b/images/430_Verxina.png new file mode 100644 index 0000000..5a41fa6 Binary files /dev/null and b/images/430_Verxina.png differ diff --git a/images/431_Vivlos.png b/images/431_Vivlos.png new file mode 100644 index 0000000..511c3c8 Binary files /dev/null and b/images/431_Vivlos.png differ diff --git a/images/432_Yayoi Akikawa.png b/images/432_Yayoi Akikawa.png new file mode 100644 index 0000000..a7ab7bf Binary files /dev/null and b/images/432_Yayoi Akikawa.png differ diff --git a/images/433_Nishino Flower.png b/images/433_Nishino Flower.png new file mode 100644 index 0000000..75b0757 Binary files /dev/null and b/images/433_Nishino Flower.png differ diff --git a/images/434_Dantsu Flame.png b/images/434_Dantsu Flame.png new file mode 100644 index 0000000..d3c2161 Binary files /dev/null and b/images/434_Dantsu Flame.png differ diff --git a/images/435_Smart Falcon.png b/images/435_Smart Falcon.png new file mode 100644 index 0000000..32ec727 Binary files /dev/null and b/images/435_Smart Falcon.png differ diff --git a/images/436_Copano Rickey.png b/images/436_Copano Rickey.png new file mode 100644 index 0000000..74c9562 Binary files /dev/null and b/images/436_Copano Rickey.png differ diff --git a/images/437_Wonder Acute.png b/images/437_Wonder Acute.png new file mode 100644 index 0000000..edf9cd5 Binary files /dev/null and b/images/437_Wonder Acute.png differ diff --git a/images/438_Tokai Teio.png b/images/438_Tokai Teio.png new file mode 100644 index 0000000..52c0710 Binary files /dev/null and b/images/438_Tokai Teio.png differ diff --git a/images/439_Fine Motion.png b/images/439_Fine Motion.png new file mode 100644 index 0000000..2c9c707 Binary files /dev/null and b/images/439_Fine Motion.png differ diff --git a/images/43_Marvelous Sunday.png b/images/43_Marvelous Sunday.png new file mode 100644 index 0000000..90c81fc Binary files /dev/null and b/images/43_Marvelous Sunday.png differ diff --git a/images/440_Still in Love.png b/images/440_Still in Love.png new file mode 100644 index 0000000..90e80c5 Binary files /dev/null and b/images/440_Still in Love.png differ diff --git a/images/441_Buena Vista.png b/images/441_Buena Vista.png new file mode 100644 index 0000000..33e3d14 Binary files /dev/null and b/images/441_Buena Vista.png differ diff --git a/images/442_Cesario.png b/images/442_Cesario.png new file mode 100644 index 0000000..7973bda Binary files /dev/null and b/images/442_Cesario.png differ diff --git a/images/443_Taiki Shuttle.png b/images/443_Taiki Shuttle.png new file mode 100644 index 0000000..79d389e Binary files /dev/null and b/images/443_Taiki Shuttle.png differ diff --git a/images/444_Fuji Kiseki.png b/images/444_Fuji Kiseki.png new file mode 100644 index 0000000..3feb99b Binary files /dev/null and b/images/444_Fuji Kiseki.png differ diff --git a/images/445_Symboli Kris S.png b/images/445_Symboli Kris S.png new file mode 100644 index 0000000..e97fbd9 Binary files /dev/null and b/images/445_Symboli Kris S.png differ diff --git a/images/446_Satono Diamond.png b/images/446_Satono Diamond.png new file mode 100644 index 0000000..8cea125 Binary files /dev/null and b/images/446_Satono Diamond.png differ diff --git a/images/447_Espoir City.png b/images/447_Espoir City.png new file mode 100644 index 0000000..27bd463 Binary files /dev/null and b/images/447_Espoir City.png differ diff --git a/images/448_Hishi Amazon.png b/images/448_Hishi Amazon.png new file mode 100644 index 0000000..f74064e Binary files /dev/null and b/images/448_Hishi Amazon.png differ diff --git a/images/449_Narita Brian.png b/images/449_Narita Brian.png new file mode 100644 index 0000000..169a3e9 Binary files /dev/null and b/images/449_Narita Brian.png differ diff --git a/images/44_Matikanefukukitaru.png b/images/44_Matikanefukukitaru.png new file mode 100644 index 0000000..7f19d0c Binary files /dev/null and b/images/44_Matikanefukukitaru.png differ diff --git a/images/450_Matikanefukukitaru.png b/images/450_Matikanefukukitaru.png new file mode 100644 index 0000000..1c2efb1 Binary files /dev/null and b/images/450_Matikanefukukitaru.png differ diff --git a/images/451_Air Shakur.png b/images/451_Air Shakur.png new file mode 100644 index 0000000..a4e417e Binary files /dev/null and b/images/451_Air Shakur.png differ diff --git a/images/452_Daiwa Scarlet.png b/images/452_Daiwa Scarlet.png new file mode 100644 index 0000000..8408940 Binary files /dev/null and b/images/452_Daiwa Scarlet.png differ diff --git a/images/453_Symboli Kris S.png b/images/453_Symboli Kris S.png new file mode 100644 index 0000000..f821dfb Binary files /dev/null and b/images/453_Symboli Kris S.png differ diff --git a/images/454_Agnes Digital.png b/images/454_Agnes Digital.png new file mode 100644 index 0000000..544cd8f Binary files /dev/null and b/images/454_Agnes Digital.png differ diff --git a/images/455_Meisho Doto.png b/images/455_Meisho Doto.png new file mode 100644 index 0000000..cffc42b Binary files /dev/null and b/images/455_Meisho Doto.png differ diff --git a/images/456_TM Opera O.png b/images/456_TM Opera O.png new file mode 100644 index 0000000..4a61300 Binary files /dev/null and b/images/456_TM Opera O.png differ diff --git a/images/457_Blast Onepiece.png b/images/457_Blast Onepiece.png new file mode 100644 index 0000000..2bcd445 Binary files /dev/null and b/images/457_Blast Onepiece.png differ diff --git a/images/458_Symboli Rudolf.png b/images/458_Symboli Rudolf.png new file mode 100644 index 0000000..39d6556 Binary files /dev/null and b/images/458_Symboli Rudolf.png differ diff --git a/images/459_Mejiro Ardan.png b/images/459_Mejiro Ardan.png new file mode 100644 index 0000000..7006ae2 Binary files /dev/null and b/images/459_Mejiro Ardan.png differ diff --git a/images/45_Meisho Doto.png b/images/45_Meisho Doto.png new file mode 100644 index 0000000..efc80bb Binary files /dev/null and b/images/45_Meisho Doto.png differ diff --git a/images/460_Maruzensky.png b/images/460_Maruzensky.png new file mode 100644 index 0000000..01138ad Binary files /dev/null and b/images/460_Maruzensky.png differ diff --git a/images/461_Seeking the Pearl.png b/images/461_Seeking the Pearl.png new file mode 100644 index 0000000..60c099e Binary files /dev/null and b/images/461_Seeking the Pearl.png differ diff --git a/images/462_Curren Chan.png b/images/462_Curren Chan.png new file mode 100644 index 0000000..4ece2ab Binary files /dev/null and b/images/462_Curren Chan.png differ diff --git a/images/463_Ikuno Dictus.png b/images/463_Ikuno Dictus.png new file mode 100644 index 0000000..df1a2a7 Binary files /dev/null and b/images/463_Ikuno Dictus.png differ diff --git a/images/464_Nice Nature.png b/images/464_Nice Nature.png new file mode 100644 index 0000000..0e728a5 Binary files /dev/null and b/images/464_Nice Nature.png differ diff --git a/images/465_Jungle Pocket.png b/images/465_Jungle Pocket.png new file mode 100644 index 0000000..3ab7627 Binary files /dev/null and b/images/465_Jungle Pocket.png differ diff --git a/images/466_Embodiment of Legends.png b/images/466_Embodiment of Legends.png new file mode 100644 index 0000000..14712d9 Binary files /dev/null and b/images/466_Embodiment of Legends.png differ diff --git a/images/467_Almond Eye.png b/images/467_Almond Eye.png new file mode 100644 index 0000000..0ea90f1 Binary files /dev/null and b/images/467_Almond Eye.png differ diff --git a/images/468_Gran Alegria.png b/images/468_Gran Alegria.png new file mode 100644 index 0000000..eb9a2a7 Binary files /dev/null and b/images/468_Gran Alegria.png differ diff --git a/images/469_Mejiro Bright.png b/images/469_Mejiro Bright.png new file mode 100644 index 0000000..67ef61e Binary files /dev/null and b/images/469_Mejiro Bright.png differ diff --git a/images/46_Mejiro Dober.png b/images/46_Mejiro Dober.png new file mode 100644 index 0000000..89137c8 Binary files /dev/null and b/images/46_Mejiro Dober.png differ diff --git a/images/470_Vodka.png b/images/470_Vodka.png new file mode 100644 index 0000000..3a72973 Binary files /dev/null and b/images/470_Vodka.png differ diff --git a/images/471_Dream Journey.png b/images/471_Dream Journey.png new file mode 100644 index 0000000..ca5aab8 Binary files /dev/null and b/images/471_Dream Journey.png differ diff --git a/images/472_Symboli Kris S.png b/images/472_Symboli Kris S.png new file mode 100644 index 0000000..87fbd07 Binary files /dev/null and b/images/472_Symboli Kris S.png differ diff --git a/images/473_Daring Tact.png b/images/473_Daring Tact.png new file mode 100644 index 0000000..4feacae Binary files /dev/null and b/images/473_Daring Tact.png differ diff --git a/images/474_Transcend.png b/images/474_Transcend.png new file mode 100644 index 0000000..ab04e0e Binary files /dev/null and b/images/474_Transcend.png differ diff --git a/images/475_Buena Vista.png b/images/475_Buena Vista.png new file mode 100644 index 0000000..3a71b83 Binary files /dev/null and b/images/475_Buena Vista.png differ diff --git a/images/476_Espoir City.png b/images/476_Espoir City.png new file mode 100644 index 0000000..a3e96a7 Binary files /dev/null and b/images/476_Espoir City.png differ diff --git a/images/477_Silence Suzuka.png b/images/477_Silence Suzuka.png new file mode 100644 index 0000000..083baee Binary files /dev/null and b/images/477_Silence Suzuka.png differ diff --git a/images/478_Rhein Kraft.png b/images/478_Rhein Kraft.png new file mode 100644 index 0000000..ac29703 Binary files /dev/null and b/images/478_Rhein Kraft.png differ diff --git a/images/479_Daring Heart.png b/images/479_Daring Heart.png new file mode 100644 index 0000000..80dea94 Binary files /dev/null and b/images/479_Daring Heart.png differ diff --git a/images/47_Nice Nature.png b/images/47_Nice Nature.png new file mode 100644 index 0000000..f2b6117 Binary files /dev/null and b/images/47_Nice Nature.png differ diff --git a/images/480_Air Messiah.png b/images/480_Air Messiah.png new file mode 100644 index 0000000..4aa103f Binary files /dev/null and b/images/480_Air Messiah.png differ diff --git a/images/481_Tamamo Cross.png b/images/481_Tamamo Cross.png new file mode 100644 index 0000000..b3be954 Binary files /dev/null and b/images/481_Tamamo Cross.png differ diff --git a/images/482_Tucker Bryne.png b/images/482_Tucker Bryne.png new file mode 100644 index 0000000..04a07ee Binary files /dev/null and b/images/482_Tucker Bryne.png differ diff --git a/images/483_Mejiro Ryan.png b/images/483_Mejiro Ryan.png new file mode 100644 index 0000000..6aff325 Binary files /dev/null and b/images/483_Mejiro Ryan.png differ diff --git a/images/484_Fusaichi Pandora.png b/images/484_Fusaichi Pandora.png new file mode 100644 index 0000000..115e0c5 Binary files /dev/null and b/images/484_Fusaichi Pandora.png differ diff --git a/images/485_Mejiro McQueen.png b/images/485_Mejiro McQueen.png new file mode 100644 index 0000000..2367a0a Binary files /dev/null and b/images/485_Mejiro McQueen.png differ diff --git a/images/486_Win Variation.png b/images/486_Win Variation.png new file mode 100644 index 0000000..11b0b0e Binary files /dev/null and b/images/486_Win Variation.png differ diff --git a/images/487_Duramente.png b/images/487_Duramente.png new file mode 100644 index 0000000..acd6786 Binary files /dev/null and b/images/487_Duramente.png differ diff --git a/images/488_Vivlos.png b/images/488_Vivlos.png new file mode 100644 index 0000000..96e2319 Binary files /dev/null and b/images/488_Vivlos.png differ diff --git a/images/489_Stay Gold.png b/images/489_Stay Gold.png new file mode 100644 index 0000000..492b26f Binary files /dev/null and b/images/489_Stay Gold.png differ diff --git a/images/48_King Halo.png b/images/48_King Halo.png new file mode 100644 index 0000000..b04b5f8 Binary files /dev/null and b/images/48_King Halo.png differ diff --git a/images/490_Admire Groove.png b/images/490_Admire Groove.png new file mode 100644 index 0000000..3ed3a7c Binary files /dev/null and b/images/490_Admire Groove.png differ diff --git a/images/491_Chrono Genesis.png b/images/491_Chrono Genesis.png new file mode 100644 index 0000000..b84b9e5 Binary files /dev/null and b/images/491_Chrono Genesis.png differ diff --git a/images/492_Calstone Light O.png b/images/492_Calstone Light O.png new file mode 100644 index 0000000..be45675 Binary files /dev/null and b/images/492_Calstone Light O.png differ diff --git a/images/493_Durandal.png b/images/493_Durandal.png new file mode 100644 index 0000000..e5b83f8 Binary files /dev/null and b/images/493_Durandal.png differ diff --git a/images/494_Dantsu Flame.png b/images/494_Dantsu Flame.png new file mode 100644 index 0000000..1fc9903 Binary files /dev/null and b/images/494_Dantsu Flame.png differ diff --git a/images/495_Daiichi Ruby.png b/images/495_Daiichi Ruby.png new file mode 100644 index 0000000..f43c5f6 Binary files /dev/null and b/images/495_Daiichi Ruby.png differ diff --git a/images/496_Fuji Kiseki.png b/images/496_Fuji Kiseki.png new file mode 100644 index 0000000..17f8384 Binary files /dev/null and b/images/496_Fuji Kiseki.png differ diff --git a/images/497_Eishin Flash.png b/images/497_Eishin Flash.png new file mode 100644 index 0000000..d5141a2 Binary files /dev/null and b/images/497_Eishin Flash.png differ diff --git a/images/498_Tosen Jordan.png b/images/498_Tosen Jordan.png new file mode 100644 index 0000000..cbaf13e Binary files /dev/null and b/images/498_Tosen Jordan.png differ diff --git a/images/499_Curren Bouquetd'or.png b/images/499_Curren Bouquetd'or.png new file mode 100644 index 0000000..c358f50 Binary files /dev/null and b/images/499_Curren Bouquetd'or.png differ diff --git a/images/49_Fuji Kiseki.png b/images/49_Fuji Kiseki.png new file mode 100644 index 0000000..08866ab Binary files /dev/null and b/images/49_Fuji Kiseki.png differ diff --git a/images/4_Maruzensky.png b/images/4_Maruzensky.png new file mode 100644 index 0000000..2e628e0 Binary files /dev/null and b/images/4_Maruzensky.png differ diff --git a/images/500_Tokai Teio.png b/images/500_Tokai Teio.png new file mode 100644 index 0000000..ec0061e Binary files /dev/null and b/images/500_Tokai Teio.png differ diff --git a/images/501_Kiyoko Hoshina.png b/images/501_Kiyoko Hoshina.png new file mode 100644 index 0000000..3268852 Binary files /dev/null and b/images/501_Kiyoko Hoshina.png differ diff --git a/images/502_Mihono Bourbon.png b/images/502_Mihono Bourbon.png new file mode 100644 index 0000000..cf8d4eb Binary files /dev/null and b/images/502_Mihono Bourbon.png differ diff --git a/images/503_Gold Ship.png b/images/503_Gold Ship.png new file mode 100644 index 0000000..57cafe6 Binary files /dev/null and b/images/503_Gold Ship.png differ diff --git a/images/504_Fenomeno.png b/images/504_Fenomeno.png new file mode 100644 index 0000000..5f42e52 Binary files /dev/null and b/images/504_Fenomeno.png differ diff --git a/images/505_Orfevre.png b/images/505_Orfevre.png new file mode 100644 index 0000000..dd7e220 Binary files /dev/null and b/images/505_Orfevre.png differ diff --git a/images/506_Inari One.png b/images/506_Inari One.png new file mode 100644 index 0000000..97a10d2 Binary files /dev/null and b/images/506_Inari One.png differ diff --git a/images/507_Air Groove.png b/images/507_Air Groove.png new file mode 100644 index 0000000..8bb619a Binary files /dev/null and b/images/507_Air Groove.png differ diff --git a/images/508_Fine Motion.png b/images/508_Fine Motion.png new file mode 100644 index 0000000..9e86311 Binary files /dev/null and b/images/508_Fine Motion.png differ diff --git a/images/509_Bubble Gum Fellow.png b/images/509_Bubble Gum Fellow.png new file mode 100644 index 0000000..9b30e2d Binary files /dev/null and b/images/509_Bubble Gum Fellow.png differ diff --git a/images/50_Sweep Tosho.png b/images/50_Sweep Tosho.png new file mode 100644 index 0000000..c826cd3 Binary files /dev/null and b/images/50_Sweep Tosho.png differ diff --git a/images/510_Special Week.png b/images/510_Special Week.png new file mode 100644 index 0000000..ff2e4f5 Binary files /dev/null and b/images/510_Special Week.png differ diff --git a/images/511_Silence Suzuka.png b/images/511_Silence Suzuka.png new file mode 100644 index 0000000..158d515 Binary files /dev/null and b/images/511_Silence Suzuka.png differ diff --git a/images/512_Tokai Teio.png b/images/512_Tokai Teio.png new file mode 100644 index 0000000..bf45409 Binary files /dev/null and b/images/512_Tokai Teio.png differ diff --git a/images/513_Maruzensky.png b/images/513_Maruzensky.png new file mode 100644 index 0000000..2e628e0 Binary files /dev/null and b/images/513_Maruzensky.png differ diff --git a/images/514_Oguri Cap.png b/images/514_Oguri Cap.png new file mode 100644 index 0000000..6518f9c Binary files /dev/null and b/images/514_Oguri Cap.png differ diff --git a/images/515_Gold Ship.png b/images/515_Gold Ship.png new file mode 100644 index 0000000..02611f9 Binary files /dev/null and b/images/515_Gold Ship.png differ diff --git a/images/516_Vodka.png b/images/516_Vodka.png new file mode 100644 index 0000000..67f815e Binary files /dev/null and b/images/516_Vodka.png differ diff --git a/images/517_Taiki Shuttle.png b/images/517_Taiki Shuttle.png new file mode 100644 index 0000000..7001211 Binary files /dev/null and b/images/517_Taiki Shuttle.png differ diff --git a/images/518_Grass Wonder.png b/images/518_Grass Wonder.png new file mode 100644 index 0000000..829141c Binary files /dev/null and b/images/518_Grass Wonder.png differ diff --git a/images/519_Mejiro McQueen.png b/images/519_Mejiro McQueen.png new file mode 100644 index 0000000..aa961d1 Binary files /dev/null and b/images/519_Mejiro McQueen.png differ diff --git a/images/51_Twin Turbo.png b/images/51_Twin Turbo.png new file mode 100644 index 0000000..13c123a Binary files /dev/null and b/images/51_Twin Turbo.png differ diff --git a/images/520_El Condor Pasa.png b/images/520_El Condor Pasa.png new file mode 100644 index 0000000..f481e93 Binary files /dev/null and b/images/520_El Condor Pasa.png differ diff --git a/images/521_TM Opera O.png b/images/521_TM Opera O.png new file mode 100644 index 0000000..6d0e2cf Binary files /dev/null and b/images/521_TM Opera O.png differ diff --git a/images/522_Symboli Rudolf.png b/images/522_Symboli Rudolf.png new file mode 100644 index 0000000..be72ccf Binary files /dev/null and b/images/522_Symboli Rudolf.png differ diff --git a/images/523_Seiun Sky.png b/images/523_Seiun Sky.png new file mode 100644 index 0000000..8784dff Binary files /dev/null and b/images/523_Seiun Sky.png differ diff --git a/images/524_Rice Shower.png b/images/524_Rice Shower.png new file mode 100644 index 0000000..0dd6372 Binary files /dev/null and b/images/524_Rice Shower.png differ diff --git a/images/525_Winning Ticket.png b/images/525_Winning Ticket.png new file mode 100644 index 0000000..d9ea2eb Binary files /dev/null and b/images/525_Winning Ticket.png differ diff --git a/images/526_Gold City.png b/images/526_Gold City.png new file mode 100644 index 0000000..556f7bd Binary files /dev/null and b/images/526_Gold City.png differ diff --git a/images/527_Sakura Bakushin O.png b/images/527_Sakura Bakushin O.png new file mode 100644 index 0000000..7ce37b8 Binary files /dev/null and b/images/527_Sakura Bakushin O.png differ diff --git a/images/528_Super Creek.png b/images/528_Super Creek.png new file mode 100644 index 0000000..a8053ce Binary files /dev/null and b/images/528_Super Creek.png differ diff --git a/images/529_Haru Urara.png b/images/529_Haru Urara.png new file mode 100644 index 0000000..7a2893a Binary files /dev/null and b/images/529_Haru Urara.png differ diff --git a/images/52_Daitaku Helios.png b/images/52_Daitaku Helios.png new file mode 100644 index 0000000..b2b574a Binary files /dev/null and b/images/52_Daitaku Helios.png differ diff --git a/images/530_Tazuna Hayakawa.png b/images/530_Tazuna Hayakawa.png new file mode 100644 index 0000000..7209d59 Binary files /dev/null and b/images/530_Tazuna Hayakawa.png differ diff --git a/images/531_Aoi Kiryuin.png b/images/531_Aoi Kiryuin.png new file mode 100644 index 0000000..4150d1d Binary files /dev/null and b/images/531_Aoi Kiryuin.png differ diff --git a/images/532_Daiwa Scarlet.png b/images/532_Daiwa Scarlet.png new file mode 100644 index 0000000..b300ea4 Binary files /dev/null and b/images/532_Daiwa Scarlet.png differ diff --git a/images/533_Hishi Amazon.png b/images/533_Hishi Amazon.png new file mode 100644 index 0000000..3794684 Binary files /dev/null and b/images/533_Hishi Amazon.png differ diff --git a/images/534_Air Groove.png b/images/534_Air Groove.png new file mode 100644 index 0000000..9c9f2fc Binary files /dev/null and b/images/534_Air Groove.png differ diff --git a/images/535_Agnes Digital.png b/images/535_Agnes Digital.png new file mode 100644 index 0000000..de04cab Binary files /dev/null and b/images/535_Agnes Digital.png differ diff --git a/images/536_Tamamo Cross.png b/images/536_Tamamo Cross.png new file mode 100644 index 0000000..83f0bfa Binary files /dev/null and b/images/536_Tamamo Cross.png differ diff --git a/images/537_Fine Motion.png b/images/537_Fine Motion.png new file mode 100644 index 0000000..b97b813 Binary files /dev/null and b/images/537_Fine Motion.png differ diff --git a/images/538_Biwa Hayahide.png b/images/538_Biwa Hayahide.png new file mode 100644 index 0000000..04735dc Binary files /dev/null and b/images/538_Biwa Hayahide.png differ diff --git a/images/539_Mayano Top Gun.png b/images/539_Mayano Top Gun.png new file mode 100644 index 0000000..cb14660 Binary files /dev/null and b/images/539_Mayano Top Gun.png differ diff --git a/images/53_Ikuno Dictus.png b/images/53_Ikuno Dictus.png new file mode 100644 index 0000000..ae90bf5 Binary files /dev/null and b/images/53_Ikuno Dictus.png differ diff --git a/images/540_Manhattan Cafe.png b/images/540_Manhattan Cafe.png new file mode 100644 index 0000000..15e6778 Binary files /dev/null and b/images/540_Manhattan Cafe.png differ diff --git a/images/541_Mihono Bourbon.png b/images/541_Mihono Bourbon.png new file mode 100644 index 0000000..9f18f54 Binary files /dev/null and b/images/541_Mihono Bourbon.png differ diff --git a/images/542_Mejiro Ryan.png b/images/542_Mejiro Ryan.png new file mode 100644 index 0000000..56bd62e Binary files /dev/null and b/images/542_Mejiro Ryan.png differ diff --git a/images/543_Yukino Bijin.png b/images/543_Yukino Bijin.png new file mode 100644 index 0000000..41d4bc2 Binary files /dev/null and b/images/543_Yukino Bijin.png differ diff --git a/images/544_Ines Fujin.png b/images/544_Ines Fujin.png new file mode 100644 index 0000000..da13a55 Binary files /dev/null and b/images/544_Ines Fujin.png differ diff --git a/images/545_Agnes Tachyon.png b/images/545_Agnes Tachyon.png new file mode 100644 index 0000000..b5f3905 Binary files /dev/null and b/images/545_Agnes Tachyon.png differ diff --git a/images/546_Air Shakur.png b/images/546_Air Shakur.png new file mode 100644 index 0000000..a425fbc Binary files /dev/null and b/images/546_Air Shakur.png differ diff --git a/images/547_Eishin Flash.png b/images/547_Eishin Flash.png new file mode 100644 index 0000000..9d7f915 Binary files /dev/null and b/images/547_Eishin Flash.png differ diff --git a/images/548_Smart Falcon.png b/images/548_Smart Falcon.png new file mode 100644 index 0000000..79ec244 Binary files /dev/null and b/images/548_Smart Falcon.png differ diff --git a/images/549_Narita Taishin.png b/images/549_Narita Taishin.png new file mode 100644 index 0000000..3eb209f Binary files /dev/null and b/images/549_Narita Taishin.png differ diff --git a/images/54_Mejiro Palmer.png b/images/54_Mejiro Palmer.png new file mode 100644 index 0000000..f6acfeb Binary files /dev/null and b/images/54_Mejiro Palmer.png differ diff --git a/images/550_Nishino Flower.png b/images/550_Nishino Flower.png new file mode 100644 index 0000000..fa34c70 Binary files /dev/null and b/images/550_Nishino Flower.png differ diff --git a/images/551_Biko Pegasus.png b/images/551_Biko Pegasus.png new file mode 100644 index 0000000..bcf6a2a Binary files /dev/null and b/images/551_Biko Pegasus.png differ diff --git a/images/552_Marvelous Sunday.png b/images/552_Marvelous Sunday.png new file mode 100644 index 0000000..90c81fc Binary files /dev/null and b/images/552_Marvelous Sunday.png differ diff --git a/images/553_Matikanefukukitaru.png b/images/553_Matikanefukukitaru.png new file mode 100644 index 0000000..7f19d0c Binary files /dev/null and b/images/553_Matikanefukukitaru.png differ diff --git a/images/554_Meisho Doto.png b/images/554_Meisho Doto.png new file mode 100644 index 0000000..efc80bb Binary files /dev/null and b/images/554_Meisho Doto.png differ diff --git a/images/555_Mejiro Dober.png b/images/555_Mejiro Dober.png new file mode 100644 index 0000000..89137c8 Binary files /dev/null and b/images/555_Mejiro Dober.png differ diff --git a/images/556_Nice Nature.png b/images/556_Nice Nature.png new file mode 100644 index 0000000..f2b6117 Binary files /dev/null and b/images/556_Nice Nature.png differ diff --git a/images/557_King Halo.png b/images/557_King Halo.png new file mode 100644 index 0000000..b04b5f8 Binary files /dev/null and b/images/557_King Halo.png differ diff --git a/images/558_Fuji Kiseki.png b/images/558_Fuji Kiseki.png new file mode 100644 index 0000000..08866ab Binary files /dev/null and b/images/558_Fuji Kiseki.png differ diff --git a/images/559_Sweep Tosho.png b/images/559_Sweep Tosho.png new file mode 100644 index 0000000..c826cd3 Binary files /dev/null and b/images/559_Sweep Tosho.png differ diff --git a/images/55_Kitasan Black.png b/images/55_Kitasan Black.png new file mode 100644 index 0000000..c9b06e1 Binary files /dev/null and b/images/55_Kitasan Black.png differ diff --git a/images/560_Twin Turbo.png b/images/560_Twin Turbo.png new file mode 100644 index 0000000..13c123a Binary files /dev/null and b/images/560_Twin Turbo.png differ diff --git a/images/561_Daitaku Helios.png b/images/561_Daitaku Helios.png new file mode 100644 index 0000000..b2b574a Binary files /dev/null and b/images/561_Daitaku Helios.png differ diff --git a/images/562_Ikuno Dictus.png b/images/562_Ikuno Dictus.png new file mode 100644 index 0000000..ae90bf5 Binary files /dev/null and b/images/562_Ikuno Dictus.png differ diff --git a/images/563_Mejiro Palmer.png b/images/563_Mejiro Palmer.png new file mode 100644 index 0000000..f6acfeb Binary files /dev/null and b/images/563_Mejiro Palmer.png differ diff --git a/images/564_Kitasan Black.png b/images/564_Kitasan Black.png new file mode 100644 index 0000000..c9b06e1 Binary files /dev/null and b/images/564_Kitasan Black.png differ diff --git a/images/565_Satono Diamond.png b/images/565_Satono Diamond.png new file mode 100644 index 0000000..aa1a7d1 Binary files /dev/null and b/images/565_Satono Diamond.png differ diff --git a/images/566_Matikanetannhauser.png b/images/566_Matikanetannhauser.png new file mode 100644 index 0000000..025a6e9 Binary files /dev/null and b/images/566_Matikanetannhauser.png differ diff --git a/images/567_Yaeno Muteki.png b/images/567_Yaeno Muteki.png new file mode 100644 index 0000000..cd9b675 Binary files /dev/null and b/images/567_Yaeno Muteki.png differ diff --git a/images/568_Zenno Rob Roy.png b/images/568_Zenno Rob Roy.png new file mode 100644 index 0000000..622991f Binary files /dev/null and b/images/568_Zenno Rob Roy.png differ diff --git a/images/569_Riko Kashimoto.png b/images/569_Riko Kashimoto.png new file mode 100644 index 0000000..aca17b3 Binary files /dev/null and b/images/569_Riko Kashimoto.png differ diff --git a/images/56_Satono Diamond.png b/images/56_Satono Diamond.png new file mode 100644 index 0000000..aa1a7d1 Binary files /dev/null and b/images/56_Satono Diamond.png differ diff --git a/images/570_Seeking the Pearl.png b/images/570_Seeking the Pearl.png new file mode 100644 index 0000000..55d4ca2 Binary files /dev/null and b/images/570_Seeking the Pearl.png differ diff --git a/images/571_Sakura Chiyono O.png b/images/571_Sakura Chiyono O.png new file mode 100644 index 0000000..61e9e2f Binary files /dev/null and b/images/571_Sakura Chiyono O.png differ diff --git a/images/572_Kawakami Princess.png b/images/572_Kawakami Princess.png new file mode 100644 index 0000000..231ddac Binary files /dev/null and b/images/572_Kawakami Princess.png differ diff --git a/images/573_Hishi Akebono.png b/images/573_Hishi Akebono.png new file mode 100644 index 0000000..7efcaab Binary files /dev/null and b/images/573_Hishi Akebono.png differ diff --git a/images/574_Bamboo Memory.png b/images/574_Bamboo Memory.png new file mode 100644 index 0000000..4c08b5c Binary files /dev/null and b/images/574_Bamboo Memory.png differ diff --git a/images/575_Shinko Windy.png b/images/575_Shinko Windy.png new file mode 100644 index 0000000..4ffbc23 Binary files /dev/null and b/images/575_Shinko Windy.png differ diff --git a/images/576_Nakayama Festa.png b/images/576_Nakayama Festa.png new file mode 100644 index 0000000..57dad5e Binary files /dev/null and b/images/576_Nakayama Festa.png differ diff --git a/images/577_Inari One.png b/images/577_Inari One.png new file mode 100644 index 0000000..95247b6 Binary files /dev/null and b/images/577_Inari One.png differ diff --git a/images/578_Mejiro Ardan.png b/images/578_Mejiro Ardan.png new file mode 100644 index 0000000..1b9f265 Binary files /dev/null and b/images/578_Mejiro Ardan.png differ diff --git a/images/579_Tosen Jordan.png b/images/579_Tosen Jordan.png new file mode 100644 index 0000000..8df3a4f Binary files /dev/null and b/images/579_Tosen Jordan.png differ diff --git a/images/57_Matikanetannhauser.png b/images/57_Matikanetannhauser.png new file mode 100644 index 0000000..025a6e9 Binary files /dev/null and b/images/57_Matikanetannhauser.png differ diff --git a/images/580_Sirius Symboli.png b/images/580_Sirius Symboli.png new file mode 100644 index 0000000..c7b4a27 Binary files /dev/null and b/images/580_Sirius Symboli.png differ diff --git a/images/581_Narita Brian.png b/images/581_Narita Brian.png new file mode 100644 index 0000000..9f46494 Binary files /dev/null and b/images/581_Narita Brian.png differ diff --git a/images/582_Curren Chan.png b/images/582_Curren Chan.png new file mode 100644 index 0000000..1ddf7a8 Binary files /dev/null and b/images/582_Curren Chan.png differ diff --git a/images/583_Sasami Anshinzawa.png b/images/583_Sasami Anshinzawa.png new file mode 100644 index 0000000..3eec325 Binary files /dev/null and b/images/583_Sasami Anshinzawa.png differ diff --git a/images/584_Admire Vega.png b/images/584_Admire Vega.png new file mode 100644 index 0000000..fd44330 Binary files /dev/null and b/images/584_Admire Vega.png differ diff --git a/images/585_Mejiro Bright.png b/images/585_Mejiro Bright.png new file mode 100644 index 0000000..5ae9e64 Binary files /dev/null and b/images/585_Mejiro Bright.png differ diff --git a/images/586_Narita Top Road.png b/images/586_Narita Top Road.png new file mode 100644 index 0000000..f8af123 Binary files /dev/null and b/images/586_Narita Top Road.png differ diff --git a/images/587_Mr. C.B..png b/images/587_Mr. C.B..png new file mode 100644 index 0000000..845498a Binary files /dev/null and b/images/587_Mr. C.B..png differ diff --git a/images/588_Daiichi Ruby.png b/images/588_Daiichi Ruby.png new file mode 100644 index 0000000..fa39755 Binary files /dev/null and b/images/588_Daiichi Ruby.png differ diff --git a/images/589_K.S.Miracle.png b/images/589_K.S.Miracle.png new file mode 100644 index 0000000..46a69f9 Binary files /dev/null and b/images/589_K.S.Miracle.png differ diff --git a/images/58_Yaeno Muteki.png b/images/58_Yaeno Muteki.png new file mode 100644 index 0000000..cd9b675 Binary files /dev/null and b/images/58_Yaeno Muteki.png differ diff --git a/images/590_Tsurumaru Tsuyoshi.png b/images/590_Tsurumaru Tsuyoshi.png new file mode 100644 index 0000000..1443e00 Binary files /dev/null and b/images/590_Tsurumaru Tsuyoshi.png differ diff --git a/images/591_Symboli Kris S.png b/images/591_Symboli Kris S.png new file mode 100644 index 0000000..2469255 Binary files /dev/null and b/images/591_Symboli Kris S.png differ diff --git a/images/592_Light Hello.png b/images/592_Light Hello.png new file mode 100644 index 0000000..fc40730 Binary files /dev/null and b/images/592_Light Hello.png differ diff --git a/images/593_Tanino Gimlet.png b/images/593_Tanino Gimlet.png new file mode 100644 index 0000000..ef76db6 Binary files /dev/null and b/images/593_Tanino Gimlet.png differ diff --git a/images/594_Sakura Laurel.png b/images/594_Sakura Laurel.png new file mode 100644 index 0000000..5ad11bc Binary files /dev/null and b/images/594_Sakura Laurel.png differ diff --git a/images/595_Yamanin Zephyr.png b/images/595_Yamanin Zephyr.png new file mode 100644 index 0000000..4796a4b Binary files /dev/null and b/images/595_Yamanin Zephyr.png differ diff --git a/images/596_Aston Machan.png b/images/596_Aston Machan.png new file mode 100644 index 0000000..480fb3b Binary files /dev/null and b/images/596_Aston Machan.png differ diff --git a/images/597_Mejiro Ramonu.png b/images/597_Mejiro Ramonu.png new file mode 100644 index 0000000..50d05e6 Binary files /dev/null and b/images/597_Mejiro Ramonu.png differ diff --git a/images/598_Jungle Pocket.png b/images/598_Jungle Pocket.png new file mode 100644 index 0000000..e056da4 Binary files /dev/null and b/images/598_Jungle Pocket.png differ diff --git a/images/599_Hokko Tarumae.png b/images/599_Hokko Tarumae.png new file mode 100644 index 0000000..11af25a Binary files /dev/null and b/images/599_Hokko Tarumae.png differ diff --git a/images/59_Zenno Rob Roy.png b/images/59_Zenno Rob Roy.png new file mode 100644 index 0000000..622991f Binary files /dev/null and b/images/59_Zenno Rob Roy.png differ diff --git a/images/5_Oguri Cap.png b/images/5_Oguri Cap.png new file mode 100644 index 0000000..6518f9c Binary files /dev/null and b/images/5_Oguri Cap.png differ diff --git a/images/600_Katsuragi Ace.png b/images/600_Katsuragi Ace.png new file mode 100644 index 0000000..0ddc4d1 Binary files /dev/null and b/images/600_Katsuragi Ace.png differ diff --git a/images/601_Copano Rickey.png b/images/601_Copano Rickey.png new file mode 100644 index 0000000..66b1f16 Binary files /dev/null and b/images/601_Copano Rickey.png differ diff --git a/images/602_Wonder Acute.png b/images/602_Wonder Acute.png new file mode 100644 index 0000000..01d7ca4 Binary files /dev/null and b/images/602_Wonder Acute.png differ diff --git a/images/603_Mei Satake.png b/images/603_Mei Satake.png new file mode 100644 index 0000000..be6b1c4 Binary files /dev/null and b/images/603_Mei Satake.png differ diff --git a/images/604_Tap Dance City.png b/images/604_Tap Dance City.png new file mode 100644 index 0000000..53c367b Binary files /dev/null and b/images/604_Tap Dance City.png differ diff --git a/images/605_Still in Love.png b/images/605_Still in Love.png new file mode 100644 index 0000000..b341686 Binary files /dev/null and b/images/605_Still in Love.png differ diff --git a/images/606_Verxina.png b/images/606_Verxina.png new file mode 100644 index 0000000..14bf46b Binary files /dev/null and b/images/606_Verxina.png differ diff --git a/images/607_Sounds of Earth.png b/images/607_Sounds of Earth.png new file mode 100644 index 0000000..5e63696 Binary files /dev/null and b/images/607_Sounds of Earth.png differ diff --git a/images/608_Vivlos.png b/images/608_Vivlos.png new file mode 100644 index 0000000..d209f0f Binary files /dev/null and b/images/608_Vivlos.png differ diff --git a/images/609_Royce and Royce.png b/images/609_Royce and Royce.png new file mode 100644 index 0000000..7349c94 Binary files /dev/null and b/images/609_Royce and Royce.png differ diff --git a/images/60_Riko Kashimoto.png b/images/60_Riko Kashimoto.png new file mode 100644 index 0000000..aca17b3 Binary files /dev/null and b/images/60_Riko Kashimoto.png differ diff --git a/images/610_Duramente.png b/images/610_Duramente.png new file mode 100644 index 0000000..cc8be96 Binary files /dev/null and b/images/610_Duramente.png differ diff --git a/images/611_North Flight.png b/images/611_North Flight.png new file mode 100644 index 0000000..9c5277d Binary files /dev/null and b/images/611_North Flight.png differ diff --git a/images/612_Orfevre.png b/images/612_Orfevre.png new file mode 100644 index 0000000..6400fdb Binary files /dev/null and b/images/612_Orfevre.png differ diff --git a/images/613_Ryoka Tsurugi.png b/images/613_Ryoka Tsurugi.png new file mode 100644 index 0000000..9de474f Binary files /dev/null and b/images/613_Ryoka Tsurugi.png differ diff --git a/images/614_Cheval Grand.png b/images/614_Cheval Grand.png new file mode 100644 index 0000000..ef8332f Binary files /dev/null and b/images/614_Cheval Grand.png differ diff --git a/images/615_Neo Universe.png b/images/615_Neo Universe.png new file mode 100644 index 0000000..db80584 Binary files /dev/null and b/images/615_Neo Universe.png differ diff --git a/images/616_Hishi Miracle.png b/images/616_Hishi Miracle.png new file mode 100644 index 0000000..3043da7 Binary files /dev/null and b/images/616_Hishi Miracle.png differ diff --git a/images/617_Dantsu Flame.png b/images/617_Dantsu Flame.png new file mode 100644 index 0000000..94f8f5b Binary files /dev/null and b/images/617_Dantsu Flame.png differ diff --git a/images/618_Yayoi Akikawa.png b/images/618_Yayoi Akikawa.png new file mode 100644 index 0000000..3ca6061 Binary files /dev/null and b/images/618_Yayoi Akikawa.png differ diff --git a/images/619_Espoir City.png b/images/619_Espoir City.png new file mode 100644 index 0000000..0f7f6ee Binary files /dev/null and b/images/619_Espoir City.png differ diff --git a/images/61_Seeking the Pearl.png b/images/61_Seeking the Pearl.png new file mode 100644 index 0000000..55d4ca2 Binary files /dev/null and b/images/61_Seeking the Pearl.png differ diff --git a/images/620_Bubble Gum Fellow.png b/images/620_Bubble Gum Fellow.png new file mode 100644 index 0000000..faffb08 Binary files /dev/null and b/images/620_Bubble Gum Fellow.png differ diff --git a/images/621_Gentildonna.png b/images/621_Gentildonna.png new file mode 100644 index 0000000..a9a937e Binary files /dev/null and b/images/621_Gentildonna.png differ diff --git a/images/622_Rhein Kraft.png b/images/622_Rhein Kraft.png new file mode 100644 index 0000000..6f9c93d Binary files /dev/null and b/images/622_Rhein Kraft.png differ diff --git a/images/623_Cesario.png b/images/623_Cesario.png new file mode 100644 index 0000000..f8f827e Binary files /dev/null and b/images/623_Cesario.png differ diff --git a/images/624_Blast Onepiece.png b/images/624_Blast Onepiece.png new file mode 100644 index 0000000..a4e6eab Binary files /dev/null and b/images/624_Blast Onepiece.png differ diff --git a/images/625_No Reason.png b/images/625_No Reason.png new file mode 100644 index 0000000..0fad8dc Binary files /dev/null and b/images/625_No Reason.png differ diff --git a/images/626_Buena Vista.png b/images/626_Buena Vista.png new file mode 100644 index 0000000..22dbbfa Binary files /dev/null and b/images/626_Buena Vista.png differ diff --git a/images/627_Dream Journey.png b/images/627_Dream Journey.png new file mode 100644 index 0000000..7cb8d6f Binary files /dev/null and b/images/627_Dream Journey.png differ diff --git a/images/628_Daring Tact.png b/images/628_Daring Tact.png new file mode 100644 index 0000000..c9c32ba Binary files /dev/null and b/images/628_Daring Tact.png differ diff --git a/images/629_Daring Heart.png b/images/629_Daring Heart.png new file mode 100644 index 0000000..b7ffc71 Binary files /dev/null and b/images/629_Daring Heart.png differ diff --git a/images/62_Sakura Chiyono O.png b/images/62_Sakura Chiyono O.png new file mode 100644 index 0000000..61e9e2f Binary files /dev/null and b/images/62_Sakura Chiyono O.png differ diff --git a/images/630_Almond Eye.png b/images/630_Almond Eye.png new file mode 100644 index 0000000..b2c67a2 Binary files /dev/null and b/images/630_Almond Eye.png differ diff --git a/images/631_Lucky Lilac.png b/images/631_Lucky Lilac.png new file mode 100644 index 0000000..71a44d0 Binary files /dev/null and b/images/631_Lucky Lilac.png differ diff --git a/images/632_Gran Alegria.png b/images/632_Gran Alegria.png new file mode 100644 index 0000000..132de05 Binary files /dev/null and b/images/632_Gran Alegria.png differ diff --git a/images/633_Transcend.png b/images/633_Transcend.png new file mode 100644 index 0000000..c8b9414 Binary files /dev/null and b/images/633_Transcend.png differ diff --git a/images/634_Curren Bouquetd'or.png b/images/634_Curren Bouquetd'or.png new file mode 100644 index 0000000..232c7b1 Binary files /dev/null and b/images/634_Curren Bouquetd'or.png differ diff --git a/images/635_Air Messiah.png b/images/635_Air Messiah.png new file mode 100644 index 0000000..e3deed3 Binary files /dev/null and b/images/635_Air Messiah.png differ diff --git a/images/636_Tucker Bryne.png b/images/636_Tucker Bryne.png new file mode 100644 index 0000000..56cb1f7 Binary files /dev/null and b/images/636_Tucker Bryne.png differ diff --git a/images/637_Fusaichi Pandora.png b/images/637_Fusaichi Pandora.png new file mode 100644 index 0000000..2a97f3b Binary files /dev/null and b/images/637_Fusaichi Pandora.png differ diff --git a/images/638_Win Variation.png b/images/638_Win Variation.png new file mode 100644 index 0000000..22cbe5a Binary files /dev/null and b/images/638_Win Variation.png differ diff --git a/images/639_Stay Gold.png b/images/639_Stay Gold.png new file mode 100644 index 0000000..b915fb9 Binary files /dev/null and b/images/639_Stay Gold.png differ diff --git a/images/63_Kawakami Princess.png b/images/63_Kawakami Princess.png new file mode 100644 index 0000000..231ddac Binary files /dev/null and b/images/63_Kawakami Princess.png differ diff --git a/images/640_Admire Groove.png b/images/640_Admire Groove.png new file mode 100644 index 0000000..ca047f6 Binary files /dev/null and b/images/640_Admire Groove.png differ diff --git a/images/641_Chrono Genesis.png b/images/641_Chrono Genesis.png new file mode 100644 index 0000000..00d3dfc Binary files /dev/null and b/images/641_Chrono Genesis.png differ diff --git a/images/642_Calstone Light O.png b/images/642_Calstone Light O.png new file mode 100644 index 0000000..8d2889c Binary files /dev/null and b/images/642_Calstone Light O.png differ diff --git a/images/643_Durandal.png b/images/643_Durandal.png new file mode 100644 index 0000000..880fe53 Binary files /dev/null and b/images/643_Durandal.png differ diff --git a/images/644_Sakura Chitose O.png b/images/644_Sakura Chitose O.png new file mode 100644 index 0000000..f0a0e2c Binary files /dev/null and b/images/644_Sakura Chitose O.png differ diff --git a/images/645_Kiyoko Hoshina.png b/images/645_Kiyoko Hoshina.png new file mode 100644 index 0000000..b45ae5e Binary files /dev/null and b/images/645_Kiyoko Hoshina.png differ diff --git a/images/646_Fenomeno.png b/images/646_Fenomeno.png new file mode 100644 index 0000000..7ceacf8 Binary files /dev/null and b/images/646_Fenomeno.png differ diff --git a/images/647_Fuji Kiseki.png b/images/647_Fuji Kiseki.png new file mode 100644 index 0000000..f49efa3 Binary files /dev/null and b/images/647_Fuji Kiseki.png differ diff --git a/images/648_Daiwa Scarlet.png b/images/648_Daiwa Scarlet.png new file mode 100644 index 0000000..6fd5a71 Binary files /dev/null and b/images/648_Daiwa Scarlet.png differ diff --git a/images/649_Hishi Amazon.png b/images/649_Hishi Amazon.png new file mode 100644 index 0000000..c8d3863 Binary files /dev/null and b/images/649_Hishi Amazon.png differ diff --git a/images/64_Hishi Akebono.png b/images/64_Hishi Akebono.png new file mode 100644 index 0000000..7efcaab Binary files /dev/null and b/images/64_Hishi Akebono.png differ diff --git a/images/650_Air Groove.png b/images/650_Air Groove.png new file mode 100644 index 0000000..0bbee00 Binary files /dev/null and b/images/650_Air Groove.png differ diff --git a/images/651_Agnes Digital.png b/images/651_Agnes Digital.png new file mode 100644 index 0000000..975ef83 Binary files /dev/null and b/images/651_Agnes Digital.png differ diff --git a/images/652_Biwa Hayahide.png b/images/652_Biwa Hayahide.png new file mode 100644 index 0000000..721324a Binary files /dev/null and b/images/652_Biwa Hayahide.png differ diff --git a/images/653_Mayano Top Gun.png b/images/653_Mayano Top Gun.png new file mode 100644 index 0000000..4d11ceb Binary files /dev/null and b/images/653_Mayano Top Gun.png differ diff --git a/images/654_Manhattan Cafe.png b/images/654_Manhattan Cafe.png new file mode 100644 index 0000000..fea8bb6 Binary files /dev/null and b/images/654_Manhattan Cafe.png differ diff --git a/images/655_Mihono Bourbon.png b/images/655_Mihono Bourbon.png new file mode 100644 index 0000000..7dc5720 Binary files /dev/null and b/images/655_Mihono Bourbon.png differ diff --git a/images/656_Mejiro Ryan.png b/images/656_Mejiro Ryan.png new file mode 100644 index 0000000..6ae179b Binary files /dev/null and b/images/656_Mejiro Ryan.png differ diff --git a/images/657_Yukino Bijin.png b/images/657_Yukino Bijin.png new file mode 100644 index 0000000..bd099ae Binary files /dev/null and b/images/657_Yukino Bijin.png differ diff --git a/images/658_Agnes Tachyon.png b/images/658_Agnes Tachyon.png new file mode 100644 index 0000000..1868d13 Binary files /dev/null and b/images/658_Agnes Tachyon.png differ diff --git a/images/659_Eishin Flash.png b/images/659_Eishin Flash.png new file mode 100644 index 0000000..e54398c Binary files /dev/null and b/images/659_Eishin Flash.png differ diff --git a/images/65_Bamboo Memory.png b/images/65_Bamboo Memory.png new file mode 100644 index 0000000..4c08b5c Binary files /dev/null and b/images/65_Bamboo Memory.png differ diff --git a/images/660_Narita Taishin.png b/images/660_Narita Taishin.png new file mode 100644 index 0000000..bc965cc Binary files /dev/null and b/images/660_Narita Taishin.png differ diff --git a/images/661_Marvelous Sunday.png b/images/661_Marvelous Sunday.png new file mode 100644 index 0000000..fbe41b5 Binary files /dev/null and b/images/661_Marvelous Sunday.png differ diff --git a/images/662_Matikanefukukitaru.png b/images/662_Matikanefukukitaru.png new file mode 100644 index 0000000..e29ac31 Binary files /dev/null and b/images/662_Matikanefukukitaru.png differ diff --git a/images/663_Meisho Doto.png b/images/663_Meisho Doto.png new file mode 100644 index 0000000..0264e80 Binary files /dev/null and b/images/663_Meisho Doto.png differ diff --git a/images/664_Mejiro Dober.png b/images/664_Mejiro Dober.png new file mode 100644 index 0000000..05b5bc4 Binary files /dev/null and b/images/664_Mejiro Dober.png differ diff --git a/images/665_Nice Nature.png b/images/665_Nice Nature.png new file mode 100644 index 0000000..1a85d82 Binary files /dev/null and b/images/665_Nice Nature.png differ diff --git a/images/666_King Halo.png b/images/666_King Halo.png new file mode 100644 index 0000000..5f0ddf5 Binary files /dev/null and b/images/666_King Halo.png differ diff --git a/images/667_Aoi Kiryuin.png b/images/667_Aoi Kiryuin.png new file mode 100644 index 0000000..e2c12cd Binary files /dev/null and b/images/667_Aoi Kiryuin.png differ diff --git a/images/668_Tamamo Cross.png b/images/668_Tamamo Cross.png new file mode 100644 index 0000000..31fa49c Binary files /dev/null and b/images/668_Tamamo Cross.png differ diff --git a/images/669_Sweep Tosho.png b/images/669_Sweep Tosho.png new file mode 100644 index 0000000..d4e0680 Binary files /dev/null and b/images/669_Sweep Tosho.png differ diff --git a/images/66_Shinko Windy.png b/images/66_Shinko Windy.png new file mode 100644 index 0000000..4ffbc23 Binary files /dev/null and b/images/66_Shinko Windy.png differ diff --git a/images/670_Daitaku Helios.png b/images/670_Daitaku Helios.png new file mode 100644 index 0000000..5d3cfdf Binary files /dev/null and b/images/670_Daitaku Helios.png differ diff --git a/images/671_Ikuno Dictus.png b/images/671_Ikuno Dictus.png new file mode 100644 index 0000000..004d835 Binary files /dev/null and b/images/671_Ikuno Dictus.png differ diff --git a/images/672_Nice Nature.png b/images/672_Nice Nature.png new file mode 100644 index 0000000..ed7b605 Binary files /dev/null and b/images/672_Nice Nature.png differ diff --git a/images/673_Nishino Flower.png b/images/673_Nishino Flower.png new file mode 100644 index 0000000..d0cb28d Binary files /dev/null and b/images/673_Nishino Flower.png differ diff --git a/images/674_Zenno Rob Roy.png b/images/674_Zenno Rob Roy.png new file mode 100644 index 0000000..1a11c93 Binary files /dev/null and b/images/674_Zenno Rob Roy.png differ diff --git a/images/675_Seeking the Pearl.png b/images/675_Seeking the Pearl.png new file mode 100644 index 0000000..114e67c Binary files /dev/null and b/images/675_Seeking the Pearl.png differ diff --git a/images/676_Ines Fujin.png b/images/676_Ines Fujin.png new file mode 100644 index 0000000..d82f00b Binary files /dev/null and b/images/676_Ines Fujin.png differ diff --git a/images/677_Shinko Windy.png b/images/677_Shinko Windy.png new file mode 100644 index 0000000..99601ef Binary files /dev/null and b/images/677_Shinko Windy.png differ diff --git a/images/678_Inari One.png b/images/678_Inari One.png new file mode 100644 index 0000000..d89bfb2 Binary files /dev/null and b/images/678_Inari One.png differ diff --git a/images/679_El Condor Pasa.png b/images/679_El Condor Pasa.png new file mode 100644 index 0000000..3f2e2ac Binary files /dev/null and b/images/679_El Condor Pasa.png differ diff --git a/images/67_Nakayama Festa.png b/images/67_Nakayama Festa.png new file mode 100644 index 0000000..57dad5e Binary files /dev/null and b/images/67_Nakayama Festa.png differ diff --git a/images/680_Mejiro Ardan.png b/images/680_Mejiro Ardan.png new file mode 100644 index 0000000..df5678d Binary files /dev/null and b/images/680_Mejiro Ardan.png differ diff --git a/images/681_Tosen Jordan.png b/images/681_Tosen Jordan.png new file mode 100644 index 0000000..617e0ed Binary files /dev/null and b/images/681_Tosen Jordan.png differ diff --git a/images/682_Mejiro Palmer.png b/images/682_Mejiro Palmer.png new file mode 100644 index 0000000..4cb5dfe Binary files /dev/null and b/images/682_Mejiro Palmer.png differ diff --git a/images/683_Fine Motion.png b/images/683_Fine Motion.png new file mode 100644 index 0000000..1df4908 Binary files /dev/null and b/images/683_Fine Motion.png differ diff --git a/images/684_Sirius Symboli.png b/images/684_Sirius Symboli.png new file mode 100644 index 0000000..a442dcd Binary files /dev/null and b/images/684_Sirius Symboli.png differ diff --git a/images/685_Vodka.png b/images/685_Vodka.png new file mode 100644 index 0000000..304d0cd Binary files /dev/null and b/images/685_Vodka.png differ diff --git a/images/686_Mejiro Ryan.png b/images/686_Mejiro Ryan.png new file mode 100644 index 0000000..65d3ac3 Binary files /dev/null and b/images/686_Mejiro Ryan.png differ diff --git a/images/687_Admire Vega.png b/images/687_Admire Vega.png new file mode 100644 index 0000000..fe1345f Binary files /dev/null and b/images/687_Admire Vega.png differ diff --git a/images/688_Sakura Bakushin O.png b/images/688_Sakura Bakushin O.png new file mode 100644 index 0000000..2a87e59 Binary files /dev/null and b/images/688_Sakura Bakushin O.png differ diff --git a/images/689_Special Week.png b/images/689_Special Week.png new file mode 100644 index 0000000..ce55e65 Binary files /dev/null and b/images/689_Special Week.png differ diff --git a/images/68_Inari One.png b/images/68_Inari One.png new file mode 100644 index 0000000..95247b6 Binary files /dev/null and b/images/68_Inari One.png differ diff --git a/images/690_Curren Chan.png b/images/690_Curren Chan.png new file mode 100644 index 0000000..fd0c725 Binary files /dev/null and b/images/690_Curren Chan.png differ diff --git a/images/691_Smart Falcon.png b/images/691_Smart Falcon.png new file mode 100644 index 0000000..3bdb189 Binary files /dev/null and b/images/691_Smart Falcon.png differ diff --git a/images/692_Sweep Tosho.png b/images/692_Sweep Tosho.png new file mode 100644 index 0000000..11aa56d Binary files /dev/null and b/images/692_Sweep Tosho.png differ diff --git a/images/693_Tokai Teio.png b/images/693_Tokai Teio.png new file mode 100644 index 0000000..d340861 Binary files /dev/null and b/images/693_Tokai Teio.png differ diff --git a/images/694_Oguri Cap.png b/images/694_Oguri Cap.png new file mode 100644 index 0000000..a74d619 Binary files /dev/null and b/images/694_Oguri Cap.png differ diff --git a/images/695_Gold City.png b/images/695_Gold City.png new file mode 100644 index 0000000..35c9eae Binary files /dev/null and b/images/695_Gold City.png differ diff --git a/images/696_Seiun Sky.png b/images/696_Seiun Sky.png new file mode 100644 index 0000000..b4935d0 Binary files /dev/null and b/images/696_Seiun Sky.png differ diff --git a/images/697_K.S.Miracle.png b/images/697_K.S.Miracle.png new file mode 100644 index 0000000..6453236 Binary files /dev/null and b/images/697_K.S.Miracle.png differ diff --git a/images/698_Tsurumaru Tsuyoshi.png b/images/698_Tsurumaru Tsuyoshi.png new file mode 100644 index 0000000..323f1b6 Binary files /dev/null and b/images/698_Tsurumaru Tsuyoshi.png differ diff --git a/images/699_Narita Top Road.png b/images/699_Narita Top Road.png new file mode 100644 index 0000000..91b3da8 Binary files /dev/null and b/images/699_Narita Top Road.png differ diff --git a/images/69_Mejiro Ardan.png b/images/69_Mejiro Ardan.png new file mode 100644 index 0000000..1b9f265 Binary files /dev/null and b/images/69_Mejiro Ardan.png differ diff --git a/images/6_Gold Ship.png b/images/6_Gold Ship.png new file mode 100644 index 0000000..02611f9 Binary files /dev/null and b/images/6_Gold Ship.png differ diff --git a/images/700_TM Opera O.png b/images/700_TM Opera O.png new file mode 100644 index 0000000..1eb8800 Binary files /dev/null and b/images/700_TM Opera O.png differ diff --git a/images/701_Aston Machan.png b/images/701_Aston Machan.png new file mode 100644 index 0000000..2b2e82d Binary files /dev/null and b/images/701_Aston Machan.png differ diff --git a/images/702_Jungle Pocket.png b/images/702_Jungle Pocket.png new file mode 100644 index 0000000..b231f00 Binary files /dev/null and b/images/702_Jungle Pocket.png differ diff --git a/images/703_Mejiro Dober.png b/images/703_Mejiro Dober.png new file mode 100644 index 0000000..9a1b003 Binary files /dev/null and b/images/703_Mejiro Dober.png differ diff --git a/images/704_Symboli Rudolf.png b/images/704_Symboli Rudolf.png new file mode 100644 index 0000000..473179d Binary files /dev/null and b/images/704_Symboli Rudolf.png differ diff --git a/images/705_Agnes Tachyon.png b/images/705_Agnes Tachyon.png new file mode 100644 index 0000000..2addadd Binary files /dev/null and b/images/705_Agnes Tachyon.png differ diff --git a/images/706_Hishi Akebono.png b/images/706_Hishi Akebono.png new file mode 100644 index 0000000..b4277fd Binary files /dev/null and b/images/706_Hishi Akebono.png differ diff --git a/images/707_Gold Ship.png b/images/707_Gold Ship.png new file mode 100644 index 0000000..56bd06a Binary files /dev/null and b/images/707_Gold Ship.png differ diff --git a/images/708_Maruzensky.png b/images/708_Maruzensky.png new file mode 100644 index 0000000..c55a3cb Binary files /dev/null and b/images/708_Maruzensky.png differ diff --git a/images/709_Silence Suzuka.png b/images/709_Silence Suzuka.png new file mode 100644 index 0000000..eb3e46f Binary files /dev/null and b/images/709_Silence Suzuka.png differ diff --git a/images/70_Tosen Jordan.png b/images/70_Tosen Jordan.png new file mode 100644 index 0000000..8df3a4f Binary files /dev/null and b/images/70_Tosen Jordan.png differ diff --git a/images/710_Copano Rickey.png b/images/710_Copano Rickey.png new file mode 100644 index 0000000..a8206c9 Binary files /dev/null and b/images/710_Copano Rickey.png differ diff --git a/images/711_Grass Wonder.png b/images/711_Grass Wonder.png new file mode 100644 index 0000000..35e2b61 Binary files /dev/null and b/images/711_Grass Wonder.png differ diff --git a/images/712_Kitasan Black.png b/images/712_Kitasan Black.png new file mode 100644 index 0000000..57dfd16 Binary files /dev/null and b/images/712_Kitasan Black.png differ diff --git a/images/713_Taiki Shuttle.png b/images/713_Taiki Shuttle.png new file mode 100644 index 0000000..1b03ad5 Binary files /dev/null and b/images/713_Taiki Shuttle.png differ diff --git a/images/714_Nice Nature.png b/images/714_Nice Nature.png new file mode 100644 index 0000000..c46ee39 Binary files /dev/null and b/images/714_Nice Nature.png differ diff --git a/images/715_Matikanetannhauser.png b/images/715_Matikanetannhauser.png new file mode 100644 index 0000000..cfa6312 Binary files /dev/null and b/images/715_Matikanetannhauser.png differ diff --git a/images/716_Verxina.png b/images/716_Verxina.png new file mode 100644 index 0000000..c4ce1db Binary files /dev/null and b/images/716_Verxina.png differ diff --git a/images/717_Royce and Royce.png b/images/717_Royce and Royce.png new file mode 100644 index 0000000..0bf7803 Binary files /dev/null and b/images/717_Royce and Royce.png differ diff --git a/images/718_Tanino Gimlet.png b/images/718_Tanino Gimlet.png new file mode 100644 index 0000000..e6a9b44 Binary files /dev/null and b/images/718_Tanino Gimlet.png differ diff --git a/images/719_Tosen Jordan.png b/images/719_Tosen Jordan.png new file mode 100644 index 0000000..c70a091 Binary files /dev/null and b/images/719_Tosen Jordan.png differ diff --git a/images/71_Sirius Symboli.png b/images/71_Sirius Symboli.png new file mode 100644 index 0000000..c7b4a27 Binary files /dev/null and b/images/71_Sirius Symboli.png differ diff --git a/images/720_Yaeno Muteki.png b/images/720_Yaeno Muteki.png new file mode 100644 index 0000000..dcf70aa Binary files /dev/null and b/images/720_Yaeno Muteki.png differ diff --git a/images/721_Tap Dance City.png b/images/721_Tap Dance City.png new file mode 100644 index 0000000..416e225 Binary files /dev/null and b/images/721_Tap Dance City.png differ diff --git a/images/722_Air Shakur.png b/images/722_Air Shakur.png new file mode 100644 index 0000000..d699c83 Binary files /dev/null and b/images/722_Air Shakur.png differ diff --git a/images/723_Dantsu Flame.png b/images/723_Dantsu Flame.png new file mode 100644 index 0000000..fc4a372 Binary files /dev/null and b/images/723_Dantsu Flame.png differ diff --git a/images/724_Matikanefukukitaru.png b/images/724_Matikanefukukitaru.png new file mode 100644 index 0000000..77a659f Binary files /dev/null and b/images/724_Matikanefukukitaru.png differ diff --git a/images/725_Marvelous Sunday.png b/images/725_Marvelous Sunday.png new file mode 100644 index 0000000..a0a994d Binary files /dev/null and b/images/725_Marvelous Sunday.png differ diff --git a/images/726_Sakura Laurel.png b/images/726_Sakura Laurel.png new file mode 100644 index 0000000..bdbb7ad Binary files /dev/null and b/images/726_Sakura Laurel.png differ diff --git a/images/727_North Flight.png b/images/727_North Flight.png new file mode 100644 index 0000000..5e3f1c9 Binary files /dev/null and b/images/727_North Flight.png differ diff --git a/images/728_Bubble Gum Fellow.png b/images/728_Bubble Gum Fellow.png new file mode 100644 index 0000000..8ba6567 Binary files /dev/null and b/images/728_Bubble Gum Fellow.png differ diff --git a/images/729_Mejiro Ramonu.png b/images/729_Mejiro Ramonu.png new file mode 100644 index 0000000..1541f5f Binary files /dev/null and b/images/729_Mejiro Ramonu.png differ diff --git a/images/72_Narita Brian.png b/images/72_Narita Brian.png new file mode 100644 index 0000000..9f46494 Binary files /dev/null and b/images/72_Narita Brian.png differ diff --git a/images/730_Lucky Lilac.png b/images/730_Lucky Lilac.png new file mode 100644 index 0000000..288a269 Binary files /dev/null and b/images/730_Lucky Lilac.png differ diff --git a/images/731_Mejiro McQueen.png b/images/731_Mejiro McQueen.png new file mode 100644 index 0000000..98f3e24 Binary files /dev/null and b/images/731_Mejiro McQueen.png differ diff --git a/images/732_Rice Shower.png b/images/732_Rice Shower.png new file mode 100644 index 0000000..5db4c3d Binary files /dev/null and b/images/732_Rice Shower.png differ diff --git a/images/733_Daring Heart.png b/images/733_Daring Heart.png new file mode 100644 index 0000000..474b0e3 Binary files /dev/null and b/images/733_Daring Heart.png differ diff --git a/images/734_Curren Bouquetd'or.png b/images/734_Curren Bouquetd'or.png new file mode 100644 index 0000000..7a2a387 Binary files /dev/null and b/images/734_Curren Bouquetd'or.png differ diff --git a/images/735_Kawakami Princess.png b/images/735_Kawakami Princess.png new file mode 100644 index 0000000..42494a4 Binary files /dev/null and b/images/735_Kawakami Princess.png differ diff --git a/images/736_Biko Pegasus.png b/images/736_Biko Pegasus.png new file mode 100644 index 0000000..d8b191c Binary files /dev/null and b/images/736_Biko Pegasus.png differ diff --git a/images/737_Sakura Chitose O.png b/images/737_Sakura Chitose O.png new file mode 100644 index 0000000..f07d472 Binary files /dev/null and b/images/737_Sakura Chitose O.png differ diff --git a/images/738_Hokko Tarumae.png b/images/738_Hokko Tarumae.png new file mode 100644 index 0000000..db4590d Binary files /dev/null and b/images/738_Hokko Tarumae.png differ diff --git a/images/739_Mejiro Dober.png b/images/739_Mejiro Dober.png new file mode 100644 index 0000000..afff1f9 Binary files /dev/null and b/images/739_Mejiro Dober.png differ diff --git a/images/73_Curren Chan.png b/images/73_Curren Chan.png new file mode 100644 index 0000000..1ddf7a8 Binary files /dev/null and b/images/73_Curren Chan.png differ diff --git a/images/740_Special Week.png b/images/740_Special Week.png new file mode 100644 index 0000000..d930b71 Binary files /dev/null and b/images/740_Special Week.png differ diff --git a/images/741_Silence Suzuka.png b/images/741_Silence Suzuka.png new file mode 100644 index 0000000..81735fb Binary files /dev/null and b/images/741_Silence Suzuka.png differ diff --git a/images/742_Tokai Teio.png b/images/742_Tokai Teio.png new file mode 100644 index 0000000..fa976b1 Binary files /dev/null and b/images/742_Tokai Teio.png differ diff --git a/images/743_Gold Ship.png b/images/743_Gold Ship.png new file mode 100644 index 0000000..23ec7e5 Binary files /dev/null and b/images/743_Gold Ship.png differ diff --git a/images/744_Vodka.png b/images/744_Vodka.png new file mode 100644 index 0000000..ecb37c8 Binary files /dev/null and b/images/744_Vodka.png differ diff --git a/images/745_Grass Wonder.png b/images/745_Grass Wonder.png new file mode 100644 index 0000000..4f1bdd3 Binary files /dev/null and b/images/745_Grass Wonder.png differ diff --git a/images/746_El Condor Pasa.png b/images/746_El Condor Pasa.png new file mode 100644 index 0000000..160d3fe Binary files /dev/null and b/images/746_El Condor Pasa.png differ diff --git a/images/747_Seiun Sky.png b/images/747_Seiun Sky.png new file mode 100644 index 0000000..291c0cf Binary files /dev/null and b/images/747_Seiun Sky.png differ diff --git a/images/748_Tamamo Cross.png b/images/748_Tamamo Cross.png new file mode 100644 index 0000000..b7f8ce9 Binary files /dev/null and b/images/748_Tamamo Cross.png differ diff --git a/images/749_Fine Motion.png b/images/749_Fine Motion.png new file mode 100644 index 0000000..5433a0a Binary files /dev/null and b/images/749_Fine Motion.png differ diff --git a/images/74_Sasami Anshinzawa.png b/images/74_Sasami Anshinzawa.png new file mode 100644 index 0000000..3eec325 Binary files /dev/null and b/images/74_Sasami Anshinzawa.png differ diff --git a/images/750_Ines Fujin.png b/images/750_Ines Fujin.png new file mode 100644 index 0000000..d9f3f5a Binary files /dev/null and b/images/750_Ines Fujin.png differ diff --git a/images/751_Winning Ticket.png b/images/751_Winning Ticket.png new file mode 100644 index 0000000..78fbf80 Binary files /dev/null and b/images/751_Winning Ticket.png differ diff --git a/images/752_Air Shakur.png b/images/752_Air Shakur.png new file mode 100644 index 0000000..5fa175c Binary files /dev/null and b/images/752_Air Shakur.png differ diff --git a/images/753_Gold City.png b/images/753_Gold City.png new file mode 100644 index 0000000..9c050b2 Binary files /dev/null and b/images/753_Gold City.png differ diff --git a/images/754_Sakura Bakushin O.png b/images/754_Sakura Bakushin O.png new file mode 100644 index 0000000..46bd80d Binary files /dev/null and b/images/754_Sakura Bakushin O.png differ diff --git a/images/755_Super Creek.png b/images/755_Super Creek.png new file mode 100644 index 0000000..044ac81 Binary files /dev/null and b/images/755_Super Creek.png differ diff --git a/images/756_Smart Falcon.png b/images/756_Smart Falcon.png new file mode 100644 index 0000000..9534f32 Binary files /dev/null and b/images/756_Smart Falcon.png differ diff --git a/images/757_Nishino Flower.png b/images/757_Nishino Flower.png new file mode 100644 index 0000000..44289aa Binary files /dev/null and b/images/757_Nishino Flower.png differ diff --git a/images/758_Haru Urara.png b/images/758_Haru Urara.png new file mode 100644 index 0000000..409e8e5 Binary files /dev/null and b/images/758_Haru Urara.png differ diff --git a/images/759_Biko Pegasus.png b/images/759_Biko Pegasus.png new file mode 100644 index 0000000..f6afc0f Binary files /dev/null and b/images/759_Biko Pegasus.png differ diff --git a/images/75_Admire Vega.png b/images/75_Admire Vega.png new file mode 100644 index 0000000..fd44330 Binary files /dev/null and b/images/75_Admire Vega.png differ diff --git a/images/760_Tazuna Hayakawa.png b/images/760_Tazuna Hayakawa.png new file mode 100644 index 0000000..989eb7b Binary files /dev/null and b/images/760_Tazuna Hayakawa.png differ diff --git a/images/761_Mejiro McQueen.png b/images/761_Mejiro McQueen.png new file mode 100644 index 0000000..f54da81 Binary files /dev/null and b/images/761_Mejiro McQueen.png differ diff --git a/images/762_Rice Shower.png b/images/762_Rice Shower.png new file mode 100644 index 0000000..bfebc32 Binary files /dev/null and b/images/762_Rice Shower.png differ diff --git a/images/763_Oguri Cap.png b/images/763_Oguri Cap.png new file mode 100644 index 0000000..fd58980 Binary files /dev/null and b/images/763_Oguri Cap.png differ diff --git a/images/764_Special Week.png b/images/764_Special Week.png new file mode 100644 index 0000000..eecc8a1 Binary files /dev/null and b/images/764_Special Week.png differ diff --git a/images/765_Twin Turbo.png b/images/765_Twin Turbo.png new file mode 100644 index 0000000..f712373 Binary files /dev/null and b/images/765_Twin Turbo.png differ diff --git a/images/766_Mejiro Palmer.png b/images/766_Mejiro Palmer.png new file mode 100644 index 0000000..69cb1c4 Binary files /dev/null and b/images/766_Mejiro Palmer.png differ diff --git a/images/767_Kitasan Black.png b/images/767_Kitasan Black.png new file mode 100644 index 0000000..2297ea4 Binary files /dev/null and b/images/767_Kitasan Black.png differ diff --git a/images/768_Satono Diamond.png b/images/768_Satono Diamond.png new file mode 100644 index 0000000..a75cb74 Binary files /dev/null and b/images/768_Satono Diamond.png differ diff --git a/images/769_Matikanetannhauser.png b/images/769_Matikanetannhauser.png new file mode 100644 index 0000000..6979056 Binary files /dev/null and b/images/769_Matikanetannhauser.png differ diff --git a/images/76_Mejiro Bright.png b/images/76_Mejiro Bright.png new file mode 100644 index 0000000..5ae9e64 Binary files /dev/null and b/images/76_Mejiro Bright.png differ diff --git a/images/770_Yukino Bijin.png b/images/770_Yukino Bijin.png new file mode 100644 index 0000000..c130da9 Binary files /dev/null and b/images/770_Yukino Bijin.png differ diff --git a/images/771_Yaeno Muteki.png b/images/771_Yaeno Muteki.png new file mode 100644 index 0000000..7cbab4d Binary files /dev/null and b/images/771_Yaeno Muteki.png differ diff --git a/images/772_Winning Ticket.png b/images/772_Winning Ticket.png new file mode 100644 index 0000000..cdb7c98 Binary files /dev/null and b/images/772_Winning Ticket.png differ diff --git a/images/773_Rice Shower.png b/images/773_Rice Shower.png new file mode 100644 index 0000000..e9d37c9 Binary files /dev/null and b/images/773_Rice Shower.png differ diff --git a/images/774_Riko Kashimoto.png b/images/774_Riko Kashimoto.png new file mode 100644 index 0000000..3abbfb8 Binary files /dev/null and b/images/774_Riko Kashimoto.png differ diff --git a/images/775_Symboli Rudolf.png b/images/775_Symboli Rudolf.png new file mode 100644 index 0000000..8a85880 Binary files /dev/null and b/images/775_Symboli Rudolf.png differ diff --git a/images/776_Sakura Chiyono O.png b/images/776_Sakura Chiyono O.png new file mode 100644 index 0000000..140709a Binary files /dev/null and b/images/776_Sakura Chiyono O.png differ diff --git a/images/777_Kawakami Princess.png b/images/777_Kawakami Princess.png new file mode 100644 index 0000000..dc55627 Binary files /dev/null and b/images/777_Kawakami Princess.png differ diff --git a/images/778_Hishi Akebono.png b/images/778_Hishi Akebono.png new file mode 100644 index 0000000..9e95ede Binary files /dev/null and b/images/778_Hishi Akebono.png differ diff --git a/images/779_Mejiro Dober.png b/images/779_Mejiro Dober.png new file mode 100644 index 0000000..f9658cb Binary files /dev/null and b/images/779_Mejiro Dober.png differ diff --git a/images/77_Narita Top Road.png b/images/77_Narita Top Road.png new file mode 100644 index 0000000..f8af123 Binary files /dev/null and b/images/77_Narita Top Road.png differ diff --git a/images/780_Bamboo Memory.png b/images/780_Bamboo Memory.png new file mode 100644 index 0000000..c4e41bc Binary files /dev/null and b/images/780_Bamboo Memory.png differ diff --git a/images/781_Nakayama Festa.png b/images/781_Nakayama Festa.png new file mode 100644 index 0000000..a5a5c45 Binary files /dev/null and b/images/781_Nakayama Festa.png differ diff --git a/images/782_Narita Brian.png b/images/782_Narita Brian.png new file mode 100644 index 0000000..55dc919 Binary files /dev/null and b/images/782_Narita Brian.png differ diff --git a/images/783_Sweep Tosho.png b/images/783_Sweep Tosho.png new file mode 100644 index 0000000..6a197b9 Binary files /dev/null and b/images/783_Sweep Tosho.png differ diff --git a/images/784_Winning Ticket.png b/images/784_Winning Ticket.png new file mode 100644 index 0000000..7486f90 Binary files /dev/null and b/images/784_Winning Ticket.png differ diff --git a/images/785_Daiwa Scarlet.png b/images/785_Daiwa Scarlet.png new file mode 100644 index 0000000..073415f Binary files /dev/null and b/images/785_Daiwa Scarlet.png differ diff --git a/images/786_Mejiro Ryan.png b/images/786_Mejiro Ryan.png new file mode 100644 index 0000000..77964e4 Binary files /dev/null and b/images/786_Mejiro Ryan.png differ diff --git a/images/787_Light Hello.png b/images/787_Light Hello.png new file mode 100644 index 0000000..c6e700b Binary files /dev/null and b/images/787_Light Hello.png differ diff --git a/images/788_Taiki Shuttle.png b/images/788_Taiki Shuttle.png new file mode 100644 index 0000000..8e3cd30 Binary files /dev/null and b/images/788_Taiki Shuttle.png differ diff --git a/images/789_Nice Nature.png b/images/789_Nice Nature.png new file mode 100644 index 0000000..4675b8e Binary files /dev/null and b/images/789_Nice Nature.png differ diff --git a/images/78_Mr. C.B..png b/images/78_Mr. C.B..png new file mode 100644 index 0000000..845498a Binary files /dev/null and b/images/78_Mr. C.B..png differ diff --git a/images/790_Seiun Sky.png b/images/790_Seiun Sky.png new file mode 100644 index 0000000..c31b5d0 Binary files /dev/null and b/images/790_Seiun Sky.png differ diff --git a/images/791_King Halo.png b/images/791_King Halo.png new file mode 100644 index 0000000..b4b4253 Binary files /dev/null and b/images/791_King Halo.png differ diff --git a/images/792_Gold Ship.png b/images/792_Gold Ship.png new file mode 100644 index 0000000..f115641 Binary files /dev/null and b/images/792_Gold Ship.png differ diff --git a/images/793_Tokai Teio.png b/images/793_Tokai Teio.png new file mode 100644 index 0000000..428aec0 Binary files /dev/null and b/images/793_Tokai Teio.png differ diff --git a/images/794_Mihono Bourbon.png b/images/794_Mihono Bourbon.png new file mode 100644 index 0000000..b587e70 Binary files /dev/null and b/images/794_Mihono Bourbon.png differ diff --git a/images/795_Twin Turbo.png b/images/795_Twin Turbo.png new file mode 100644 index 0000000..e059b44 Binary files /dev/null and b/images/795_Twin Turbo.png differ diff --git a/images/796_Biwa Hayahide.png b/images/796_Biwa Hayahide.png new file mode 100644 index 0000000..8816fbf Binary files /dev/null and b/images/796_Biwa Hayahide.png differ diff --git a/images/797_Silence Suzuka.png b/images/797_Silence Suzuka.png new file mode 100644 index 0000000..a9e391b Binary files /dev/null and b/images/797_Silence Suzuka.png differ diff --git a/images/798_Ikuno Dictus.png b/images/798_Ikuno Dictus.png new file mode 100644 index 0000000..b8d3562 Binary files /dev/null and b/images/798_Ikuno Dictus.png differ diff --git a/images/799_Tamamo Cross.png b/images/799_Tamamo Cross.png new file mode 100644 index 0000000..f60006c Binary files /dev/null and b/images/799_Tamamo Cross.png differ diff --git a/images/79_Daiichi Ruby.png b/images/79_Daiichi Ruby.png new file mode 100644 index 0000000..fa39755 Binary files /dev/null and b/images/79_Daiichi Ruby.png differ diff --git a/images/7_Vodka.png b/images/7_Vodka.png new file mode 100644 index 0000000..67f815e Binary files /dev/null and b/images/7_Vodka.png differ diff --git a/images/800_Zenno Rob Roy.png b/images/800_Zenno Rob Roy.png new file mode 100644 index 0000000..100b654 Binary files /dev/null and b/images/800_Zenno Rob Roy.png differ diff --git a/images/801_Mihono Bourbon.png b/images/801_Mihono Bourbon.png new file mode 100644 index 0000000..a4a05d6 Binary files /dev/null and b/images/801_Mihono Bourbon.png differ diff --git a/images/802_The Throne's Assemblage.png b/images/802_The Throne's Assemblage.png new file mode 100644 index 0000000..c0f1bbf Binary files /dev/null and b/images/802_The Throne's Assemblage.png differ diff --git a/images/803_Curren Chan.png b/images/803_Curren Chan.png new file mode 100644 index 0000000..170ab70 Binary files /dev/null and b/images/803_Curren Chan.png differ diff --git a/images/804_Narita Brian.png b/images/804_Narita Brian.png new file mode 100644 index 0000000..4a5c74b Binary files /dev/null and b/images/804_Narita Brian.png differ diff --git a/images/805_Yukino Bijin.png b/images/805_Yukino Bijin.png new file mode 100644 index 0000000..5423f03 Binary files /dev/null and b/images/805_Yukino Bijin.png differ diff --git a/images/806_Daitaku Helios.png b/images/806_Daitaku Helios.png new file mode 100644 index 0000000..d65b577 Binary files /dev/null and b/images/806_Daitaku Helios.png differ diff --git a/images/807_Mayano Top Gun.png b/images/807_Mayano Top Gun.png new file mode 100644 index 0000000..3db1271 Binary files /dev/null and b/images/807_Mayano Top Gun.png differ diff --git a/images/808_Narita Taishin.png b/images/808_Narita Taishin.png new file mode 100644 index 0000000..705c376 Binary files /dev/null and b/images/808_Narita Taishin.png differ diff --git a/images/809_Marvelous Sunday.png b/images/809_Marvelous Sunday.png new file mode 100644 index 0000000..9b9ff13 Binary files /dev/null and b/images/809_Marvelous Sunday.png differ diff --git a/images/80_K.S.Miracle.png b/images/80_K.S.Miracle.png new file mode 100644 index 0000000..46a69f9 Binary files /dev/null and b/images/80_K.S.Miracle.png differ diff --git a/images/810_Manhattan Cafe.png b/images/810_Manhattan Cafe.png new file mode 100644 index 0000000..462158d Binary files /dev/null and b/images/810_Manhattan Cafe.png differ diff --git a/images/811_Silence Suzuka.png b/images/811_Silence Suzuka.png new file mode 100644 index 0000000..c5d0d9f Binary files /dev/null and b/images/811_Silence Suzuka.png differ diff --git a/images/812_Admire Vega.png b/images/812_Admire Vega.png new file mode 100644 index 0000000..5193c89 Binary files /dev/null and b/images/812_Admire Vega.png differ diff --git a/images/813_Matikanefukukitaru.png b/images/813_Matikanefukukitaru.png new file mode 100644 index 0000000..c55b770 Binary files /dev/null and b/images/813_Matikanefukukitaru.png differ diff --git a/images/814_Meisho Doto.png b/images/814_Meisho Doto.png new file mode 100644 index 0000000..446f68c Binary files /dev/null and b/images/814_Meisho Doto.png differ diff --git a/images/815_Sasami Anshinzawa.png b/images/815_Sasami Anshinzawa.png new file mode 100644 index 0000000..898ccab Binary files /dev/null and b/images/815_Sasami Anshinzawa.png differ diff --git a/images/816_Team Sirius.png b/images/816_Team Sirius.png new file mode 100644 index 0000000..27222d0 Binary files /dev/null and b/images/816_Team Sirius.png differ diff --git a/images/817_Nishino Flower.png b/images/817_Nishino Flower.png new file mode 100644 index 0000000..d28db83 Binary files /dev/null and b/images/817_Nishino Flower.png differ diff --git a/images/818_Sakura Bakushin O.png b/images/818_Sakura Bakushin O.png new file mode 100644 index 0000000..ef376f2 Binary files /dev/null and b/images/818_Sakura Bakushin O.png differ diff --git a/images/819_Tosen Jordan.png b/images/819_Tosen Jordan.png new file mode 100644 index 0000000..5fda73d Binary files /dev/null and b/images/819_Tosen Jordan.png differ diff --git a/images/81_Tsurumaru Tsuyoshi.png b/images/81_Tsurumaru Tsuyoshi.png new file mode 100644 index 0000000..1443e00 Binary files /dev/null and b/images/81_Tsurumaru Tsuyoshi.png differ diff --git a/images/820_Agnes Digital.png b/images/820_Agnes Digital.png new file mode 100644 index 0000000..36c25c7 Binary files /dev/null and b/images/820_Agnes Digital.png differ diff --git a/images/821_Narita Top Road.png b/images/821_Narita Top Road.png new file mode 100644 index 0000000..f493b5f Binary files /dev/null and b/images/821_Narita Top Road.png differ diff --git a/images/822_Mejiro Bright.png b/images/822_Mejiro Bright.png new file mode 100644 index 0000000..db7571f Binary files /dev/null and b/images/822_Mejiro Bright.png differ diff --git a/images/823_Satono Diamond.png b/images/823_Satono Diamond.png new file mode 100644 index 0000000..1f47725 Binary files /dev/null and b/images/823_Satono Diamond.png differ diff --git a/images/824_Marvelous Sunday.png b/images/824_Marvelous Sunday.png new file mode 100644 index 0000000..388b857 Binary files /dev/null and b/images/824_Marvelous Sunday.png differ diff --git a/images/825_Symboli Rudolf.png b/images/825_Symboli Rudolf.png new file mode 100644 index 0000000..58da87c Binary files /dev/null and b/images/825_Symboli Rudolf.png differ diff --git a/images/826_Sirius Symboli.png b/images/826_Sirius Symboli.png new file mode 100644 index 0000000..0e30af6 Binary files /dev/null and b/images/826_Sirius Symboli.png differ diff --git a/images/827_Air Shakur.png b/images/827_Air Shakur.png new file mode 100644 index 0000000..7b74fa3 Binary files /dev/null and b/images/827_Air Shakur.png differ diff --git a/images/828_Daiwa Scarlet.png b/images/828_Daiwa Scarlet.png new file mode 100644 index 0000000..4d45df1 Binary files /dev/null and b/images/828_Daiwa Scarlet.png differ diff --git a/images/829_Bamboo Memory.png b/images/829_Bamboo Memory.png new file mode 100644 index 0000000..23886ed Binary files /dev/null and b/images/829_Bamboo Memory.png differ diff --git a/images/82_Symboli Kris S.png b/images/82_Symboli Kris S.png new file mode 100644 index 0000000..2469255 Binary files /dev/null and b/images/82_Symboli Kris S.png differ diff --git a/images/830_Seeking the Pearl.png b/images/830_Seeking the Pearl.png new file mode 100644 index 0000000..353c65f Binary files /dev/null and b/images/830_Seeking the Pearl.png differ diff --git a/images/831_Kawakami Princess.png b/images/831_Kawakami Princess.png new file mode 100644 index 0000000..8eb2178 Binary files /dev/null and b/images/831_Kawakami Princess.png differ diff --git a/images/832_Mr. C.B..png b/images/832_Mr. C.B..png new file mode 100644 index 0000000..56aaa5a Binary files /dev/null and b/images/832_Mr. C.B..png differ diff --git a/images/833_Haru Urara.png b/images/833_Haru Urara.png new file mode 100644 index 0000000..fad432a Binary files /dev/null and b/images/833_Haru Urara.png differ diff --git a/images/834_Ikuno Dictus.png b/images/834_Ikuno Dictus.png new file mode 100644 index 0000000..771d713 Binary files /dev/null and b/images/834_Ikuno Dictus.png differ diff --git a/images/835_Rice Shower.png b/images/835_Rice Shower.png new file mode 100644 index 0000000..f36bd52 Binary files /dev/null and b/images/835_Rice Shower.png differ diff --git a/images/836_Agnes Tachyon.png b/images/836_Agnes Tachyon.png new file mode 100644 index 0000000..58e8df2 Binary files /dev/null and b/images/836_Agnes Tachyon.png differ diff --git a/images/837_El Condor Pasa.png b/images/837_El Condor Pasa.png new file mode 100644 index 0000000..8f0fe7c Binary files /dev/null and b/images/837_El Condor Pasa.png differ diff --git a/images/838_Matikanetannhauser.png b/images/838_Matikanetannhauser.png new file mode 100644 index 0000000..237136b Binary files /dev/null and b/images/838_Matikanetannhauser.png differ diff --git a/images/839_Zenno Rob Roy.png b/images/839_Zenno Rob Roy.png new file mode 100644 index 0000000..a1ebc0e Binary files /dev/null and b/images/839_Zenno Rob Roy.png differ diff --git a/images/83_Light Hello.png b/images/83_Light Hello.png new file mode 100644 index 0000000..fc40730 Binary files /dev/null and b/images/83_Light Hello.png differ diff --git a/images/840_Special Week.png b/images/840_Special Week.png new file mode 100644 index 0000000..3b3184b Binary files /dev/null and b/images/840_Special Week.png differ diff --git a/images/841_Air Groove.png b/images/841_Air Groove.png new file mode 100644 index 0000000..4aaf146 Binary files /dev/null and b/images/841_Air Groove.png differ diff --git a/images/842_Maruzensky.png b/images/842_Maruzensky.png new file mode 100644 index 0000000..062e8ce Binary files /dev/null and b/images/842_Maruzensky.png differ diff --git a/images/843_Nakayama Festa.png b/images/843_Nakayama Festa.png new file mode 100644 index 0000000..6469e64 Binary files /dev/null and b/images/843_Nakayama Festa.png differ diff --git a/images/844_Sakura Chiyono O.png b/images/844_Sakura Chiyono O.png new file mode 100644 index 0000000..d9de5bc Binary files /dev/null and b/images/844_Sakura Chiyono O.png differ diff --git a/images/845_Manhattan Cafe.png b/images/845_Manhattan Cafe.png new file mode 100644 index 0000000..4d4d622 Binary files /dev/null and b/images/845_Manhattan Cafe.png differ diff --git a/images/846_Tokai Teio.png b/images/846_Tokai Teio.png new file mode 100644 index 0000000..13e442e Binary files /dev/null and b/images/846_Tokai Teio.png differ diff --git a/images/847_Twin Turbo.png b/images/847_Twin Turbo.png new file mode 100644 index 0000000..1aec1bd Binary files /dev/null and b/images/847_Twin Turbo.png differ diff --git a/images/848_Biwa Hayahide.png b/images/848_Biwa Hayahide.png new file mode 100644 index 0000000..4ab5134 Binary files /dev/null and b/images/848_Biwa Hayahide.png differ diff --git a/images/849_Daiichi Ruby.png b/images/849_Daiichi Ruby.png new file mode 100644 index 0000000..b247bd8 Binary files /dev/null and b/images/849_Daiichi Ruby.png differ diff --git a/images/84_Tanino Gimlet.png b/images/84_Tanino Gimlet.png new file mode 100644 index 0000000..ef76db6 Binary files /dev/null and b/images/84_Tanino Gimlet.png differ diff --git a/images/850_Mejiro Palmer.png b/images/850_Mejiro Palmer.png new file mode 100644 index 0000000..b2b8b5c Binary files /dev/null and b/images/850_Mejiro Palmer.png differ diff --git a/images/851_Daitaku Helios.png b/images/851_Daitaku Helios.png new file mode 100644 index 0000000..de7685d Binary files /dev/null and b/images/851_Daitaku Helios.png differ diff --git a/images/852_Shinko Windy.png b/images/852_Shinko Windy.png new file mode 100644 index 0000000..7238867 Binary files /dev/null and b/images/852_Shinko Windy.png differ diff --git a/images/853_Symboli Kris S.png b/images/853_Symboli Kris S.png new file mode 100644 index 0000000..032d869 Binary files /dev/null and b/images/853_Symboli Kris S.png differ diff --git a/images/854_Mejiro Ardan.png b/images/854_Mejiro Ardan.png new file mode 100644 index 0000000..3073e18 Binary files /dev/null and b/images/854_Mejiro Ardan.png differ diff --git a/images/855_Yaeno Muteki.png b/images/855_Yaeno Muteki.png new file mode 100644 index 0000000..a8f3c9c Binary files /dev/null and b/images/855_Yaeno Muteki.png differ diff --git a/images/856_Mihono Bourbon.png b/images/856_Mihono Bourbon.png new file mode 100644 index 0000000..1da6c6b Binary files /dev/null and b/images/856_Mihono Bourbon.png differ diff --git a/images/857_Eishin Flash.png b/images/857_Eishin Flash.png new file mode 100644 index 0000000..7623979 Binary files /dev/null and b/images/857_Eishin Flash.png differ diff --git a/images/858_Narita Brian.png b/images/858_Narita Brian.png new file mode 100644 index 0000000..37d9aea Binary files /dev/null and b/images/858_Narita Brian.png differ diff --git a/images/859_Air Groove.png b/images/859_Air Groove.png new file mode 100644 index 0000000..d801cd1 Binary files /dev/null and b/images/859_Air Groove.png differ diff --git a/images/85_Sakura Laurel.png b/images/85_Sakura Laurel.png new file mode 100644 index 0000000..5ad11bc Binary files /dev/null and b/images/85_Sakura Laurel.png differ diff --git a/images/860_Sakura Laurel.png b/images/860_Sakura Laurel.png new file mode 100644 index 0000000..c92885b Binary files /dev/null and b/images/860_Sakura Laurel.png differ diff --git a/images/861_Yamanin Zephyr.png b/images/861_Yamanin Zephyr.png new file mode 100644 index 0000000..73824af Binary files /dev/null and b/images/861_Yamanin Zephyr.png differ diff --git a/images/862_Special Week.png b/images/862_Special Week.png new file mode 100644 index 0000000..c47bfec Binary files /dev/null and b/images/862_Special Week.png differ diff --git a/images/863_Sweep Tosho.png b/images/863_Sweep Tosho.png new file mode 100644 index 0000000..857b65e Binary files /dev/null and b/images/863_Sweep Tosho.png differ diff --git a/images/864_Grass Wonder.png b/images/864_Grass Wonder.png new file mode 100644 index 0000000..4cb54dc Binary files /dev/null and b/images/864_Grass Wonder.png differ diff --git a/images/865_K.S.Miracle.png b/images/865_K.S.Miracle.png new file mode 100644 index 0000000..c793d83 Binary files /dev/null and b/images/865_K.S.Miracle.png differ diff --git a/images/866_Marvelous Sunday.png b/images/866_Marvelous Sunday.png new file mode 100644 index 0000000..13b3519 Binary files /dev/null and b/images/866_Marvelous Sunday.png differ diff --git a/images/867_Biko Pegasus.png b/images/867_Biko Pegasus.png new file mode 100644 index 0000000..aadca5b Binary files /dev/null and b/images/867_Biko Pegasus.png differ diff --git a/images/868_Hishi Akebono.png b/images/868_Hishi Akebono.png new file mode 100644 index 0000000..a96c647 Binary files /dev/null and b/images/868_Hishi Akebono.png differ diff --git a/images/869_Mejiro Ramonu.png b/images/869_Mejiro Ramonu.png new file mode 100644 index 0000000..fe8b868 Binary files /dev/null and b/images/869_Mejiro Ramonu.png differ diff --git a/images/86_Yamanin Zephyr.png b/images/86_Yamanin Zephyr.png new file mode 100644 index 0000000..4796a4b Binary files /dev/null and b/images/86_Yamanin Zephyr.png differ diff --git a/images/870_Katsuragi Ace.png b/images/870_Katsuragi Ace.png new file mode 100644 index 0000000..d9e64b7 Binary files /dev/null and b/images/870_Katsuragi Ace.png differ diff --git a/images/871_Symboli Kris S.png b/images/871_Symboli Kris S.png new file mode 100644 index 0000000..4d70702 Binary files /dev/null and b/images/871_Symboli Kris S.png differ diff --git a/images/872_Ancestors & Guides.png b/images/872_Ancestors & Guides.png new file mode 100644 index 0000000..7da24e0 Binary files /dev/null and b/images/872_Ancestors & Guides.png differ diff --git a/images/873_Nice Nature.png b/images/873_Nice Nature.png new file mode 100644 index 0000000..54ff312 Binary files /dev/null and b/images/873_Nice Nature.png differ diff --git a/images/874_Mejiro McQueen.png b/images/874_Mejiro McQueen.png new file mode 100644 index 0000000..bb713e2 Binary files /dev/null and b/images/874_Mejiro McQueen.png differ diff --git a/images/875_Tokai Teio.png b/images/875_Tokai Teio.png new file mode 100644 index 0000000..69f9c77 Binary files /dev/null and b/images/875_Tokai Teio.png differ diff --git a/images/876_Mihono Bourbon.png b/images/876_Mihono Bourbon.png new file mode 100644 index 0000000..2e2711f Binary files /dev/null and b/images/876_Mihono Bourbon.png differ diff --git a/images/877_Sakura Laurel.png b/images/877_Sakura Laurel.png new file mode 100644 index 0000000..76b162d Binary files /dev/null and b/images/877_Sakura Laurel.png differ diff --git a/images/878_Ikuno Dictus.png b/images/878_Ikuno Dictus.png new file mode 100644 index 0000000..f419609 Binary files /dev/null and b/images/878_Ikuno Dictus.png differ diff --git a/images/879_Tanino Gimlet.png b/images/879_Tanino Gimlet.png new file mode 100644 index 0000000..8af9c0e Binary files /dev/null and b/images/879_Tanino Gimlet.png differ diff --git a/images/87_Aston Machan.png b/images/87_Aston Machan.png new file mode 100644 index 0000000..480fb3b Binary files /dev/null and b/images/87_Aston Machan.png differ diff --git a/images/880_Oguri Cap.png b/images/880_Oguri Cap.png new file mode 100644 index 0000000..d4f768f Binary files /dev/null and b/images/880_Oguri Cap.png differ diff --git a/images/881_Jungle Pocket.png b/images/881_Jungle Pocket.png new file mode 100644 index 0000000..5c3d6b3 Binary files /dev/null and b/images/881_Jungle Pocket.png differ diff --git a/images/882_Daiwa Scarlet.png b/images/882_Daiwa Scarlet.png new file mode 100644 index 0000000..9025caf Binary files /dev/null and b/images/882_Daiwa Scarlet.png differ diff --git a/images/883_Aston Machan.png b/images/883_Aston Machan.png new file mode 100644 index 0000000..f0527f7 Binary files /dev/null and b/images/883_Aston Machan.png differ diff --git a/images/884_Vodka.png b/images/884_Vodka.png new file mode 100644 index 0000000..c8cbb93 Binary files /dev/null and b/images/884_Vodka.png differ diff --git a/images/885_Mayano Top Gun.png b/images/885_Mayano Top Gun.png new file mode 100644 index 0000000..a11ed26 Binary files /dev/null and b/images/885_Mayano Top Gun.png differ diff --git a/images/886_TM Opera O.png b/images/886_TM Opera O.png new file mode 100644 index 0000000..0dbf8a3 Binary files /dev/null and b/images/886_TM Opera O.png differ diff --git a/images/887_Gold City.png b/images/887_Gold City.png new file mode 100644 index 0000000..958e33a Binary files /dev/null and b/images/887_Gold City.png differ diff --git a/images/888_Mejiro Palmer.png b/images/888_Mejiro Palmer.png new file mode 100644 index 0000000..fd7b40d Binary files /dev/null and b/images/888_Mejiro Palmer.png differ diff --git a/images/889_Daitaku Helios.png b/images/889_Daitaku Helios.png new file mode 100644 index 0000000..55a4306 Binary files /dev/null and b/images/889_Daitaku Helios.png differ diff --git a/images/88_Mejiro Ramonu.png b/images/88_Mejiro Ramonu.png new file mode 100644 index 0000000..50d05e6 Binary files /dev/null and b/images/88_Mejiro Ramonu.png differ diff --git a/images/890_Wonder Acute.png b/images/890_Wonder Acute.png new file mode 100644 index 0000000..08662b9 Binary files /dev/null and b/images/890_Wonder Acute.png differ diff --git a/images/891_Manhattan Cafe.png b/images/891_Manhattan Cafe.png new file mode 100644 index 0000000..89d3a1a Binary files /dev/null and b/images/891_Manhattan Cafe.png differ diff --git a/images/892_Jungle Pocket.png b/images/892_Jungle Pocket.png new file mode 100644 index 0000000..f4d2c7b Binary files /dev/null and b/images/892_Jungle Pocket.png differ diff --git a/images/893_Air Groove.png b/images/893_Air Groove.png new file mode 100644 index 0000000..5ac449e Binary files /dev/null and b/images/893_Air Groove.png differ diff --git a/images/894_Mei Satake.png b/images/894_Mei Satake.png new file mode 100644 index 0000000..538e229 Binary files /dev/null and b/images/894_Mei Satake.png differ diff --git a/images/895_El Condor Pasa.png b/images/895_El Condor Pasa.png new file mode 100644 index 0000000..4e2e17d Binary files /dev/null and b/images/895_El Condor Pasa.png differ diff --git a/images/896_Admire Vega.png b/images/896_Admire Vega.png new file mode 100644 index 0000000..992e417 Binary files /dev/null and b/images/896_Admire Vega.png differ diff --git a/images/897_Nakayama Festa.png b/images/897_Nakayama Festa.png new file mode 100644 index 0000000..98b17a6 Binary files /dev/null and b/images/897_Nakayama Festa.png differ diff --git a/images/898_Hishi Amazon.png b/images/898_Hishi Amazon.png new file mode 100644 index 0000000..8b40955 Binary files /dev/null and b/images/898_Hishi Amazon.png differ diff --git a/images/899_Tanino Gimlet.png b/images/899_Tanino Gimlet.png new file mode 100644 index 0000000..c21b70b Binary files /dev/null and b/images/899_Tanino Gimlet.png differ diff --git a/images/89_Jungle Pocket.png b/images/89_Jungle Pocket.png new file mode 100644 index 0000000..e056da4 Binary files /dev/null and b/images/89_Jungle Pocket.png differ diff --git a/images/8_Taiki Shuttle.png b/images/8_Taiki Shuttle.png new file mode 100644 index 0000000..7001211 Binary files /dev/null and b/images/8_Taiki Shuttle.png differ diff --git a/images/900_Tap Dance City.png b/images/900_Tap Dance City.png new file mode 100644 index 0000000..3c76e60 Binary files /dev/null and b/images/900_Tap Dance City.png differ diff --git a/images/901_Fine Motion.png b/images/901_Fine Motion.png new file mode 100644 index 0000000..e085023 Binary files /dev/null and b/images/901_Fine Motion.png differ diff --git a/images/902_Gold Ship.png b/images/902_Gold Ship.png new file mode 100644 index 0000000..e58f591 Binary files /dev/null and b/images/902_Gold Ship.png differ diff --git a/images/903_Tsurumaru Tsuyoshi.png b/images/903_Tsurumaru Tsuyoshi.png new file mode 100644 index 0000000..33c6965 Binary files /dev/null and b/images/903_Tsurumaru Tsuyoshi.png differ diff --git a/images/904_King Halo.png b/images/904_King Halo.png new file mode 100644 index 0000000..6f4fe79 Binary files /dev/null and b/images/904_King Halo.png differ diff --git a/images/905_Haru Urara.png b/images/905_Haru Urara.png new file mode 100644 index 0000000..99f46bd Binary files /dev/null and b/images/905_Haru Urara.png differ diff --git a/images/906_Mejiro McQueen.png b/images/906_Mejiro McQueen.png new file mode 100644 index 0000000..ca30369 Binary files /dev/null and b/images/906_Mejiro McQueen.png differ diff --git a/images/907_Sounds of Earth.png b/images/907_Sounds of Earth.png new file mode 100644 index 0000000..c8f8e96 Binary files /dev/null and b/images/907_Sounds of Earth.png differ diff --git a/images/908_Mejiro Dober.png b/images/908_Mejiro Dober.png new file mode 100644 index 0000000..cb0d0af Binary files /dev/null and b/images/908_Mejiro Dober.png differ diff --git a/images/909_Mejiro Ramonu.png b/images/909_Mejiro Ramonu.png new file mode 100644 index 0000000..1b733f3 Binary files /dev/null and b/images/909_Mejiro Ramonu.png differ diff --git a/images/90_Hokko Tarumae.png b/images/90_Hokko Tarumae.png new file mode 100644 index 0000000..11af25a Binary files /dev/null and b/images/90_Hokko Tarumae.png differ diff --git a/images/910_Mejiro Ryan.png b/images/910_Mejiro Ryan.png new file mode 100644 index 0000000..72f9159 Binary files /dev/null and b/images/910_Mejiro Ryan.png differ diff --git a/images/911_Vivlos.png b/images/911_Vivlos.png new file mode 100644 index 0000000..48b56fe Binary files /dev/null and b/images/911_Vivlos.png differ diff --git a/images/912_Duramente.png b/images/912_Duramente.png new file mode 100644 index 0000000..77ab87b Binary files /dev/null and b/images/912_Duramente.png differ diff --git a/images/913_Satono Diamond.png b/images/913_Satono Diamond.png new file mode 100644 index 0000000..5961bdd Binary files /dev/null and b/images/913_Satono Diamond.png differ diff --git a/images/914_Carvers of History.png b/images/914_Carvers of History.png new file mode 100644 index 0000000..2cd16e3 Binary files /dev/null and b/images/914_Carvers of History.png differ diff --git a/images/915_Twin Turbo.png b/images/915_Twin Turbo.png new file mode 100644 index 0000000..d2f4405 Binary files /dev/null and b/images/915_Twin Turbo.png differ diff --git a/images/916_Hokko Tarumae.png b/images/916_Hokko Tarumae.png new file mode 100644 index 0000000..2b0f8b0 Binary files /dev/null and b/images/916_Hokko Tarumae.png differ diff --git a/images/917_Winning Ticket.png b/images/917_Winning Ticket.png new file mode 100644 index 0000000..26e5ab2 Binary files /dev/null and b/images/917_Winning Ticket.png differ diff --git a/images/918_Sakura Bakushin O.png b/images/918_Sakura Bakushin O.png new file mode 100644 index 0000000..a9845d2 Binary files /dev/null and b/images/918_Sakura Bakushin O.png differ diff --git a/images/919_North Flight.png b/images/919_North Flight.png new file mode 100644 index 0000000..1fc26cd Binary files /dev/null and b/images/919_North Flight.png differ diff --git a/images/91_Katsuragi Ace.png b/images/91_Katsuragi Ace.png new file mode 100644 index 0000000..0ddc4d1 Binary files /dev/null and b/images/91_Katsuragi Ace.png differ diff --git a/images/920_Gentildonna.png b/images/920_Gentildonna.png new file mode 100644 index 0000000..86318f0 Binary files /dev/null and b/images/920_Gentildonna.png differ diff --git a/images/921_Orfevre.png b/images/921_Orfevre.png new file mode 100644 index 0000000..b21420e Binary files /dev/null and b/images/921_Orfevre.png differ diff --git a/images/922_Ryoka Tsurugi.png b/images/922_Ryoka Tsurugi.png new file mode 100644 index 0000000..9550ba4 Binary files /dev/null and b/images/922_Ryoka Tsurugi.png differ diff --git a/images/923_Kitasan Black.png b/images/923_Kitasan Black.png new file mode 100644 index 0000000..8df8136 Binary files /dev/null and b/images/923_Kitasan Black.png differ diff --git a/images/924_Duramente.png b/images/924_Duramente.png new file mode 100644 index 0000000..1b401f0 Binary files /dev/null and b/images/924_Duramente.png differ diff --git a/images/925_Sounds of Earth.png b/images/925_Sounds of Earth.png new file mode 100644 index 0000000..71eefed Binary files /dev/null and b/images/925_Sounds of Earth.png differ diff --git a/images/926_Vivlos.png b/images/926_Vivlos.png new file mode 100644 index 0000000..6cb25e0 Binary files /dev/null and b/images/926_Vivlos.png differ diff --git a/images/927_Cheval Grand.png b/images/927_Cheval Grand.png new file mode 100644 index 0000000..fd38bf7 Binary files /dev/null and b/images/927_Cheval Grand.png differ diff --git a/images/928_Rhein Kraft.png b/images/928_Rhein Kraft.png new file mode 100644 index 0000000..86fd53f Binary files /dev/null and b/images/928_Rhein Kraft.png differ diff --git a/images/929_K.S.Miracle.png b/images/929_K.S.Miracle.png new file mode 100644 index 0000000..55eb1b5 Binary files /dev/null and b/images/929_K.S.Miracle.png differ diff --git a/images/92_Copano Rickey.png b/images/92_Copano Rickey.png new file mode 100644 index 0000000..66b1f16 Binary files /dev/null and b/images/92_Copano Rickey.png differ diff --git a/images/930_Yamanin Zephyr.png b/images/930_Yamanin Zephyr.png new file mode 100644 index 0000000..8861763 Binary files /dev/null and b/images/930_Yamanin Zephyr.png differ diff --git a/images/931_Bamboo Memory.png b/images/931_Bamboo Memory.png new file mode 100644 index 0000000..f279c34 Binary files /dev/null and b/images/931_Bamboo Memory.png differ diff --git a/images/932_Neo Universe.png b/images/932_Neo Universe.png new file mode 100644 index 0000000..831f717 Binary files /dev/null and b/images/932_Neo Universe.png differ diff --git a/images/933_Hishi Miracle.png b/images/933_Hishi Miracle.png new file mode 100644 index 0000000..d6a4fe7 Binary files /dev/null and b/images/933_Hishi Miracle.png differ diff --git a/images/934_No Reason.png b/images/934_No Reason.png new file mode 100644 index 0000000..b64cbe7 Binary files /dev/null and b/images/934_No Reason.png differ diff --git a/images/935_Narita Taishin.png b/images/935_Narita Taishin.png new file mode 100644 index 0000000..ed942d1 Binary files /dev/null and b/images/935_Narita Taishin.png differ diff --git a/images/936_Vodka.png b/images/936_Vodka.png new file mode 100644 index 0000000..00a87a1 Binary files /dev/null and b/images/936_Vodka.png differ diff --git a/images/937_Jungle Pocket.png b/images/937_Jungle Pocket.png new file mode 100644 index 0000000..5157759 Binary files /dev/null and b/images/937_Jungle Pocket.png differ diff --git a/images/938_Seiun Sky.png b/images/938_Seiun Sky.png new file mode 100644 index 0000000..16cbff6 Binary files /dev/null and b/images/938_Seiun Sky.png differ diff --git a/images/939_Verxina.png b/images/939_Verxina.png new file mode 100644 index 0000000..5a41fa6 Binary files /dev/null and b/images/939_Verxina.png differ diff --git a/images/93_Wonder Acute.png b/images/93_Wonder Acute.png new file mode 100644 index 0000000..01d7ca4 Binary files /dev/null and b/images/93_Wonder Acute.png differ diff --git a/images/940_Vivlos.png b/images/940_Vivlos.png new file mode 100644 index 0000000..511c3c8 Binary files /dev/null and b/images/940_Vivlos.png differ diff --git a/images/941_Yayoi Akikawa.png b/images/941_Yayoi Akikawa.png new file mode 100644 index 0000000..a7ab7bf Binary files /dev/null and b/images/941_Yayoi Akikawa.png differ diff --git a/images/942_Nishino Flower.png b/images/942_Nishino Flower.png new file mode 100644 index 0000000..75b0757 Binary files /dev/null and b/images/942_Nishino Flower.png differ diff --git a/images/943_Dantsu Flame.png b/images/943_Dantsu Flame.png new file mode 100644 index 0000000..d3c2161 Binary files /dev/null and b/images/943_Dantsu Flame.png differ diff --git a/images/944_Smart Falcon.png b/images/944_Smart Falcon.png new file mode 100644 index 0000000..32ec727 Binary files /dev/null and b/images/944_Smart Falcon.png differ diff --git a/images/945_Copano Rickey.png b/images/945_Copano Rickey.png new file mode 100644 index 0000000..74c9562 Binary files /dev/null and b/images/945_Copano Rickey.png differ diff --git a/images/946_Wonder Acute.png b/images/946_Wonder Acute.png new file mode 100644 index 0000000..edf9cd5 Binary files /dev/null and b/images/946_Wonder Acute.png differ diff --git a/images/947_Tokai Teio.png b/images/947_Tokai Teio.png new file mode 100644 index 0000000..52c0710 Binary files /dev/null and b/images/947_Tokai Teio.png differ diff --git a/images/948_Fine Motion.png b/images/948_Fine Motion.png new file mode 100644 index 0000000..2c9c707 Binary files /dev/null and b/images/948_Fine Motion.png differ diff --git a/images/949_Still in Love.png b/images/949_Still in Love.png new file mode 100644 index 0000000..90e80c5 Binary files /dev/null and b/images/949_Still in Love.png differ diff --git a/images/94_Mei Satake.png b/images/94_Mei Satake.png new file mode 100644 index 0000000..be6b1c4 Binary files /dev/null and b/images/94_Mei Satake.png differ diff --git a/images/950_Buena Vista.png b/images/950_Buena Vista.png new file mode 100644 index 0000000..33e3d14 Binary files /dev/null and b/images/950_Buena Vista.png differ diff --git a/images/951_Cesario.png b/images/951_Cesario.png new file mode 100644 index 0000000..7973bda Binary files /dev/null and b/images/951_Cesario.png differ diff --git a/images/952_Taiki Shuttle.png b/images/952_Taiki Shuttle.png new file mode 100644 index 0000000..79d389e Binary files /dev/null and b/images/952_Taiki Shuttle.png differ diff --git a/images/953_Fuji Kiseki.png b/images/953_Fuji Kiseki.png new file mode 100644 index 0000000..3feb99b Binary files /dev/null and b/images/953_Fuji Kiseki.png differ diff --git a/images/954_Symboli Kris S.png b/images/954_Symboli Kris S.png new file mode 100644 index 0000000..e97fbd9 Binary files /dev/null and b/images/954_Symboli Kris S.png differ diff --git a/images/955_Satono Diamond.png b/images/955_Satono Diamond.png new file mode 100644 index 0000000..8cea125 Binary files /dev/null and b/images/955_Satono Diamond.png differ diff --git a/images/956_Espoir City.png b/images/956_Espoir City.png new file mode 100644 index 0000000..27bd463 Binary files /dev/null and b/images/956_Espoir City.png differ diff --git a/images/957_Hishi Amazon.png b/images/957_Hishi Amazon.png new file mode 100644 index 0000000..f74064e Binary files /dev/null and b/images/957_Hishi Amazon.png differ diff --git a/images/958_Narita Brian.png b/images/958_Narita Brian.png new file mode 100644 index 0000000..169a3e9 Binary files /dev/null and b/images/958_Narita Brian.png differ diff --git a/images/959_Matikanefukukitaru.png b/images/959_Matikanefukukitaru.png new file mode 100644 index 0000000..1c2efb1 Binary files /dev/null and b/images/959_Matikanefukukitaru.png differ diff --git a/images/95_Tap Dance City.png b/images/95_Tap Dance City.png new file mode 100644 index 0000000..53c367b Binary files /dev/null and b/images/95_Tap Dance City.png differ diff --git a/images/960_Air Shakur.png b/images/960_Air Shakur.png new file mode 100644 index 0000000..a4e417e Binary files /dev/null and b/images/960_Air Shakur.png differ diff --git a/images/961_Daiwa Scarlet.png b/images/961_Daiwa Scarlet.png new file mode 100644 index 0000000..8408940 Binary files /dev/null and b/images/961_Daiwa Scarlet.png differ diff --git a/images/962_Symboli Kris S.png b/images/962_Symboli Kris S.png new file mode 100644 index 0000000..f821dfb Binary files /dev/null and b/images/962_Symboli Kris S.png differ diff --git a/images/963_Agnes Digital.png b/images/963_Agnes Digital.png new file mode 100644 index 0000000..544cd8f Binary files /dev/null and b/images/963_Agnes Digital.png differ diff --git a/images/964_Meisho Doto.png b/images/964_Meisho Doto.png new file mode 100644 index 0000000..cffc42b Binary files /dev/null and b/images/964_Meisho Doto.png differ diff --git a/images/965_TM Opera O.png b/images/965_TM Opera O.png new file mode 100644 index 0000000..4a61300 Binary files /dev/null and b/images/965_TM Opera O.png differ diff --git a/images/966_Blast Onepiece.png b/images/966_Blast Onepiece.png new file mode 100644 index 0000000..2bcd445 Binary files /dev/null and b/images/966_Blast Onepiece.png differ diff --git a/images/967_Symboli Rudolf.png b/images/967_Symboli Rudolf.png new file mode 100644 index 0000000..39d6556 Binary files /dev/null and b/images/967_Symboli Rudolf.png differ diff --git a/images/968_Mejiro Ardan.png b/images/968_Mejiro Ardan.png new file mode 100644 index 0000000..7006ae2 Binary files /dev/null and b/images/968_Mejiro Ardan.png differ diff --git a/images/969_Maruzensky.png b/images/969_Maruzensky.png new file mode 100644 index 0000000..01138ad Binary files /dev/null and b/images/969_Maruzensky.png differ diff --git a/images/96_Still in Love.png b/images/96_Still in Love.png new file mode 100644 index 0000000..b341686 Binary files /dev/null and b/images/96_Still in Love.png differ diff --git a/images/970_Seeking the Pearl.png b/images/970_Seeking the Pearl.png new file mode 100644 index 0000000..60c099e Binary files /dev/null and b/images/970_Seeking the Pearl.png differ diff --git a/images/971_Curren Chan.png b/images/971_Curren Chan.png new file mode 100644 index 0000000..4ece2ab Binary files /dev/null and b/images/971_Curren Chan.png differ diff --git a/images/972_Ikuno Dictus.png b/images/972_Ikuno Dictus.png new file mode 100644 index 0000000..df1a2a7 Binary files /dev/null and b/images/972_Ikuno Dictus.png differ diff --git a/images/973_Nice Nature.png b/images/973_Nice Nature.png new file mode 100644 index 0000000..0e728a5 Binary files /dev/null and b/images/973_Nice Nature.png differ diff --git a/images/974_Jungle Pocket.png b/images/974_Jungle Pocket.png new file mode 100644 index 0000000..3ab7627 Binary files /dev/null and b/images/974_Jungle Pocket.png differ diff --git a/images/975_Embodiment of Legends.png b/images/975_Embodiment of Legends.png new file mode 100644 index 0000000..14712d9 Binary files /dev/null and b/images/975_Embodiment of Legends.png differ diff --git a/images/976_Almond Eye.png b/images/976_Almond Eye.png new file mode 100644 index 0000000..0ea90f1 Binary files /dev/null and b/images/976_Almond Eye.png differ diff --git a/images/977_Gran Alegria.png b/images/977_Gran Alegria.png new file mode 100644 index 0000000..eb9a2a7 Binary files /dev/null and b/images/977_Gran Alegria.png differ diff --git a/images/978_Mejiro Bright.png b/images/978_Mejiro Bright.png new file mode 100644 index 0000000..67ef61e Binary files /dev/null and b/images/978_Mejiro Bright.png differ diff --git a/images/979_Vodka.png b/images/979_Vodka.png new file mode 100644 index 0000000..3a72973 Binary files /dev/null and b/images/979_Vodka.png differ diff --git a/images/97_Verxina.png b/images/97_Verxina.png new file mode 100644 index 0000000..14bf46b Binary files /dev/null and b/images/97_Verxina.png differ diff --git a/images/980_Dream Journey.png b/images/980_Dream Journey.png new file mode 100644 index 0000000..ca5aab8 Binary files /dev/null and b/images/980_Dream Journey.png differ diff --git a/images/981_Symboli Kris S.png b/images/981_Symboli Kris S.png new file mode 100644 index 0000000..87fbd07 Binary files /dev/null and b/images/981_Symboli Kris S.png differ diff --git a/images/982_Daring Tact.png b/images/982_Daring Tact.png new file mode 100644 index 0000000..4feacae Binary files /dev/null and b/images/982_Daring Tact.png differ diff --git a/images/983_Transcend.png b/images/983_Transcend.png new file mode 100644 index 0000000..ab04e0e Binary files /dev/null and b/images/983_Transcend.png differ diff --git a/images/984_Buena Vista.png b/images/984_Buena Vista.png new file mode 100644 index 0000000..3a71b83 Binary files /dev/null and b/images/984_Buena Vista.png differ diff --git a/images/985_Espoir City.png b/images/985_Espoir City.png new file mode 100644 index 0000000..a3e96a7 Binary files /dev/null and b/images/985_Espoir City.png differ diff --git a/images/986_Silence Suzuka.png b/images/986_Silence Suzuka.png new file mode 100644 index 0000000..083baee Binary files /dev/null and b/images/986_Silence Suzuka.png differ diff --git a/images/987_Rhein Kraft.png b/images/987_Rhein Kraft.png new file mode 100644 index 0000000..ac29703 Binary files /dev/null and b/images/987_Rhein Kraft.png differ diff --git a/images/988_Daring Heart.png b/images/988_Daring Heart.png new file mode 100644 index 0000000..80dea94 Binary files /dev/null and b/images/988_Daring Heart.png differ diff --git a/images/989_Air Messiah.png b/images/989_Air Messiah.png new file mode 100644 index 0000000..4aa103f Binary files /dev/null and b/images/989_Air Messiah.png differ diff --git a/images/98_Sounds of Earth.png b/images/98_Sounds of Earth.png new file mode 100644 index 0000000..5e63696 Binary files /dev/null and b/images/98_Sounds of Earth.png differ diff --git a/images/990_Tamamo Cross.png b/images/990_Tamamo Cross.png new file mode 100644 index 0000000..b3be954 Binary files /dev/null and b/images/990_Tamamo Cross.png differ diff --git a/images/991_Tucker Bryne.png b/images/991_Tucker Bryne.png new file mode 100644 index 0000000..04a07ee Binary files /dev/null and b/images/991_Tucker Bryne.png differ diff --git a/images/992_Mejiro Ryan.png b/images/992_Mejiro Ryan.png new file mode 100644 index 0000000..6aff325 Binary files /dev/null and b/images/992_Mejiro Ryan.png differ diff --git a/images/993_Fusaichi Pandora.png b/images/993_Fusaichi Pandora.png new file mode 100644 index 0000000..115e0c5 Binary files /dev/null and b/images/993_Fusaichi Pandora.png differ diff --git a/images/994_Mejiro McQueen.png b/images/994_Mejiro McQueen.png new file mode 100644 index 0000000..2367a0a Binary files /dev/null and b/images/994_Mejiro McQueen.png differ diff --git a/images/995_Win Variation.png b/images/995_Win Variation.png new file mode 100644 index 0000000..11b0b0e Binary files /dev/null and b/images/995_Win Variation.png differ diff --git a/images/996_Duramente.png b/images/996_Duramente.png new file mode 100644 index 0000000..acd6786 Binary files /dev/null and b/images/996_Duramente.png differ diff --git a/images/997_Vivlos.png b/images/997_Vivlos.png new file mode 100644 index 0000000..96e2319 Binary files /dev/null and b/images/997_Vivlos.png differ diff --git a/images/998_Stay Gold.png b/images/998_Stay Gold.png new file mode 100644 index 0000000..492b26f Binary files /dev/null and b/images/998_Stay Gold.png differ diff --git a/images/999_Admire Groove.png b/images/999_Admire Groove.png new file mode 100644 index 0000000..3ed3a7c Binary files /dev/null and b/images/999_Admire Groove.png differ diff --git a/images/99_Vivlos.png b/images/99_Vivlos.png new file mode 100644 index 0000000..d209f0f Binary files /dev/null and b/images/99_Vivlos.png differ diff --git a/images/9_Grass Wonder.png b/images/9_Grass Wonder.png new file mode 100644 index 0000000..829141c Binary files /dev/null and b/images/9_Grass Wonder.png differ diff --git a/main.py b/main.py new file mode 100644 index 0000000..005e61c --- /dev/null +++ b/main.py @@ -0,0 +1,58 @@ +""" +Umamusume Support Card Manager +Main entry point for the application +""" + +import argparse +import sys +import os + +# Add project root to path +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +def run_scraper(): + """Run the web scraper to fetch card data""" + from scraper.gametora_scraper import run_scraper as scrape + scrape() + +def run_gui(): + """Launch the Tkinter GUI application""" + from gui.main_window import MainWindow + app = MainWindow() + app.run() + +def main(): + parser = argparse.ArgumentParser( + description="Umamusume Support Card Manager", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + python main.py # Launch the GUI (default) + python main.py --gui # Launch the GUI + python main.py --scrape # Run the web scraper + """ + ) + + parser.add_argument( + '--scrape', + action='store_true', + help='Run the web scraper to fetch data from GameTora' + ) + parser.add_argument( + '--gui', + action='store_true', + help='Launch the GUI application (default action)' + ) + + args = parser.parse_args() + + if args.scrape: + print("Starting web scraper...") + run_scraper() + else: + # Default to GUI + print("Launching Umamusume Support Card Manager...") + run_gui() + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..cf2feed --- /dev/null +++ b/requirements.txt @@ -0,0 +1,19 @@ +# Umamusume Support Card Manager +# Required Python packages + +# Web scraping +playwright>=1.40.0 +beautifulsoup4>=4.12.0 +requests>=2.31.0 + +# Image handling +Pillow>=10.0.0 + +# Database (included with Python, but listing for clarity) +# sqlite3 - built-in + +# GUI (included with Python) +# tkinter - built-in + +# Optional: for development +# pytest>=7.0.0 diff --git a/scraper/gametora_scraper.py b/scraper/gametora_scraper.py new file mode 100644 index 0000000..f9aa9d9 --- /dev/null +++ b/scraper/gametora_scraper.py @@ -0,0 +1,572 @@ +""" +GameTora Umamusume Support Card Scraper +Scrapes all support cards with their effects at key levels (1, 25, 40, 50) +Includes character art download +""" + +import sqlite3 +import time +import re +import os +import requests +import sys +import os + +# Ensure we can import from parent directory +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from playwright.sync_api import sync_playwright +from db.db_queries import get_conn, init_database + +BASE_URL = "https://gametora.com" + +if getattr(sys, 'frozen', False): + # In frozen state, look in the same directory as the executable + IMAGES_PATH = os.path.join(os.path.dirname(sys.executable), "images") +else: + IMAGES_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "images") + +# Key levels to scrape (limit break milestones) +KEY_LEVELS = [20, 25, 30, 35, 40, 45, 50] + +# Rarity mapping based on image filename +RARITY_MAP = { + "rarity_01": "R", + "rarity_02": "SR", + "rarity_03": "SSR" +} + +# Type mapping based on image filename - uses utx_ico_obtain_XX pattern! +TYPE_MAP = { + "obtain_00": "Speed", + "obtain_01": "Stamina", + "obtain_02": "Power", + "obtain_03": "Guts", + "obtain_04": "Wisdom", + "obtain_05": "Friend", + "obtain_06": "Group" +} + +def scrape_all_support_links(page): + """Scrape all support card links from the list page""" + print("Loading support card list...") + page.goto(f"{BASE_URL}/umamusume/supports", timeout=60000) + page.wait_for_load_state("networkidle") + + # Scroll to load all cards (lazy loading) - more scrolls for complete list + print("Scrolling to load all cards...") + for i in range(30): + page.evaluate("window.scrollTo(0, document.body.scrollHeight)") + page.wait_for_timeout(400) + + # Scroll back up and down to ensure all loaded + page.evaluate("window.scrollTo(0, 0)") + page.wait_for_timeout(500) + for i in range(10): + page.evaluate("window.scrollTo(0, document.body.scrollHeight)") + page.wait_for_timeout(300) + + # Extract all card links + links = page.evaluate(""" + () => { + const links = Array.from(document.querySelectorAll('a[href*="/umamusume/supports/"]')) + .map(a => a.href) + .filter(href => href.match(/\\/supports\\/\\d+-/)); + return [...new Set(links)]; + } + """) + + print(f"Found {len(links)} support cards") + return sorted(links) + +def parse_rarity_from_image(img_src): + """Extract rarity from image source URL""" + if not img_src: + return "R" # Default to R if not found + for key, rarity in RARITY_MAP.items(): + if key in img_src: + return rarity + return "R" # Default to R + +def parse_type_from_image(img_src): + """Extract type from image source URL""" + if not img_src: + return "Unknown" + for key, card_type in TYPE_MAP.items(): + if key in img_src: + return card_type + return "Unknown" + +def get_max_level_for_rarity(rarity): + """Get maximum level based on rarity""" + if rarity == "SSR": + return 50 + elif rarity == "SR": + return 45 + else: # R + return 40 + +def download_card_image(page, card_id, card_name): + """Download the card's character art image""" + os.makedirs(IMAGES_PATH, exist_ok=True) + + try: + # Find the main card image + img_url = page.evaluate(""" + () => { + // Look for the main card image - usually a large character portrait + const imgs = Array.from(document.querySelectorAll('img')); + + // Find images that might be the card art (usually larger images with character names) + const cardImg = imgs.find(img => + img.src.includes('/supports/') || + img.src.includes('/cards/') || + (img.width > 100 && img.height > 100 && img.src.includes('umamusume')) + ); + + // Also look for images in the infobox + const infoboxImg = document.querySelector('[class*="infobox"] img'); + + return cardImg ? cardImg.src : (infoboxImg ? infoboxImg.src : null); + } + """) + + if img_url: + # Clean filename + safe_name = re.sub(r'[<>:"/\\|?*]', '_', card_name) + file_path = os.path.join(IMAGES_PATH, f"{card_id}_{safe_name}.png") + + # Download image + response = requests.get(img_url, timeout=10) + if response.status_code == 200: + with open(file_path, 'wb') as f: + f.write(response.content) + return file_path + except Exception as e: + print(f" Warning: Could not download image: {e}") + + return None + +def scrape_support_card(page, url, conn, max_retries=3): + """Scrape a single support card with key levels and retries""" + + for attempt in range(max_retries): + try: + page.goto(url, timeout=60000) + page.wait_for_load_state("networkidle") + page.wait_for_timeout(2000) # Extra wait for JS rendering + + # Extract basic card info including type + card_data = page.evaluate(""" + () => { + const h1 = document.querySelector('h1'); + const title = h1 ? h1.textContent.trim() : ''; + + // Find rarity image + const imgs = Array.from(document.querySelectorAll('img')); + const rarityImg = imgs.find(i => i.src.includes('rarity')); + + // Find type image - uses utx_ico_obtain pattern + const typeImg = imgs.find(i => i.src.includes('obtain_0')); + + return { + title: title, + rarityImgSrc: rarityImg ? rarityImg.src : null, + typeImgSrc: typeImg ? typeImg.src : null + }; + } + """) + + # Parse name from title (remove rarity and "Support Card") + full_title = card_data['title'] + name = re.sub(r'\s*\(SSR\)|\s*\(SR\)|\s*\(R\)', '', full_title) + name = name.replace('Support Card', '').strip() + + if not name: + print(f" Warning: Empty name, skipping") + return False + + rarity = parse_rarity_from_image(card_data['rarityImgSrc']) + card_type = parse_type_from_image(card_data['typeImgSrc']) + max_level = get_max_level_for_rarity(rarity) + + print(f"Scraping: {name} | {rarity} | {card_type} | Max Level: {max_level}") + + cur = conn.cursor() + + # Insert card + cur.execute(""" + INSERT OR REPLACE INTO support_cards (name, rarity, card_type, max_level, gametora_url) + VALUES (?, ?, ?, ?, ?) + """, (name, rarity, card_type, max_level, url)) + conn.commit() + + cur.execute("SELECT card_id FROM support_cards WHERE gametora_url = ?", (url,)) + card_id = cur.fetchone()[0] + + # Download character art + image_path = download_card_image(page, card_id, name) + if image_path: + cur.execute("UPDATE support_cards SET image_path = ? WHERE card_id = ?", (image_path, card_id)) + conn.commit() + + # Clear existing effects for this card (in case of re-scrape) + cur.execute("DELETE FROM support_effects WHERE card_id = ?", (card_id,)) + cur.execute("DELETE FROM support_hints WHERE card_id = ?", (card_id,)) + cur.execute("DELETE FROM event_skills WHERE event_id IN (SELECT event_id FROM support_events WHERE card_id = ?)", (card_id,)) + cur.execute("DELETE FROM support_events WHERE card_id = ?", (card_id,)) + + # Scrape effects at key levels only + scrape_effects_key_levels(page, card_id, max_level, cur) + + # Scrape hints + scrape_hints(page, card_id, cur) + + # Scrape events + scrape_events(page, card_id, cur) + + conn.commit() + return True + + except Exception as e: + print(f" Attempt {attempt + 1} failed: {e}") + if attempt < max_retries - 1: + print(f" Retrying...") + time.sleep(1) + else: + print(f" All retries failed for {url}") + return False + +def set_level(page, target_level): + """Set the page to a specific level using JavaScript to click buttons""" + + # Use JavaScript to handle all the clicking - need to check children.length === 0 + # and wait for level text to change after each click + actual_level = page.evaluate(""" + async (targetLevel) => { + // Get current level from the page + const getLevel = () => { + const el = Array.from(document.querySelectorAll('div')).find(d => + d.textContent.trim().startsWith('Level ') && d.children.length === 0 + ); + if (!el) { + const text = document.body.innerText; + const match = text.match(/Level\\s*(\\d+)/i); + return match ? parseInt(match[1]) : 30; + } + return parseInt(el.textContent.replace('Level ', '').trim()); + }; + + // Find a button by its exact text - MUST check children.length === 0 + const clickButton = (text) => { + const btns = Array.from(document.querySelectorAll('div')); + const btn = btns.find(d => d.textContent.trim() === text && d.children.length === 0); + if (btn) { + btn.click(); + return true; + } + return false; + }; + + let currentLevel = getLevel(); + + // Navigate to target level + while (currentLevel !== targetLevel) { + let btnText; + if (currentLevel > targetLevel) { + const diff = currentLevel - targetLevel; + btnText = diff >= 5 ? '-5' : '-1'; + } else { + const diff = targetLevel - currentLevel; + btnText = diff >= 5 ? '+5' : '+1'; + } + + if (!clickButton(btnText)) { + // Button not found, we might be at max/min level + break; + } + + // CRITICAL: Wait for level text to actually change + const startLevel = currentLevel; + let start = Date.now(); + while (Date.now() - start < 1000) { + await new Promise(r => setTimeout(r, 50)); + const newLevel = getLevel(); + if (newLevel !== startLevel) { + currentLevel = newLevel; + break; + } + } + + // If we're stuck, break out + if (currentLevel === startLevel) { + break; + } + } + + // Final wait for effects to update + await new Promise(r => setTimeout(r, 200)); + return getLevel(); + } + """, target_level) + + return actual_level + +def extract_effects(page): + """Extract effects from current page state using proper DOM selectors""" + effects = page.evaluate(""" + () => { + const effects = []; + + // Method 1: Try to find effects using the specific class structure + const effectContainers = document.querySelectorAll('[class*="effect__"]'); + + effectContainers.forEach(container => { + const text = container.innerText.trim(); + if (text.includes('Unlocked at level')) return; + + const fullText = text.split('\\n').join(' '); + + const patterns = [ + + // Basic Stats + { regex: /Speed Bonus\\s*(\\d+)/, name: 'Speed Bonus' }, + { regex: /Stamina Bonus\\s*(\\d+)/, name: 'Stamina Bonus' }, + { regex: /Power Bonus\\s*(\\d+)/, name: 'Power Bonus' }, + { regex: /Guts Bonus\\s*(\\d+)/, name: 'Guts Bonus' }, + { regex: /Wisdom Bonus\\s*(\\d+)/, name: 'Wisdom Bonus' }, + { regex: /Wit Bonus\\s*(\\d+)/, name: 'Wisdom Bonus' }, // Alias Wit -> Wisdom + { regex: /Skill Pts Bonus\\s*(\\d+)/, name: 'Skill Pts Bonus' }, + + // Initial Stats + { regex: /Initial Speed\\s*(\\d+)/, name: 'Initial Speed' }, + { regex: /Initial Stamina\\s*(\\d+)/, name: 'Initial Stamina' }, + { regex: /Initial Power\\s*(\\d+)/, name: 'Initial Power' }, + { regex: /Initial Guts\\s*(\\d+)/, name: 'Initial Guts' }, + { regex: /Initial Wisdom\\s*(\\d+)/, name: 'Initial Wisdom' }, + { regex: /Initial Wit\\s*(\\d+)/, name: 'Initial Wisdom' }, // Alias Wit -> Wisdom + + // Special Bonuses + { regex: /Friendship Bonus\\s*(\\d+%?)/, name: 'Friendship Bonus' }, + { regex: /Mood Effect\\s*(\\d+%?)/, name: 'Mood Effect' }, + { regex: /Motivation Effect\\s*(\\d+%?)/, name: 'Motivation Effect' }, + { regex: /Training Effectiveness\\s*(\\d+%?)/, name: 'Training Effectiveness' }, + { regex: /Race Bonus\\s*(\\d+%?)/, name: 'Race Bonus' }, + { regex: /Fan Bonus\\s*(\\d+%?)/, name: 'Fan Bonus' }, + + // Hints + { regex: /Hint Rate\\s*(\\d+%?)/, name: 'Hint Rate' }, + { regex: /Hint Frequency\\s*(\\d+%?)/, name: 'Hint Rate' }, // Alias Frequency -> Rate + { regex: /Hint Lv Up\\s*(\\d+%?)/, name: 'Hint Lv Up' }, + { regex: /Hint Levels\\s*Lv\\s*(\\d+)/, name: 'Hint Lv Up' }, // Alias Hint Levels -> Hint Lv Up + + // Specialty/Bond + { regex: /Starting Bond\\s*(\\d+)/, name: 'Starting Bond' }, + { regex: /Initial Friendship Gauge\\s*(\\d+)/, name: 'Starting Bond' }, // Alias -> Starting Bond + { regex: /Specialty Rate\\s*(\\d+%?)/, name: 'Specialty Rate' }, + { regex: /Specialty Priority\\s*(\\d+)/, name: 'Specialty Rate' }, // Alias Priority -> Rate (usually same concept) + + // Recovery/Usage + { regex: /Race Status\\s*(\\d+)/, name: 'Race Status' }, + { regex: /Energy Discount\\s*(\\d+%?)/, name: 'Energy Discount' }, + { regex: /Wit Friendship Recovery\\s*(\\d+)/, name: 'Wisdom Friendship Recovery' }, + + // Catch-all Unique + { regex: /Unique Effect\\s*(.*)/, name: 'Unique Effect' }, + ]; + + + for (const p of patterns) { + const match = fullText.match(p.regex); + if (match && !effects.some(e => e.name === p.name)) { + effects.push({ name: p.name, value: match[1] }); + } + } + }); + + // Method 2: Fallback - scan entire page text + if (effects.length === 0) { + const bodyText = document.body.innerText; + const lines = bodyText.split('\\n'); + + const simplePatterns = [ + /^(Friendship Bonus)\\s*(\\d+%?)$/, + /^(Mood Effect)\\s*(\\d+%?)$/, + /^(Race Bonus)\\s*(\\d+%?)$/, + /^(Fan Bonus)\\s*(\\d+%?)$/, + /^(Training Effectiveness)\\s*(\\d+%?)$/, + ]; + + for (const line of lines) { + const trimmed = line.trim(); + for (const pattern of simplePatterns) { + const match = trimmed.match(pattern); + if (match && !effects.some(e => e.name === match[1])) { + effects.push({ name: match[1], value: match[2] }); + } + } + } + } + + return effects; + } + """) + return effects + +def scrape_effects_key_levels(page, card_id, max_level, cur): + """Scrape effects at key levels based on card rarity/max level""" + + # Determine which levels to scrape based on max_level (rarity) + if max_level == 50: # SSR + levels_to_scrape = [30, 35, 40, 45, 50] + elif max_level == 45: # SR + levels_to_scrape = [25, 30, 35, 40, 45] + else: # R (max 40) + levels_to_scrape = [20, 25, 30, 35, 40] + + # Filter out any that might exceed max somehow (safety check) + levels_to_scrape = [l for l in levels_to_scrape if l <= max_level] + + for level in levels_to_scrape: + actual_level = set_level(page, level) + effects = extract_effects(page) + + for effect in effects: + cur.execute(""" + INSERT INTO support_effects (card_id, level, effect_name, effect_value) + VALUES (?, ?, ?, ?) + """, (card_id, actual_level, effect['name'], effect['value'])) + + print(f" Level {actual_level}: {len(effects)} effects") + +def scrape_hints(page, card_id, cur): + """Scrape support hints/training skills""" + hints = page.evaluate(""" + () => { + const hints = []; + const text = document.body.innerText; + + const hintsMatch = text.match(/Support [Hh]ints([\\s\\S]*?)(?:Training [Ee]vents|Skills from [Ee]vents|$)/); + if (!hintsMatch) return hints; + + const hintsSection = hintsMatch[1]; + const lines = hintsSection.split('\\n'); + + for (const line of lines) { + const trimmed = line.trim(); + if (trimmed.length > 3 && trimmed.length < 60 && + !trimmed.includes('Lv') && !trimmed.includes('%') && + !trimmed.includes('Details') && trimmed[0] === trimmed[0].toUpperCase()) { + hints.push({ name: trimmed, description: '' }); + } + } + + return hints.slice(0, 10); + } + """) + + for hint in hints: + cur.execute(""" + INSERT INTO support_hints (card_id, hint_name, hint_description) + VALUES (?, ?, ?) + """, (card_id, hint.get('name', ''), hint.get('description', ''))) + + if hints: + print(f" Found {len(hints)} hints") + +def scrape_events(page, card_id, cur): + """Scrape training events""" + events = page.evaluate(""" + () => { + const events = []; + const text = document.body.innerText; + + const eventsMatch = text.match(/Training [Ee]vents([\\s\\S]*?)(?:$)/); + if (!eventsMatch) return events; + + const eventsSection = eventsMatch[1]; + const lines = eventsSection.split('\\n'); + + for (const line of lines) { + const trimmed = line.trim(); + if (trimmed.length > 5 && trimmed.length < 80 && + !trimmed.includes('%') && !trimmed.includes('Energy') && + !trimmed.includes('bond') && !trimmed.includes('+') && + trimmed[0] === trimmed[0].toUpperCase()) { + events.push({ name: trimmed, type: 'Event' }); + } + } + + return events.slice(0, 15); + } + """) + + for event in events: + cur.execute(""" + INSERT INTO support_events (card_id, event_name, event_type) + VALUES (?, ?, ?) + """, (card_id, event.get('name', ''), event.get('type', 'Unknown'))) + + if events: + print(f" Found {len(events)} events") + +def run_scraper(): + """Main scraper function""" + print("=" * 60) + print("GameTora Umamusume Support Card Scraper") + print(f"Scraping effects at levels: {KEY_LEVELS}") + print("=" * 60) + + # Initialize fresh database + print("\nInitializing database...") + init_database() + + # Create images directory + os.makedirs(IMAGES_PATH, exist_ok=True) + + conn = get_conn() + + with sync_playwright() as p: + print("\nLaunching browser...") + browser = p.chromium.launch(headless=True) + context = browser.new_context() + page = context.new_page() + + # Get all card links + links = scrape_all_support_links(page) + + print(f"\nStarting to scrape {len(links)} cards...") + print("Including character art download.") + print("This will take approximately 30-45 minutes.\n") + + success_count = 0 + fail_count = 0 + + for i, url in enumerate(links, 1): + print(f"\n[{i}/{len(links)}] ", end="") + if scrape_support_card(page, url, conn): + success_count += 1 + else: + fail_count += 1 + + time.sleep(0.3) + + if i % 50 == 0: + print(f"\n{'='*40}") + print(f"Progress: {i}/{len(links)} ({i*100//len(links)}%)") + print(f"Success: {success_count}, Failed: {fail_count}") + print(f"{'='*40}") + + browser.close() + + conn.close() + + print("\n" + "=" * 60) + print("Scraping Complete!") + print(f"Successfully scraped: {success_count} cards") + print(f"Failed: {fail_count} cards") + print(f"Images saved to: {IMAGES_PATH}") + print("=" * 60) + +if __name__ == "__main__": + run_scraper() diff --git a/scripts/prepare_release_db.py b/scripts/prepare_release_db.py new file mode 100644 index 0000000..d1cb000 --- /dev/null +++ b/scripts/prepare_release_db.py @@ -0,0 +1,70 @@ +import sqlite3 +import shutil +import os +import sys + +# Add parent dir to path to find version.py +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from version import VERSION + +# Paths +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +DB_DIR = os.path.join(BASE_DIR, "database") +SOURCE_DB = os.path.join(DB_DIR, "umamusume.db") +SEED_DB = os.path.join(DB_DIR, "umamusume_seed.db") + +def create_seed_db(): + print(f"Source DB: {SOURCE_DB}") + print(f"Target Seed DB: {SEED_DB}") + print(f"Injecting Version: {VERSION}") + + if not os.path.exists(SOURCE_DB): + print("Error: Source database not found!") + return + + # Copy file + print("Copying database...") + shutil.copy2(SOURCE_DB, SEED_DB) + + # Connect to seed DB and wipe user data + print("Cleaning user data...") + conn = sqlite3.connect(SEED_DB) + cur = conn.cursor() + + try: + # Wipe user tables + cur.execute("DELETE FROM owned_cards") + cur.execute("DELETE FROM deck_slots") + cur.execute("DELETE FROM user_decks") + # Ensure ID sequences reset + cur.execute("DELETE FROM sqlite_sequence WHERE name IN ('owned_cards', 'user_decks', 'deck_slots')") + + # Verify card data remains + cur.execute("SELECT COUNT(*) FROM support_cards") + card_count = cur.fetchone()[0] + print(f"Preserved {card_count} support cards.") + + # Add Metadata Table + cur.execute(""" + CREATE TABLE IF NOT EXISTS system_metadata ( + key TEXT PRIMARY KEY, + value TEXT + ) + """) + cur.execute("INSERT OR REPLACE INTO system_metadata (key, value) VALUES (?, ?)", ('app_version', VERSION)) + + conn.commit() + + # Optimize size + print("Vacuuming database...") + cur.execute("VACUUM") + + print("Seed database created successfully!") + + except Exception as e: + print(f"Error cleaning database: {e}") + finally: + conn.close() + +if __name__ == "__main__": + create_seed_db() diff --git a/test_scraper.py b/test_scraper.py new file mode 100644 index 0000000..db2c08f --- /dev/null +++ b/test_scraper.py @@ -0,0 +1,87 @@ +"""Quick test of the fixed level navigation""" +import os +import sys +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +from playwright.sync_api import sync_playwright + +URL = "https://gametora.com/umamusume/supports/30022-mejiro-mcqueen" + +def test_levels(): + print("Testing fixed level navigation...") + + with sync_playwright() as p: + browser = p.chromium.launch(headless=True) + page = browser.new_page() + + page.goto(URL, timeout=60000) + page.wait_for_load_state("networkidle") + page.wait_for_timeout(2000) + + for target in [1, 25, 40, 50]: + actual = page.evaluate(""" + async (targetLevel) => { + const getLevel = () => { + const el = Array.from(document.querySelectorAll('div')).find(d => + d.textContent.trim().startsWith('Level ') && d.children.length === 0 + ); + if (!el) { + const text = document.body.innerText; + const match = text.match(/Level\\s*(\\d+)/i); + return match ? parseInt(match[1]) : 30; + } + return parseInt(el.textContent.replace('Level ', '').trim()); + }; + + const clickButton = (text) => { + const btns = Array.from(document.querySelectorAll('div')); + const btn = btns.find(d => d.textContent.trim() === text && d.children.length === 0); + if (btn) { + btn.click(); + return true; + } + return false; + }; + + let currentLevel = getLevel(); + + while (currentLevel !== targetLevel) { + let btnText; + if (currentLevel > targetLevel) { + const diff = currentLevel - targetLevel; + btnText = diff >= 5 ? '-5' : '-1'; + } else { + const diff = targetLevel - currentLevel; + btnText = diff >= 5 ? '+5' : '+1'; + } + + if (!clickButton(btnText)) break; + + const startLevel = currentLevel; + let start = Date.now(); + while (Date.now() - start < 1000) { + await new Promise(r => setTimeout(r, 50)); + const newLevel = getLevel(); + if (newLevel !== startLevel) { + currentLevel = newLevel; + break; + } + } + + if (currentLevel === startLevel) break; + } + + await new Promise(r => setTimeout(r, 200)); + return getLevel(); + } + """, target) + + status = "āœ“" if actual == target else "āœ—" + print(f"Target: {target} -> Actual: {actual} {status}") + + browser.close() + + print("Done!") + +if __name__ == "__main__": + test_levels() diff --git a/updater/__init__.py b/updater/__init__.py new file mode 100644 index 0000000..842da25 --- /dev/null +++ b/updater/__init__.py @@ -0,0 +1,8 @@ +""" +Updater module for UmamusumeCardManager +Handles checking for updates and downloading new versions from GitHub Releases. +""" + +from updater.update_checker import check_for_updates, download_update, apply_update + +__all__ = ['check_for_updates', 'download_update', 'apply_update'] diff --git a/updater/update_checker.py b/updater/update_checker.py new file mode 100644 index 0000000..db0e1a7 --- /dev/null +++ b/updater/update_checker.py @@ -0,0 +1,264 @@ +""" +Update checker for UmamusumeCardManager +Checks GitHub Releases for new versions and handles downloading updates. +""" + +import os +import sys +import tempfile +import subprocess +import requests +from typing import Optional, Callable, Tuple + +# Import version info +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from version import VERSION, GITHUB_API_URL, APP_NAME + + +def parse_version(version_str: str) -> Tuple[int, int, int]: + """ + Parse a version string into a tuple of integers. + Handles formats like "1.0.0", "v1.0.0", "1.2.3-beta", etc. + """ + # Remove 'v' prefix if present + version_str = version_str.lstrip('v').lstrip('V') + + # Remove any suffix like -beta, -rc1, etc. + if '-' in version_str: + version_str = version_str.split('-')[0] + + parts = version_str.split('.') + + # Ensure we have at least 3 parts + while len(parts) < 3: + parts.append('0') + + try: + return (int(parts[0]), int(parts[1]), int(parts[2])) + except ValueError: + return (0, 0, 0) + + +def compare_versions(local: str, remote: str) -> int: + """ + Compare two version strings. + Returns: + -1 if local < remote (update available) + 0 if local == remote (up to date) + 1 if local > remote (local is newer) + """ + local_tuple = parse_version(local) + remote_tuple = parse_version(remote) + + if local_tuple < remote_tuple: + return -1 + elif local_tuple > remote_tuple: + return 1 + else: + return 0 + + +def check_for_updates() -> Optional[dict]: + """ + Check GitHub Releases for a new version. + + Returns: + dict with update info if available, None if up to date or error. + { + 'current_version': str, + 'new_version': str, + 'download_url': str, + 'release_notes': str, + 'html_url': str # Link to the release page + } + """ + try: + # Add a user-agent header (GitHub API requires this) + headers = { + 'User-Agent': f'{APP_NAME}-Updater', + 'Accept': 'application/vnd.github.v3+json' + } + + response = requests.get(GITHUB_API_URL, headers=headers, timeout=10) + + if response.status_code == 404: + # No releases found + print("No releases found on GitHub.") + return None + + response.raise_for_status() + release_data = response.json() + + remote_version = release_data.get('tag_name', '') + + # Compare versions + if compare_versions(VERSION, remote_version) < 0: + # Find the Windows exe asset + download_url = None + for asset in release_data.get('assets', []): + asset_name = asset.get('name', '').lower() + if asset_name.endswith('.exe'): + download_url = asset.get('browser_download_url') + break + + if not download_url: + print("No .exe asset found in the latest release.") + return None + + return { + 'current_version': VERSION, + 'new_version': remote_version, + 'download_url': download_url, + 'release_notes': release_data.get('body', 'No release notes provided.'), + 'html_url': release_data.get('html_url', '') + } + else: + # Already up to date + return None + + except requests.exceptions.Timeout: + print("Update check timed out.") + return None + except requests.exceptions.RequestException as e: + print(f"Error checking for updates: {e}") + return None + except Exception as e: + print(f"Unexpected error during update check: {e}") + return None + + +def download_update(download_url: str, progress_callback: Optional[Callable[[int, int], None]] = None) -> Optional[str]: + """ + Download the update file. + + Args: + download_url: URL to download the new exe from + progress_callback: Optional callback function(downloaded_bytes, total_bytes) + + Returns: + Path to the downloaded file, or None if failed. + """ + try: + headers = { + 'User-Agent': f'{APP_NAME}-Updater' + } + + response = requests.get(download_url, headers=headers, stream=True, timeout=60) + response.raise_for_status() + + # Get total file size + total_size = int(response.headers.get('content-length', 0)) + + # Create temp file for download + temp_dir = tempfile.gettempdir() + temp_path = os.path.join(temp_dir, f'{APP_NAME}_update.exe') + + downloaded = 0 + chunk_size = 8192 + + with open(temp_path, 'wb') as f: + for chunk in response.iter_content(chunk_size=chunk_size): + if chunk: + f.write(chunk) + downloaded += len(chunk) + if progress_callback and total_size > 0: + progress_callback(downloaded, total_size) + + return temp_path + + except Exception as e: + print(f"Error downloading update: {e}") + return None + + +def get_current_exe_path() -> str: + """Get the path to the current running executable.""" + if getattr(sys, 'frozen', False): + # Running as compiled exe + return sys.executable + else: + # Running as script + return os.path.abspath(sys.argv[0]) + + +def apply_update(new_exe_path: str) -> bool: + """ + Apply the update by replacing the current exe with the new one. + + This creates a batch script that: + 1. Waits for the current process to exit + 2. Replaces the old exe with the new one + 3. Starts the new exe + 4. Cleans up the batch script + + Args: + new_exe_path: Path to the downloaded new exe + + Returns: + True if the update process was started successfully. + """ + try: + current_exe = get_current_exe_path() + + # If running as a script, we can't self-update + if not getattr(sys, 'frozen', False): + print("Cannot apply update when running as a script.") + print(f"New version downloaded to: {new_exe_path}") + return False + + # Create a batch script to perform the update + batch_script = os.path.join(tempfile.gettempdir(), f'{APP_NAME}_updater.bat') + + # Simple batch script that just waits and applies the update + # We don't auto-restart because PyInstaller temp cleanup causes DLL errors + script_content = f'''@echo off +title {APP_NAME} Updater +echo ======================================== +echo {APP_NAME} Updater +echo ======================================== +echo. +echo Waiting for application to close... +timeout /t 3 >nul + +echo. +echo Applying update... +move /Y "{new_exe_path}" "{current_exe}" +if errorlevel 1 ( + echo. + echo ERROR: Update failed! + echo Please close the application completely and try again. + pause + exit /b 1 +) + +echo. +echo ======================================== +echo Update applied successfully! +echo ======================================== +echo. +echo Please start the application manually. +echo This window will close in 5 seconds... +timeout /t 5 >nul +exit +''' + + with open(batch_script, 'w') as f: + f.write(script_content) + + # Start the batch script with a visible window so user can see progress + CREATE_NEW_CONSOLE = 0x00000010 + subprocess.Popen( + ['cmd', '/c', batch_script], + creationflags=CREATE_NEW_CONSOLE + ) + + return True + + except Exception as e: + print(f"Error applying update: {e}") + return False + + +def get_current_version() -> str: + """Get the current application version.""" + return VERSION diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..f7d2ffa --- /dev/null +++ b/utils.py @@ -0,0 +1,28 @@ + +import os +import sys + +def resolve_image_path(db_path): + """ + Resolve the absolute path to an image file. + Handles the case where the database contains paths from a different machine/drive. + Also handles frozen (PyInstaller) state. + """ + if not db_path: + return None + + filename = os.path.basename(db_path) + + # Check if running as frozen executable + if getattr(sys, 'frozen', False): + # PyInstaller creates a temp folder and stores path in _MEIPASS + if hasattr(sys, '_MEIPASS'): + root_dir = sys._MEIPASS + else: + root_dir = os.path.dirname(sys.executable) + else: + # Get the project root directory (directory where this utils.py resides) + root_dir = os.path.dirname(os.path.abspath(__file__)) + + # Construct optimal path + return os.path.join(root_dir, 'images', filename) diff --git a/verify_fix.py b/verify_fix.py new file mode 100644 index 0000000..131dddc --- /dev/null +++ b/verify_fix.py @@ -0,0 +1,33 @@ + +import sqlite3 +import os +import sys + +# Add current dir to path to import utils +sys.path.append(os.path.dirname(os.path.abspath(__file__))) +from utils import resolve_image_path + +DB_PATH = r"y:\Keith\umamusuma card application\database\umamusume.db" +print(f"Checking DB at: {DB_PATH}") + +try: + conn = sqlite3.connect(DB_PATH) + cur = conn.cursor() + cur.execute("SELECT card_id, name, image_path FROM support_cards LIMIT 5") + rows = cur.fetchall() + + print("\nVerifying Path Resolution:") + for row in rows: + card_id, name, original_path = row + resolved = resolve_image_path(original_path) + exists = os.path.exists(resolved) if resolved else False + + print(f"Card: {name}") + print(f" Original: {original_path}") + print(f" Resolved: {resolved}") + print(f" Exists: {exists}") + print("-" * 50) + + conn.close() +except Exception as e: + print(f"Error: {e}") diff --git a/version.py b/version.py new file mode 100644 index 0000000..567aa25 --- /dev/null +++ b/version.py @@ -0,0 +1,12 @@ +""" +Version information for UmamusumeCardManager +This file is the single source of truth for the application version. +""" + +# Semantic versioning: MAJOR.MINOR.PATCH +VERSION = "5.3.2" + +# Application metadata +APP_NAME = "UmamusumeCardManager" +GITHUB_REPO = "kiyreload27/UmamusumeCardManager" +GITHUB_API_URL = f"https://api.github.com/repos/{GITHUB_REPO}/releases/latest"