CardExporter keeps Videre's MTGO card database and CDN assets in sync with Magic: The Gathering Online by extracting the MTGO client's local card data into PostgreSQL, card/product renders, and generated files for Cloudflare R2.
MTGO distributes the data CardExporter needs across several sources:
- card XML in the ClickOnce data directory;
- runtime client models used to fill gaps in set metadata;
- validation-rule files that describe format legalities; and
- WPF resources and client assemblies that contain symbols and other image assets.
CardExporter turns those sources into three forms of operating state:
- PostgreSQL records for cards, sets, products, faces, and legalities.
- Pending image work for new or changed card and product catalog IDs.
- Manifest files that track MTGO source inputs and generated CDN objects.
Each scheduled import first fetches Videre's MTGO version manifest and compares its codebase field with manifests/mtgo-version.json. When the codebase is unchanged, the run returns before checking local MTGO files, PostgreSQL, image work, or client assets. When it is new, changed, or temporarily unavailable, CardExporter falls back to the local manifests and database checks below.
The normal flow is:
MTGO source files ──> import ──> PostgreSQL
│ │
│ └─ new or changed image catalog IDs
└─ source-file manifest
catalog IDs ──> sync-images ──> Cloudflare R2 ──> CDN manifest
client assemblies ──> sync-assets ──> Cloudflare R2 ──> CDN manifest
manifests/mtgo-source-files.xml controls incremental import work:
- card-data changes trigger card, set, and product imports;
- validation-rule changes update legalities without requiring a full card import; and
- unchanged tracked inputs do not rewrite the database.
After an import identifies new or changed catalog IDs, image synchronization renders those IDs through the MTGO client. Successful uploads update CDN tracking. Failed uploads do not roll back the database import; the affected image work remains pending for a later sync-images run.
- Docker with Docker Compose
- Access to a shared
mtgo-dbPostgreSQL database - A valid MTGO account for commands that log into the client, render images, or read live runtime metadata
- Cloudflare R2 credentials for commands that upload files or list bucket contents
The container provides Wine, Xvfb, and the Windows .NET runtime required by the MTGO and WPF code paths. Linux dotnet can build the solution, but commands that load WPF resources or interact with MTGO should run through the image's wine-run alias.
Create .env in the repository root using the settings described in Configuration.
docker compose --profile import run --rm cardexporter \
dotnet build Project.slnxdocker compose --profile import run --rm cardexporter \
wine-run CardExporter/CardExporter.csproj import --sync-images --dry-runThe dry run checks the tracked inputs and reports planned work without changing PostgreSQL, R2, or either manifest.
docker compose --profile import run --rm cardexporter \
wine-run CardExporter/CardExporter.csproj import --sync-imagesCreate a .env file in the repository root.
# PostgreSQL
CARDEXPORTER_DATABASE_URL=Host=<mtgo-db-host>;Port=5432;Database=mtgo;Username=<user>;Password=<password>
# Cloudflare R2. Required by upload and bucket-reconciliation commands.
CF_S3_Access_Key_ID=...
CF_S3_Secret_Access_Key=...
R2_BUCKET_NAME=mtgo-cdn
R2_ENDPOINT_URL=https://<account-id>.r2.cloudflarestorage.com
R2_PUBLIC_BASE_URL=https://r2.videreproject.comCardExporter does not create or maintain permanent PostgreSQL tables. The catalog schema lives in mtgo-db; CardExporter only writes into those existing tables and creates temporary staging tables for each import transaction.
The Docker setup already supplies the default paths. Override them only when running against a different filesystem layout.
CARDEXPORTER_SOURCE_MANIFEST_ROOT=/workspace/manifests
CARDEXPORTER_MTGO_VERSION_MANIFEST_URL=https://api.videreproject.com/mtgo/manifest
CARDEXPORTER_CDN_MANIFEST=/workspace/manifests/mtgo-cdn.csv
CARDEXPORTER_MTGO_APP_DIR=/path/to/MTGO/app
CARDEXPORTER_MTGO_CACHE_ROOT=/path/to/MTGO/card/cache
EXPORT_OUTPUT_ROOT=/workspace/output
EXPORT_CARD_HEIGHT=300
CARDEXPORTER_ASSET_OUTPUT_ROOT=/workspace/output/assets| Command | Use it for | Primary side effects |
|---|---|---|
import |
Incremental card, set, product, and legality imports | PostgreSQL and source tracking; optional image/CDN work with --sync-images |
sync-images |
Rendering and uploading missing or pending card/product images | Local render output, R2, CDN tracking, and image-work state |
export-images |
Rendering selected card/product images for inspection | Local files only |
r2-manifest |
Rebuilding the local CDN manifest from the bucket | manifests/mtgo-cdn.csv |
r2-upload |
Uploading already-rendered local PNGs | R2 and CDN tracking |
sync-assets |
Extracting and publishing MTGO client assets | Generated asset files, R2, and CDN tracking |
export-mtgo-assets |
Extracting MTGO client assets without publishing them | Local files only |
inspect |
Investigating MTGO source data and parser behavior | Diagnostic output |
Import changed MTGO data into PostgreSQL.
docker compose --profile import run --rm cardexporter \
wine-run CardExporter/CardExporter.csproj importThe source-file manifest determines which import stages need to run. Add --sync-images when the same invocation should also process pending card/product image work and client-asset synchronization.
docker compose --profile import run --rm cardexporter \
wine-run CardExporter/CardExporter.csproj import --sync-imagesAdd --dry-run to report detected changes and planned work without mutating PostgreSQL, R2, or the manifest files.
Render and upload card or product catalog IDs that PostgreSQL expects but the CDN manifest does not yet track.
Use this command for:
- an initial image backfill;
- retrying uploads after a partial failure; or
- processing image work independently from a card-data import.
docker compose --profile import run --rm cardexporter \
wine-run CardExporter/CardExporter.csproj sync-imagesAdd --dry-run to list the missing IDs without rendering or uploading them.
Render card or product images to disk without uploading them. This is useful for checking output quality before a sync.
docker compose --profile import run --rm cardexporter \
wine-run CardExporter/CardExporter.csproj export-images --catalog-ids 57140Common filters and overrides:
--catalog-ids 57140
--set SOS
--card-height 300
--output-root output
List the R2 bucket and rebuild manifests/mtgo-cdn.csv from object metadata.
docker compose --profile import run --rm cardexporter \
wine-run CardExporter/CardExporter.csproj r2-manifestThis is a reconciliation and recovery command. Use it after a manual bucket migration or when the local CDN manifest must be reconstructed from R2. It does not render or upload files.
Upload local PNGs from --output-root. The CDN manifest is updated only for successful uploads.
docker compose --profile import run --rm cardexporter \
wine-run CardExporter/CardExporter.csproj r2-upload --output-root outputUse r2-upload when files have already been rendered locally and should be published without running the full image-synchronization flow.
Extract MTGO client assets and upload generated files whose SHA-256 differs from CDN tracking.
docker compose --profile import run --rm cardexporter \
wine-run CardExporter/CardExporter.csproj sync-assetsThe command publishes these prefixes:
card-counters/
mana-symbols/
player-counters/
set-symbols/
Extract MTGO symbols and client image assets to disk without uploading them.
docker compose --profile import run --rm cardexporter \
wine-run CardExporter/CardExporter.csproj export-mtgo-assetsFiles are written under output/assets/ unless --output-root or CARDEXPORTER_ASSET_OUTPUT_ROOT selects another directory.
Inspect the MTGO data directory while developing parsers or investigating individual source records.
docker compose --profile import run --rm cardexporter \
wine-run CardExporter/CardExporter.csproj inspect --find-catalog-id 57140CardExporter uses separate state for source detection, database work, and CDN publication.
manifests/mtgo-source-files.xml records tracked MTGO inputs by size, timestamp, and SHA-256. It is used to determine which import or asset stages need to run.
manifests/mtgo-version.json is the first import gate. It mirrors Videre's public MTGO version manifest, while the skip decision uses the manifest's codebase field. The file is written only after a successful run, so a failed import does not mark a changed MTGO codebase as handled.
The database records card and product catalog IDs added or changed by an import. R2 uploads for their respective renders are handled outside the database transaction, so a successful database import can be followed by a failed upload. In that case, the image remains pending and can be retried with sync-images or r2-upload in a separate invocation.
manifests/mtgo-cdn.csv stores CDN object metadata used by synchronization and upload commands, including object keys, public URLs, timestamps, content types, byte counts, and SHA-256 hashes.
Use r2-manifest when this local file must be rebuilt from the actual bucket contents.
manifests/mtgo-art-overrides.xml describes known MTGO art-cache repairs that must be applied before rendering affected card images. Most of these substitute artIDs from their reprints, with a handful of cards using scanned art from the original paper printings.
Files under output/ are staging artifacts. Export and synchronization commands recreate the files they need, so the directory can be discarded between runs unless its contents are awaiting a manual r2-upload.
The default public R2 base URL is:
https://r2.videreproject.com
Object keys follow these conventions:
cards/{catalogId}-300px.png
products/{catalogId}-300px.png
card-counters/{slug}.svg
player-counters/{slug}.png
set-symbols/{setCode}-{rarity}.png
mana-symbols/{symbol}.svg
Cards and products can share an MTGO catalog ID, so they use separate CDN prefixes.
CardExporter/
├── CardExporter/
│ ├── src/
│ │ ├── CLI/ # Command dispatch and command implementations
│ │ ├── Database/
│ │ │ ├── Postgres/ # Staging tables, copy writers, merge logic, image-work queries
│ │ │ └── R2/ # R2 client, CDN manifest, and object-key helpers
│ │ └── MTGO/
│ │ ├── Files/ # Source-file indexing and manifests
│ │ ├── Parsing/ # MTGO XML parsing and SDK normalization adapters
│ │ ├── Records/ # Card, set, face, legality, and product records
│ │ └── Rendering/ # Card rendering and client-asset extraction
│ └── CardExporter.csproj
├── manifests/ # Source, CDN, and art-override manifests
├── docker-compose.yml # Wine/MTGO runtime service
├── wine-entrypoint.sh # Wine audio and runtime setup
└── Project.slnx
Licensed under Apache-2.0.
This project is not affiliated with Wizards of the Coast or Daybreak Games.