Moved seperate things into separate files
This commit is contained in:
787
scryfall_deser/src/deser.rs
Normal file
787
scryfall_deser/src/deser.rs
Normal file
@@ -0,0 +1,787 @@
|
|||||||
|
use chrono::NaiveDate;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde_json::Value;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
// Info from here:
|
||||||
|
// https://scryfall.com/docs/api/cards
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct ScryfallCard {
|
||||||
|
// Core Card Fields
|
||||||
|
pub arena_id: Option<u64>,
|
||||||
|
pub id: Uuid,
|
||||||
|
pub lang: String,
|
||||||
|
pub mtgo_id: Option<u64>,
|
||||||
|
pub mtgo_foil_id: Option<u64>,
|
||||||
|
pub multiverse_ids: Option<Vec<u64>>,
|
||||||
|
pub tcgplayer_id: Option<u64>,
|
||||||
|
pub tcgplayer_etched_id: Option<u64>,
|
||||||
|
pub cardmarket_id: Option<u64>,
|
||||||
|
pub object: String,
|
||||||
|
pub layout: String, // Perhaps some kind of enum of these: https://scryfall.com/docs/api/layouts?
|
||||||
|
pub oracle_id: Option<Uuid>,
|
||||||
|
pub prints_search_uri: String, // URI
|
||||||
|
pub rulings_uri: String, // URI
|
||||||
|
pub scryfall_uri: String, // URI
|
||||||
|
pub uri: String, // URI
|
||||||
|
|
||||||
|
// Gameplay Fields
|
||||||
|
// https://scryfall.com/docs/api/cards#gameplay-fields
|
||||||
|
pub all_parts: Option<Vec<ScryfallRelatedCardObject>>,
|
||||||
|
pub card_faces: Option<Vec<ScryfallCardFaceObject>>,
|
||||||
|
|
||||||
|
// NOTE: Much of the next is a repeat of what's in the ScryfallCardFaceObject if you change something here, change something there
|
||||||
|
// NOTE: Probably a bad idea to rename color -> colour just for the sake
|
||||||
|
pub cmc: Option<f64>, // TODO: Make this a proper Decimal - see "Little Girl" card for example of cmc of 0.5
|
||||||
|
#[serde(rename = "color_identity")]
|
||||||
|
pub colour_identity: Option<Vec<Colour>>,
|
||||||
|
#[serde(rename = "color_indicator")]
|
||||||
|
pub colour_indicator: Option<Vec<Colour>>,
|
||||||
|
#[serde(rename = "colors")]
|
||||||
|
pub colours: Option<Vec<Colour>>,
|
||||||
|
pub edhrec_rank: Option<u64>,
|
||||||
|
pub defense: Option<String>,
|
||||||
|
pub hand_modifier: Option<String>,
|
||||||
|
pub keywords: Vec<String>, // Words like "Flying"
|
||||||
|
pub legalities: FormatLegalities,
|
||||||
|
pub life_modifier: Option<String>,
|
||||||
|
pub loyalty: Option<String>,
|
||||||
|
pub mana_cost: Option<String>,
|
||||||
|
pub name: String,
|
||||||
|
pub oracle_text: Option<String>,
|
||||||
|
pub penny_rank: Option<u64>,
|
||||||
|
pub power: Option<String>,
|
||||||
|
pub produced_mana: Option<Vec<Colour>>,
|
||||||
|
pub reserved: bool,
|
||||||
|
pub toughness: Option<String>,
|
||||||
|
pub type_line: String,
|
||||||
|
|
||||||
|
// Print Fields
|
||||||
|
// https://scryfall.com/docs/api/cards#print-fields
|
||||||
|
pub artist: Option<String>,
|
||||||
|
pub artist_ids: Option<Vec<String>>,
|
||||||
|
pub attraction_lights: Option<Vec<u8>>,
|
||||||
|
pub booster: bool,
|
||||||
|
#[serde(rename = "border_color")]
|
||||||
|
pub border_colour: BorderColour,
|
||||||
|
pub card_back_id: Option<Uuid>, // Scryfall docs says this should not be null, but ZHS Growing Rites of Itlimoc seems to not have one... maybe it's the back side?
|
||||||
|
pub collector_number: String,
|
||||||
|
pub content_warning: Option<bool>,
|
||||||
|
pub digital: bool,
|
||||||
|
pub finishes: Vec<Finish>,
|
||||||
|
#[serde(rename = "flavor_name")]
|
||||||
|
pub flavour_name: Option<String>,
|
||||||
|
#[serde(rename = "flavor_text")]
|
||||||
|
pub flavour_text: Option<String>,
|
||||||
|
pub frame_effects: Option<Vec<FrameEffect>>,
|
||||||
|
pub frame: Frame,
|
||||||
|
pub full_art: bool,
|
||||||
|
pub games: Vec<Game>,
|
||||||
|
pub highres_image: bool,
|
||||||
|
pub illustration_id: Option<Uuid>,
|
||||||
|
pub image_status: ImageStatus,
|
||||||
|
pub image_uris: Option<ImageURIs>,
|
||||||
|
pub oversized: bool,
|
||||||
|
pub prices: Prices,
|
||||||
|
pub printed_name: Option<String>,
|
||||||
|
pub printed_text: Option<String>,
|
||||||
|
pub printed_type_line: Option<String>,
|
||||||
|
pub promo: bool,
|
||||||
|
pub promo_types: Option<Vec<PromoTypes>>,
|
||||||
|
pub purchase_uris: Option<PurchaseUris>,
|
||||||
|
pub rarity: Rarity,
|
||||||
|
pub related_uris: Value, // TODO: - list all the URIs? Maybe? Who cares?
|
||||||
|
pub released_at: NaiveDate,
|
||||||
|
pub reprint: bool,
|
||||||
|
pub scryfall_set_uri: String, // URI
|
||||||
|
pub set_name: String,
|
||||||
|
pub set_search_uri: String, // URI
|
||||||
|
pub set_type: SetType,
|
||||||
|
pub set_uri: String, // URI
|
||||||
|
pub set: String,
|
||||||
|
pub set_id: Uuid,
|
||||||
|
pub story_spotlight: bool,
|
||||||
|
pub textless: bool,
|
||||||
|
pub variation: bool,
|
||||||
|
pub variation_of: Option<Uuid>,
|
||||||
|
pub security_stamp: Option<SecurityStamp>,
|
||||||
|
pub watermark: Option<String>,
|
||||||
|
pub preview: Option<Preview>,
|
||||||
|
|
||||||
|
// These aren't in the Scryfall docs, but some cards do have 'em
|
||||||
|
pub foil: Option<bool>,
|
||||||
|
pub nonfoil: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://scryfall.com/docs/api/cards#card-face-objects
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct ScryfallCardFaceObject {
|
||||||
|
pub artist: Option<String>,
|
||||||
|
pub artist_id: Option<Uuid>, // UUID
|
||||||
|
pub cmc: Option<f64>, // TODO: Make this a proper Decimal - see "Little Girl" card for example of cmc of 0.5
|
||||||
|
#[serde(rename = "color_identity")]
|
||||||
|
pub colour_identity: Option<Vec<Colour>>,
|
||||||
|
#[serde(rename = "color_indicator")]
|
||||||
|
pub colour_indicator: Option<Vec<Colour>>,
|
||||||
|
#[serde(rename = "colors")]
|
||||||
|
pub colours: Option<Vec<Colour>>,
|
||||||
|
pub defense: Option<String>,
|
||||||
|
pub flavour_text: Option<String>,
|
||||||
|
pub illustration_id: Option<Uuid>,
|
||||||
|
pub image_uris: Option<ImageURIs>,
|
||||||
|
pub layout: Option<String>,
|
||||||
|
pub loyalty: Option<String>,
|
||||||
|
pub mana_cost: Option<String>,
|
||||||
|
pub name: String,
|
||||||
|
pub object: String,
|
||||||
|
pub oracle_id: Option<Uuid>,
|
||||||
|
pub oracle_text: Option<String>,
|
||||||
|
pub power: Option<String>,
|
||||||
|
pub printed_name: Option<String>,
|
||||||
|
pub printed_text: Option<String>,
|
||||||
|
pub printed_type_line: Option<String>,
|
||||||
|
pub toughness: Option<String>,
|
||||||
|
pub type_line: Option<String>,
|
||||||
|
pub watermark: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://scryfall.com/docs/api/cards#related-card-objects
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct ScryfallRelatedCardObject {
|
||||||
|
pub id: Uuid,
|
||||||
|
pub object: String, // Always "related_card"
|
||||||
|
pub component: Component,
|
||||||
|
pub name: String,
|
||||||
|
pub type_line: String,
|
||||||
|
pub uri: String, // URI
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, PartialEq, Debug)]
|
||||||
|
pub enum Colour {
|
||||||
|
#[serde(rename = "W")]
|
||||||
|
White,
|
||||||
|
#[serde(rename = "U")]
|
||||||
|
Blue,
|
||||||
|
#[serde(rename = "B")]
|
||||||
|
Black,
|
||||||
|
#[serde(rename = "R")]
|
||||||
|
Red,
|
||||||
|
#[serde(rename = "G")]
|
||||||
|
Green,
|
||||||
|
#[serde(rename = "C")] // I don't think it's meant to work like this... but eh
|
||||||
|
Colourless,
|
||||||
|
#[serde(rename = "T")] // See "Sole Performer"
|
||||||
|
Tap,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub enum Legality {
|
||||||
|
#[serde(rename = "legal")]
|
||||||
|
Legal,
|
||||||
|
#[serde(rename = "not_legal")]
|
||||||
|
NotLegal,
|
||||||
|
#[serde(rename = "banned")]
|
||||||
|
Banned,
|
||||||
|
#[serde(rename = "restricted")]
|
||||||
|
Restricted,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct FormatLegalities {
|
||||||
|
standard: Legality,
|
||||||
|
future: Legality,
|
||||||
|
historic: Legality,
|
||||||
|
timeless: Legality,
|
||||||
|
gladiator: Legality,
|
||||||
|
pioneer: Legality,
|
||||||
|
explorer: Legality,
|
||||||
|
modern: Legality,
|
||||||
|
legacy: Legality,
|
||||||
|
pauper: Legality,
|
||||||
|
vintage: Legality,
|
||||||
|
penny: Legality,
|
||||||
|
commander: Legality,
|
||||||
|
oathbreaker: Legality,
|
||||||
|
standardbrawl: Legality,
|
||||||
|
brawl: Legality,
|
||||||
|
alchemy: Legality,
|
||||||
|
paupercommander: Legality,
|
||||||
|
duel: Legality,
|
||||||
|
oldschool: Legality,
|
||||||
|
premodern: Legality,
|
||||||
|
predh: Legality,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub enum BorderColour {
|
||||||
|
#[serde(rename = "black")]
|
||||||
|
Black,
|
||||||
|
#[serde(rename = "white")]
|
||||||
|
White,
|
||||||
|
#[serde(rename = "borderless")]
|
||||||
|
Borderless,
|
||||||
|
#[serde(rename = "yellow")]
|
||||||
|
Yellow,
|
||||||
|
#[serde(rename = "silver")]
|
||||||
|
Silver,
|
||||||
|
#[serde(rename = "gold")]
|
||||||
|
Gold,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub enum Finish {
|
||||||
|
#[serde(rename = "foil")]
|
||||||
|
Foil,
|
||||||
|
#[serde(rename = "nonfoil")]
|
||||||
|
NonFoil,
|
||||||
|
#[serde(rename = "etched")]
|
||||||
|
Etched,
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://scryfall.com/docs/api/frames#frames
|
||||||
|
// This is probably dumb...
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub enum Frame {
|
||||||
|
#[serde(rename = "1993")]
|
||||||
|
NinetyThree,
|
||||||
|
#[serde(rename = "1997")]
|
||||||
|
NinetySeven,
|
||||||
|
#[serde(rename = "2003")]
|
||||||
|
OhThree,
|
||||||
|
#[serde(rename = "2015")]
|
||||||
|
Fifteen,
|
||||||
|
#[serde(rename = "future")]
|
||||||
|
Future,
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://scryfall.com/docs/api/frames#frame-effects
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub enum FrameEffect {
|
||||||
|
#[serde(rename = "legendary")]
|
||||||
|
Legendary,
|
||||||
|
#[serde(rename = "miracle")]
|
||||||
|
Miracle,
|
||||||
|
#[serde(rename = "enchantment")]
|
||||||
|
Enchantment,
|
||||||
|
#[serde(rename = "draft")]
|
||||||
|
Draft,
|
||||||
|
#[serde(rename = "devoid")]
|
||||||
|
Devoid,
|
||||||
|
#[serde(rename = "tombstone")]
|
||||||
|
Tombstone,
|
||||||
|
#[serde(rename = "colorshifted")]
|
||||||
|
Colourshifted,
|
||||||
|
#[serde(rename = "inverted")]
|
||||||
|
Inverted,
|
||||||
|
#[serde(rename = "sunmoondfc")]
|
||||||
|
SunMoonDFC,
|
||||||
|
#[serde(rename = "compasslanddfc")]
|
||||||
|
CompassLandDFC,
|
||||||
|
#[serde(rename = "originpwdfc")]
|
||||||
|
OriginPwDFC,
|
||||||
|
#[serde(rename = "mooneldrazidfc")]
|
||||||
|
MoonEldraziDFC,
|
||||||
|
#[serde(rename = "waxingandwaningmoondfc")]
|
||||||
|
WaxingAndWaningMoonDFC,
|
||||||
|
#[serde(rename = "showcase")]
|
||||||
|
Showcase,
|
||||||
|
#[serde(rename = "extendedart")]
|
||||||
|
ExtendedArt,
|
||||||
|
#[serde(rename = "companion")]
|
||||||
|
Companion,
|
||||||
|
#[serde(rename = "etched")]
|
||||||
|
Etched,
|
||||||
|
#[serde(rename = "snow")]
|
||||||
|
Snow,
|
||||||
|
#[serde(rename = "lesson")]
|
||||||
|
Lesson,
|
||||||
|
#[serde(rename = "shatteredglass")]
|
||||||
|
ShatteredGlass,
|
||||||
|
#[serde(rename = "convertdfc")]
|
||||||
|
ConvertDFC,
|
||||||
|
#[serde(rename = "fandfc")]
|
||||||
|
FanDFC,
|
||||||
|
#[serde(rename = "upsidedowndfc")]
|
||||||
|
UpsideDownDFC,
|
||||||
|
#[serde(rename = "spree")]
|
||||||
|
Spree,
|
||||||
|
#[serde(rename = "fullart")]
|
||||||
|
FullArt,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub enum Game {
|
||||||
|
#[serde(rename = "paper")]
|
||||||
|
Paper,
|
||||||
|
#[serde(rename = "mtgo")]
|
||||||
|
Mtgo,
|
||||||
|
#[serde(rename = "arena")]
|
||||||
|
Arena,
|
||||||
|
#[serde(rename = "astral")]
|
||||||
|
Astral,
|
||||||
|
#[serde(rename = "sega")]
|
||||||
|
Sega,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub enum ImageStatus {
|
||||||
|
#[serde(rename = "missing")]
|
||||||
|
Missing,
|
||||||
|
#[serde(rename = "placeholder")]
|
||||||
|
Placeholder,
|
||||||
|
#[serde(rename = "lowres")]
|
||||||
|
LowResolution,
|
||||||
|
#[serde(rename = "highres_scan")]
|
||||||
|
HighResolutionScan,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct ImageURIs {
|
||||||
|
png: Option<String>,
|
||||||
|
border_crop: Option<String>,
|
||||||
|
art_crop: Option<String>,
|
||||||
|
large: Option<String>,
|
||||||
|
normal: Option<String>,
|
||||||
|
small: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct Preview {
|
||||||
|
pub previewed_at: Option<NaiveDate>,
|
||||||
|
pub source_uri: Option<String>, // URI
|
||||||
|
pub source: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct Prices {
|
||||||
|
usd: Option<String>, // TODO Convert to f64?
|
||||||
|
usd_foil: Option<String>,
|
||||||
|
usd_etched: Option<String>,
|
||||||
|
eur: Option<String>,
|
||||||
|
eur_foil: Option<String>,
|
||||||
|
tix: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub enum Rarity {
|
||||||
|
#[serde(rename = "common")]
|
||||||
|
Common,
|
||||||
|
#[serde(rename = "uncommon")]
|
||||||
|
Uncommon,
|
||||||
|
#[serde(rename = "rare")]
|
||||||
|
Rare,
|
||||||
|
#[serde(rename = "special")]
|
||||||
|
Special,
|
||||||
|
#[serde(rename = "mythic")]
|
||||||
|
Mythic,
|
||||||
|
#[serde(rename = "bonus")]
|
||||||
|
Bonus,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct PurchaseUris {
|
||||||
|
tcgplayer: String, // Option?
|
||||||
|
cardmarket: String,
|
||||||
|
cardhoarder: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub enum SecurityStamp {
|
||||||
|
#[serde(rename = "oval")]
|
||||||
|
Oval,
|
||||||
|
#[serde(rename = "triangle")]
|
||||||
|
Triangle,
|
||||||
|
#[serde(rename = "acorn")]
|
||||||
|
Acorn,
|
||||||
|
#[serde(rename = "circle")]
|
||||||
|
Circle,
|
||||||
|
#[serde(rename = "arena")]
|
||||||
|
Arena,
|
||||||
|
#[serde(rename = "heart")]
|
||||||
|
Heart,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub enum Component {
|
||||||
|
#[serde(rename = "token")]
|
||||||
|
Token,
|
||||||
|
#[serde(rename = "meld_part")]
|
||||||
|
MeldPart,
|
||||||
|
#[serde(rename = "meld_result")]
|
||||||
|
MeldResult,
|
||||||
|
#[serde(rename = "combo_piece")]
|
||||||
|
ComboPiece,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub enum SetType {
|
||||||
|
#[serde(rename = "alchemy")]
|
||||||
|
Alchemy,
|
||||||
|
#[serde(rename = "archenemy")]
|
||||||
|
Archenemy,
|
||||||
|
#[serde(rename = "arsenal")]
|
||||||
|
Arsenal,
|
||||||
|
#[serde(rename = "box")]
|
||||||
|
Box,
|
||||||
|
#[serde(rename = "commander")]
|
||||||
|
Commander,
|
||||||
|
#[serde(rename = "core")]
|
||||||
|
Core,
|
||||||
|
#[serde(rename = "draft_innovation")]
|
||||||
|
DraftInnovation,
|
||||||
|
#[serde(rename = "duel_deck")]
|
||||||
|
DuelDeck,
|
||||||
|
#[serde(rename = "expansion")]
|
||||||
|
Expansion,
|
||||||
|
#[serde(rename = "from_the_vault")]
|
||||||
|
FromTheVault,
|
||||||
|
#[serde(rename = "funny")]
|
||||||
|
Funny,
|
||||||
|
#[serde(rename = "masterpiece")]
|
||||||
|
Masterpiece,
|
||||||
|
#[serde(rename = "masters")]
|
||||||
|
Masters,
|
||||||
|
#[serde(rename = "memorabilia")]
|
||||||
|
Memorabilia,
|
||||||
|
#[serde(rename = "minigame")]
|
||||||
|
Minigame,
|
||||||
|
#[serde(rename = "planechase")]
|
||||||
|
Planechase,
|
||||||
|
#[serde(rename = "premium_deck")]
|
||||||
|
PremiumDeck,
|
||||||
|
#[serde(rename = "promo")]
|
||||||
|
Promo,
|
||||||
|
#[serde(rename = "spellbook")]
|
||||||
|
SpellBook,
|
||||||
|
#[serde(rename = "starter")]
|
||||||
|
Starter,
|
||||||
|
#[serde(rename = "token")]
|
||||||
|
Token,
|
||||||
|
#[serde(rename = "treasure_chest")]
|
||||||
|
TreasureChest,
|
||||||
|
#[serde(rename = "vanguard")]
|
||||||
|
Vanguard,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Complete this
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub enum PromoTypes {
|
||||||
|
#[serde(rename = "alchemy")]
|
||||||
|
Alchemy,
|
||||||
|
#[serde(rename = "arenaleague")]
|
||||||
|
ArenaLeague,
|
||||||
|
#[serde(rename = "beginnerbox")]
|
||||||
|
BeginnerBox,
|
||||||
|
#[serde(rename = "boosterfun")]
|
||||||
|
BoosterFun,
|
||||||
|
#[serde(rename = "boxtopper")]
|
||||||
|
BoxTopper,
|
||||||
|
#[serde(rename = "brawldeck")]
|
||||||
|
BrawlDeck,
|
||||||
|
#[serde(rename = "bundle")]
|
||||||
|
Bundle,
|
||||||
|
#[serde(rename = "buyabox")]
|
||||||
|
BuyABox,
|
||||||
|
#[serde(rename = "confettifoil")]
|
||||||
|
ConfettiFoil,
|
||||||
|
#[serde(rename = "convention")]
|
||||||
|
Convention,
|
||||||
|
#[serde(rename = "datestamped")]
|
||||||
|
DateStamped,
|
||||||
|
#[serde(rename = "dossier")]
|
||||||
|
Dossier,
|
||||||
|
#[serde(rename = "doublerainbow")]
|
||||||
|
DoubleRainbow,
|
||||||
|
#[serde(rename = "embossed")]
|
||||||
|
Embossed,
|
||||||
|
#[serde(rename = "event")]
|
||||||
|
Event,
|
||||||
|
#[serde(rename = "fnm")]
|
||||||
|
Fnm,
|
||||||
|
#[serde(rename = "gameday")]
|
||||||
|
GameDay,
|
||||||
|
#[serde(rename = "godzillaseries")]
|
||||||
|
GodzillaSeries,
|
||||||
|
#[serde(rename = "halofoil")]
|
||||||
|
HaloFoil,
|
||||||
|
#[serde(rename = "imagine")]
|
||||||
|
Imagine,
|
||||||
|
#[serde(rename = "instore")]
|
||||||
|
InStore,
|
||||||
|
#[serde(rename = "intropack")]
|
||||||
|
IntroPack,
|
||||||
|
#[serde(rename = "invisibleink")]
|
||||||
|
InvisibleInk,
|
||||||
|
#[serde(rename = "judgegift")]
|
||||||
|
JudgeGift,
|
||||||
|
#[serde(rename = "league")]
|
||||||
|
League,
|
||||||
|
#[serde(rename = "magnified")]
|
||||||
|
Magnified,
|
||||||
|
#[serde(rename = "manafoil")]
|
||||||
|
ManaFoil,
|
||||||
|
#[serde(rename = "mediainsert")]
|
||||||
|
MediaInsert,
|
||||||
|
#[serde(rename = "planeswalkerdeck")]
|
||||||
|
PlaneswalkerDeck,
|
||||||
|
#[serde(rename = "plastic")]
|
||||||
|
Plastic,
|
||||||
|
#[serde(rename = "playerrewards")]
|
||||||
|
PlayerRewards,
|
||||||
|
#[serde(rename = "playtest")]
|
||||||
|
Playtest,
|
||||||
|
#[serde(rename = "poster")]
|
||||||
|
Poster,
|
||||||
|
#[serde(rename = "prerelease")]
|
||||||
|
Prerelease,
|
||||||
|
#[serde(rename = "premiereshop")]
|
||||||
|
PremiereShop,
|
||||||
|
#[serde(rename = "promopack")]
|
||||||
|
PromoPack,
|
||||||
|
#[serde(rename = "rainbowfoil")]
|
||||||
|
RainbowFoil,
|
||||||
|
#[serde(rename = "ravnicacity")]
|
||||||
|
RavnicaCity,
|
||||||
|
#[serde(rename = "rebalanced")]
|
||||||
|
Rebalanced,
|
||||||
|
#[serde(rename = "release")]
|
||||||
|
Release,
|
||||||
|
#[serde(rename = "resale")]
|
||||||
|
Resale,
|
||||||
|
#[serde(rename = "ripplefoil")]
|
||||||
|
RippleFoil,
|
||||||
|
#[serde(rename = "setpromo")]
|
||||||
|
SetPromo,
|
||||||
|
#[serde(rename = "serialized")]
|
||||||
|
Serialised,
|
||||||
|
#[serde(rename = "silverfoil")]
|
||||||
|
SilverFoil,
|
||||||
|
#[serde(rename = "sldbonus")]
|
||||||
|
SldBonus,
|
||||||
|
#[serde(rename = "stamped")]
|
||||||
|
Stamped,
|
||||||
|
#[serde(rename = "startercollection")]
|
||||||
|
StarterCollection,
|
||||||
|
#[serde(rename = "starterdeck")]
|
||||||
|
StarterDeck,
|
||||||
|
#[serde(rename = "stepandcompleat")]
|
||||||
|
StepAndCompleat,
|
||||||
|
#[serde(rename = "surgefoil")]
|
||||||
|
SurgeFoil,
|
||||||
|
#[serde(rename = "textured")]
|
||||||
|
Textured,
|
||||||
|
#[serde(rename = "themepack")]
|
||||||
|
ThemePack,
|
||||||
|
#[serde(rename = "thick")]
|
||||||
|
Thick,
|
||||||
|
#[serde(rename = "tourney")]
|
||||||
|
Tourney,
|
||||||
|
#[serde(rename = "upsidedown")]
|
||||||
|
Upsidedown,
|
||||||
|
#[serde(rename = "vault")]
|
||||||
|
Vault,
|
||||||
|
#[serde(rename = "wizardsplaynetwork")]
|
||||||
|
WizardsPlayNetwork,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn weird_cards() -> Vec<String> {
|
||||||
|
// These all seem to be double faced cards with the same "card" on both sides.
|
||||||
|
vec![
|
||||||
|
"018830b2-dff9-45f3-9cc2-dc5b2eec0e54".to_string(),
|
||||||
|
"0489be0d-2117-46a8-97ab-31fe480685e2".to_string(),
|
||||||
|
"048ddb71-e9ea-4f11-9b8a-c53961cf3a2c".to_string(),
|
||||||
|
"087c3a0d-c710-4451-989e-596b55352184".to_string(),
|
||||||
|
"236e9bcf-ced2-4bee-8188-41dd94df02da".to_string(),
|
||||||
|
"36ea852d-ed2b-4c56-9b73-52dce8a3e520".to_string(),
|
||||||
|
"399bf36a-5901-437f-b5d3-32283cedbbcb".to_string(),
|
||||||
|
"3cb0824c-57cc-46bf-bd43-425d58b8a762".to_string(),
|
||||||
|
"fe388da5-9197-4d07-be7f-c49fcdf56dfa".to_string(),
|
||||||
|
"f973a1f3-6dcb-470d-89d2-6ddbf2426999".to_string(),
|
||||||
|
"f4e7b3a4-a346-4177-9cfe-0142b40ef4a6".to_string(),
|
||||||
|
"e25ce640-baf5-442b-8b75-d05dd9fb20dd".to_string(),
|
||||||
|
"dae8751c-4c72-4034-a192-a1e166f20246".to_string(),
|
||||||
|
"d74a72a2-d46a-41c2-a400-70571197b020".to_string(),
|
||||||
|
"d5f7a626-7b6b-41ba-a0f5-3aefe511b267".to_string(),
|
||||||
|
"d5dfd236-b1da-4552-b94f-ebf6bb9dafdf".to_string(),
|
||||||
|
"d002b29b-c3a6-4c91-86e1-96a50ce29966".to_string(),
|
||||||
|
"caf8d01d-07aa-43da-a26e-4a2ba3a76f2d".to_string(),
|
||||||
|
"c05c6c38-d204-458c-af17-4cf5efd2c7fc".to_string(),
|
||||||
|
"bffbe9ec-edbc-43ed-a3bf-60635e7e625c".to_string(),
|
||||||
|
"b96d6ea4-a3a4-4e33-be97-b3767f2bb63a".to_string(),
|
||||||
|
"acdb72e2-c000-4b92-b5ea-73115969020f".to_string(),
|
||||||
|
"aae84079-b65b-4132-86fb-e82503bb6c7b".to_string(),
|
||||||
|
"a724ebbc-0f77-42e9-95e0-b3e7cb130148".to_string(),
|
||||||
|
"a4a2dd5b-6143-4b8d-ae71-e148cf19b66c".to_string(),
|
||||||
|
"a129558c-45a1-441c-97f0-b70b4e9d8a56".to_string(),
|
||||||
|
"9f63277b-e139-46c8-b9e3-0cfb647f44cc".to_string(),
|
||||||
|
"9e69f9e0-4981-4fc0-955f-7ebe04264fca".to_string(),
|
||||||
|
"9d943cf2-0462-4f31-9a92-d76fe4971b17".to_string(),
|
||||||
|
"9cd6a16f-1eff-4624-8f7f-4d9e70a694bb".to_string(),
|
||||||
|
"9680a2d6-1d66-4f69-b400-a79fea4187d8".to_string(),
|
||||||
|
"94eea6e3-20bc-4dab-90ba-3113c120fb90".to_string(),
|
||||||
|
"94594d48-b728-4be6-9d7a-c67088df8acd".to_string(),
|
||||||
|
"3d89c9be-2489-47e4-8e53-f980c82442b4".to_string(),
|
||||||
|
"3e3f0bcd-0796-494d-bf51-94b33c1671e9".to_string(),
|
||||||
|
"4696f5de-fe5b-40df-a194-1a73b4c5150f".to_string(),
|
||||||
|
"4d227cd3-ebfe-4dd3-929a-4f8ff7c8981e".to_string(),
|
||||||
|
"5ab0412a-2b2f-430f-8830-002a42125148".to_string(),
|
||||||
|
"60c92f1b-0c78-4809-9365-e1ffa515cb4b".to_string(),
|
||||||
|
"6620b5f4-b1e5-4d1b-bbf2-c6ad9c8284c5".to_string(),
|
||||||
|
"67574bb4-c443-40fa-b7e6-05e9965c98b8".to_string(),
|
||||||
|
"6adadbc9-4a08-4c1d-adf7-edee73799d9e".to_string(),
|
||||||
|
"6c69ecd2-cb36-4628-802b-fd5ff7405f22".to_string(),
|
||||||
|
"76c343f5-6955-4ba2-a435-36d55182d1dd".to_string(),
|
||||||
|
"7e703632-5ed0-4509-a12b-594269f865f1".to_string(),
|
||||||
|
"82fa24fb-aecc-4c33-9e79-c29651ddafbe".to_string(),
|
||||||
|
"843b35ec-7b59-4a22-8fee-2e876a02306b".to_string(),
|
||||||
|
"8ae0caed-940d-45bc-9877-7cc014b2700e".to_string(),
|
||||||
|
"8b5341ab-85a6-44b2-b738-1110e699c02b".to_string(),
|
||||||
|
"8bcf942f-5afd-414e-a50d-00d884fe59da".to_string(),
|
||||||
|
"9052f5c7-ee3b-457d-97ca-ac6b4518997c".to_string(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::fs;
|
||||||
|
use std::io::{BufRead, BufReader};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialise_nissa() {
|
||||||
|
let mut f = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
f.push("test_files/nissa.json");
|
||||||
|
assert!(f.exists());
|
||||||
|
let fc = fs::read_to_string(f).unwrap();
|
||||||
|
let _nissa: ScryfallCard = serde_json::from_str(&fc).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialise_black_lotus() {
|
||||||
|
let mut f = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
f.push("test_files/black_lotus.json");
|
||||||
|
assert!(f.exists());
|
||||||
|
let fc = fs::read_to_string(f).unwrap();
|
||||||
|
let _bl: ScryfallCard = serde_json::from_str(&fc).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialise_little_girl() {
|
||||||
|
let mut f = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
f.push("test_files/little_girl.json");
|
||||||
|
assert!(f.exists());
|
||||||
|
let fc = fs::read_to_string(f).unwrap();
|
||||||
|
let _lg: ScryfallCard = serde_json::from_str(&fc).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_line_by_line_with_bad_skip() {
|
||||||
|
// This function is uuuuuuugly and I'm sure a terrible way to go about things
|
||||||
|
// It is ever so slightly faster than the other one though!
|
||||||
|
let mut f = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
f.push("test_files/all-cards.json");
|
||||||
|
assert!(f.exists(), "You need to download the all-cards-... file from Scryfall bulk data. Can be found here: https://scryfall.com/docs/api/bulk-data and rename to all-cards.json");
|
||||||
|
let ac = fs::File::open(f).unwrap();
|
||||||
|
let reader = BufReader::new(ac);
|
||||||
|
let weird_cards = weird_cards();
|
||||||
|
for line in reader.lines().skip(1) {
|
||||||
|
let mut line = line.unwrap();
|
||||||
|
let c = line.pop().unwrap();
|
||||||
|
// this is so dumb...
|
||||||
|
if c == '}' {
|
||||||
|
line.push('}');
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't look...
|
||||||
|
let mut skip = false;
|
||||||
|
for weird_card in &weird_cards {
|
||||||
|
if line.contains(weird_card) {
|
||||||
|
skip = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if skip {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if line.is_empty() {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let a_card: Result<ScryfallCard, serde_json::Error> =
|
||||||
|
serde_json::from_str(line.as_ref());
|
||||||
|
if let Err(error) = a_card {
|
||||||
|
println!("{:#?}", line);
|
||||||
|
println!("{:#?}", error);
|
||||||
|
}
|
||||||
|
//let a_card = a_card.unwrap();
|
||||||
|
//println!("{:?}", a_card.promo_types)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn deserialize_line_by_line() {
|
||||||
|
// This function is uuuuuuugly and I'm sure a terrible way to go about things
|
||||||
|
// It is ever so slightly faster than the other one though!
|
||||||
|
let mut f = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
f.push("test_files/all-cards.json");
|
||||||
|
assert!(f.exists(), "You need to download the all-cards-... file from Scryfall bulk data. Can be found here: https://scryfall.com/docs/api/bulk-data and rename to all-cards.json");
|
||||||
|
let ac = fs::File::open(f).unwrap();
|
||||||
|
let reader = BufReader::new(ac);
|
||||||
|
for line in reader.lines().skip(1) {
|
||||||
|
let mut line = line.unwrap();
|
||||||
|
let c = line.pop().unwrap();
|
||||||
|
// this is so dumb...
|
||||||
|
if c == '}' {
|
||||||
|
line.push('}');
|
||||||
|
}
|
||||||
|
|
||||||
|
if line.is_empty() {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let a_card: Result<ScryfallCard, serde_json::Error> =
|
||||||
|
serde_json::from_str(line.as_ref());
|
||||||
|
if let Err(error) = a_card {
|
||||||
|
println!("{:#?}", line);
|
||||||
|
println!("{:#?}", error);
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
//let a_card = a_card.unwrap();
|
||||||
|
//println!("{:?}", a_card.promo_types)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn deserialize_whole_file() {
|
||||||
|
let mut f = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
f.push("test_files/all-cards.json");
|
||||||
|
assert!(f.exists(), "You need to download the all-cards-... file from Scryfall bulk data. Can be found here: https://scryfall.com/docs/api/bulk-data and rename to all-cards.json");
|
||||||
|
|
||||||
|
let ac = fs::read_to_string(f).unwrap();
|
||||||
|
let _ac: Vec<ScryfallCard> = serde_json::from_str(&ac).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
89
scryfall_deser/src/download.rs
Normal file
89
scryfall_deser/src/download.rs
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::io::Write;
|
||||||
|
use tempfile::NamedTempFile;
|
||||||
|
use ureq;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct ScryfallBulkData {
|
||||||
|
pub id: Uuid,
|
||||||
|
pub uri: String,
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
pub stype: String,
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
pub download_uri: String,
|
||||||
|
pub updated_at: String,
|
||||||
|
pub content_type: String,
|
||||||
|
pub content_encoding: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct ScryfallBulk {
|
||||||
|
pub object: String,
|
||||||
|
pub has_more: bool,
|
||||||
|
pub data: Vec<ScryfallBulkData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, PartialEq, Debug)]
|
||||||
|
pub enum ScryfallBulkType {
|
||||||
|
#[serde(rename = "oracle_cards")]
|
||||||
|
OracleCards,
|
||||||
|
#[serde(rename = "unique_artwork")]
|
||||||
|
UniqueArtwork,
|
||||||
|
#[serde(rename = "default_cards")]
|
||||||
|
DefaultCards,
|
||||||
|
#[serde(rename = "all_cards")]
|
||||||
|
AllCards,
|
||||||
|
#[serde(rename = "rulings")]
|
||||||
|
Rulings,
|
||||||
|
}
|
||||||
|
|
||||||
|
const SCRYFALL_BULK_API: &str = "https://api.scryfall.com/bulk-data";
|
||||||
|
|
||||||
|
pub fn download_latest(
|
||||||
|
stype: ScryfallBulkType,
|
||||||
|
mut dest_file: &NamedTempFile,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let bulk_body: ScryfallBulk = ureq::get(SCRYFALL_BULK_API)
|
||||||
|
.header("User-Agent", "Arthur's Card Finger Testing v0.1")
|
||||||
|
.header("Accept", "application/json")
|
||||||
|
.call()?
|
||||||
|
.body_mut()
|
||||||
|
.read_json::<ScryfallBulk>()?;
|
||||||
|
|
||||||
|
let mut download_uri = String::new();
|
||||||
|
for scryfall_bulk in bulk_body.data {
|
||||||
|
if serde_json::to_string(&stype).unwrap() == scryfall_bulk.stype {
|
||||||
|
download_uri = scryfall_bulk.download_uri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert!(!download_uri.is_empty());
|
||||||
|
let cards_response = ureq::get(download_uri)
|
||||||
|
.header("User-Agent", "Arthur's Card Finger Testing v0.1")
|
||||||
|
.header("Accept", "application/json")
|
||||||
|
.call()?
|
||||||
|
.body_mut()
|
||||||
|
.with_config()
|
||||||
|
.limit(700 * 1024 * 1024)
|
||||||
|
.read_to_string()?;
|
||||||
|
write!(dest_file, "{}", cards_response)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::io::{Seek, SeekFrom};
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn get_scryfall_bulk_page() {
|
||||||
|
let mut file = NamedTempFile::new().unwrap();
|
||||||
|
let _ = download_latest(ScryfallBulkType::OracleCards, &file);
|
||||||
|
let file_size = file.seek(SeekFrom::End(0)).unwrap();
|
||||||
|
assert!(file_size > 4092);
|
||||||
|
println!("File size: {}", file_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,870 +1,7 @@
|
|||||||
use chrono::NaiveDate;
|
mod download;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use serde_json::Value;
|
|
||||||
use std::fs;
|
|
||||||
use std::io::{Read, Seek, SeekFrom, Write};
|
|
||||||
use tempfile::NamedTempFile;
|
|
||||||
use ureq;
|
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
pub use crate::download::download_latest;
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
struct ScryfallBulkData {
|
|
||||||
pub id: Uuid,
|
|
||||||
pub uri: String,
|
|
||||||
#[serde(rename = "type")]
|
|
||||||
pub stype: String,
|
|
||||||
pub name: String,
|
|
||||||
pub description: String,
|
|
||||||
pub download_uri: String,
|
|
||||||
pub updated_at: String,
|
|
||||||
pub content_type: String,
|
|
||||||
pub content_encoding: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
mod deser;
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
struct ScryfallBulk {
|
|
||||||
pub object: String,
|
|
||||||
pub has_more: bool,
|
|
||||||
pub data: Vec<ScryfallBulkData>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, PartialEq, Debug)]
|
pub use crate::deser::ScryfallCard;
|
||||||
pub enum ScryfallBulkType {
|
|
||||||
#[serde(rename = "oracle_cards")]
|
|
||||||
OracleCards,
|
|
||||||
#[serde(rename = "unique_artwork")]
|
|
||||||
UniqueArtwork,
|
|
||||||
#[serde(rename = "default_cards")]
|
|
||||||
DefaultCards,
|
|
||||||
#[serde(rename = "all_cards")]
|
|
||||||
AllCards,
|
|
||||||
#[serde(rename = "rulings")]
|
|
||||||
Rulings,
|
|
||||||
}
|
|
||||||
|
|
||||||
const SCRYFALL_BULK_API: &str = "https://api.scryfall.com/bulk-data";
|
|
||||||
|
|
||||||
pub fn download_latest(
|
|
||||||
stype: ScryfallBulkType,
|
|
||||||
mut dest_file: &NamedTempFile,
|
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let bulk_body: ScryfallBulk = ureq::get(SCRYFALL_BULK_API)
|
|
||||||
.header("User-Agent", "Arthur's Card Finger Testing v0.1")
|
|
||||||
.header("Accept", "application/json")
|
|
||||||
.call()?
|
|
||||||
.body_mut()
|
|
||||||
.read_json::<ScryfallBulk>()?;
|
|
||||||
|
|
||||||
let mut download_uri = String::new();
|
|
||||||
for scryfall_bulk in bulk_body.data {
|
|
||||||
if serde_json::to_string(&stype).unwrap() == scryfall_bulk.stype {
|
|
||||||
download_uri = scryfall_bulk.download_uri;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert!(!download_uri.is_empty());
|
|
||||||
let cards_response = ureq::get(download_uri)
|
|
||||||
.header("User-Agent", "Arthur's Card Finger Testing v0.1")
|
|
||||||
.header("Accept", "application/json")
|
|
||||||
.call()?
|
|
||||||
.body_mut()
|
|
||||||
.with_config()
|
|
||||||
.limit(700 * 1024 * 1024)
|
|
||||||
.read_to_string()?;
|
|
||||||
write!(dest_file, "{}", cards_response)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Info from here:
|
|
||||||
// https://scryfall.com/docs/api/cards
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
#[serde(deny_unknown_fields)]
|
|
||||||
struct ScryfallCard {
|
|
||||||
// Core Card Fields
|
|
||||||
pub arena_id: Option<u64>,
|
|
||||||
pub id: Uuid,
|
|
||||||
pub lang: String,
|
|
||||||
pub mtgo_id: Option<u64>,
|
|
||||||
pub mtgo_foil_id: Option<u64>,
|
|
||||||
pub multiverse_ids: Option<Vec<u64>>,
|
|
||||||
pub tcgplayer_id: Option<u64>,
|
|
||||||
pub tcgplayer_etched_id: Option<u64>,
|
|
||||||
pub cardmarket_id: Option<u64>,
|
|
||||||
pub object: String,
|
|
||||||
pub layout: String, // Perhaps some kind of enum of these: https://scryfall.com/docs/api/layouts?
|
|
||||||
pub oracle_id: Option<Uuid>,
|
|
||||||
pub prints_search_uri: String, // URI
|
|
||||||
pub rulings_uri: String, // URI
|
|
||||||
pub scryfall_uri: String, // URI
|
|
||||||
pub uri: String, // URI
|
|
||||||
|
|
||||||
// Gameplay Fields
|
|
||||||
// https://scryfall.com/docs/api/cards#gameplay-fields
|
|
||||||
pub all_parts: Option<Vec<ScryfallRelatedCardObject>>,
|
|
||||||
pub card_faces: Option<Vec<ScryfallCardFaceObject>>,
|
|
||||||
|
|
||||||
// NOTE: Much of the next is a repeat of what's in the ScryfallCardFaceObject if you change something here, change something there
|
|
||||||
// NOTE: Probably a bad idea to rename color -> colour just for the sake
|
|
||||||
pub cmc: Option<f64>, // TODO: Make this a proper Decimal - see "Little Girl" card for example of cmc of 0.5
|
|
||||||
#[serde(rename = "color_identity")]
|
|
||||||
pub colour_identity: Option<Vec<Colour>>,
|
|
||||||
#[serde(rename = "color_indicator")]
|
|
||||||
pub colour_indicator: Option<Vec<Colour>>,
|
|
||||||
#[serde(rename = "colors")]
|
|
||||||
pub colours: Option<Vec<Colour>>,
|
|
||||||
pub edhrec_rank: Option<u64>,
|
|
||||||
pub defense: Option<String>,
|
|
||||||
pub hand_modifier: Option<String>,
|
|
||||||
pub keywords: Vec<String>, // Words like "Flying"
|
|
||||||
pub legalities: FormatLegalities,
|
|
||||||
pub life_modifier: Option<String>,
|
|
||||||
pub loyalty: Option<String>,
|
|
||||||
pub mana_cost: Option<String>,
|
|
||||||
pub name: String,
|
|
||||||
pub oracle_text: Option<String>,
|
|
||||||
pub penny_rank: Option<u64>,
|
|
||||||
pub power: Option<String>,
|
|
||||||
pub produced_mana: Option<Vec<Colour>>,
|
|
||||||
pub reserved: bool,
|
|
||||||
pub toughness: Option<String>,
|
|
||||||
pub type_line: String,
|
|
||||||
|
|
||||||
// Print Fields
|
|
||||||
// https://scryfall.com/docs/api/cards#print-fields
|
|
||||||
pub artist: Option<String>,
|
|
||||||
pub artist_ids: Option<Vec<String>>,
|
|
||||||
pub attraction_lights: Option<Vec<u8>>,
|
|
||||||
pub booster: bool,
|
|
||||||
#[serde(rename = "border_color")]
|
|
||||||
pub border_colour: BorderColour,
|
|
||||||
pub card_back_id: Option<Uuid>, // Scryfall docs says this should not be null, but ZHS Growing Rites of Itlimoc seems to not have one... maybe it's the back side?
|
|
||||||
pub collector_number: String,
|
|
||||||
pub content_warning: Option<bool>,
|
|
||||||
pub digital: bool,
|
|
||||||
pub finishes: Vec<Finish>,
|
|
||||||
#[serde(rename = "flavor_name")]
|
|
||||||
pub flavour_name: Option<String>,
|
|
||||||
#[serde(rename = "flavor_text")]
|
|
||||||
pub flavour_text: Option<String>,
|
|
||||||
pub frame_effects: Option<Vec<FrameEffect>>,
|
|
||||||
pub frame: Frame,
|
|
||||||
pub full_art: bool,
|
|
||||||
pub games: Vec<Game>,
|
|
||||||
pub highres_image: bool,
|
|
||||||
pub illustration_id: Option<Uuid>,
|
|
||||||
pub image_status: ImageStatus,
|
|
||||||
pub image_uris: Option<ImageURIs>,
|
|
||||||
pub oversized: bool,
|
|
||||||
pub prices: Prices,
|
|
||||||
pub printed_name: Option<String>,
|
|
||||||
pub printed_text: Option<String>,
|
|
||||||
pub printed_type_line: Option<String>,
|
|
||||||
pub promo: bool,
|
|
||||||
pub promo_types: Option<Vec<PromoTypes>>,
|
|
||||||
pub purchase_uris: Option<PurchaseUris>,
|
|
||||||
pub rarity: Rarity,
|
|
||||||
pub related_uris: Value, // TODO: - list all the URIs? Maybe? Who cares?
|
|
||||||
pub released_at: NaiveDate,
|
|
||||||
pub reprint: bool,
|
|
||||||
pub scryfall_set_uri: String, // URI
|
|
||||||
pub set_name: String,
|
|
||||||
pub set_search_uri: String, // URI
|
|
||||||
pub set_type: SetType,
|
|
||||||
pub set_uri: String, // URI
|
|
||||||
pub set: String,
|
|
||||||
pub set_id: Uuid,
|
|
||||||
pub story_spotlight: bool,
|
|
||||||
pub textless: bool,
|
|
||||||
pub variation: bool,
|
|
||||||
pub variation_of: Option<Uuid>,
|
|
||||||
pub security_stamp: Option<SecurityStamp>,
|
|
||||||
pub watermark: Option<String>,
|
|
||||||
pub preview: Option<Preview>,
|
|
||||||
|
|
||||||
// These aren't in the Scryfall docs, but some cards do have 'em
|
|
||||||
pub foil: Option<bool>,
|
|
||||||
pub nonfoil: Option<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://scryfall.com/docs/api/cards#card-face-objects
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
struct ScryfallCardFaceObject {
|
|
||||||
pub artist: Option<String>,
|
|
||||||
pub artist_id: Option<Uuid>, // UUID
|
|
||||||
pub cmc: Option<f64>, // TODO: Make this a proper Decimal - see "Little Girl" card for example of cmc of 0.5
|
|
||||||
#[serde(rename = "color_identity")]
|
|
||||||
pub colour_identity: Option<Vec<Colour>>,
|
|
||||||
#[serde(rename = "color_indicator")]
|
|
||||||
pub colour_indicator: Option<Vec<Colour>>,
|
|
||||||
#[serde(rename = "colors")]
|
|
||||||
pub colours: Option<Vec<Colour>>,
|
|
||||||
pub defense: Option<String>,
|
|
||||||
pub flavour_text: Option<String>,
|
|
||||||
pub illustration_id: Option<Uuid>,
|
|
||||||
pub image_uris: Option<ImageURIs>,
|
|
||||||
pub layout: Option<String>,
|
|
||||||
pub loyalty: Option<String>,
|
|
||||||
pub mana_cost: Option<String>,
|
|
||||||
pub name: String,
|
|
||||||
pub object: String,
|
|
||||||
pub oracle_id: Option<Uuid>,
|
|
||||||
pub oracle_text: Option<String>,
|
|
||||||
pub power: Option<String>,
|
|
||||||
pub printed_name: Option<String>,
|
|
||||||
pub printed_text: Option<String>,
|
|
||||||
pub printed_type_line: Option<String>,
|
|
||||||
pub toughness: Option<String>,
|
|
||||||
pub type_line: Option<String>,
|
|
||||||
pub watermark: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://scryfall.com/docs/api/cards#related-card-objects
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
struct ScryfallRelatedCardObject {
|
|
||||||
pub id: Uuid,
|
|
||||||
pub object: String, // Always "related_card"
|
|
||||||
pub component: Component,
|
|
||||||
pub name: String,
|
|
||||||
pub type_line: String,
|
|
||||||
pub uri: String, // URI
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, PartialEq, Debug)]
|
|
||||||
enum Colour {
|
|
||||||
#[serde(rename = "W")]
|
|
||||||
White,
|
|
||||||
#[serde(rename = "U")]
|
|
||||||
Blue,
|
|
||||||
#[serde(rename = "B")]
|
|
||||||
Black,
|
|
||||||
#[serde(rename = "R")]
|
|
||||||
Red,
|
|
||||||
#[serde(rename = "G")]
|
|
||||||
Green,
|
|
||||||
#[serde(rename = "C")] // I don't think it's meant to work like this... but eh
|
|
||||||
Colourless,
|
|
||||||
#[serde(rename = "T")] // See "Sole Performer"
|
|
||||||
Tap,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
enum Legality {
|
|
||||||
#[serde(rename = "legal")]
|
|
||||||
Legal,
|
|
||||||
#[serde(rename = "not_legal")]
|
|
||||||
NotLegal,
|
|
||||||
#[serde(rename = "banned")]
|
|
||||||
Banned,
|
|
||||||
#[serde(rename = "restricted")]
|
|
||||||
Restricted,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
struct FormatLegalities {
|
|
||||||
standard: Legality,
|
|
||||||
future: Legality,
|
|
||||||
historic: Legality,
|
|
||||||
timeless: Legality,
|
|
||||||
gladiator: Legality,
|
|
||||||
pioneer: Legality,
|
|
||||||
explorer: Legality,
|
|
||||||
modern: Legality,
|
|
||||||
legacy: Legality,
|
|
||||||
pauper: Legality,
|
|
||||||
vintage: Legality,
|
|
||||||
penny: Legality,
|
|
||||||
commander: Legality,
|
|
||||||
oathbreaker: Legality,
|
|
||||||
standardbrawl: Legality,
|
|
||||||
brawl: Legality,
|
|
||||||
alchemy: Legality,
|
|
||||||
paupercommander: Legality,
|
|
||||||
duel: Legality,
|
|
||||||
oldschool: Legality,
|
|
||||||
premodern: Legality,
|
|
||||||
predh: Legality,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
enum BorderColour {
|
|
||||||
#[serde(rename = "black")]
|
|
||||||
Black,
|
|
||||||
#[serde(rename = "white")]
|
|
||||||
White,
|
|
||||||
#[serde(rename = "borderless")]
|
|
||||||
Borderless,
|
|
||||||
#[serde(rename = "yellow")]
|
|
||||||
Yellow,
|
|
||||||
#[serde(rename = "silver")]
|
|
||||||
Silver,
|
|
||||||
#[serde(rename = "gold")]
|
|
||||||
Gold,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
enum Finish {
|
|
||||||
#[serde(rename = "foil")]
|
|
||||||
Foil,
|
|
||||||
#[serde(rename = "nonfoil")]
|
|
||||||
NonFoil,
|
|
||||||
#[serde(rename = "etched")]
|
|
||||||
Etched,
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://scryfall.com/docs/api/frames#frames
|
|
||||||
// This is probably dumb...
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
enum Frame {
|
|
||||||
#[serde(rename = "1993")]
|
|
||||||
NinetyThree,
|
|
||||||
#[serde(rename = "1997")]
|
|
||||||
NinetySeven,
|
|
||||||
#[serde(rename = "2003")]
|
|
||||||
OhThree,
|
|
||||||
#[serde(rename = "2015")]
|
|
||||||
Fifteen,
|
|
||||||
#[serde(rename = "future")]
|
|
||||||
Future,
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://scryfall.com/docs/api/frames#frame-effects
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
enum FrameEffect {
|
|
||||||
#[serde(rename = "legendary")]
|
|
||||||
Legendary,
|
|
||||||
#[serde(rename = "miracle")]
|
|
||||||
Miracle,
|
|
||||||
#[serde(rename = "enchantment")]
|
|
||||||
Enchantment,
|
|
||||||
#[serde(rename = "draft")]
|
|
||||||
Draft,
|
|
||||||
#[serde(rename = "devoid")]
|
|
||||||
Devoid,
|
|
||||||
#[serde(rename = "tombstone")]
|
|
||||||
Tombstone,
|
|
||||||
#[serde(rename = "colorshifted")]
|
|
||||||
Colourshifted,
|
|
||||||
#[serde(rename = "inverted")]
|
|
||||||
Inverted,
|
|
||||||
#[serde(rename = "sunmoondfc")]
|
|
||||||
SunMoonDFC,
|
|
||||||
#[serde(rename = "compasslanddfc")]
|
|
||||||
CompassLandDFC,
|
|
||||||
#[serde(rename = "originpwdfc")]
|
|
||||||
OriginPwDFC,
|
|
||||||
#[serde(rename = "mooneldrazidfc")]
|
|
||||||
MoonEldraziDFC,
|
|
||||||
#[serde(rename = "waxingandwaningmoondfc")]
|
|
||||||
WaxingAndWaningMoonDFC,
|
|
||||||
#[serde(rename = "showcase")]
|
|
||||||
Showcase,
|
|
||||||
#[serde(rename = "extendedart")]
|
|
||||||
ExtendedArt,
|
|
||||||
#[serde(rename = "companion")]
|
|
||||||
Companion,
|
|
||||||
#[serde(rename = "etched")]
|
|
||||||
Etched,
|
|
||||||
#[serde(rename = "snow")]
|
|
||||||
Snow,
|
|
||||||
#[serde(rename = "lesson")]
|
|
||||||
Lesson,
|
|
||||||
#[serde(rename = "shatteredglass")]
|
|
||||||
ShatteredGlass,
|
|
||||||
#[serde(rename = "convertdfc")]
|
|
||||||
ConvertDFC,
|
|
||||||
#[serde(rename = "fandfc")]
|
|
||||||
FanDFC,
|
|
||||||
#[serde(rename = "upsidedowndfc")]
|
|
||||||
UpsideDownDFC,
|
|
||||||
#[serde(rename = "spree")]
|
|
||||||
Spree,
|
|
||||||
#[serde(rename = "fullart")]
|
|
||||||
FullArt,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
enum Game {
|
|
||||||
#[serde(rename = "paper")]
|
|
||||||
Paper,
|
|
||||||
#[serde(rename = "mtgo")]
|
|
||||||
Mtgo,
|
|
||||||
#[serde(rename = "arena")]
|
|
||||||
Arena,
|
|
||||||
#[serde(rename = "astral")]
|
|
||||||
Astral,
|
|
||||||
#[serde(rename = "sega")]
|
|
||||||
Sega,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
enum ImageStatus {
|
|
||||||
#[serde(rename = "missing")]
|
|
||||||
Missing,
|
|
||||||
#[serde(rename = "placeholder")]
|
|
||||||
Placeholder,
|
|
||||||
#[serde(rename = "lowres")]
|
|
||||||
LowResolution,
|
|
||||||
#[serde(rename = "highres_scan")]
|
|
||||||
HighResolutionScan,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
struct ImageURIs {
|
|
||||||
png: Option<String>,
|
|
||||||
border_crop: Option<String>,
|
|
||||||
art_crop: Option<String>,
|
|
||||||
large: Option<String>,
|
|
||||||
normal: Option<String>,
|
|
||||||
small: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
struct Preview {
|
|
||||||
pub previewed_at: Option<NaiveDate>,
|
|
||||||
pub source_uri: Option<String>, // URI
|
|
||||||
pub source: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
struct Prices {
|
|
||||||
usd: Option<String>, // TODO Convert to f64?
|
|
||||||
usd_foil: Option<String>,
|
|
||||||
usd_etched: Option<String>,
|
|
||||||
eur: Option<String>,
|
|
||||||
eur_foil: Option<String>,
|
|
||||||
tix: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
enum Rarity {
|
|
||||||
#[serde(rename = "common")]
|
|
||||||
Common,
|
|
||||||
#[serde(rename = "uncommon")]
|
|
||||||
Uncommon,
|
|
||||||
#[serde(rename = "rare")]
|
|
||||||
Rare,
|
|
||||||
#[serde(rename = "special")]
|
|
||||||
Special,
|
|
||||||
#[serde(rename = "mythic")]
|
|
||||||
Mythic,
|
|
||||||
#[serde(rename = "bonus")]
|
|
||||||
Bonus,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
struct PurchaseUris {
|
|
||||||
tcgplayer: String, // Option?
|
|
||||||
cardmarket: String,
|
|
||||||
cardhoarder: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
enum SecurityStamp {
|
|
||||||
#[serde(rename = "oval")]
|
|
||||||
Oval,
|
|
||||||
#[serde(rename = "triangle")]
|
|
||||||
Triangle,
|
|
||||||
#[serde(rename = "acorn")]
|
|
||||||
Acorn,
|
|
||||||
#[serde(rename = "circle")]
|
|
||||||
Circle,
|
|
||||||
#[serde(rename = "arena")]
|
|
||||||
Arena,
|
|
||||||
#[serde(rename = "heart")]
|
|
||||||
Heart,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
enum Component {
|
|
||||||
#[serde(rename = "token")]
|
|
||||||
Token,
|
|
||||||
#[serde(rename = "meld_part")]
|
|
||||||
MeldPart,
|
|
||||||
#[serde(rename = "meld_result")]
|
|
||||||
MeldResult,
|
|
||||||
#[serde(rename = "combo_piece")]
|
|
||||||
ComboPiece,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
enum SetType {
|
|
||||||
#[serde(rename = "alchemy")]
|
|
||||||
Alchemy,
|
|
||||||
#[serde(rename = "archenemy")]
|
|
||||||
Archenemy,
|
|
||||||
#[serde(rename = "arsenal")]
|
|
||||||
Arsenal,
|
|
||||||
#[serde(rename = "box")]
|
|
||||||
Box,
|
|
||||||
#[serde(rename = "commander")]
|
|
||||||
Commander,
|
|
||||||
#[serde(rename = "core")]
|
|
||||||
Core,
|
|
||||||
#[serde(rename = "draft_innovation")]
|
|
||||||
DraftInnovation,
|
|
||||||
#[serde(rename = "duel_deck")]
|
|
||||||
DuelDeck,
|
|
||||||
#[serde(rename = "expansion")]
|
|
||||||
Expansion,
|
|
||||||
#[serde(rename = "from_the_vault")]
|
|
||||||
FromTheVault,
|
|
||||||
#[serde(rename = "funny")]
|
|
||||||
Funny,
|
|
||||||
#[serde(rename = "masterpiece")]
|
|
||||||
Masterpiece,
|
|
||||||
#[serde(rename = "masters")]
|
|
||||||
Masters,
|
|
||||||
#[serde(rename = "memorabilia")]
|
|
||||||
Memorabilia,
|
|
||||||
#[serde(rename = "minigame")]
|
|
||||||
Minigame,
|
|
||||||
#[serde(rename = "planechase")]
|
|
||||||
Planechase,
|
|
||||||
#[serde(rename = "premium_deck")]
|
|
||||||
PremiumDeck,
|
|
||||||
#[serde(rename = "promo")]
|
|
||||||
Promo,
|
|
||||||
#[serde(rename = "spellbook")]
|
|
||||||
SpellBook,
|
|
||||||
#[serde(rename = "starter")]
|
|
||||||
Starter,
|
|
||||||
#[serde(rename = "token")]
|
|
||||||
Token,
|
|
||||||
#[serde(rename = "treasure_chest")]
|
|
||||||
TreasureChest,
|
|
||||||
#[serde(rename = "vanguard")]
|
|
||||||
Vanguard,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO Complete this
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Deserialize, Debug)]
|
|
||||||
enum PromoTypes {
|
|
||||||
#[serde(rename = "alchemy")]
|
|
||||||
Alchemy,
|
|
||||||
#[serde(rename = "arenaleague")]
|
|
||||||
ArenaLeague,
|
|
||||||
#[serde(rename = "beginnerbox")]
|
|
||||||
BeginnerBox,
|
|
||||||
#[serde(rename = "boosterfun")]
|
|
||||||
BoosterFun,
|
|
||||||
#[serde(rename = "boxtopper")]
|
|
||||||
BoxTopper,
|
|
||||||
#[serde(rename = "brawldeck")]
|
|
||||||
BrawlDeck,
|
|
||||||
#[serde(rename = "bundle")]
|
|
||||||
Bundle,
|
|
||||||
#[serde(rename = "buyabox")]
|
|
||||||
BuyABox,
|
|
||||||
#[serde(rename = "confettifoil")]
|
|
||||||
ConfettiFoil,
|
|
||||||
#[serde(rename = "convention")]
|
|
||||||
Convention,
|
|
||||||
#[serde(rename = "datestamped")]
|
|
||||||
DateStamped,
|
|
||||||
#[serde(rename = "dossier")]
|
|
||||||
Dossier,
|
|
||||||
#[serde(rename = "doublerainbow")]
|
|
||||||
DoubleRainbow,
|
|
||||||
#[serde(rename = "embossed")]
|
|
||||||
Embossed,
|
|
||||||
#[serde(rename = "event")]
|
|
||||||
Event,
|
|
||||||
#[serde(rename = "fnm")]
|
|
||||||
Fnm,
|
|
||||||
#[serde(rename = "gameday")]
|
|
||||||
GameDay,
|
|
||||||
#[serde(rename = "godzillaseries")]
|
|
||||||
GodzillaSeries,
|
|
||||||
#[serde(rename = "halofoil")]
|
|
||||||
HaloFoil,
|
|
||||||
#[serde(rename = "imagine")]
|
|
||||||
Imagine,
|
|
||||||
#[serde(rename = "instore")]
|
|
||||||
InStore,
|
|
||||||
#[serde(rename = "intropack")]
|
|
||||||
IntroPack,
|
|
||||||
#[serde(rename = "invisibleink")]
|
|
||||||
InvisibleInk,
|
|
||||||
#[serde(rename = "judgegift")]
|
|
||||||
JudgeGift,
|
|
||||||
#[serde(rename = "league")]
|
|
||||||
League,
|
|
||||||
#[serde(rename = "magnified")]
|
|
||||||
Magnified,
|
|
||||||
#[serde(rename = "manafoil")]
|
|
||||||
ManaFoil,
|
|
||||||
#[serde(rename = "mediainsert")]
|
|
||||||
MediaInsert,
|
|
||||||
#[serde(rename = "planeswalkerdeck")]
|
|
||||||
PlaneswalkerDeck,
|
|
||||||
#[serde(rename = "plastic")]
|
|
||||||
Plastic,
|
|
||||||
#[serde(rename = "playerrewards")]
|
|
||||||
PlayerRewards,
|
|
||||||
#[serde(rename = "playtest")]
|
|
||||||
Playtest,
|
|
||||||
#[serde(rename = "poster")]
|
|
||||||
Poster,
|
|
||||||
#[serde(rename = "prerelease")]
|
|
||||||
Prerelease,
|
|
||||||
#[serde(rename = "premiereshop")]
|
|
||||||
PremiereShop,
|
|
||||||
#[serde(rename = "promopack")]
|
|
||||||
PromoPack,
|
|
||||||
#[serde(rename = "rainbowfoil")]
|
|
||||||
RainbowFoil,
|
|
||||||
#[serde(rename = "ravnicacity")]
|
|
||||||
RavnicaCity,
|
|
||||||
#[serde(rename = "rebalanced")]
|
|
||||||
Rebalanced,
|
|
||||||
#[serde(rename = "release")]
|
|
||||||
Release,
|
|
||||||
#[serde(rename = "resale")]
|
|
||||||
Resale,
|
|
||||||
#[serde(rename = "ripplefoil")]
|
|
||||||
RippleFoil,
|
|
||||||
#[serde(rename = "setpromo")]
|
|
||||||
SetPromo,
|
|
||||||
#[serde(rename = "serialized")]
|
|
||||||
Serialised,
|
|
||||||
#[serde(rename = "silverfoil")]
|
|
||||||
SilverFoil,
|
|
||||||
#[serde(rename = "sldbonus")]
|
|
||||||
SldBonus,
|
|
||||||
#[serde(rename = "stamped")]
|
|
||||||
Stamped,
|
|
||||||
#[serde(rename = "startercollection")]
|
|
||||||
StarterCollection,
|
|
||||||
#[serde(rename = "starterdeck")]
|
|
||||||
StarterDeck,
|
|
||||||
#[serde(rename = "stepandcompleat")]
|
|
||||||
StepAndCompleat,
|
|
||||||
#[serde(rename = "surgefoil")]
|
|
||||||
SurgeFoil,
|
|
||||||
#[serde(rename = "textured")]
|
|
||||||
Textured,
|
|
||||||
#[serde(rename = "themepack")]
|
|
||||||
ThemePack,
|
|
||||||
#[serde(rename = "thick")]
|
|
||||||
Thick,
|
|
||||||
#[serde(rename = "tourney")]
|
|
||||||
Tourney,
|
|
||||||
#[serde(rename = "upsidedown")]
|
|
||||||
Upsidedown,
|
|
||||||
#[serde(rename = "vault")]
|
|
||||||
Vault,
|
|
||||||
#[serde(rename = "wizardsplaynetwork")]
|
|
||||||
WizardsPlayNetwork,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn weird_cards() -> Vec<String> {
|
|
||||||
// These all seem to be double faced cards with the same "card" on both sides.
|
|
||||||
vec![
|
|
||||||
"018830b2-dff9-45f3-9cc2-dc5b2eec0e54".to_string(),
|
|
||||||
"0489be0d-2117-46a8-97ab-31fe480685e2".to_string(),
|
|
||||||
"048ddb71-e9ea-4f11-9b8a-c53961cf3a2c".to_string(),
|
|
||||||
"087c3a0d-c710-4451-989e-596b55352184".to_string(),
|
|
||||||
"236e9bcf-ced2-4bee-8188-41dd94df02da".to_string(),
|
|
||||||
"36ea852d-ed2b-4c56-9b73-52dce8a3e520".to_string(),
|
|
||||||
"399bf36a-5901-437f-b5d3-32283cedbbcb".to_string(),
|
|
||||||
"3cb0824c-57cc-46bf-bd43-425d58b8a762".to_string(),
|
|
||||||
"fe388da5-9197-4d07-be7f-c49fcdf56dfa".to_string(),
|
|
||||||
"f973a1f3-6dcb-470d-89d2-6ddbf2426999".to_string(),
|
|
||||||
"f4e7b3a4-a346-4177-9cfe-0142b40ef4a6".to_string(),
|
|
||||||
"e25ce640-baf5-442b-8b75-d05dd9fb20dd".to_string(),
|
|
||||||
"dae8751c-4c72-4034-a192-a1e166f20246".to_string(),
|
|
||||||
"d74a72a2-d46a-41c2-a400-70571197b020".to_string(),
|
|
||||||
"d5f7a626-7b6b-41ba-a0f5-3aefe511b267".to_string(),
|
|
||||||
"d5dfd236-b1da-4552-b94f-ebf6bb9dafdf".to_string(),
|
|
||||||
"d002b29b-c3a6-4c91-86e1-96a50ce29966".to_string(),
|
|
||||||
"caf8d01d-07aa-43da-a26e-4a2ba3a76f2d".to_string(),
|
|
||||||
"c05c6c38-d204-458c-af17-4cf5efd2c7fc".to_string(),
|
|
||||||
"bffbe9ec-edbc-43ed-a3bf-60635e7e625c".to_string(),
|
|
||||||
"b96d6ea4-a3a4-4e33-be97-b3767f2bb63a".to_string(),
|
|
||||||
"acdb72e2-c000-4b92-b5ea-73115969020f".to_string(),
|
|
||||||
"aae84079-b65b-4132-86fb-e82503bb6c7b".to_string(),
|
|
||||||
"a724ebbc-0f77-42e9-95e0-b3e7cb130148".to_string(),
|
|
||||||
"a4a2dd5b-6143-4b8d-ae71-e148cf19b66c".to_string(),
|
|
||||||
"a129558c-45a1-441c-97f0-b70b4e9d8a56".to_string(),
|
|
||||||
"9f63277b-e139-46c8-b9e3-0cfb647f44cc".to_string(),
|
|
||||||
"9e69f9e0-4981-4fc0-955f-7ebe04264fca".to_string(),
|
|
||||||
"9d943cf2-0462-4f31-9a92-d76fe4971b17".to_string(),
|
|
||||||
"9cd6a16f-1eff-4624-8f7f-4d9e70a694bb".to_string(),
|
|
||||||
"9680a2d6-1d66-4f69-b400-a79fea4187d8".to_string(),
|
|
||||||
"94eea6e3-20bc-4dab-90ba-3113c120fb90".to_string(),
|
|
||||||
"94594d48-b728-4be6-9d7a-c67088df8acd".to_string(),
|
|
||||||
"3d89c9be-2489-47e4-8e53-f980c82442b4".to_string(),
|
|
||||||
"3e3f0bcd-0796-494d-bf51-94b33c1671e9".to_string(),
|
|
||||||
"4696f5de-fe5b-40df-a194-1a73b4c5150f".to_string(),
|
|
||||||
"4d227cd3-ebfe-4dd3-929a-4f8ff7c8981e".to_string(),
|
|
||||||
"5ab0412a-2b2f-430f-8830-002a42125148".to_string(),
|
|
||||||
"60c92f1b-0c78-4809-9365-e1ffa515cb4b".to_string(),
|
|
||||||
"6620b5f4-b1e5-4d1b-bbf2-c6ad9c8284c5".to_string(),
|
|
||||||
"67574bb4-c443-40fa-b7e6-05e9965c98b8".to_string(),
|
|
||||||
"6adadbc9-4a08-4c1d-adf7-edee73799d9e".to_string(),
|
|
||||||
"6c69ecd2-cb36-4628-802b-fd5ff7405f22".to_string(),
|
|
||||||
"76c343f5-6955-4ba2-a435-36d55182d1dd".to_string(),
|
|
||||||
"7e703632-5ed0-4509-a12b-594269f865f1".to_string(),
|
|
||||||
"82fa24fb-aecc-4c33-9e79-c29651ddafbe".to_string(),
|
|
||||||
"843b35ec-7b59-4a22-8fee-2e876a02306b".to_string(),
|
|
||||||
"8ae0caed-940d-45bc-9877-7cc014b2700e".to_string(),
|
|
||||||
"8b5341ab-85a6-44b2-b738-1110e699c02b".to_string(),
|
|
||||||
"8bcf942f-5afd-414e-a50d-00d884fe59da".to_string(),
|
|
||||||
"9052f5c7-ee3b-457d-97ca-ac6b4518997c".to_string(),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use std::fs;
|
|
||||||
use std::io::{BufRead, BufReader};
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deserialise_nissa() {
|
|
||||||
let mut f = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
||||||
f.push("test_files/nissa.json");
|
|
||||||
assert!(f.exists());
|
|
||||||
let fc = fs::read_to_string(f).unwrap();
|
|
||||||
let _nissa: ScryfallCard = serde_json::from_str(&fc).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deserialise_black_lotus() {
|
|
||||||
let mut f = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
||||||
f.push("test_files/black_lotus.json");
|
|
||||||
assert!(f.exists());
|
|
||||||
let fc = fs::read_to_string(f).unwrap();
|
|
||||||
let _bl: ScryfallCard = serde_json::from_str(&fc).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deserialise_little_girl() {
|
|
||||||
let mut f = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
||||||
f.push("test_files/little_girl.json");
|
|
||||||
assert!(f.exists());
|
|
||||||
let fc = fs::read_to_string(f).unwrap();
|
|
||||||
let _lg: ScryfallCard = serde_json::from_str(&fc).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn deserialize_line_by_line_with_bad_skip() {
|
|
||||||
// This function is uuuuuuugly and I'm sure a terrible way to go about things
|
|
||||||
// It is ever so slightly faster than the other one though!
|
|
||||||
let mut f = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
||||||
f.push("test_files/all-cards.json");
|
|
||||||
assert!(f.exists(), "You need to download the all-cards-... file from Scryfall bulk data. Can be found here: https://scryfall.com/docs/api/bulk-data and rename to all-cards.json");
|
|
||||||
let ac = fs::File::open(f).unwrap();
|
|
||||||
let reader = BufReader::new(ac);
|
|
||||||
let weird_cards = weird_cards();
|
|
||||||
for line in reader.lines().skip(1) {
|
|
||||||
let mut line = line.unwrap();
|
|
||||||
let c = line.pop().unwrap();
|
|
||||||
// this is so dumb...
|
|
||||||
if c == '}' {
|
|
||||||
line.push('}');
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't look...
|
|
||||||
let mut skip = false;
|
|
||||||
for weird_card in &weird_cards {
|
|
||||||
if line.contains(weird_card) {
|
|
||||||
skip = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if skip {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if line.is_empty() {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let a_card: Result<ScryfallCard, serde_json::Error> =
|
|
||||||
serde_json::from_str(line.as_ref());
|
|
||||||
if let Err(error) = a_card {
|
|
||||||
println!("{:#?}", line);
|
|
||||||
println!("{:#?}", error);
|
|
||||||
}
|
|
||||||
//let a_card = a_card.unwrap();
|
|
||||||
//println!("{:?}", a_card.promo_types)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore]
|
|
||||||
fn deserialize_line_by_line() {
|
|
||||||
// This function is uuuuuuugly and I'm sure a terrible way to go about things
|
|
||||||
// It is ever so slightly faster than the other one though!
|
|
||||||
let mut f = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
||||||
f.push("test_files/all-cards.json");
|
|
||||||
assert!(f.exists(), "You need to download the all-cards-... file from Scryfall bulk data. Can be found here: https://scryfall.com/docs/api/bulk-data and rename to all-cards.json");
|
|
||||||
let ac = fs::File::open(f).unwrap();
|
|
||||||
let reader = BufReader::new(ac);
|
|
||||||
for line in reader.lines().skip(1) {
|
|
||||||
let mut line = line.unwrap();
|
|
||||||
let c = line.pop().unwrap();
|
|
||||||
// this is so dumb...
|
|
||||||
if c == '}' {
|
|
||||||
line.push('}');
|
|
||||||
}
|
|
||||||
|
|
||||||
if line.is_empty() {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
let a_card: Result<ScryfallCard, serde_json::Error> =
|
|
||||||
serde_json::from_str(line.as_ref());
|
|
||||||
if let Err(error) = a_card {
|
|
||||||
println!("{:#?}", line);
|
|
||||||
println!("{:#?}", error);
|
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
//let a_card = a_card.unwrap();
|
|
||||||
//println!("{:?}", a_card.promo_types)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore]
|
|
||||||
fn deserialize_whole_file() {
|
|
||||||
let mut f = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
||||||
f.push("test_files/all-cards.json");
|
|
||||||
assert!(f.exists(), "You need to download the all-cards-... file from Scryfall bulk data. Can be found here: https://scryfall.com/docs/api/bulk-data and rename to all-cards.json");
|
|
||||||
|
|
||||||
let ac = fs::read_to_string(f).unwrap();
|
|
||||||
let _ac: Vec<ScryfallCard> = serde_json::from_str(&ac).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[ignore]
|
|
||||||
fn get_scryfall_bulk_page() {
|
|
||||||
let mut file = NamedTempFile::new().unwrap();
|
|
||||||
let _ = download_latest(ScryfallBulkType::OracleCards, &file);
|
|
||||||
let file_size = file.seek(SeekFrom::End(0)).unwrap();
|
|
||||||
assert!(file_size > 4092);
|
|
||||||
println!("File size: {}", file_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user