Add find, refactor types
This commit is contained in:
parent
a2d9e5bcbc
commit
748cb12c2c
8 changed files with 1464 additions and 34 deletions
18
api.ts
18
api.ts
|
@ -1,6 +1,8 @@
|
|||
import { stringify } from "querystring";
|
||||
import { get } from "request";
|
||||
|
||||
import { Article } from "./types";
|
||||
|
||||
const URI = "https://api.cardmarket.com/ws/v2.0/output.json";
|
||||
|
||||
export default class CardMarketApi {
|
||||
|
@ -48,4 +50,20 @@ export default class CardMarketApi {
|
|||
);
|
||||
});
|
||||
}
|
||||
|
||||
async getAllArticles(uid: string): Promise<Article[]> {
|
||||
const perPage = 1000;
|
||||
let start = 0;
|
||||
let response;
|
||||
let data: Article[] = [];
|
||||
do {
|
||||
response = await this.get(`/users/${uid}/articles`, {
|
||||
start,
|
||||
maxResults: perPage
|
||||
});
|
||||
data = data.concat(response.article as Article[]);
|
||||
start += response.article.length;
|
||||
} while (response.article.length == perPage);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
|
16
convert.ts
16
convert.ts
|
@ -1,7 +1,10 @@
|
|||
import { existsSync } from "fs";
|
||||
|
||||
import { asyncLoadJSON, asyncSaveJSON } from "./utils";
|
||||
|
||||
interface JSONCard {
|
||||
mcmId: number;
|
||||
set: string;
|
||||
}
|
||||
|
||||
interface JSONSet {
|
||||
|
@ -11,12 +14,23 @@ interface JSONSet {
|
|||
type JSONDB = Record<string, JSONSet>;
|
||||
|
||||
async function run() {
|
||||
if (!existsSync("AllPrintings.json")) {
|
||||
console.error(
|
||||
"AllPrintings.json not found. Download from: https://www.mtgjson.com/files/AllPrintings.json"
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
console.info("Loading AllPrintings.json");
|
||||
const db = await asyncLoadJSON<JSONDB>("AllPrintings.json");
|
||||
let acc = {};
|
||||
for (const set in db) {
|
||||
db[set].cards.forEach(c => (acc[c.mcmId] = c));
|
||||
db[set].cards.forEach(c => {
|
||||
c.set = set;
|
||||
acc[c.mcmId] = c;
|
||||
});
|
||||
}
|
||||
asyncSaveJSON("mcmCards.json", acc);
|
||||
console.info("Saved converted info to mcmCards.json. You're ready to go!");
|
||||
}
|
||||
|
||||
run();
|
||||
|
|
34
fetch.ts
34
fetch.ts
|
@ -1,30 +1,5 @@
|
|||
import { existsSync } from "fs";
|
||||
|
||||
import CardMarketApi from "./api";
|
||||
import { asyncLoadJSON, asyncSaveJSON } from "./utils";
|
||||
|
||||
interface MCMCard {
|
||||
name: string;
|
||||
rarity: string;
|
||||
}
|
||||
|
||||
type MCMDB = Record<string, MCMCard>;
|
||||
|
||||
async function getAllArticles(api: CardMarketApi, uid: string) {
|
||||
const perPage = 1000;
|
||||
let start = 0;
|
||||
let response;
|
||||
let data = [];
|
||||
do {
|
||||
response = await api.get(`/users/${uid}/articles`, {
|
||||
start,
|
||||
maxResults: perPage
|
||||
});
|
||||
data = data.concat(response.article);
|
||||
start += response.article.length;
|
||||
} while (response.article.length == perPage);
|
||||
return data;
|
||||
}
|
||||
import { asyncSaveJSON } from "./utils";
|
||||
|
||||
async function run() {
|
||||
if (process.argv.length < 3) {
|
||||
|
@ -33,13 +8,8 @@ async function run() {
|
|||
return;
|
||||
}
|
||||
const uid = process.argv[2];
|
||||
if (!existsSync("mcmCards.json")) {
|
||||
console.error("Card db is missing! Run 'yarn convert-db' first.");
|
||||
process.exit(1);
|
||||
}
|
||||
let db = await asyncLoadJSON<MCMDB>("mcmCards.json");
|
||||
let api = new CardMarketApi();
|
||||
const articles = await getAllArticles(api, uid);
|
||||
const articles = await api.getAllArticles(uid);
|
||||
await asyncSaveJSON(`${uid}-cards.json`, articles);
|
||||
}
|
||||
|
||||
|
|
55
find.ts
Normal file
55
find.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
import { existsSync } from "fs";
|
||||
|
||||
import { Article, MCMDB } from "./types";
|
||||
import { asyncLoadJSON, asyncSaveJSON, leanArticle, leanCard } from "./utils";
|
||||
|
||||
async function run() {
|
||||
if (process.argv.length < 3) {
|
||||
console.error("Usage: yarn fetch <uid>");
|
||||
process.exit(1);
|
||||
return;
|
||||
}
|
||||
const uid = process.argv[2];
|
||||
const uidCards = `${uid}-cards.json`;
|
||||
if (!existsSync("mcmCards.json")) {
|
||||
console.error("Card db is missing! Run 'yarn convert-db' first.");
|
||||
process.exit(1);
|
||||
}
|
||||
if (!existsSync(uidCards)) {
|
||||
console.error(`Could not find ${uidCards}! Run 'yarn fetch ${uid}' first.`);
|
||||
process.exit(1);
|
||||
}
|
||||
let db = await asyncLoadJSON<MCMDB>("mcmCards.json");
|
||||
let articles = await asyncLoadJSON<Article[]>(`${uid}-cards.json`);
|
||||
|
||||
let cards = articles
|
||||
.filter(art => art.idProduct in db)
|
||||
.map(art => {
|
||||
const card = db[art.idProduct];
|
||||
return {
|
||||
...leanArticle(art),
|
||||
...leanCard(card)
|
||||
};
|
||||
});
|
||||
|
||||
let valid = cards.filter(
|
||||
c =>
|
||||
(c.language == "Italian" || c.language == "English") &&
|
||||
c.price <= 0.1 &&
|
||||
(c.rarity == "rare" || c.rarity == "mythic")
|
||||
);
|
||||
let netprice = valid.reduce((a, c) => (a += c.price), 0);
|
||||
console.log(
|
||||
`Found ${
|
||||
valid.length
|
||||
} cards (rare or mythic) <= € 0.10 (IT/EN), price to buy all: € ${netprice.toFixed(
|
||||
2
|
||||
)}.`
|
||||
);
|
||||
await asyncSaveJSON(
|
||||
`${uid}-filtered-cards.json`,
|
||||
valid.sort((a, b) => a.edhrecRank - b.edhrecRank)
|
||||
);
|
||||
}
|
||||
|
||||
run();
|
|
@ -7,7 +7,8 @@
|
|||
"license": "MIT",
|
||||
"scripts": {
|
||||
"fetch": "ts-node fetch.ts",
|
||||
"convert-db": "ts-node convert.ts"
|
||||
"init-db": "ts-node convert.ts",
|
||||
"find": "ts-node find.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": "^12.12.11",
|
||||
|
|
133
types.ts
Normal file
133
types.ts
Normal file
|
@ -0,0 +1,133 @@
|
|||
export interface ForeignData {
|
||||
flavorText: string;
|
||||
language: string;
|
||||
multiverseId: number;
|
||||
name: string;
|
||||
text: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface Legalities {
|
||||
commander: string;
|
||||
duel: string;
|
||||
legacy: string;
|
||||
modern: string;
|
||||
vintage: string;
|
||||
}
|
||||
|
||||
export interface Prices {
|
||||
mtgo: Record<string, number>;
|
||||
mtgoFoil: Record<string, number>;
|
||||
paper: Record<string, number>;
|
||||
paperFoil: Record<string, number>;
|
||||
}
|
||||
|
||||
export interface PurchaseUrls {
|
||||
cardmarket: string;
|
||||
tcgplayer: string;
|
||||
}
|
||||
|
||||
export interface MCMCard {
|
||||
artist: string;
|
||||
borderColor: string;
|
||||
colorIdentity: string[];
|
||||
colors: string[];
|
||||
convertedManaCost: number;
|
||||
edhrecRank: number;
|
||||
flavorText: string;
|
||||
foreignData: ForeignData[];
|
||||
frameVersion: string;
|
||||
hasFoil: boolean;
|
||||
hasNonFoil: boolean;
|
||||
isMtgo: boolean;
|
||||
isPaper: boolean;
|
||||
layout: string;
|
||||
legalities: Legalities;
|
||||
manaCost: string;
|
||||
mcmId: number;
|
||||
mcmMetaId: number;
|
||||
mtgoFoilId: number;
|
||||
mtgoId: number;
|
||||
multiverseId: number;
|
||||
name: string;
|
||||
number: string;
|
||||
originalText: string;
|
||||
originalType: string;
|
||||
power: string;
|
||||
prices: Prices;
|
||||
printings: string[];
|
||||
purchaseUrls: PurchaseUrls;
|
||||
rarity: string;
|
||||
rulings: any[];
|
||||
scryfallId: string;
|
||||
scryfallIllustrationId: string;
|
||||
scryfallOracleId: string;
|
||||
subtypes: string[];
|
||||
supertypes: any[];
|
||||
tcgplayerProductId: number;
|
||||
text: string;
|
||||
toughness: string;
|
||||
type: string;
|
||||
types: string[];
|
||||
uuid: string;
|
||||
set: string;
|
||||
}
|
||||
|
||||
export type MCMDB = Record<string, MCMCard>;
|
||||
|
||||
// Lighther version of MCMCard without a lot of useless information
|
||||
export interface LeanMCMCard {
|
||||
colorIdentity: string[];
|
||||
colors: string[];
|
||||
convertedManaCost: number;
|
||||
edhrecRank: number;
|
||||
manaCost: string;
|
||||
mcmId: number;
|
||||
name: string;
|
||||
rarity: string;
|
||||
scryfallId: string;
|
||||
subtypes: string[];
|
||||
supertypes: any[];
|
||||
text: string;
|
||||
type: string;
|
||||
types: string[];
|
||||
set: string;
|
||||
}
|
||||
|
||||
export interface Language {
|
||||
idLanguage: number;
|
||||
languageName: string;
|
||||
}
|
||||
|
||||
export interface Link {
|
||||
rel: string;
|
||||
href: string;
|
||||
method: string;
|
||||
action: string;
|
||||
idArticle?: number;
|
||||
}
|
||||
|
||||
export interface Article {
|
||||
idArticle: number;
|
||||
idProduct: number;
|
||||
language: Language;
|
||||
comments: string;
|
||||
price: number;
|
||||
count: number;
|
||||
inShoppingCart: boolean;
|
||||
condition: string;
|
||||
isFoil: boolean;
|
||||
isSigned: boolean;
|
||||
isPlayset: boolean;
|
||||
isAltered: boolean;
|
||||
links: Link[];
|
||||
}
|
||||
|
||||
export interface LeanArticle {
|
||||
idArticle: number;
|
||||
language: string;
|
||||
comments: string;
|
||||
price: number;
|
||||
count: number;
|
||||
condition: string;
|
||||
}
|
33
utils.ts
33
utils.ts
|
@ -1,5 +1,7 @@
|
|||
import { readFile, writeFile } from "fs";
|
||||
|
||||
import { Article, LeanArticle, LeanMCMCard, MCMCard } from "./types";
|
||||
|
||||
export async function asyncLoadJSON<T>(filename: string): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
readFile(filename, "utf8", (err, data) => {
|
||||
|
@ -24,3 +26,34 @@ export async function asyncSaveJSON(
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function leanCard(card: MCMCard): LeanMCMCard {
|
||||
return {
|
||||
colorIdentity: card.colorIdentity,
|
||||
colors: card.colors,
|
||||
convertedManaCost: card.convertedManaCost,
|
||||
edhrecRank: card.edhrecRank,
|
||||
manaCost: card.manaCost,
|
||||
mcmId: card.mcmId,
|
||||
name: card.name,
|
||||
rarity: card.rarity,
|
||||
scryfallId: card.scryfallId,
|
||||
subtypes: card.subtypes,
|
||||
supertypes: card.supertypes,
|
||||
text: card.text,
|
||||
type: card.type,
|
||||
types: card.types,
|
||||
set: card.set
|
||||
};
|
||||
}
|
||||
|
||||
export function leanArticle(article: Article): LeanArticle {
|
||||
return {
|
||||
idArticle: article.idArticle,
|
||||
language: article.language.languageName,
|
||||
comments: article.comments,
|
||||
price: article.price,
|
||||
count: article.count,
|
||||
condition: article.condition
|
||||
};
|
||||
}
|
||||
|
|
1206
yarn-error.log
Normal file
1206
yarn-error.log
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue