# Overview of scryr

scryr is a lightweight wrapper around Scryfall, an amazing (and free!) Magic: The Gathering API. With scryr you can ingest card data as tidy data frames, allowing for frictionless integration with tidyverse pipelines.

Currently there are 2 main endpoints: `cards` and `sets`. The other 4 endpoints (`bulk_data`, `catalogs`, `rulings`, and `symbols`) are mostly auxiliary to the main ones.

    # Start scryr and helpers
    library(dplyr)
    library(scryr)

## Cards

This endpoints is, by far, the most complex. Make sure to read `scry_cards()`’ full documentation before diving in! For the curious, more relevant information about cards can be found in `vignette("syntax")` (Query Syntax) and `vignette("layouts")` (Layouts and Faces).

The most important function here is `scry_cards()`. It returns a data frame of card data given a query:

    # Legendary vampires
    vampires <- scry_cards("t:vampire t:legend")

    # There are many, many columns
    print(vampires)
    #> # A tibble: 48 × 70
    #>    id     name   set   lang  colors color_identity mana_cost   cmc oracle_text
    #>    <chr>  <chr>  <chr> <chr> <list> <list>         <chr>     <dbl> <chr>
    #>  1 913dd… Anje … c19   en    <chr … <chr [2]>      {1}{B}{R}     3 "Haste\n{T},…
    #>  2 1bfac… Anje,… vow   en    <chr … <chr [2]>      {2}{B}{R}     4 "Whenever An…
    #>  3 b8630… Anowo… voc   en    <chr … <chr [1]>      {3}{B}{B}     5 "At the begi…
    #>  4 bca84… Anowo… znc   en    <chr … <chr [2]>      {2}{U}{B}     4 "Other Rogue…
    #>  5 e811f… Arvad… dom   en    <chr … <chr [2]>      {3}{W}{B}     5 "Deathtouch,…
    #>  6 213ad… Ascen… hop   en    <chr … <chr [1]>      {4}{B}{B}     6 "Flying (Thi…
    #>  7 e5fb4… Baron… me1   en    <chr … <chr [1]>      {5}{B}{B…     8 "Flying\nWhe…
    #>  8 487e8… Crova… tpr   en    <chr … <chr [1]>      {2}{B}{B}     4 "Crovax the …
    #>  9 2c58c… Drana… c17   en    <chr … <chr [1]>      {3}{B}{B}     5 "Flying\n{X}…
    #> 10 31d0c… Drana… jmp   en    <chr … <chr [1]>      {1}{B}{B}     3 "Flying, fir…
    #> # … with 38 more rows, and 61 more variables: power <chr>, toughness <chr>,
    #> #   type_line <chr>, edhrec_rank <int>, keywords <list>, layout <chr>,
    #> #   legalities <list>, oversized <lgl>, reserved <lgl>, oracle_id <chr>,
    #> #   mtgo_id <int>, multiverse_ids <list>, tcgplayer_id <int>,
    #> #   cardmarket_id <int>, uri <chr>, scryfall_uri <chr>, rulings_uri <chr>,
    #> #   prints_search_uri <chr>, artist <chr>, artist_ids <list>, booster <lgl>,
    #> #   border_color <chr>, card_back_id <chr>, collector_number <chr>, …

Note that many columns are list-columns with deeply nested information inside. This is a result of Scryfall’s data model and is the reason why scryr needs tibbles to work. But don’t be alarmed! It’s all pretty consistent.

    # Get Anje's related cards
    vampires %>%
      filter(name == "Anje, Maid of Dishonor") %>%
      pull(all_parts)
    #> [[1]]
    #> # A tibble: 2 × 6
    #>   object       id           component  name     type_line     uri
    #>   <chr>        <chr>        <chr>      <chr>    <chr>         <chr>
    #> 1 related_card 1bfac4ab-97… combo_pie… Anje, M… Legendary Cr… https://api.scryf…
    #> 2 related_card a6f374bc-cd… token      Blood    Token Artifa… https://api.scryf…

    # Get Anje's color identity
    vampires %>%
      filter(name == "Anje Falkenrath") %>%
      pull(color_identity)
    #> [[1]]
    #> [1] "B" "R"

There are also “singular” functions, that is, functions that return one card instead of many. They are `scry_card()` and its siblings, all of them methods that find a card given some sort of identifier.

    # Using an ID
    scry_card("913dd06f-ed2f-4128-9c9d-9cd0d8a55425")$name
    #> [1] "Anje Falkenrath"

    # Using a name
    scry_card_name("Anje Falkenrath")$name
    #> [1] "Anje Falkenrath"

    # Using a collector number and a set
    scry_card_number(37, "c19")$name
    #> [1] "Anje Falkenrath"

    # Just get a random vampire commander
    scry_card_random("t:vampire t:legend")$name
    #> [1] "Rayami, First of the Fallen"

If you’re unsure of exactly what card you’re looking for, don’t worry. Scryfall also has an endpoint that tries to autocomplete the name of a card and scryr makes it available so that you don’t have to ever leave R to look for a card.

    # There she is
    autocomplete_name("falken")[12]
    #> [1] "Anje Falkenrath"

## Sets

The other main endpoint retrieves information about sets. There are also many list-columns but, again, they are all handled consistently; following in the footsteps of `cards`, `sets` also has a “plural” function and a “singular” function. Note that `scry_cards()` is the only “plural” method that can filter results with its `q` argument.

    # Get all sets
    scry_sets()
    #> # A tibble: 721 × 19
    #>    id     code  name   tcgplayer_id uri     scryfall_uri search_uri  released_at
    #>    <chr>  <chr> <chr>         <int> <chr>   <chr>        <chr>       <date>
    #>  1 b314f… unf   Unfin…         2958 https:… https://scr… https://ap… 2022-12-31
    #>  2 a6012… tunf  Unfin…           NA https:… https://scr… https://ap… 2022-12-31
    #>  3 b11b2… pw22  Wizar…           NA https:… https://scr… https://ap… 2022-03-05
    #>  4 59a20… neo   Kamig…         2965 https:… https://scr… https://ap… 2022-02-18
    #>  5 8bb11… tneo  Kamig…           NA https:… https://scr… https://ap… 2022-02-18
    #>  6 5bd03… tnec  Neon …           NA https:… https://scr… https://ap… 2022-02-18
    #>  7 5b4d9… nec   Neon …           NA https:… https://scr… https://ap… 2022-02-18
    #>  8 78a7f… cc2   Comma…         2905 https:… https://scr… https://ap… 2022-01-28
    #>  9 5c163… dbl   Innis…         2942 https:… https://scr… https://ap… 2022-01-28
    #> 10 8a673… y22   Alche…           NA https:… https://scr… https://ap… 2021-12-09
    #> # … with 711 more rows, and 11 more variables: set_type <chr>,
    #> #   card_count <int>, digital <lgl>, nonfoil_only <lgl>, foil_only <lgl>,
    #> #   icon_svg_uri <chr>, parent_set_code <chr>, mtgo_code <chr>,
    #> #   arena_code <chr>, block_code <chr>, block <chr>

    # Get a single set with an ID
    scry_set("vow")
    #> # A tibble: 1 × 19
    #>   id      code  name    mtgo_code arena_code tcgplayer_id uri      scryfall_uri
    #>   <chr>   <chr> <chr>   <chr>     <chr>             <int> <chr>    <chr>
    #> 1 8144b6… vow   Innist… vow       vow                2862 https:/… https://scry…
    #> # … with 11 more variables: search_uri <chr>, released_at <date>,
    #> #   set_type <chr>, card_count <int>, printed_size <int>, digital <lgl>,
    #> #   nonfoil_only <lgl>, foil_only <lgl>, block_code <chr>, block <chr>,
    #> #   icon_svg_uri <chr>

## Other Endpoints

