Skip to content

Instantly share code, notes, and snippets.

@muzzol
Last active October 16, 2025 11:03
Show Gist options
  • Select an option

  • Save muzzol/560383a4b99e3ac5e91c803dd516a704 to your computer and use it in GitHub Desktop.

Select an option

Save muzzol/560383a4b99e3ac5e91c803dd516a704 to your computer and use it in GitHub Desktop.
#!/bin/bash
### [email protected] # https://t.me/muzzol ###
### tool to export your MTGA collection on linux
### to sites like moxfield
#
# mtga-tracker-daemon is used to get IDs from MTGA
# scryfall/echomtg is used for scrapping card info
# some basic linux tools are used (it'll check)
#
### STEP-BY-STEP GUIDE
## mtga-tracker-daemon
# download from https://github.com/frcaton/mtga-tracker-daemon
# unpack and run mtga-tracker-daemon from inside bin dir
# I don't know why the author of the daemon suggests to install
# it as a service, but is not really need it and I don't like to
# have services running on my machine.
# wget https://github.com/frcaton/mtga-tracker-daemon/releases/download/1.0.8.1/mtga-tracker-daemon-Linux.tar.gz
# tar --one-top-level -xvzf mtga-tracker-daemon-Linux.tar.gz
# cd mtga-tracker-daemon-Linux/bin/
# ./mtga-tracker-daemon
#
# at this moment you should see a line similar to
# Listening for connections on http://localhost:6842/
#
# open a browser and go to http://localhost:6842/status
# take a look at processId. if value is -1 restart MTGA and after some
# seconds refresh your browser to see a number.
# go to your collection in MTGA (I'm not really sure if that's necessary but
# I always do it to remember last cards I added).
# go to http://localhost:6842/cards and you'll see a lot of items.
# grpId is the card identifier, owned is the amount you have.
# click on save (first button) and it'll create a cards.json file, so
# you're done with mtga-tracker-daemon. you can close the daemon (CTRL + C)
# and you can also close MTGA.
#
## file conversion
# use muz-mtga-export-json.sh to convert from cards.json to some
# formats. all formats are very similar but some pages need specific
# fields like Condition or Price that we can ignore as we import
# from Arena and not paper cards.
# download this script from github:
# wget https://gist.githubusercontent.com/muzzol/560383a4b99e3ac5e91c803dd516a704/raw/muz-mtga-export-json.sh
#
# Review the script!!! I could be a crypto scammer trying to steal
# your savings and give them to some orange dictator!!!
# make the script executable and run it like this
# chmod +x muz-mtga-export-json.sh
# ./muz-mtga-export-json.sh /path/to/cards.json
#
# now it'll take some time to check for all cards so relax and
# play some mono-red against those cute bloody chocobos
#
# once finished you'll see some new text files created.
#
# this script uses a cache file at ${HOME}/.cache/muz-mtga-export/muz-mtga-cache-cards.csv
# so it doesn't overload API site and it goes faster. You can run it several times
# and it'll try to find any new card. If you increased the amunt of a card
# you already own it'll update that too.
# if you find any problem you can just remove the cache file and run the script again.
#
## MOXFIELD collection
# go to https://moxfield.com/collection
# and click on More -> Import CSV
# search for your mtga-export-moxfield.csv file just created
# CSV Format should be Moxfield, Collection location should be Arena
# and I recomend using a binder to easily identify new imports.
# This step will ADD to your current collection, so if you already
# have cards, be carefull with duplicates.
# You'll probably see some errors because there's some discrepancies
# between echomtg and moxfield, just ignore them.
# Some fields are hardcoded like Condition (NM) and language (English)
# but it doesn't affect anything else.
# now that you have all your collection you can go to public decks
# https://moxfield.com/decks/public
# click on any deck and then click on Enable Collection
# It will show you which cards you already have.
#
# That's all, I use linux exclusively so I don't test it on Win or Mac.
# If you have any suggestion don't hesitate to contact me
# Happy tapping!!!
######################################################################
######################################################################
VER="0.4"
JSON_FILE="$1"
[ ! -e "$JSON_FILE" ] && echo "ERROR: missing json file" && echo "Ex: $0 cards.json" && exit 1
JSON_CONTENT=`cat "$JSON_FILE"`
# little check, json should contain at least 1 card
echo "$JSON_CONTENT" | jq -r '.cards[1]' > /dev/null
[ "$?" != "0" ] && echo "ERR: jason cards file [$JSON_FILE] doesn't seem valid" && exit 1
## we cache results to avoid unnecesary calls to scryfall
# API samples
# https://api.scryfall.com/cards/arena/75451
# https://api.echomtg.com/api/data/item/?emid=96614
CACHE_DIR="${HOME}/.cache/muz-mtga-export"
[ -e "$CACHE_DIR" ] || mkdir -vp "$CACHE_DIR"
CACHE_FILE="${CACHE_DIR}/muz-mtga-cache-cards.csv"
OUT_CSV="mtga-export.csv"
OUT_TXT="mtga-export.txt"
OUT_MF="mtga-export-moxfield.csv"
OUT_ERRORS="mtga-export-errors.txt"
### STANDARD PACKAGES REQUIREMENTS
REQS="bash jq curl"
# checks: packages, files
checks(){
for r in $REQS ; do
type "$r" > /dev/null
if [ "$?" != "0" ]; then
echo "ERR: can't find [$r]"
exit 1
fi
done
for o in "$OUT_CSV" "$OUT_TXT" "$OUT_ERRORS" ; do
if [ -e "$o" ]; then
echo "WARNING: file $o found"
echo "move it or delete it before launching this tool"
exit 1
fi
done
# initialize moxfield file
echo '"Count","Name","Edition","Condition","Language","Foil","Collector Number","Alter","Playtest Card","Purchase Price"' > "$OUT_MF"
}
checks
# we show some info
echo "`date` - $0 - muz MTGA export tool $VER"
echo "INF: using cache file [$CACHE_FILE]"
parse_json(){
J_IDS=`echo "$JSON_CONTENT" | jq -r '.cards[] | "\(.grpId);\(.owned)"' | sort`
# counter
IDS_TOTAL=`echo "$J_IDS" | wc -l`
COUNTER="0"
for j in $J_IDS ; do
# sleep 0.3
((COUNTER++))
CARD_ID=`echo "$j" | cut -d";" -f1`
CARD_NUMBER=`echo "$j" | cut -d";" -f2`
echo -n "INF: [`printf '%04d' ${COUNTER}`/${IDS_TOTAL}] checking card id [$CARD_ID]: "
# checking cache file
CACHE_FULL=`cat "$CACHE_FILE" 2> /dev/null | grep "^${j};"`
# echo "DEBUG: CACHE_FULL [$CACHE_FULL]"
if [ "$CACHE_FULL" == "" ]; then
echo "NEW CARDS"
echo -n "INF: getting card details - "
# CARD_FULL=`curl -s "https://api.scryfall.com/cards/arena/${CARD_ID}"`
CARD_FULL=`curl -s "https://api.echomtg.com/api/data/item/?emid=${CARD_ID}"`
# echo "DEBUG: CARD_FULL [$CARD_FULL]"
# echomtg uses [.card_name] - scryfall uses [.name]
CARD_NAME=`echo "$CARD_FULL" | jq -r ".card_name // .name // empty"`
# echomtg uses [.set_code] - scryfall uses [.set]
CARD_SET=`echo "$CARD_FULL" | jq -r ".set_code // .set // empty"`
if [ "$CARD_NAME" == "" ]; then
echo "no name found"
echo "ERR: card details not found"
if [ ! -e "$OUT_ERRORS" ]; then
echo "# CARDS NOT FOUND. CHECK SCRYFALL/ECHOMTG" > "$OUT_ERRORS"
fi
echo "CARD_ID:$CARD_ID" >> "$OUT_ERRORS"
continue
fi
echo "$CARD_ID - $CARD_NUMBER x $CARD_NAME ($CARD_SET)"
# we remove old info if found and save on cache
sed -i "/^${CARD_ID};/d" "$CACHE_FILE" 2> /dev/null
echo "${j};$CARD_NAME;$CARD_SET" >> "$CACHE_FILE"
else
echo "Cached - $CACHE_FULL"
CARD_NAME=`echo "$CACHE_FULL" | cut -d";" -f3`
CARD_SET=`echo "$CACHE_FULL" | cut -d";" -f4`
fi
echo "${CACHE_FULL}" >> "$OUT_CSV"
echo "${CARD_NUMBER} ${CARD_NAME}" >> "$OUT_TXT"
echo "\"${CARD_NUMBER}\",\"${CARD_NAME}\",\"${CARD_SET}\",\"NM\",\"English\",\"\",\"1\",\"\",\"\"," >> "$OUT_MF"
# read a
done
}
parse_json "$JSON_FILE"
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment