Example #1
0
def add_card_to_referral_map(card: MTGJSONCard) -> None:
    """
    Given a card, add it to MTGJSON proprietary referral map
    :param card: Card to add to map
    """
    # TCGPlayer
    if card.get("tcgplayerProductId", None):
        key_tcg = mtgjson4.util.url_keygen(card.get("tcgplayerProductId"))
        outputter.write_referral_url_information(
            {key_tcg: card.get_tcgplayer_url()})

    # MTGStocks
    if card.get("mtgstocksId", None):
        key_stocks = mtgjson4.util.url_keygen(
            int(str(card.get("mtgstocksId")) + mtgjson4.MTGSTOCKS_BUFFER))
        outputter.write_referral_url_information(
            {key_stocks: card.get_mtg_stocks_url()})

    # CardMarket
    if card.get("mcmId", None):
        key_mkm = mtgjson4.util.url_keygen(
            int(
                str(card.get("mcmId")) + mtgjson4.CARD_MARKET_BUFFER +
                str(card.get("mcmMetaId"))))
        outputter.write_referral_url_information(
            {key_mkm: card.get_card_market_url()})
Example #2
0
def add_card_to_referral_map(card: MTGJSONCard) -> None:
    """
    Given a card, add it to MTGJSON proprietary referral map
    :param card: Card to add to map
    """
    # TCGPlayer
    if card.get("tcgplayerProductId", None):
        key_tcg = mtgjson4.util.url_keygen(card.get("tcgplayerProductId"))
        outputter.write_referral_url_information({key_tcg: card.get_tcgplayer_url()})

    # MTGStocks
    if card.get("mtgstocksId", None):
        key_stocks = mtgjson4.util.url_keygen(
            int(str(card.get("mtgstocksId")) + mtgjson4.MTGSTOCKS_BUFFER)
        )
        outputter.write_referral_url_information(
            {key_stocks: card.get_mtg_stocks_url()}
        )

    # CardMarket
    if card.get("mcmId", None):
        key_mkm = mtgjson4.util.url_keygen(
            int(
                str(card.get("mcmId"))
                + mtgjson4.CARD_MARKET_BUFFER
                + str(card.get("mcmMetaId"))
            )
        )
        outputter.write_referral_url_information({key_mkm: card.get_card_market_url()})
Example #3
0
def test_uuid_creation(mock_card: Dict[str, Any],
                       mock_file_info: Dict[str, Any]) -> None:
    """
    Tests to ensure UUIDs don't regress
    :param mock_card:
    :param mock_file_info:
    :return:
    """
    card = MTGJSONCard(mock_file_info["code"])
    card.set_all(mock_card)

    uuid_new = card.get_uuid()
    assert uuid_new == "4b560297-2f1e-5f65-b118-289c21bdf887"
Example #4
0
def test_uuid_creation(
    mock_card: Dict[str, Any], mock_file_info: Dict[str, Any]
) -> None:
    """
    Tests to ensure UUIDs don't regress
    :param mock_card:
    :param mock_file_info:
    :return:
    """
    card = MTGJSONCard(mock_file_info["code"])
    card.set_all(mock_card)

    uuid_new = card.get_uuid()
    assert uuid_new == "4b560297-2f1e-5f65-b118-289c21bdf887"
Example #5
0
def build_mtgjson_card(sf_card: Dict[str, Any],
                       sf_card_face: int = 0) -> List[MTGJSONCard]:
    """
    Build a mtgjson card (and all sub pieces of that card)
    :param sf_card: Card to build
    :param sf_card_face: Which part of the card (defaults to 0)
    :return: List of card(s) build (usually 1)
    """
    mtgjson_cards: List[MTGJSONCard] = []
    single_card = MTGJSONCard(sf_card["set"])

    # Let us know what card we're trying to parse -- good for debugging :)
    LOGGER.info("Parsing {0} from {1}".format(sf_card.get("name"),
                                              sf_card.get("set")))

    # If flip-type, go to card_faces for alt attributes
    face_data: Dict[str, Any] = sf_card

    if "card_faces" in sf_card:
        single_card.set_all({
            "names":
            sf_card["name"].split(" // "),
            "scryfallId":
            sf_card["id"],
            "scryfallOracleId":
            sf_card["oracle_id"],
            "scryfallIllustrationId":
            sf_card.get("illustration_id"),
        })
        face_data = sf_card["card_faces"][sf_card_face]

        # Split cards and rotational cards have this field, flip cards do not.
        # Remove rotational cards via the additional check
        if "mana_cost" in sf_card and "//" in sf_card["mana_cost"]:
            single_card.set(
                "colors",
                get_card_colors(
                    sf_card["mana_cost"].split(" // ")[sf_card_face]),
            )
            single_card.set(
                "faceConvertedManaCost",
                get_cmc(
                    sf_card["mana_cost"].split("//")[sf_card_face].strip()),
            )
        elif sf_card["layout"] in ["split", "transform", "aftermath"]:
            # Handle non-normal cards, as they'll a face split
            single_card.set(
                "faceConvertedManaCost",
                get_cmc(face_data.get("mana_cost", "0").strip()),
            )

        # Watermark is only attributed on the front side, so we'll account for it
        single_card.set(
            "watermark",
            sf_card["card_faces"][0].get("watermark", None),
            single_card.clean_up_watermark,
        )

        if sf_card["card_faces"][-1]["oracle_text"].startswith("Aftermath"):
            single_card.set("layout", "aftermath")

        single_card.set("artist",
                        sf_card["card_faces"][sf_card_face].get("artist", ""))

        # Recursively parse the other cards within this card too
        # Only call recursive if it is the first time we see this card object
        if sf_card_face == 0:
            for i in range(1, len(sf_card["card_faces"])):
                LOGGER.info("Parsing additional card {0} face {1}".format(
                    sf_card.get("name"), i))
                mtgjson_cards += build_mtgjson_card(sf_card, i)
    else:
        single_card.set_all({
            "scryfallId":
            sf_card.get("id"),
            "scryfallOracleId":
            sf_card["oracle_id"],
            "scryfallIllustrationId":
            sf_card.get("illustration_id"),
        })

    # Characteristics that can are not shared to both sides of flip-type cards
    if face_data.get("mana_cost"):
        single_card.set("manaCost", face_data.get("mana_cost"))

    if "colors" not in single_card.keys():
        if "colors" in face_data:
            single_card.set("colors", face_data.get("colors"))
        else:
            single_card.set("colors", sf_card.get("colors"))

    single_card.set_all({
        "borderColor": sf_card.get("border_color"),
        "colorIdentity": sf_card.get("color_identity"),
        "convertedManaCost": sf_card.get("cmc"),
        "frameEffect": sf_card.get("frame_effect"),
        "frameVersion": sf_card.get("frame"),
        "hand": sf_card.get("hand_modifier"),
        "hasFoil": sf_card.get("foil"),
        "hasNonFoil": sf_card.get("nonfoil"),
        "isFullArt": sf_card.get("full_art"),
        "isOnlineOnly": sf_card.get("digital"),
        "isOversized": sf_card.get("oversized"),
        "isPromo": sf_card.get("promo"),
        "isReprint": sf_card.get("reprint"),
        "isReserved": sf_card.get("reserved"),
        "isStorySpotlight": sf_card.get("story_spotlight"),
        "isTextless": sf_card.get("textless"),
        "life": sf_card.get("life_modifier"),
        "loyalty": face_data.get("loyalty"),
        "name": face_data.get("name"),
        "number": sf_card.get("collector_number"),
        "power": face_data.get("power"),
        "tcgplayerProductId": sf_card.get("tcgplayer_id"),
        "text": face_data.get("oracle_text"),
        "toughness": face_data.get("toughness"),
        "type": face_data.get("type_line"),
    })

    # Set MKM IDs if it exists
    if MKM_API.get(None):
        mkm_card_found = False
        for key, mkm_obj in MKM_SET_CARDS.get().items():
            if single_card.get("name").lower() not in key:
                continue

            if "number" not in mkm_obj.keys() or (
                    mkm_obj.get("number") in single_card.get("number")):
                single_card.set_all({
                    "mcmId": mkm_obj["idProduct"],
                    "mcmMetaId": mkm_obj["idMetaproduct"],
                })
                single_card.set_mkm_url(mkm_obj["website"])
                mkm_card_found = True
                break

        if not mkm_card_found:
            LOGGER.warning("Unable to find MKM information for #{} {}".format(
                single_card.get("number"), single_card.get("name")))

    if "artist" not in single_card.keys():
        single_card.set("artist", sf_card.get("artist"))

    if "layout" not in single_card.keys():
        single_card.set("layout", sf_card.get("layout"))

    if "watermark" not in single_card.keys():
        single_card.set(
            "watermark",
            face_data.get("watermark", None),
            single_card.clean_up_watermark,
        )

    # "isPaper", "isMtgo", "isArena"
    for game_mode in sf_card.get("games", []):
        single_card.set("is{}".format(game_mode.capitalize()), True)

    if "flavor_text" in face_data:
        single_card.set("flavorText", face_data.get("flavor_text"))
    else:
        single_card.set("flavorText", sf_card.get("flavor_text"))

    if "color_indicator" in face_data:
        single_card.set("colorIndicator", face_data.get("color_indicator"))
    elif "color_indicator" in sf_card:
        single_card.set("colorIndicator", sf_card.get("color_indicator"))

    try:
        single_card.set("multiverseId",
                        sf_card["multiverse_ids"][sf_card_face])
    except IndexError:
        try:
            single_card.set("multiverseId", sf_card["multiverse_ids"][0])
        except IndexError:
            single_card.set("multiverseId", None)

    # Add a "side" entry for split cards
    # Will only work for two faced cards (not meld, as they don't need this)
    if "names" in single_card.keys() and single_card.names_count(2):
        # chr(97) = 'a', chr(98) = 'b', ...
        single_card.set(
            "side",
            chr(single_card.get("names").index(single_card.get("name")) + 97))

    # Characteristics that we have to format ourselves from provided data
    single_card.set(
        "isTimeshifted",
        (sf_card.get("frame") == "future") or (sf_card.get("set") == "tsb"),
    )

    single_card.set("rarity", sf_card.get("rarity"))

    # Characteristics that we need custom functions to parse
    print_search_url: str = sf_card["prints_search_uri"].replace("%22", "")
    single_card.set("legalities",
                    scryfall.parse_legalities(sf_card["legalities"]))
    single_card.set(
        "rulings",
        sorted(
            scryfall.parse_rulings(sf_card["rulings_uri"]),
            key=lambda ruling: ruling["date"],
        ),
    )
    single_card.set("printings",
                    sorted(scryfall.parse_printings(print_search_url)))

    card_types: Tuple[List[str], List[str],
                      List[str]] = scryfall.parse_card_types(
                          single_card.get("type"))
    single_card.set("supertypes", card_types[0])
    single_card.set("types", card_types[1])
    single_card.set("subtypes", card_types[2])

    # Handle meld and all parts tokens issues
    # Will re-address naming if a split card already
    if "all_parts" in sf_card:
        meld_holder = []
        single_card.set("names", [])
        for a_part in sf_card["all_parts"]:
            if a_part["component"] != "token":
                if "//" in a_part.get("name"):
                    single_card.set("names", a_part.get("name").split(" // "))
                    break

                # This is a meld only-fix, so we ignore tokens/combo pieces
                if "meld" in a_part["component"]:
                    meld_holder.append(a_part["component"])

                    single_card.append("names", a_part.get("name"))

        # If the only entry is the original card, empty the names array
        if single_card.names_count(1) and single_card.get(
                "name") in single_card.get("names"):
            single_card.remove("names")

        # Meld cards should be CardA, Meld, CardB. This fixes that via swap
        # meld_holder

        if meld_holder and meld_holder[1] != "meld_result":
            single_card.get("names")[1], single_card.get("names")[2] = (
                single_card.get("names")[2],
                single_card.get("names")[1],
            )

    # Since we built meld cards later, we will add the "side" attribute now
    if single_card.names_count(3):  # MELD
        if single_card.get("name") == single_card.get("names")[0]:
            single_card.set("side", "a")
        elif single_card.get("name") == single_card.get("names")[2]:
            single_card.set("side", "b")
        else:
            single_card.set("side", "c")

    # Characteristics that we cannot get from Scryfall
    # Characteristics we have to do further API calls for
    single_card.set(
        "foreignData",
        scryfall.parse_foreign(
            print_search_url,
            single_card.get("name"),
            single_card.get("number"),
            sf_card["set"],
        ),
    )

    if single_card.get("multiverseId") is not None:
        gatherer_cards = gatherer.get_cards(single_card.get("multiverseId"),
                                            single_card.set_code)
        try:
            gatherer_card = gatherer_cards[sf_card_face]
            single_card.set("originalType", gatherer_card.original_types)
            single_card.set("originalText", gatherer_card.original_text)
        except IndexError:
            LOGGER.warning("Unable to parse originals for {}".format(
                single_card.get("name")))

    mtgjson_cards.append(single_card)
    return mtgjson_cards
