Add MTGA Assistant: native Linux deck and game tracker

PySide6 app that follows MTG Arena's Player.log under Steam/Proton and shows
my remaining library with draw odds, my zones, and everything revealed about
the opponent (board, graveyard, exile, known hand/library, seen this match).

- Auto-detects the Steam library, Proton prefix log and MTGA install
- Card names/costs/types from MTGA's local SQLite card database
- Tracks card identity across zone changes, shuffles and Bo3 games
- Scryfall card images with a lazy, size-capped LRU disk cache
- Live log following with restart detection, plus --replay mode
- Flags log gaps where MTGA omits oversized game-state messages

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aeth3randClaude Opus 5.5 committed 2026-10-16 09:56:12 -04:00
1 parent 734336168c
commit 7dc2ce0da8
21 files changed
+2736

No files matched your search

+50
View File
@@ -0,0 +1,50 @@
"""Entry point: mtga-assistant [--log PATH] [--replay PATH [--rate N]]."""
from __future__ import annotations
import argparse
import sys
from pathlib import Path
from PySide6.QtWidgets import QApplication
from . import paths
from .carddb import CardDB
from .images import ImageCache
from .ui.main_window import MainWindow
def main() -> int:
ap = argparse.ArgumentParser(description="MTG Arena deck and game tracker")
ap.add_argument("--log", type=Path, help="Player.log to follow (default: auto-detect)")
ap.add_argument("--replay", type=Path, help="replay a saved log instead of following the live one")
ap.add_argument("--rate", type=float, default=40.0, help="replay speed in log events per second")
ap.add_argument("--mtga-dir", type=Path, help="MTGA install directory (default: auto-detect)")
args, qt_args = ap.parse_known_args()
cfg = paths.load_config()
if args.log:
cfg.log_path = args.log
if args.mtga_dir:
cfg.mtga_dir = args.mtga_dir
app = QApplication([sys.argv[0], *qt_args])
app.setApplicationName("MTGA Assistant")
app.setDesktopFileName("mtga-assistant") # Wayland app_id, usable in Hyprland window rules
mtga_dir = paths.find_mtga_dir(cfg)
db_path = paths.find_card_db(mtga_dir) if mtga_dir else None
cards = CardDB(db_path)
images = ImageCache(paths.CACHE_DIR, cards, cfg.cache_max_mb * 1024 * 1024)
if args.replay:
win = MainWindow(cards, images, args.replay, replay_rate=args.rate)
else:
win = MainWindow(cards, images, paths.find_log_path(cfg))
app.aboutToQuit.connect(win.shutdown)
win.show()
return app.exec()
if __name__ == "__main__":
sys.exit(main())