Rewrite README with logo and screenshots
Add the logo and screenshots, restructure into features, installation, usage, configuration and development, and bring everything up to date (background mode, installers, menus, limitations). The project description now covers Linux and Windows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d9ef771db8
commit
90f846c70b
7 files changed
+188
-82
No files matched your search
@@ -1,120 +1,226 @@
|
||||
# mtga-assistant
|
||||
<p align="center">
|
||||
<img src="images/mtga-assistant-icon.png" alt="MTGA Assistant logo" width="128">
|
||||
</p>
|
||||
|
||||
A native Linux deck and game tracker for **Magic: The Gathering Arena** running under Steam/Proton.
|
||||
It follows MTGA's `Player.log`, much like Untapped.gg and other trackers do, and shows:
|
||||
<h1 align="center">MTGA Assistant</h1>
|
||||
|
||||
Two views, switched from the top bar (Ctrl+1 / Ctrl+2):
|
||||
<p align="center">
|
||||
A deck and game tracker for <b>Magic: The Gathering Arena</b> on Linux and Windows.
|
||||
</p>
|
||||
|
||||
- **Match**, from top to bottom (drag the dividers to resize; sizes are remembered):
|
||||
- *You · Match · Opponent*: life totals, poison/energy and other player counters, commanders,
|
||||
emblems, hand/library/graveyard counts, turn timer and timeouts, land drops used/allowed, who
|
||||
was on the play, plus the match panel (turn, phase, game number, Bo3 score and draw count,
|
||||
game time).
|
||||
- *You · Turn · Opponent*: each player's stats for the selected turn and the whole game
|
||||
(cards drawn, spells cast, lands played, creatures died, life gained/lost, damage, discards,
|
||||
mills, exiles, counters, tokens, land drops). The two sides mirror each other, with the
|
||||
whole-game column next to the middle panel, which picks the turn (◀ ▶, or *Live* to follow
|
||||
the current one).
|
||||
- *My deck · Opponent · Preview*: remaining library with draw odds, your zones; the opponent's
|
||||
board, graveyard, exile, cards known to be in their hand or library, and every card seen this
|
||||
match; hover a card for its [Scryfall](https://scryfall.com) image.
|
||||
- **History**: stats (win rate overall, last 10/100 games, last 7 days, on the play/draw, average
|
||||
length and turns) and a sortable list of every finished game: date, event, deck, commanders,
|
||||
opponent, both decks' colours, who was on the play, result, turns and length. Click a header to
|
||||
sort, right-click a cell to show only (or hide) games with that value; the stats follow the
|
||||
filters. Click a game to open it in the Match view ("Back to live" returns). Games from the
|
||||
previous MTGA session (`Player-prev.log`) are imported on startup.
|
||||
MTGA Assistant follows MTGA's `Player.log`, as Untapped.gg and other trackers do. It shows your
|
||||
library with draw odds, everything revealed about your opponent, per-turn stats, and a filterable
|
||||
history of every game you play. It runs natively on Linux (MTGA through Steam/Proton) and on
|
||||
Windows (Steam, Epic or the standalone installer).
|
||||
|
||||
*⚙ Customize* shows or hides each panel of the Match page (You, Match, Opponent, Turn stats,
|
||||
My deck, Preview, Opponent's cards) and the details in the player panels. *Customize → Arrange…*
|
||||
reorders (drag, or ↑/↓) and shows/hides the My deck and Opponent sections and the turn stats.
|
||||
Your choices are remembered.
|
||||
## Screenshots
|
||||
|
||||
**Match**: both players, the match, per-turn stats, your deck, a card preview and everything known
|
||||
about the opponent.
|
||||
|
||||

|
||||
|
||||
**A past game** opened from History, with "Back to live" to return.
|
||||
|
||||

|
||||
|
||||
**History**: stats and every finished game; sort by any column.
|
||||
|
||||

|
||||
|
||||
**Filtered history**: right-click any value to filter; the stats follow the filter.
|
||||
|
||||

|
||||
|
||||
**Customization**: reorder and show/hide deck sections and turn stats.
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
### Match
|
||||
|
||||
Three rows; drag the dividers to resize them (sizes are remembered).
|
||||
|
||||
- **You · Match · Opponent**: life totals, poison/energy and other player counters, commanders
|
||||
(with location and commander tax), emblems, hand/library/graveyard/exile counts, turn timer and
|
||||
timeouts used, land drops used/allowed (e.g. `0/2` with extra land effects), who was on the play,
|
||||
plus the match panel: turn, phase, game number, Bo3 score, who has been on the draw more, and
|
||||
game time.
|
||||
- **You · Turn · Opponent**: each player's stats for the selected turn and the whole game: cards
|
||||
drawn, spells cast, lands played, creatures died, life gained/lost, damage, discards, mills,
|
||||
exiles, spells countered, tokens, counters and land drops. The middle panel picks the turn
|
||||
(◀ ▶, or *Live* to follow the current one).
|
||||
- **My deck · Preview · Opponent**:
|
||||
- *My deck*: the remaining library with draw odds, and your hand, stack, battlefield, graveyard,
|
||||
exile and sideboard. Counts show copies in that zone against copies in the deck (`2/5`).
|
||||
- *Opponent*: their battlefield, stack, graveyard and exile, cards known to be in their hand or
|
||||
library (seen going back there, or revealed), and every card seen this match.
|
||||
- *Preview*: hover a card to see its [Scryfall](https://scryfall.com) image. Clear it with ✕,
|
||||
a click on the image, or Esc.
|
||||
|
||||
Card names, mana costs and types come from MTGA's own local card database, so they work offline.
|
||||
|
||||
### History
|
||||
|
||||
Every finished game is recorded with its date, event, deck, commanders, opponent, both decks'
|
||||
colours, who was on the play, the result, turns and length. Above the list are your win rate
|
||||
overall, for the last 10 and 100 games, for the last 7 days, and on the play and on the draw,
|
||||
plus average game length and turns.
|
||||
|
||||
- **Sort**: click a column header; click again to reverse.
|
||||
- **Filter**: right-click a cell to show only (or hide) games with that value, such as a deck,
|
||||
commander, event, opponent's colours or play/draw. Filters combine, appear as removable chips,
|
||||
and the stats follow them.
|
||||
- **Open a game**: click it to view it in the Match page as it ended, including turn-by-turn
|
||||
stats. *Back to live* returns to the current game.
|
||||
- Columns can be resized; games from the previous MTGA session (`Player-prev.log`) are imported
|
||||
on startup.
|
||||
|
||||
### Customization
|
||||
|
||||
- **⚙ Customize**: show or hide each panel of the Match page (You, Match, Opponent, Turn stats,
|
||||
My deck, Preview, Opponent's cards) and the details in the player panels. The menu stays open
|
||||
while you tick and untick.
|
||||
- **Customize → Arrange deck sections and turn stats…**: reorder (drag, or ↑/↓) and show/hide the
|
||||
My deck and Opponent sections and the turn stats.
|
||||
|
||||
All choices are remembered.
|
||||
|
||||
### Runs in the background
|
||||
|
||||
So that no game is missed, closing the window keeps the app running in the system tray (on
|
||||
Hyprland, Waybar's tray) and recording history. Quit from the tray menu, *☰ → Quit*, or Ctrl+Q.
|
||||
|
||||
- **Opens when MTGA starts**: the app watches MTGA's log folder using OS file notifications
|
||||
(inotify on Linux, ReadDirectoryChangesW on Windows) rather than polling. When MTGA launches it
|
||||
starts a fresh `Player.log`, and the window pops up. This works for Steam, Epic and standalone
|
||||
installs.
|
||||
- **One instance**: starting the app again shows the running copy instead of opening a second
|
||||
one.
|
||||
- **Start at login**: *☰ → Start at login (in the background)*. The installers can also set this
|
||||
up.
|
||||
|
||||
Both behaviours can be switched off in the ☰ menu.
|
||||
|
||||
## Requirements
|
||||
|
||||
Runs on **Linux** and **Windows**.
|
||||
|
||||
- **Detailed logs enabled** in MTGA: *Options → Account → Detailed Logs (Plugin Support)*.
|
||||
- MTGA's log, install folder and card database are auto-detected:
|
||||
- Linux: MTGA through Steam (Proton), found via your Steam library folders.
|
||||
- Windows: Steam, Epic Games or the standalone Wizards installer. The log is always in
|
||||
- **Detailed logs enabled in MTGA**: *Options → Account → Detailed Logs (Plugin Support)*.
|
||||
- **Python 3.12 or newer.** The installers check for it and offer to install it.
|
||||
- MTGA's log, install folder and card database are found automatically:
|
||||
- **Linux**: MTGA through Steam (Proton), found via your Steam library folders.
|
||||
- **Windows**: Steam, Epic Games or the standalone installer. The log is always in
|
||||
`%USERPROFILE%\AppData\LocalLow\Wizards Of The Coast\MTGA\Player.log`.
|
||||
- To run from source: [uv](https://docs.astral.sh/uv/) (`pacman -S uv` on Arch;
|
||||
`winget install astral-sh.uv` on Windows).
|
||||
|
||||
## Running
|
||||
## Installation
|
||||
|
||||
From source (any OS):
|
||||
### Linux
|
||||
|
||||
```sh
|
||||
uv run mtga-assistant # follow the live Player.log
|
||||
uv run mtga-assistant --replay path/to/Player-prev.log --rate 40 # replay a saved log
|
||||
uv run pytest # tests
|
||||
./install.sh
|
||||
```
|
||||
|
||||
On Windows you can instead use the packaged build: unzip `MTGA-Assistant-windows.zip` and run
|
||||
`MTGA Assistant.exe`.
|
||||
The installer:
|
||||
|
||||
Start it before or after MTGA: on startup it reads the existing log to catch up on a match in
|
||||
progress, then follows new lines. When MTGA restarts and replaces the log, the tracker resets.
|
||||
1. Checks for Python 3.12+, offering your distro's install command (pacman, apt, dnf or zypper)
|
||||
if it's missing.
|
||||
2. Installs the app and its dependencies into `~/.local/share/mtga-assistant/app`. No root is
|
||||
needed.
|
||||
3. Checks that Qt can start, and suggests the missing system packages if it can't.
|
||||
4. Installs the icon and a launcher, `~/.local/share/applications/mtga-assistant.desktop`, which
|
||||
starts the app with `--background`.
|
||||
5. Asks whether to start the app at login, then launches it.
|
||||
|
||||
### Linux desktop integration
|
||||
Run `./install.sh` again after pulling to update. `./install.sh --uninstall` removes the app and
|
||||
keeps your history and settings, and `--yes` answers every question with yes.
|
||||
|
||||
On Wayland the window's app id is `mtga-assistant`. For example, to keep it floating on another
|
||||
workspace in Hyprland:
|
||||
### Windows
|
||||
|
||||
1. Download this project (on the repository page: *Download ZIP*) and extract it.
|
||||
2. Double-click **`install.bat`**.
|
||||
|
||||
The installer checks for Python 3.12+ (offering to install it with winget), installs the
|
||||
dependencies into a private build folder, builds the app with PyInstaller, and installs it to
|
||||
`%LOCALAPPDATA%\Programs\MTGA Assistant` with Start Menu and Desktop shortcuts. No admin rights are
|
||||
needed. It asks whether to start the app at login, then launches it.
|
||||
|
||||
Run `install.bat` again to update after downloading a newer version. `install.bat -Uninstall`
|
||||
removes the app and keeps your history and settings.
|
||||
|
||||
## Usage
|
||||
|
||||
Start the app before or after MTGA. On startup it reads the existing log to catch up on a match in
|
||||
progress, then follows new lines. When MTGA restarts, the tracker resets for the new session.
|
||||
|
||||
| Shortcut | Action |
|
||||
|---|---|
|
||||
| Ctrl+1 / Ctrl+2 | Match / History |
|
||||
| Esc | Clear the card preview |
|
||||
| Ctrl+Q | Quit (closing the window only hides it) |
|
||||
|
||||
Command-line options: `--background` (start hidden), `--log PATH` and `--mtga-dir PATH` (override
|
||||
auto-detection), `--replay PATH [--rate N]` (replay a saved log, for testing).
|
||||
|
||||
**Hyprland**: the window's app id is `mtga-assistant`. For example, to keep it floating on another
|
||||
workspace:
|
||||
|
||||
```
|
||||
windowrule = float, class:^(mtga-assistant)$
|
||||
windowrule = workspace 2, class:^(mtga-assistant)$
|
||||
```
|
||||
|
||||
### Building the Windows app
|
||||
|
||||
PyInstaller can't cross-compile, so build on Windows (with uv installed):
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File packaging\build_windows.ps1
|
||||
```
|
||||
|
||||
This produces `dist\MTGA Assistant\MTGA Assistant.exe` and `dist\MTGA-Assistant-windows.zip`.
|
||||
The same spec builds a Linux bundle when run on Linux
|
||||
(`uv run --group build pyinstaller packaging/mtga-assistant.spec`). After editing
|
||||
`assets/icon.svg`, regenerate the icons with `uv run python packaging/make_icon.py`.
|
||||
|
||||
## Configuration
|
||||
|
||||
Optional `config.toml`:
|
||||
|
||||
| | Config file | History | Image cache |
|
||||
|---|---|---|---|
|
||||
| Linux | `~/.config/mtga-assistant/config.toml` | `~/.local/share/mtga-assistant/` | `~/.cache/mtga-assistant/` |
|
||||
| Windows | `%APPDATA%\mtga-assistant\config.toml` | `%LOCALAPPDATA%\mtga-assistant\` | `%LOCALAPPDATA%\mtga-assistant\Cache\` |
|
||||
Settings made in the app are saved automatically. An optional `config.toml` overrides
|
||||
auto-detection and limits:
|
||||
|
||||
```toml
|
||||
log_path = "/path/to/Player.log" # override auto-detection
|
||||
mtga_dir = "/path/to/MTGA" # the folder containing MTGA_Data
|
||||
cache_max_mb = 500 # image cache cap
|
||||
cache_max_mb = 500 # card image cache cap
|
||||
history_max_mb = 300 # cap for stored game details (summaries are always kept)
|
||||
```
|
||||
|
||||
Game history is stored in `history.db` (roughly 20–100 KB per game). On Windows the app reads a
|
||||
private copy of MTGA's card database (kept in the cache folder, about 260 MB) so that MTGA's
|
||||
updater is never blocked by the app holding the file open.
|
||||
| | Config file | History | Card image cache |
|
||||
|---|---|---|---|
|
||||
| Linux | `~/.config/mtga-assistant/config.toml` | `~/.local/share/mtga-assistant/history.db` | `~/.cache/mtga-assistant/images/` |
|
||||
| Windows | `%APPDATA%\mtga-assistant\config.toml` | `%LOCALAPPDATA%\mtga-assistant\history.db` | `%LOCALAPPDATA%\mtga-assistant\Cache\images\` |
|
||||
|
||||
## Image cache
|
||||
- **Card images** are downloaded from Scryfall only for cards that actually appear (about
|
||||
60–100 KB each). When the cache passes `cache_max_mb`, the least recently viewed images are
|
||||
deleted. *☰ → Clear image cache* empties it.
|
||||
- **History** takes roughly 20–100 KB per game. Past `history_max_mb`, the oldest games keep
|
||||
their row in the list but can no longer be opened.
|
||||
- **On Windows** the app reads a private copy of MTGA's card database (about 260 MB, in the cache
|
||||
folder), so MTGA's updater is never blocked by the app holding the file open.
|
||||
|
||||
Images are downloaded only for cards that actually appear, at Scryfall's `normal` size (about
|
||||
60–100 KB each), and stored in `~/.cache/mtga-assistant/images`. When the cache passes
|
||||
`cache_max_mb`, the least recently viewed images are deleted. *Cache → Clear image cache* empties it.
|
||||
## Development
|
||||
|
||||
```sh
|
||||
uv run mtga-assistant # run from the source tree
|
||||
uv run mtga-assistant --replay path/to/Player-prev.log --rate 40
|
||||
uv run pytest # tests
|
||||
```
|
||||
|
||||
- **Windows build without installing**: on Windows with [uv](https://docs.astral.sh/uv/),
|
||||
`powershell -ExecutionPolicy Bypass -File packaging\build_windows.ps1` produces
|
||||
`dist\MTGA Assistant\MTGA Assistant.exe` and `dist\MTGA-Assistant-windows.zip`. PyInstaller
|
||||
can't cross-compile, so this must run on Windows. On Linux, the same spec
|
||||
(`uv run --group build pyinstaller packaging/mtga-assistant.spec`) builds a Linux bundle.
|
||||
- **Icon**: the app icon comes from `images/mtga-assistant-icon.png`. After changing it, run
|
||||
`uv run python packaging/make_icon.py` to regenerate the Windows `.ico` and the copy bundled
|
||||
with the app.
|
||||
|
||||
## Known limitations
|
||||
|
||||
- MTGA leaves oversized game-state messages out of the log ("Message summarized because one or
|
||||
more GameStateMessages exceeded the 50 GameObject or 50 Annotation limit"), typically during board
|
||||
wipes. Some zones can then be stale until they next change. The app detects this and shows a
|
||||
warning.
|
||||
- After a library shuffle, a known card's position in the opponent's library is lost. It stays listed
|
||||
under "Library … known" until it shows up again. If it is drawn without being revealed, it may
|
||||
stay listed.
|
||||
- **Gaps in the log**: MTGA leaves oversized game-state messages out of the log ("Message
|
||||
summarized because one or more GameStateMessages exceeded the 50 GameObject or 50 Annotation
|
||||
limit"), typically during board wipes. Later messages usually fill the gap in. If some of your
|
||||
cards stay unaccounted for, the status bar shows "⚠ N of your cards not tracked" and library
|
||||
odds may be slightly off.
|
||||
- **Shuffled cards**: after a library shuffle, a known card's position in the opponent's library
|
||||
is lost. It stays listed under "Library … known" until it shows up again, so if it's drawn
|
||||
without being revealed it may stay listed.
|
||||
- **Inferred land drops**: the log doesn't say how many land plays are allowed. They're inferred
|
||||
from "additional land" effects in play, so conditional effects (e.g. "as long as you control an
|
||||
Elf") are always counted.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 673 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 690 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 818 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 711 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 643 KiB |
+1
-1
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "mtga-assistant"
|
||||
version = "0.1.0"
|
||||
description = "Native Linux deck and game tracker for MTG Arena, driven by Player.log"
|
||||
description = "Deck and game tracker for MTG Arena on Linux and Windows, driven by Player.log"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
|
||||
Reference in new issue
Block a user