Example #6
0
def build_mtgjson_tokens(sf_tokens: List[Dict[str, Any]],
                         sf_card_face: int = 0) -> List[MTGJSONCard]:
    """
    Convert Scryfall tokens to MTGJSON tokens
    :param sf_tokens: All tokens in a set
    :param sf_card_face: Faces of the token index
    :return: List of MTGJSON tokens
    """
    token_cards: List[MTGJSONCard] = []

    for sf_token in sf_tokens:
        token_card = MTGJSONCard(sf_token["set"])

        if "card_faces" in sf_token:
            token_card.set("names", sf_token["name"].split(" // "))
            face_data = sf_token["card_faces"][sf_card_face]

            # Prevent duplicate UUIDs for split card halves
            # Remove the last character and replace with the id of the card face
            token_card.set("scryfallId", sf_token["id"])
            token_card.set("scryfallOracleId", sf_token["oracle_id"])
            token_card.set("scryfallIllustrationId",
                           sf_token.get("illustration_id"))

            # Recursively parse the other cards within this card too
            # Only call recursive if it is the first time we see this card object
            if sf_card_face == 0:
                for i in range(1, len(sf_token["card_faces"])):
                    LOGGER.info("Parsing additional card {0} face {1}".format(
                        sf_token.get("name"), i))
                    token_cards += build_mtgjson_tokens([sf_token], i)

            if "id" not in sf_token.keys():
                LOGGER.info(
                    "Scryfall_ID not found in {}. Discarding {}".format(
                        sf_token.get("name"), sf_token))
                continue

            token_card.set_all({
                "name":
                face_data.get("name"),
                "type":
                face_data.get("type_line"),
                "text":
                face_data.get("oracle_text"),
                "power":
                face_data.get("power"),
                "colors":
                face_data.get("colors"),
                "colorIdentity":
                sf_token.get("color_identity"),
                "toughness":
                face_data.get("toughness"),
                "loyalty":
                face_data.get("loyalty"),
                "watermark":
                sf_token.get("watermark"),
                "scryfallId":
                sf_token["id"],
                "scryfallOracleId":
                sf_token.get("oracle_id"),
                "scryfallIllustrationId":
                sf_token.get("illustration_id"),
                "layout":
                "double_faced_token",
                "side":
                chr(97 + sf_card_face),
                "borderColor":
                face_data.get("border_color"),
                "artist":
                face_data.get("artist"),
                "isOnlineOnly":
                sf_token.get("digital"),
                "number":
                sf_token.get("collector_number"),
            })
        else:
            token_card.set_all({
                "name":
                sf_token.get("name"),
                "type":
                sf_token.get("type_line"),
                "text":
                sf_token.get("oracle_text"),
                "power":
                sf_token.get("power"),
                "colors":
                sf_token.get("colors"),
                "colorIdentity":
                sf_token.get("color_identity"),
                "toughness":
                sf_token.get("toughness"),
                "loyalty":
                sf_token.get("loyalty"),
                "watermark":
                sf_token.get("watermark"),
                "scryfallId":
                sf_token["id"],
                "scryfallOracleId":
                sf_token.get("oracle_id"),
                "scryfallIllustrationId":
                sf_token.get("illustration_id"),
                "borderColor":
                sf_token.get("border_color"),
                "artist":
                sf_token.get("artist"),
                "isOnlineOnly":
                sf_token.get("digital"),
                "number":
                sf_token.get("collector_number"),
            })

            if sf_token.get("layout") == "token":
                token_card.set("layout", "normal")
            else:
                token_card.set("layout", sf_token.get("layout"))

        reverse_related: List[str] = []
        if "all_parts" in sf_token:
            for a_part in sf_token["all_parts"]:
                if a_part.get("name") != token_card.get("name"):
                    reverse_related.append(a_part.get("name"))
        token_card.set("reverseRelated", reverse_related)

        LOGGER.info("Parsed {0} from {1}".format(token_card.get("name"),
                                                 sf_token.get("set")))
        token_cards.append(token_card)

    return token_cards
Example #7
0
def build_mtgjson_card(
    sf_card: Dict[str, Any], sf_card_face: int = 0
) -> List[MTGJSONCard]:
    """
    Build a mtgjson card (and all sub pieces of that card)
    :param sf_card: Card to build
    :param sf_card_face: Which part of the card (defaults to 0)
    :return: List of card(s) build (usually 1)
    """
    mtgjson_cards: List[MTGJSONCard] = []
    single_card = MTGJSONCard(sf_card["set"])

    # Let us know what card we're trying to parse -- good for debugging :)
    LOGGER.info("Parsing {0} from {1}".format(sf_card.get("name"), sf_card.get("set")))

    # If flip-type, go to card_faces for alt attributes
    face_data: Dict[str, Any] = sf_card

    if "card_faces" in sf_card:
        single_card.set_all(
            {
                "names": sf_card["name"].split(" // "),
                "scryfallId": sf_card["id"],
                "scryfallOracleId": sf_card["oracle_id"],
                "scryfallIllustrationId": sf_card.get("illustration_id"),
            }
        )
        face_data = sf_card["card_faces"][sf_card_face]

        # Split cards and rotational cards have this field, flip cards do not.
        # Remove rotational cards via the additional check
        if "mana_cost" in sf_card and "//" in sf_card["mana_cost"]:
            single_card.set(
                "colors",
                get_card_colors(sf_card["mana_cost"].split(" // ")[sf_card_face]),
            )
            single_card.set(
                "faceConvertedManaCost",
                get_cmc(sf_card["mana_cost"].split("//")[sf_card_face].strip()),
            )
        elif sf_card["layout"] in ["split", "transform", "aftermath"]:
            # Handle non-normal cards, as they'll a face split
            single_card.set(
                "faceConvertedManaCost",
                get_cmc(face_data.get("mana_cost", "0").strip()),
            )

        # Watermark is only attributed on the front side, so we'll account for it
        single_card.set(
            "watermark",
            sf_card["card_faces"][0].get("watermark", None),
            single_card.clean_up_watermark,
        )

        if sf_card["card_faces"][-1]["oracle_text"].startswith("Aftermath"):
            single_card.set("layout", "aftermath")

        single_card.set("artist", sf_card["card_faces"][sf_card_face].get("artist", ""))

        # Recursively parse the other cards within this card too
        # Only call recursive if it is the first time we see this card object
        if sf_card_face == 0:
            for i in range(1, len(sf_card["card_faces"])):
                LOGGER.info(
                    "Parsing additional card {0} face {1}".format(
                        sf_card.get("name"), i
                    )
                )
                mtgjson_cards += build_mtgjson_card(sf_card, i)
    else:
        single_card.set_all(
            {
                "scryfallId": sf_card.get("id"),
                "scryfallOracleId": sf_card["oracle_id"],
                "scryfallIllustrationId": sf_card.get("illustration_id"),
            }
        )

    # Characteristics that can are not shared to both sides of flip-type cards
    if face_data.get("mana_cost"):
        single_card.set("manaCost", face_data.get("mana_cost"))

    if "colors" not in single_card.keys():
        if "colors" in face_data:
            single_card.set("colors", face_data.get("colors"))
        else:
            single_card.set("colors", sf_card.get("colors"))

    single_card.set_all(
        {
            "name": face_data.get("name"),
            "type": face_data.get("type_line"),
            "text": face_data.get("oracle_text"),
            "power": face_data.get("power"),
            "toughness": face_data.get("toughness"),
            "loyalty": face_data.get("loyalty"),
            "borderColor": sf_card.get("border_color"),
            "colorIdentity": sf_card.get("color_identity"),
            "frameVersion": sf_card.get("frame"),
            "hasFoil": sf_card.get("foil"),
            "hasNonFoil": sf_card.get("nonfoil"),
            "isOnlineOnly": sf_card.get("digital"),
            "isOversized": sf_card.get("oversized"),
            "number": sf_card.get("collector_number"),
            "isReserved": sf_card.get("reserved"),
            "frameEffect": sf_card.get("frame_effect"),
            "tcgplayerProductId": sf_card.get("tcgplayer_id"),
            "life": sf_card.get("life_modifier"),
            "hand": sf_card.get("hand_modifier"),
            "convertedManaCost": sf_card.get("cmc"),
        }
    )

    # Set MKM IDs if it exists
    if MKM_API.get(None):
        mkm_card_found = False
        for key, mkm_obj in MKM_SET_CARDS.get().items():
            if single_card.get("name").lower() not in key:
                continue

            if "number" not in mkm_obj.keys() or (
                mkm_obj.get("number") in single_card.get("number")
            ):
                single_card.set_all(
                    {
                        "mcmId": mkm_obj["idProduct"],
                        "mcmMetaId": mkm_obj["idMetaproduct"],
                    }
                )
                single_card.set_mkm_url(mkm_obj["website"])
                mkm_card_found = True
                break

        if not mkm_card_found:
            LOGGER.warning(
                "Unable to find MKM information for #{} {}".format(
                    single_card.get("number"), single_card.get("name")
                )
            )

    if "artist" not in single_card.keys():
        single_card.set("artist", sf_card.get("artist"))

    if "layout" not in single_card.keys():
        single_card.set("layout", sf_card.get("layout"))

    if "watermark" not in single_card.keys():
        single_card.set(
            "watermark",
            face_data.get("watermark", None),
            single_card.clean_up_watermark,
        )

    if "flavor_text" in face_data:
        single_card.set("flavorText", face_data.get("flavor_text"))
    else:
        single_card.set("flavorText", sf_card.get("flavor_text"))

    if "color_indicator" in face_data:
        single_card.set("colorIndicator", face_data.get("color_indicator"))
    elif "color_indicator" in sf_card:
        single_card.set("colorIndicator", sf_card.get("color_indicator"))

    try:
        single_card.set("multiverseId", sf_card["multiverse_ids"][sf_card_face])
    except IndexError:
        try:
            single_card.set("multiverseId", sf_card["multiverse_ids"][0])
        except IndexError:
            single_card.set("multiverseId", None)

    # Add a "side" entry for split cards
    # Will only work for two faced cards (not meld, as they don't need this)
    if "names" in single_card.keys() and single_card.names_count(2):
        # chr(97) = 'a', chr(98) = 'b', ...
        single_card.set(
            "side", chr(single_card.get("names").index(single_card.get("name")) + 97)
        )

    # Characteristics that we have to format ourselves from provided data
    single_card.set(
        "isTimeshifted",
        (sf_card.get("frame") == "future") or (sf_card.get("set") == "tsb"),
    )

    single_card.set("rarity", sf_card.get("rarity"))

    # Characteristics that we need custom functions to parse
    print_search_url: str = sf_card["prints_search_uri"].replace("%22", "")
    single_card.set("legalities", scryfall.parse_legalities(sf_card["legalities"]))
    single_card.set(
        "rulings",
        sorted(
            scryfall.parse_rulings(sf_card["rulings_uri"]),
            key=lambda ruling: ruling["date"],
        ),
    )
    single_card.set("printings", sorted(scryfall.parse_printings(print_search_url)))

    card_types: Tuple[List[str], List[str], List[str]] = scryfall.parse_card_types(
        single_card.get("type")
    )
    single_card.set("supertypes", card_types[0])
    single_card.set("types", card_types[1])
    single_card.set("subtypes", card_types[2])

    # Handle meld and all parts tokens issues
    # Will re-address naming if a split card already
    if "all_parts" in sf_card:
        meld_holder = []
        single_card.set("names", [])
        for a_part in sf_card["all_parts"]:
            if a_part["component"] != "token":
                if "//" in a_part.get("name"):
                    single_card.set("names", a_part.get("name").split(" // "))
                    break

                # This is a meld only-fix, so we ignore tokens/combo pieces
                if "meld" in a_part["component"]:
                    meld_holder.append(a_part["component"])

                    single_card.append("names", a_part.get("name"))

        # If the only entry is the original card, empty the names array
        if single_card.names_count(1) and single_card.get("name") in single_card.get(
            "names"
        ):
            single_card.remove("names")

        # Meld cards should be CardA, Meld, CardB. This fixes that via swap
        # meld_holder

        if meld_holder and meld_holder[1] != "meld_result":
            single_card.get("names")[1], single_card.get("names")[2] = (
                single_card.get("names")[2],
                single_card.get("names")[1],
            )

    # Since we built meld cards later, we will add the "side" attribute now
    if single_card.names_count(3):  # MELD
        if single_card.get("name") == single_card.get("names")[0]:
            single_card.set("side", "a")
        elif single_card.get("name") == single_card.get("names")[2]:
            single_card.set("side", "b")
        else:
            single_card.set("side", "c")

    # Characteristics that we cannot get from Scryfall
    # Characteristics we have to do further API calls for
    single_card.set(
        "foreignData",
        scryfall.parse_foreign(
            print_search_url,
            single_card.get("name"),
            single_card.get("number"),
            sf_card["set"],
        ),
    )

    if single_card.get("multiverseId") is not None:
        gatherer_cards = gatherer.get_cards(single_card.get("multiverseId"))
        try:
            gatherer_card = gatherer_cards[sf_card_face]
            single_card.set("originalType", gatherer_card.original_types)
            single_card.set("originalText", gatherer_card.original_text)
        except IndexError:
            LOGGER.warning(
                "Unable to parse originals for {}".format(single_card.get("name"))
            )

    mtgjson_cards.append(single_card)
    return mtgjson_cards
Example #8
0
def build_mtgjson_tokens(
    sf_tokens: List[Dict[str, Any]], sf_card_face: int = 0
) -> List[MTGJSONCard]:
    """
    Convert Scryfall tokens to MTGJSON tokens
    :param sf_tokens: All tokens in a set
    :param sf_card_face: Faces of the token index
    :return: List of MTGJSON tokens
    """
    token_cards: List[MTGJSONCard] = []

    for sf_token in sf_tokens:
        token_card = MTGJSONCard(sf_token["set"])

        if "card_faces" in sf_token:
            token_card.set("names", sf_token["name"].split(" // "))
            face_data = sf_token["card_faces"][sf_card_face]

            # Prevent duplicate UUIDs for split card halves
            # Remove the last character and replace with the id of the card face
            token_card.set("scryfallId", sf_token["id"])
            token_card.set("scryfallOracleId", sf_token["oracle_id"])
            token_card.set("scryfallIllustrationId", sf_token.get("illustration_id"))

            # Recursively parse the other cards within this card too
            # Only call recursive if it is the first time we see this card object
            if sf_card_face == 0:
                for i in range(1, len(sf_token["card_faces"])):
                    LOGGER.info(
                        "Parsing additional card {0} face {1}".format(
                            sf_token.get("name"), i
                        )
                    )
                    token_cards += build_mtgjson_tokens([sf_token], i)

            if "id" not in sf_token.keys():
                LOGGER.info(
                    "Scryfall_ID not found in {}. Discarding {}".format(
                        sf_token.get("name"), sf_token
                    )
                )
                continue

            token_card.set_all(
                {
                    "name": face_data.get("name"),
                    "type": face_data.get("type_line"),
                    "text": face_data.get("oracle_text"),
                    "power": face_data.get("power"),
                    "colors": face_data.get("colors"),
                    "colorIdentity": sf_token.get("color_identity"),
                    "toughness": face_data.get("toughness"),
                    "loyalty": face_data.get("loyalty"),
                    "watermark": sf_token.get("watermark"),
                    "scryfallId": sf_token["id"],
                    "scryfallOracleId": sf_token.get("oracle_id"),
                    "scryfallIllustrationId": sf_token.get("illustration_id"),
                    "layout": "double_faced_token",
                    "side": chr(97 + sf_card_face),
                    "borderColor": face_data.get("border_color"),
                    "artist": face_data.get("artist"),
                    "isOnlineOnly": sf_token.get("digital"),
                    "number": sf_token.get("collector_number"),
                }
            )
        else:
            token_card.set_all(
                {
                    "name": sf_token.get("name"),
                    "type": sf_token.get("type_line"),
                    "text": sf_token.get("oracle_text"),
                    "power": sf_token.get("power"),
                    "colors": sf_token.get("colors"),
                    "colorIdentity": sf_token.get("color_identity"),
                    "toughness": sf_token.get("toughness"),
                    "loyalty": sf_token.get("loyalty"),
                    "layout": "normal",
                    "watermark": sf_token.get("watermark"),
                    "scryfallId": sf_token["id"],
                    "scryfallOracleId": sf_token.get("oracle_id"),
                    "scryfallIllustrationId": sf_token.get("illustration_id"),
                    "borderColor": sf_token.get("border_color"),
                    "artist": sf_token.get("artist"),
                    "isOnlineOnly": sf_token.get("digital"),
                    "number": sf_token.get("collector_number"),
                }
            )

        reverse_related: List[str] = []
        if "all_parts" in sf_token:
            for a_part in sf_token["all_parts"]:
                if a_part.get("name") != token_card.get("name"):
                    reverse_related.append(a_part.get("name"))
        token_card.set("reverseRelated", reverse_related)

        LOGGER.info(
            "Parsed {0} from {1}".format(token_card.get("name"), sf_token.get("set"))
        )
        token_cards.append(token_card)

    return token_cards