All other endpoints return way less information than the two above. Here is a short demonstration of what else you can do with the rest of scryr:

    # Get information from a catalog
    head(scry_catalog("keyword-actions"))
    #> [1] "Meld"        "Bolster"     "Clash"       "Fateseal"    "Manifest"
    #> [6] "Monstrosity"

    # Get rulings for a card
    scry_ruling("913dd06f-ed2f-4128-9c9d-9cd0d8a55425")
    #> # A tibble: 1 × 4
    #>   oracle_id                            source published_at comment
    #>   <chr>                                <chr>  <date>       <chr>
    #> 1 4dab6a96-4376-4aea-983d-406167993214 wotc   2019-08-23   If you discard a car…

    # Get information about symbols
    scry_symbols()
    #> # A tibble: 34 × 11
    #>    symbol colors   cmc loose_variant english      gatherer_alterna… transposable
    #>    <chr>  <list> <dbl> <chr>         <chr>        <list>            <lgl>
    #>  1 {X}    <NULL>   0   X             X generic m… <chr [2]>         FALSE
    #>  2 {Y}    <NULL>   0   Y             Y generic m… <NULL>            FALSE
    #>  3 {Z}    <NULL>   0   Z             Z generic m… <NULL>            FALSE
    #>  4 {0}    <NULL>   0   0             zero mana    <chr [1]>         FALSE
    #>  5 {½}    <NULL>   0.5 ½             one-half ge… <chr [1]>         FALSE
    #>  6 {1}    <NULL>   1   1             one generic… <chr [1]>         FALSE
    #>  7 {2}    <NULL>   2   2             two generic… <chr [1]>         FALSE
    #>  8 {3}    <NULL>   3   3             three gener… <chr [1]>         FALSE
    #>  9 {4}    <NULL>   4   4             four generi… <chr [1]>         FALSE
    #> 10 {5}    <NULL>   5   5             five generi… <chr [1]>         FALSE
    #> # … with 24 more rows, and 4 more variables: represents_mana <lgl>,
    #> #   appears_in_mana_costs <lgl>, funny <lgl>, svg_uri <chr>

    # Parse mana costs
    parse_cost("2g2")$cost
    #> [1] "{4}{G}"

    # Get names of bulk files
    scry_bulk_files()$name
    #> [1] "Oracle Cards"   "Unique Artwork" "Default Cards"  "All Cards"
    #> [5] "Rulings"

    # Download (and parse) bulk rulings
    scry_bulk_file("Rulings")
    #> # A tibble: 44,484 × 4
    #>    oracle_id                            source published_at comment
    #>    <chr>                                <chr>  <date>       <chr>
    #>  1 0004ebd0-dfd6-4276-b4a6-de0003e94237 wotc   2004-10-04   If there are two of…
    #>  2 0007c283-5b7a-4c00-9ca1-b455c8dff8c3 wotc   2019-08-23   The “commander tax”…
    #>  3 0007c283-5b7a-4c00-9ca1-b455c8dff8c3 wotc   2019-08-23   Certain cards in ot…
    #>  4 0007c283-5b7a-4c00-9ca1-b455c8dff8c3 wotc   2019-08-23   If your commander i…
    #>  5 000e5d65-96c3-498b-bd01-72b1a1991850 wotc   2004-10-04   The target loses ju…
    #>  6 0012bc78-e69d-4a67-a302-e5fe0dfd4407 wotc   2019-05-03   A land normally has…
    #>  7 00187de2-bc48-4137-97d8-a9a0fafc76c1 wotc   2019-01-25   You can always acti…
    #>  8 00187de2-bc48-4137-97d8-a9a0fafc76c1 wotc   2019-01-25   Pteramander’s activ…
    #>  9 00187de2-bc48-4137-97d8-a9a0fafc76c1 wotc   2019-01-25   If a creature someh…
    #> 10 001c6369-df13-427d-89df-718d5c09f382 wotc   2009-05-01   Vedalken Heretic’s …
    #> # … with 44,474 more rows