Add card USD pricing and a deck maybeboard
Prices come from Scryfall's prices.usd on printings, shown as a hover badge on card tiles. The price is picked independently of whichever printing supplies the display image (the cheapest known price across all printings), since the display printing is often a promo/variant with no listed price. The maybeboard lets a deck track cards under consideration without counting them in deck analysis stats or library assignment totals. Cards move between mainboard and maybeboard via a per-card toggle; maybeboarding the commander clears commander status. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -612,6 +612,8 @@ struct ScryPrinting {
|
||||
image_uris: Option<ImageUris>,
|
||||
#[serde(default)]
|
||||
card_faces: Option<Vec<PrintFace>>,
|
||||
#[serde(default)]
|
||||
prices: Option<ScryPrices>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@@ -620,6 +622,12 @@ struct ImageUris {
|
||||
normal: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ScryPrices {
|
||||
#[serde(default)]
|
||||
usd: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct PrintFace {
|
||||
#[serde(default)]
|
||||
@@ -632,8 +640,8 @@ fn load_printings(conn: &Connection, reader: impl Read, cancel: &CancelToken) ->
|
||||
{
|
||||
let mut ins = conn.prepare(
|
||||
"INSERT OR IGNORE INTO printings
|
||||
(scryfall_id,oracle_id,set_code,collector_number,finishes,rarity,image_uri,back_image_uri)
|
||||
VALUES (?1,?2,?3,?4,?5,?6,?7,?8)",
|
||||
(scryfall_id,oracle_id,set_code,collector_number,finishes,rarity,image_uri,back_image_uri,price_usd)
|
||||
VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9)",
|
||||
)?;
|
||||
stream_json_array::<_, ScryPrinting, _>(reader, |p| {
|
||||
if cancel.is_cancelled() {
|
||||
@@ -664,6 +672,12 @@ fn load_printings(conn: &Connection, reader: impl Read, cancel: &CancelToken) ->
|
||||
.and_then(|f| f.image_uris.as_ref())
|
||||
.and_then(|i| i.normal.clone())
|
||||
.unwrap_or_default();
|
||||
let price_usd = p
|
||||
.prices
|
||||
.as_ref()
|
||||
.and_then(|pr| pr.usd.as_ref())
|
||||
.and_then(|s| s.parse::<f64>().ok())
|
||||
.unwrap_or(0.0);
|
||||
ins.execute(params![
|
||||
p.id,
|
||||
oracle_id,
|
||||
@@ -673,6 +687,7 @@ fn load_printings(conn: &Connection, reader: impl Read, cancel: &CancelToken) ->
|
||||
p.rarity,
|
||||
image,
|
||||
back_image,
|
||||
price_usd,
|
||||
])?;
|
||||
count += 1;
|
||||
Ok(())
|
||||
@@ -953,4 +968,34 @@ mod tests {
|
||||
assert_eq!(front, "http://img/split-combined");
|
||||
assert_eq!(back, "", "split cards have no distinct back face");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn captures_usd_price_defaulting_to_zero_when_absent() {
|
||||
let printings = r#"[
|
||||
{"id":"p-priced","oracle_id":"oid-priced","set":"m19","collector_number":"1",
|
||||
"rarity":"common","prices":{"usd":"12.34","usd_foil":"20.00"}},
|
||||
{"id":"p-null","oracle_id":"oid-null","set":"m19","collector_number":"2",
|
||||
"rarity":"common","prices":{"usd":null}},
|
||||
{"id":"p-noprices","oracle_id":"oid-noprices","set":"m19","collector_number":"3",
|
||||
"rarity":"common"}
|
||||
]"#;
|
||||
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let dest = dir.path().join("reference.db");
|
||||
let conn = open_reference_for_build(&dest).unwrap();
|
||||
|
||||
load_printings(&conn, printings.as_bytes(), &CancelToken::new()).unwrap();
|
||||
|
||||
let fetch = |id: &str| -> f64 {
|
||||
conn.query_row(
|
||||
"SELECT price_usd FROM printings WHERE scryfall_id=?1",
|
||||
params![id],
|
||||
|r| r.get(0),
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
assert_eq!(fetch("p-priced"), 12.34);
|
||||
assert_eq!(fetch("p-null"), 0.0);
|
||||
assert_eq!(fetch("p-noprices"), 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user