Skip to content

Instantly share code, notes, and snippets.

@chadrien
Last active September 16, 2024 11:23
Show Gist options
  • Save chadrien/1b7a64edd8a60accf7c6ffe3e7800dc8 to your computer and use it in GitHub Desktop.
Save chadrien/1b7a64edd8a60accf7c6ffe3e7800dc8 to your computer and use it in GitHub Desktop.
CardCastle to Moxfield CSV converter
import Papa from 'papaparse';
import commandLineArgs from 'command-line-args';
import { readFileSync, writeFileSync } from 'fs';
import { Sets } from "scryfall-sdk";
const optionDefinitions = [
{ name: 'file', alias: 'f', type: String },
{ name: 'output', alias: 'o', type: String },
];
const options = commandLineArgs(optionDefinitions);
const condition = {
Mint: 'M',
'Near Mint': 'NM',
'Lightly Played': 'LP',
'Moderately Played': 'MP',
'Heavily Played': 'HP',
'Damaged': 'D',
}
const language = {
en: 'en',
sp: 'es',
fr: 'fr',
de: 'de',
it: 'it',
pt: 'pt',
jp: 'ja',
kr: 'ko',
ru: 'ru',
cs: 'zhs',
ct: 'zht',
ph: 'ph',
}
type CardCastleCsvRow = {
'Card Name': string;
'Set Name': string;
Condition: keyof typeof condition;
Foil: boolean;
Language: keyof typeof language;
}
type MoxfieldCsvRow = {
Count: number;
Name: string;
Edition: string;
Condition: (typeof condition)[keyof typeof condition];
Language: (typeof language)[keyof typeof language];
Foil: '' | 'foil';
}
async function cardCastleCsvRowToMoxfieldCsvRow(input: CardCastleCsvRow): Promise<MoxfieldCsvRow> {
return {
Count: 1,
Name: input['Card Name'],
Edition: await setNameToSetCode(input['Set Name']),
Condition: condition[input.Condition],
Language: language[input.Language],
Foil: input.Foil ? 'foil' : '',
}
}
async function setNameToSetCode(setName: string): Promise<string> {
return (await Sets.byName(setName)).code
}
async function main() {
const input = readFileSync(options.file, { encoding: 'utf8', flag: 'r' });
const result = Papa.parse(input, {
delimiter: ',',
header: true,
skipEmptyLines: true,
transform(value, field) {
if (field === 'Foil') {
return value === 'true'
}
return value
},
})
const mappedToMoxfield = (await Promise.all(
result.data
.map(async (row) => await cardCastleCsvRowToMoxfieldCsvRow(row as CardCastleCsvRow))
))
.reduce((acc, row) => {
const existingRow = acc.find((r) => r.Name === row.Name && r.Edition === row.Edition && r.Condition === row.Condition && r.Language === row.Language && r.Foil === row.Foil)
if (existingRow) {
existingRow.Count += 1
} else {
acc.push(row)
}
return acc
}, [] as MoxfieldCsvRow[])
const output = Papa.unparse(mappedToMoxfield, {
delimiter: ',',
header: true,
})
writeFileSync(options.output, output, { encoding: 'utf8', flag: 'w' });
process.exit(0)
}
main()
{
"name": "cardcastle-to-moxfield",
"main": "index.ts",
"dependencies": {
"command-line-args": "^6.0.0",
"papaparse": "^5.4.1",
"scryfall-sdk": "^5.0.2"
},
"devDependencies": {
"@types/command-line-args": "^5.2.3",
"@types/papaparse": "^5.3.14",
"ts-node": "^10.9.2",
"typescript": "^5.6.2"
}
}
{
"compilerOptions": {
"target": "es2016",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment