diff --git a/lib/CardAPI.js b/lib/CardAPI.js index 39e8147..ed3f354 100644 --- a/lib/CardAPI.js +++ b/lib/CardAPI.js @@ -4,6 +4,7 @@ const Constants = require('./Constants') const Config = require('./Config') const Compressor = require('./Compressor') const TextParser = require('./TextParser') +const { parseScryfallCardTypeExtra, getCardMainTypes } = require('./util/GroupKeyByCardTypePriority'); function pad(num, size) { var s = num + ""; @@ -21,6 +22,7 @@ class CardAPI { resolve(lookup) } }) + self.fallbackCache = {} const config = Config(customConfig) window.fetch(`${config.apiUrl}/json/version.json`, { cache: "no-store" }) .then(resp => resp.json()) @@ -110,11 +112,38 @@ class CardAPI { imgUrl, } } + async getCardInfoFallback(cardName, config) { + const name = this.normalizeCardName(cardName, config) + let card = this.fallbackCache[name] + if (typeof card === 'undefined') { + card = await window.fetch(`https://api.scryfall.com/cards/named?exact=${cardName}`, { cache: "no-store" }) + .then(res => res.json()) + .then(sf => { + if (sf.object !== 'card' || !sf.set) { + throw new Error() + } + return { + name: sf.name, + setCode: sf.set, + cardNum: sf.collector_number, + mid: sf.multiverse_ids && sf.multiverse_ids[0], + types: getCardMainTypes(parseScryfallCardTypeExtra(sf.type_line)), + cmc: sf.cmc, + } + }) + .catch(e => { + return null + }) + this.fallbackCache[name] = card + } + return card + } getCardInfo(cardName, customConfig) { const self = this const config = Config(customConfig) return self.lookupPromise .then(lookup => self.performLookup(lookup, cardName, config)) + .then(card => (card !== null ? card : self.getCardInfoFallback(cardName, config))) .then(card => self.attachCardMetaData(cardName, card, config)) } getRandomCard(customConfig) { diff --git a/lib/util/GroupKeyByCardTypePriority.js b/lib/util/GroupKeyByCardTypePriority.js new file mode 100644 index 0000000..48b16b7 --- /dev/null +++ b/lib/util/GroupKeyByCardTypePriority.js @@ -0,0 +1,98 @@ + +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +const GROUP_CARD_TYPE_PRIORITY = ["Sorcery", "Instant", "Planeswalker", "Enchantment", "Artifact", "Creature", "Land"]; +const GROUP_CARD_TYPE_DISPLAY_PRIORITY = ["Commander", "Companion", "Creature", "Planeswalker", "Artifact", "Enchantment", "Instant", "Sorcery", "Land", "Sideboard", "Uncategorized"]; + +exports.EnumGroupCardType = void 0; + +(function (EnumGroupCardType) { + EnumGroupCardType["Sorcery"] = "Sorcery"; + EnumGroupCardType["Instant"] = "Instant"; + EnumGroupCardType["Planeswalker"] = "Planeswalker"; + EnumGroupCardType["Enchantment"] = "Enchantment"; + EnumGroupCardType["Artifact"] = "Artifact"; + EnumGroupCardType["Creature"] = "Creature"; + EnumGroupCardType["Land"] = "Land"; + EnumGroupCardType["Commander"] = "Commander"; + EnumGroupCardType["Uncategorized"] = "Uncategorized"; + EnumGroupCardType["Sideboard"] = "Sideboard"; + EnumGroupCardType["Companion"] = "Companion"; +})(exports.EnumGroupCardType || (exports.EnumGroupCardType = {})); + +var EnumRarity; + +(function (EnumRarity) { + EnumRarity["Common"] = "common"; + EnumRarity["Uncommon"] = "uncommon"; + EnumRarity["Rare"] = "rare"; + EnumRarity["Mythic"] = "mythic"; +})(EnumRarity || (EnumRarity = {})); + +function dfGroupArrayFieldByPriority(priority, defaultValue) { + return arrayValue => { + let returnValue = defaultValue; + arrayValue = [arrayValue].flat(); + priority.find(type => { + if (arrayValue.includes(type)) { + returnValue = type; + return true; + } + }); + return returnValue; + }; +} +function dfGroupFieldByPriority(priority, defaultValue) { + return inputValue => { + let returnValue = defaultValue; + priority.find(type => { + if (inputValue === type) { + returnValue = type; + return true; + } + }); + return returnValue; + }; +} + +const groupKeyByCardTypePriority = /*#__PURE__*/dfGroupArrayFieldByPriority(GROUP_CARD_TYPE_PRIORITY); + +exports.GROUP_CARD_TYPE_DISPLAY_PRIORITY = GROUP_CARD_TYPE_DISPLAY_PRIORITY; +exports.GROUP_CARD_TYPE_PRIORITY = GROUP_CARD_TYPE_PRIORITY; +exports.dfGroupArrayFieldByPriority = dfGroupArrayFieldByPriority; +exports.dfGroupFieldByPriority = dfGroupFieldByPriority; +exports.groupKeyByCardTypePriority = groupKeyByCardTypePriority; + +function array_unique(array){ + return array.filter(function(el, index, arr) { + return index == arr.indexOf(el); + }); +} + +function getCardMainTypes(types) { + let mainTypes = types.reduce((a, b) => { + a.push(...b[0]); + return a; + }, []); + return array_unique(mainTypes); +} + +function parseScryfallCardTypeExtra(type_line_en) { + return type_line_en.split(/\s*\/\/\s*/).map(parseScryfallCardType); +} + +function parseScryfallCardType(type_line_en) { + let ls = type_line_en.trim().split(/—/).filter(v => v.length); + + if (!ls.length || ls.length > 2) { + throw new SyntaxError(`Invalid card type: ${type_line_en}`); + } + + return ls.map(t => t.trim().split(/\s+/).filter(v => v.length)); +} + +exports.getCardMainTypes = getCardMainTypes +exports.parseScryfallCardTypeExtra = parseScryfallCardTypeExtra +exports.parseScryfallCardType = parseScryfallCardType diff --git a/package.json b/package.json index c86e5b4..ab5faf3 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "cron-code": "npm run build && node script/upload_code.js", "ci": "jest --watch", "test": "jest", - "build": "rm dist/*.js && browserify lib/index.js -t babelify -p tinyify > dist/autocard.js", + "build": "rimraf dist/*.js && browserify lib/index.js -t babelify -p tinyify > dist/autocard.js", "watch": "watchify lib/index.js -t babelify -o build/autocard.js --debug --verbose" }, "repository": { @@ -26,25 +26,22 @@ "url": "https://github.com/mpaulweeks/mtgify/issues" }, "homepage": "https://github.com/mpaulweeks/mtgify#readme", - "engines": { - "node": "10.16.0", - "npm": "6.9.0" - }, "devDependencies": { "babel-core": "^6.26.3", "babel-preset-stage-2": "^6.24.1", "babelify": "^8.0.0", "browserify": "^16.5.0", "jest": "^26.1.0", + "rimraf": "^3.0.2", "tinyify": "^2.5.2", "watchify": "^3.11.1" }, "dependencies": { - "@google-cloud/storage": "^5.1.2", + "@google-cloud/storage": "^5.16.1", "JSONStream": "^1.3.5", "event-stream": "^4.0.1", "natives": "^1.1.6", - "node-fetch": "^2.6.1", + "node-fetch": "^3.1.0", "unzip": "^0.1.11" }, "babel": {