CardBndr

Download CardBndr for macOS

The fastest way to manage your Magic collection on macOS. Free & open source.

Requires macOS 13 Ventura or later · Universal binary (Apple Silicon & Intel supported) · Free & open source

System Requirements

macOS

  • macOS 13 Ventura or later
  • Apple Silicon or Intel processor
  • ~150 MB disk space

Windows

CardBndr is coming to Windows. Check back soon!

Coming Soon

Changelog

Release history and feature availability

v1.10.0

Vendor-agnostic refactor: complete metadata provider genericization

  • Price provider labels: consistent vendor-neutral display across all UI contexts (dialogs, dropdowns, history)
  • History cleanup: 83 legacy database records updated with generic terminology
  • Event filter translation: dropdown now shows human-readable labels (e.g. "Clear All Cards" vs "clear_all_cards")
  • Help infrastructure: frontmatter stripping removes YAML headers from documentation display
  • 23 files refactored; all API URLs and database schemas preserved for backward compatibility
View Release History

v1.9.2

Interim vendor branding removal (merged with v1.10.0)

  • Metadata API and Market Index labels introduced
  • SQL cleanup script created for historical record migration

v1.9.1

Contextual Help button in header bar

  • Help (?) IconButton added to header utility bar
  • Button dispatches to the correct guide based on the active tab (Database → search guide, Inventory → how-to, Collections → collection guide, History → keyboard shortcuts)
  • If the Settings dialog is open, the button shows the price-sync troubleshooting FAQ instead
  • HelpService powers BottomSheet with topic-switcher dropdown and selectable GitHub-flavoured Markdown

v1.9.0

Tech-debt phase 2: sync reliability, ETA, footer status, donation UI

  • Metadata API rate-limit handling with automatic retry after cooldown
  • ETA estimate in every sync status message (cooldown time excluded)
  • Footer shows live operation progress during background syncs
  • Set sync skips sets already present in mtg_cards (no more full re-sync on import)
  • Variant-prints sync scoped to newly added sets only
  • Chunk error log includes HTTP status code and reason string
  • About dialog: $5 / $10 / $20 preset + custom donation amount via PayPal
  • Brand logo updated to crkparrot_logo.png; new set icons added

v1.8.5

About dialog: preset + custom donation amounts

  • Replaced single PayPal button with $5 / $10 / $20 OutlinedButtons + custom TextField
  • Send icon button submits custom amount (also triggered by pressing Enter in the field)
  • _open_donation() appends ?amount=X&currency_code=USD to the PayPal URL
  • page passed into AboutDialogComponent so launch_url works for all buttons

v1.8.4

Retry failed chunks, ETA estimates, footer progress display

  • _fetch_metadata_bulk: failed (rate-limited) chunk IDs collected and retried after full main pass
  • Retry waits only as long as needed since last cooldown (max 60s total between passes)
  • ETA shown in every status message: chunk N/M (X updated, Y errors) — ~Xm Ys left
  • Cooldown pause includes ETA-after-resume estimate
  • Market Index fetch also gets ETA tracking and cooldown ETA message
  • Footer shows live operation status during any background sync
  • Footer reverts to tab record-count once the operation finishes

v1.8.3

Metadata API rate-limit cooldown + better retry backoff

  • fetch_collection: default retries raised to 4; backoff starts at 2s (2/4/8/16s)
  • _fetch_metadata_bulk: after 3 consecutive 503 chunks, pauses 60s to let the rate-limit window expire
  • _fetch_market_bulk: same streak-based 60s cooldown
  • Status bar shows "rate limit hit — pausing Xs" during cooldown

v1.8.2

Set sync: scope variant-prints to newly synced sets only

  • sync_sets now returns synced_set_codes (list of codes actually written this run)
  • run_sets_sync scopes get_distinct_oracle_ids to synced_set_codes + explicit_codes
  • If no new sets were found and no explicit codes, prints sync is skipped entirely

v1.8.1

Chunk error detail + set sync skip already-known sets

  • Metadata API and Market Index chunk errors now log HTTP status code and reason (e.g. HTTP 429 — Too Many Requests)
  • get_local_set_codes UNIONs mtg_cards.set_code so imported sets are never re-synced as new

v1.8.0

Table overhaul, Special editor, changelog sorting & price sort fixes

  • Special column: click-to-edit dialog replaces inline TextField; truncated display with full-text tooltip
  • Changelog in About dialog now auto-sorted newest-first by semantic version
  • Table horizontal scroll: ft.Row wrapper prevents column overlap on narrow windows
  • Column widths enforced: Type 110px, Special 90px, Price 85px, Total Value 85px, Location 140px
  • Type column: tooltip shows full type line; sort arrow integrated via col() helper
  • Table width set dynamically from page.width — fills full available space on resize
  • Price & Total Value sorting: NULL prices always sort last regardless of ASC/DESC direction
  • Sort state: self.sort_column tracking added to both InventoryView and DatabaseView
  • DatabaseView refactored into 4 mixins; all view files stay under 1,000 lines

v1.7.4

Fix: Finish validation in import no longer downgrades user-declared finish

  • Foil/etched finishes are now preserved even when Metadata API finishes list is 'nonfoil'-only
  • Prevents foil+normal copies from merging into a single normal row in _collapse_db_rows
  • Validation now warns in log but keeps the import-file finish (never silently demotes)
  • Added pre/post-validate debug_import trace log for every card in the import pipeline

v1.7.3

