Fix MTGJSON download: use .gz URLs and handle pre-uncompressed files

This commit is contained in:
2026-07-20 04:46:15 +00:00
parent 65a1f95b7f
commit ad2742c1cf
2 changed files with 39 additions and 22 deletions
+23 -7
View File
@@ -41,13 +41,13 @@ logger = logging.getLogger(__name__)
# MTGJSON API URLs # MTGJSON API URLs
MTGJSON_BASE_URL = "https://mtgjson.com/api/v5" MTGJSON_BASE_URL = "https://mtgjson.com/api/v5"
REQUIRED_FILES = { REQUIRED_FILES = {
"AllPrintings.json.gz": MTGJSON_BASE_URL + "/AllPrintings.json", "AllPrintings.json.gz": MTGJSON_BASE_URL + "/AllPrintings.json.gz",
"AllSetFiles.zip": MTGJSON_BASE_URL + "/AllSetFiles.zip", "AllSetFiles.zip": MTGJSON_BASE_URL + "/AllSetFiles.zip",
"AllIdentifiers.json.gz": MTGJSON_BASE_URL + "/AllIdentifiers.json", "AllIdentifiers.json.gz": MTGJSON_BASE_URL + "/AllIdentifiers.json.gz",
"CardTypes.json.gz": MTGJSON_BASE_URL + "/CardTypes.json", "CardTypes.json.gz": MTGJSON_BASE_URL + "/CardTypes.json.gz",
"DeckList.json.gz": MTGJSON_BASE_URL + "/DeckList.json", "DeckList.json.gz": MTGJSON_BASE_URL + "/DeckList.json.gz",
"Keywords.json.gz": MTGJSON_BASE_URL + "/Keywords.json", "Keywords.json.gz": MTGJSON_BASE_URL + "/Keywords.json.gz",
"SetList.json.gz": MTGJSON_BASE_URL + "/SetList.json", "SetList.json.gz": MTGJSON_BASE_URL + "/SetList.json.gz",
} }
DATA_DIR = Path("/app/data/mtgjson") DATA_DIR = Path("/app/data/mtgjson")
@@ -55,10 +55,14 @@ REFRESH_LOG_TABLE = "mtg_refresh_log"
# Expected minimum file sizes (in bytes) for MTGJSON v5 files # Expected minimum file sizes (in bytes) for MTGJSON v5 files
EXPECTED_MIN_SIZES = { EXPECTED_MIN_SIZES = {
"AllPrintings.json.gz": 500 * 1024 * 1024, # 500 MB
"AllPrintings.json": 500 * 1024 * 1024, # 500 MB "AllPrintings.json": 500 * 1024 * 1024, # 500 MB
"AllSetFiles.json": 10 * 1024 * 1024, # 10 MB "AllSetFiles.json": 10 * 1024 * 1024, # 10 MB
"AllIdentifiers.json.gz": 100 * 1024 * 1024, # 100 MB
"AllIdentifiers.json": 100 * 1024 * 1024, # 100 MB "AllIdentifiers.json": 100 * 1024 * 1024, # 100 MB
"CardTypes.json.gz": 1 * 1024 * 1024, # 1 MB
"CardTypes.json": 1 * 1024 * 1024, # 1 MB "CardTypes.json": 1 * 1024 * 1024, # 1 MB
"Keywords.json.gz": 0.5 * 1024 * 1024, # 0.5 MB
"Keywords.json": 0.5 * 1024 * 1024, # 0.5 MB "Keywords.json": 0.5 * 1024 * 1024, # 0.5 MB
"MagicSets.json": 50 * 1024 * 1024, # 50 MB "MagicSets.json": 50 * 1024 * 1024, # 50 MB
"MagicRoots.json": 1 * 1024 * 1024, # 1 MB "MagicRoots.json": 1 * 1024 * 1024, # 1 MB
@@ -307,18 +311,30 @@ class MTGJSONManager:
return False return False
def _unpack_gzip(self, gz_file: Path) -> bool: def _unpack_gzip(self, gz_file: Path) -> bool:
"""Unpack a gzip file.""" """Unpack a gzip file or handle pre-uncompressed JSON."""
dest_file = gz_file.with_suffix("") dest_file = gz_file.with_suffix("")
logger.info(f"Unpacking {gz_file.name}") logger.info(f"Unpacking {gz_file.name}")
try: try:
# Check if file is actually gzipped by reading first bytes
with open(gz_file, 'rb') as f:
magic = f.read(2)
if magic == b'\x1f\x8b':
# File is gzipped - proceed normally
with gzip.open(gz_file, 'rt', encoding='utf-8') as f_in: with gzip.open(gz_file, 'rt', encoding='utf-8') as f_in:
content = f_in.read() content = f_in.read()
dest_file.write_text(content, encoding='utf-8') dest_file.write_text(content, encoding='utf-8')
logger.info(f"Unpacked {gz_file.name} to {dest_file.name}") logger.info(f"Unpacked {gz_file.name} to {dest_file.name}")
return True return True
else:
# File is already plain JSON - just rename
logger.info(f"{gz_file.name} is pre-uncompressed JSON, renaming to {dest_file.name}")
dest_file.write_bytes(gz_file.read_bytes())
gz_file.unlink()
return True
except Exception as e: except Exception as e:
logger.error(f"Failed to unpack {gz_file.name}: {e}") logger.error(f"Failed to unpack {gz_file.name}: {e}")
+9 -8
View File
@@ -1,6 +1,6 @@
{ {
"task_description": "MTG Online Backend - MTGJSON Data Integration & Docker Deployment", "task_description": "MTG Online Backend - MTGJSON Data Integration & Docker Deployment",
"current_step": "Testing: destroy all containers, rebuild backend, deploy stack", "current_step": "Testing full container lifecycle",
"files_created": [ "files_created": [
"backend/app/services/mtgjson_manager.py", "backend/app/services/mtgjson_manager.py",
"backend/scripts/sanity_check_mtgjson.py", "backend/scripts/sanity_check_mtgjson.py",
@@ -26,17 +26,18 @@
"Implemented retry logic with exponential backoff (up to 3 attempts)", "Implemented retry logic with exponential backoff (up to 3 attempts)",
"Cleanup deletes corrupted data before retry", "Cleanup deletes corrupted data before retry",
"Container marked unhealthy if validation fails after all retries", "Container marked unhealthy if validation fails after all retries",
"Doubled all timeout values to prevent timeouts during download/upsert",
"Download timeout increased to 60 minutes (3600s) for large files" "Download timeout increased to 60 minutes (3600s) for large files"
], ],
"next_steps": [ "next_steps": [
"Destroy all containers", "Save state to state.json",
"Build backend image", "Commit and push to Gitea",
"Deploy stack", "Stop and destroy all Docker containers",
"Monitor until healthy", "Build backend Docker container",
"Check logs for success" "Deploy stack and monitor",
"Check container health status",
"Verify logs show successful initialization"
], ],
"blockers": [], "blockers": [],
"commit_hash": "20fb572", "commit_hash": "0643544",
"timestamp": 1784598400 "timestamp": 1784598400
} }