- Fix MtgSet model to match database schema (removed created_at, added image column) - Create load_mtgjson_data.py script to load AllSetFiles, AllPrintings.psql, and other MTGJSON data - Create download_mtgjson_data.py script to download MTGJSON API data files - Add SPEC_synergy-mapping-engine.md documentation API endpoints are now working (200 OK) but database needs data loading via download_mtgjson_data.py then load_mtgjson_data.py
156 lines
5.6 KiB
Python
156 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
MTGJSON Data Downloader
|
|
|
|
Downloads MTGJSON data files into the container for loading.
|
|
Handles decompression of gzip files and unzipping of zip files.
|
|
|
|
Usage:
|
|
python download_mtgjson_data.py
|
|
"""
|
|
|
|
import asyncio
|
|
import json
|
|
import gzip
|
|
import logging
|
|
import os
|
|
import sys
|
|
import zipfile
|
|
from pathlib import Path
|
|
from urllib.request import urlretrieve, urlopen
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# MTGJSON download URLs
|
|
MTGJSON_BASE_URL = "https://mtgjson.com/api/5x"
|
|
MTGJSON_FILES = {
|
|
"AllPrintings.psql.gz": "AllPrintings.psql.gz",
|
|
"AllSetFiles.zip": "AllSetFiles.zip",
|
|
"AllDeckFiles.zip": "AllDeckFiles.zip",
|
|
"AllIdentifiers.json.gz": "AllIdentifiers.json.gz",
|
|
"CardTypes.json.gz": "CardTypes.json.gz",
|
|
"DeckList.json.gz": "DeckList.json.gz",
|
|
"Keywords.json.gz": "Keywords.json.gz",
|
|
"SetList.json.gz": "SetList.json.gz",
|
|
}
|
|
|
|
|
|
def download_file(url, dest_dir, filename):
|
|
"""Download a file from URL to destination directory"""
|
|
dest_path = dest_dir / filename
|
|
if dest_path.exists():
|
|
logger.info(f"{filename} already exists, skipping download")
|
|
return True
|
|
|
|
logger.info(f"Downloading {filename}...")
|
|
try:
|
|
urlretrieve(url, dest_path)
|
|
logger.info(f"Downloaded {filename} to {dest_path}")
|
|
return True
|
|
except Exception as e:
|
|
logger.error(f"Failed to download {filename}: {e}")
|
|
return False
|
|
|
|
|
|
def extract_zip(zip_path, dest_dir):
|
|
"""Extract a zip file to destination directory"""
|
|
logger.info(f"Extracting {zip_path.name} to {dest_dir}...")
|
|
try:
|
|
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
|
zip_ref.extractall(dest_dir)
|
|
logger.info(f"Extracted {zip_path.name} successfully")
|
|
# Remove the zip file after extraction
|
|
zip_path.unlink()
|
|
return True
|
|
except Exception as e:
|
|
logger.error(f"Failed to extract {zip_path}: {e}")
|
|
return False
|
|
|
|
|
|
def extract_gzip(gz_path, dest_path=None):
|
|
"""Extract a gzip file"""
|
|
if not dest_path:
|
|
dest_path = gz_path.with_suffix('')
|
|
|
|
logger.info(f"Extracting {gz_path.name} to {dest_path}...")
|
|
try:
|
|
with gzip.open(gz_path, 'rt', encoding='utf-8') as f_in:
|
|
with open(dest_path, 'w', encoding='utf-8') as f_out:
|
|
f_out.write(f_in.read())
|
|
logger.info(f"Extracted {gz_path.name} to {dest_path}")
|
|
# Remove the gz file after extraction
|
|
gz_path.unlink()
|
|
return True
|
|
except Exception as e:
|
|
logger.error(f"Failed to extract {gz_path}: {e}")
|
|
return False
|
|
|
|
|
|
async def download_all():
|
|
"""Download and extract all MTGJSON data files"""
|
|
logger.info("Starting MTGJSON data download...")
|
|
|
|
# Create data directory
|
|
data_dir = Path("/app/data/mtgjson")
|
|
data_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Download AllPrintings.psql.gz
|
|
if download_file(MTGJSON_BASE_URL + "/AllPrintings.psql.gz", data_dir, "AllPrintings.psql.gz"):
|
|
# Extract gzip
|
|
gz_path = data_dir / "AllPrintings.psql.gz"
|
|
if extract_gzip(gz_path, data_dir / "AllPrintings.psql"):
|
|
logger.info("AllPrintings.psql extracted successfully")
|
|
|
|
# Download AllSetFiles.zip
|
|
if download_file(MTGJSON_BASE_URL + "/AllSetFiles.zip", data_dir, "AllSetFiles.zip"):
|
|
zip_path = data_dir / "AllSetFiles.zip"
|
|
allsetfiles_dir = data_dir / "allsetfiles"
|
|
allsetfiles_dir.mkdir(exist_ok=True)
|
|
if extract_zip(zip_path, allsetfiles_dir):
|
|
logger.info("AllSetFiles extracted successfully")
|
|
|
|
# Download AllDeckFiles.zip
|
|
if download_file(MTGJSON_BASE_URL + "/AllDeckFiles.zip", data_dir, "AllDeckFiles.zip"):
|
|
zip_path = data_dir / "AllDeckFiles.zip"
|
|
alldeckfiles_dir = data_dir / "alldeckfiles"
|
|
alldeckfiles_dir.mkdir(exist_ok=True)
|
|
if extract_zip(zip_path, alldeckfiles_dir):
|
|
logger.info("AllDeckFiles extracted successfully")
|
|
|
|
# Download AllIdentifiers.json.gz
|
|
if download_file(MTGJSON_BASE_URL + "/AllIdentifiers.json.gz", data_dir, "AllIdentifiers.json.gz"):
|
|
gz_path = data_dir / "AllIdentifiers.json.gz"
|
|
if extract_gzip(gz_path, data_dir / "AllIdentifiers.json"):
|
|
logger.info("AllIdentifiers.json extracted successfully")
|
|
|
|
# Download CardTypes.json.gz
|
|
if download_file(MTGJSON_BASE_URL + "/CardTypes.json.gz", data_dir, "CardTypes.json.gz"):
|
|
gz_path = data_dir / "CardTypes.json.gz"
|
|
if extract_gzip(gz_path, data_dir / "CardTypes.json"):
|
|
logger.info("CardTypes.json extracted successfully")
|
|
|
|
# Download DeckList.json.gz
|
|
if download_file(MTGJSON_BASE_URL + "/DeckList.json.gz", data_dir, "DeckList.json.gz"):
|
|
gz_path = data_dir / "DeckList.json.gz"
|
|
if extract_gzip(gz_path, data_dir / "DeckList.json"):
|
|
logger.info("DeckList.json extracted successfully")
|
|
|
|
# Download Keywords.json.gz
|
|
if download_file(MTGJSON_BASE_URL + "/Keywords.json.gz", data_dir, "Keywords.json.gz"):
|
|
gz_path = data_dir / "Keywords.json.gz"
|
|
if extract_gzip(gz_path, data_dir / "Keywords.json"):
|
|
logger.info("Keywords.json extracted successfully")
|
|
|
|
# Download SetList.json.gz
|
|
if download_file(MTGJSON_BASE_URL + "/SetList.json.gz", data_dir, "SetList.json.gz"):
|
|
gz_path = data_dir / "SetList.json.gz"
|
|
if extract_gzip(gz_path, data_dir / "SetList.json"):
|
|
logger.info("SetList.json extracted successfully")
|
|
|
|
logger.info("MTGJSON data download and extraction complete!")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(download_all())
|