2019-11-21 16:59:49 +00:00
|
|
|
import * as ejs from "ejs";
|
|
|
|
import { existsSync } from "fs";
|
|
|
|
import { createServer } from "http";
|
|
|
|
|
2019-11-22 10:47:27 +00:00
|
|
|
import {
|
|
|
|
Article,
|
|
|
|
asyncLoadJSON,
|
|
|
|
CardItem,
|
|
|
|
dictMap,
|
|
|
|
filterDict,
|
|
|
|
leanArticle,
|
|
|
|
leanCard,
|
|
|
|
MCMDB,
|
|
|
|
onlyUnique,
|
|
|
|
spanBy,
|
|
|
|
} from "../lib";
|
2019-11-21 16:59:49 +00:00
|
|
|
|
|
|
|
const colorNames = {
|
|
|
|
CL: "Colorless",
|
|
|
|
MC: "Multicolor",
|
2019-11-22 10:47:27 +00:00
|
|
|
L: "Land",
|
2019-11-21 16:59:49 +00:00
|
|
|
W: "White",
|
|
|
|
U: "Blue",
|
|
|
|
B: "Black",
|
|
|
|
R: "Red",
|
|
|
|
G: "Green",
|
|
|
|
WU: "Azorius",
|
|
|
|
UB: "Dimir",
|
|
|
|
BR: "Rakdos",
|
|
|
|
RG: "Gruul",
|
|
|
|
WG: "Selesnya",
|
|
|
|
WB: "Orzhov",
|
|
|
|
UR: "Izzet",
|
|
|
|
BG: "Golgari",
|
|
|
|
WR: "Boros",
|
|
|
|
UG: "Simic",
|
|
|
|
WUG: "Bant",
|
|
|
|
WUB: "Esper",
|
|
|
|
UBR: "Grixis",
|
|
|
|
BRG: "Jund",
|
|
|
|
WRG: "Naya",
|
|
|
|
WBG: "Abzan",
|
|
|
|
WUR: "Jeskai",
|
|
|
|
UBG: "Sultai",
|
|
|
|
WBR: "Mardu",
|
|
|
|
URG: "Temur"
|
|
|
|
};
|
|
|
|
|
|
|
|
const columns: Record<string, (c: CardItem) => boolean> = {
|
2019-11-22 10:47:27 +00:00
|
|
|
W: c => c.types[0] != "Land" && colorid(c.colorIdentity) == "W",
|
|
|
|
U: c => c.types[0] != "Land" && colorid(c.colorIdentity) == "U",
|
|
|
|
B: c => c.types[0] != "Land" && colorid(c.colorIdentity) == "B",
|
|
|
|
R: c => c.types[0] != "Land" && colorid(c.colorIdentity) == "R",
|
|
|
|
G: c => c.types[0] != "Land" && colorid(c.colorIdentity) == "G",
|
|
|
|
MC: c => c.types[0] != "Land" && c.colorIdentity.length > 1,
|
|
|
|
CL: c => c.types[0] != "Land" && colorid(c.colorIdentity) == "CL",
|
|
|
|
L: c => c.types[0] == "Land"
|
2019-11-21 16:59:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
function wubrg(a: string, b: string) {
|
|
|
|
const order = ["W", "U", "B", "R", "G"];
|
|
|
|
const indexA = order.indexOf(a);
|
|
|
|
const indexB = order.indexOf(b);
|
|
|
|
return indexA - indexB;
|
|
|
|
}
|
|
|
|
|
|
|
|
function colorid(colors: string[]): string {
|
|
|
|
if (colors.length < 1) {
|
|
|
|
return "CL";
|
|
|
|
}
|
|
|
|
return colors.sort(wubrg).join("");
|
|
|
|
}
|
|
|
|
|
2019-11-22 10:47:27 +00:00
|
|
|
function prettyColor(color: string) {
|
|
|
|
if (color in colorNames) {
|
|
|
|
return colorNames[color];
|
|
|
|
}
|
|
|
|
return color;
|
|
|
|
}
|
|
|
|
|
|
|
|
const allTypes = [
|
|
|
|
"Creature",
|
|
|
|
"Planeswalker",
|
|
|
|
"Instant",
|
|
|
|
"Sorcery",
|
|
|
|
"Artifact",
|
|
|
|
"Enchantment"
|
|
|
|
];
|
|
|
|
function typeSort(a: string, b: string): number {
|
|
|
|
const indexA = allTypes.indexOf(a);
|
|
|
|
const indexB = allTypes.indexOf(b);
|
|
|
|
return indexA - indexB;
|
|
|
|
}
|
|
|
|
|
|
|
|
function abcSort(a: string, b: string): number {
|
|
|
|
if (a > b) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (b > a) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This would be properly typed but as of currently TS does not allow circular references for types
|
|
|
|
function deepSum(dict: any): number {
|
|
|
|
if (Array.isArray(dict)) {
|
|
|
|
return dict.length;
|
|
|
|
}
|
|
|
|
let total = 0;
|
|
|
|
for (let key in dict) {
|
|
|
|
if (Array.isArray(dict[key])) {
|
|
|
|
total += dict[key].length;
|
|
|
|
} else {
|
|
|
|
total += deepSum(dict[key]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return total;
|
|
|
|
}
|
|
|
|
|
2019-11-21 16:59:49 +00:00
|
|
|
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: CardItem[] = 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")
|
|
|
|
)
|
|
|
|
.filter(onlyUnique);
|
|
|
|
|
2019-11-22 10:47:27 +00:00
|
|
|
// Filter by colors and cmc (nested)
|
|
|
|
let colorcards = filterDict(valid, columns);
|
|
|
|
let cmccards = dictMap(colorcards, (cards, col) =>
|
|
|
|
dictMap(
|
|
|
|
spanBy(cards, c =>
|
|
|
|
col == "MC" || col == "L" ? colorid(c.colorIdentity) : c.types[0]
|
|
|
|
),
|
|
|
|
typed => spanBy(typed, c => c.convertedManaCost)
|
|
|
|
)
|
|
|
|
);
|
2019-11-21 16:59:49 +00:00
|
|
|
const server = createServer(async (req, res) => {
|
|
|
|
const template = await ejs.renderFile("templates/cube.ejs", {
|
|
|
|
user: uid,
|
|
|
|
cards: valid,
|
2019-11-22 10:47:27 +00:00
|
|
|
cmccards,
|
2019-11-21 16:59:49 +00:00
|
|
|
columns,
|
2019-11-22 10:47:27 +00:00
|
|
|
utils: { wubrg, prettyColor, colorid, deepSum, typeSort, abcSort }
|
2019-11-21 16:59:49 +00:00
|
|
|
});
|
|
|
|
res.end(template);
|
|
|
|
});
|
2019-11-22 10:47:27 +00:00
|
|
|
|
2019-11-21 16:59:49 +00:00
|
|
|
server.on("clientError", (err, socket) => {
|
|
|
|
socket.end("HTTP/1.1 400 Bad Request\r\n\r\n");
|
|
|
|
});
|
|
|
|
server.listen(8000);
|
|
|
|
}
|
|
|
|
|
|
|
|
run();
|