Root cause fix: finish leaked as 'normal' through _resolve_set_codes

  • _resolve_set_codes was rebuilding ImportedCard without finish=card.finish — every card defaulted to 'normal'
  • Added finish=card.finish to the ImportedCard constructor in _resolve_set_codes
  • Removed the silent finish='normal' guard that was masking the root cause
  • Added per-row debug log in CSV parser: raw condition → finish mapping

v1.7.1

CSV import: explicit finish matching, per-row error handling & etched fix

  • parse_csv_file now aggregates by (name, set_code, finish): Normal and Foil copies of the same card are kept as separate entries
  • Per-row try/except in CSV parser logs the exact row number on any unexpected parse error
  • File-not-found guard added to both import_xml_file_sync and import_csv_file_sync
  • Fixed etched cards merging with normal in staging table: etched encoded as foil=2 (distinct from normal foil=0)
  • migrate_legacy_cards_to_inventory correctly reconstructs etched finish from foil=2 sentinel
  • Import snack message now reads: 'Successfully imported X card(s). Y card(s) skipped due to errors.'

v1.7.0

History service, force_full_refresh & CSV BOM fix

  • New history_service.py with EVENT_MAP: raw event codes translated to human-readable labels in History tab
  • 'Clear All Cards' now records a clear_all_cards history event
  • force_full_refresh() method consolidates all post-import/clear refresh calls
  • CSV export now writes UTF-8 BOM (utf-8-sig) for Excel compatibility

v1.6.1

Fix startup AssertionError (Flet control UID bug)

  • Replaced table.columns = [...] with in-place .clear()/.extend() in all three table views
  • Replaced event_dropdown.options = [...] with in-place .clear()/.extend() in history view
  • Prevents Flet build_update_commands AssertionError on unmounted controls

v1.6.0

CSV Import & ImportService

  • ImportService moved to services/import_service.py (importer.py is now a compat shim)
  • CSV parser: maps Name, Set, Set Code, Collector Number, Rarity, Condition, Language, Quantity
  • Missing optional headers gracefully defaulted; missing Name column rejects file with log entry
  • Skipped rows (empty name, invalid quantity) logged to session.log via logger service
  • Import button shows format pre-dialog (XML / CSV) before opening file browser
  • Import dialog title and path hint update dynamically based on selected format
  • History event renamed xml_import → inventory_import (matches inventory_export)
  • Import worker now uses threading.Thread (no more silent page.run_thread swallowing)

v1.5.1

Export history event & file location fix

  • Export now records an 'inventory_export' event in the History tab
  • History tab refreshes automatically after export completes

v1.5.0

Inventory Export (XML & CSV)

  • New ExportService: export any inventory to XML or CSV
  • XML export: Magic Assistant–compatible structure (mirrors import format)
  • CSV export: flat format with Name, Set, Set Code, Collector Number, Rarity, Condition, Language, Quantity
  • Export dialog: format chooser (XML / CSV) via radio buttons
  • FilePicker save_file integration: user picks save location on disk
  • Export Inventory option added to inventory context menu
  • Export actions logged via logger.info (initiated / completed / failed)

v1.4.2

Safer Deletions with Verification Dialog

  • New VerificationDialog component: Requires typing 'cardbndr' to confirm dangerous actions
  • Integrated verification for 'Delete Inventory' and 'Clear All Cards' operations
  • Delete action logging: Records initiation, completion, and errors in session logs

v1.4.1

Export Debug Report Fix

  • Fixed Export Debug Report button: closes settings dialog before showing snack
  • Reveals exported zip in Finder/Explorer automatically after export

v1.4.0

Production-Grade Logging & Error Reporting

  • Central logger (logger_service.py): RotatingFileHandler 5MB × 3 backups
  • Log path: ~/.cardbndr/logs/session.log
  • Privacy: personal paths anonymised as <USER> in all log output
  • Panic Dialog: crash screen with Copy Debug Info + Open Log Folder buttons
  • Breadcrumb tracking: Database and Inventory searches logged with params
  • Advanced Filters dialog logs applied filter state
  • Settings: Export Debug Report button zips logs + system info to Desktop

v1.3.3

Logo Display Fix & UI Polish

  • Fixed logo display: Now uses absolute paths for reliable asset loading
  • Added changelog management: Version updates automatically reflect in About dialog

v1.3.2

Fixed price filter logic across inventory & database tabs

  • Finish-aware price fallback: foil-only cards now included in price filters
  • Database tab now displays high-value cards (€30,000+) correctly
  • Unified price selection logic with COALESCE fallbacks

v1.3.1

Inventory tab price filter fix

  • Foil-only Gaea's Cradle search fixed with finish-aware price columns

v1.3.0

Major UI/UX Overhaul

  • Preview Pane Refactoring: Split into fixed top section + scrollable printings grid
  • Centered Layout: All card info centered with 330px constrained width
  • Header Redesign: Single-row layout with logo, centered stats dashboard, utility buttons
  • Keyboard Shortcuts: Enter (apply filters), Page Up/Down (scroll), Home/End (jump), Escape (clear/close)
  • Set Icon Optimization: 24×24 sized icons, 4 per row, tight spacing (4px)

v1.0.0

Initial Release

  • Universal XML Importer: High-speed processing of 38k+ cards with physical-set priority.
  • Smart Collection Grouping: Collapses Normal/Foil duplicates in 8ED/9ED while preserving variants.
  • Advanced Card Preview: Shows all collector numbers/arts for cards like Leonardo da Vinci.
  • Corrected External Links: Fixed market links for Judge Promos and Gaea's Cradle.
  • Inventory Management: Right-click to clear cards without deleting the inventory.

Ready to bind your collection?

Get started in minutes. All your data stays on your Mac.

Download for macOS