diff --git a/.claude/skills/bgg-api/SKILL.md b/.claude/skills/bgg-api/SKILL.md index b493739..c9245bd 100644 --- a/.claude/skills/bgg-api/SKILL.md +++ b/.claude/skills/bgg-api/SKILL.md @@ -60,7 +60,7 @@ The first `/collection` call typically returns **HTTP 202** with a "please retry - Login with `BGG_USERNAME` / `BGG_PASSWORD` env vars; persist Playwright storage state locally (gitignored) so repeat runs skip login. Never write credentials to disk, logs, or error messages. - Per game: navigate to the game page → "Add to Collection" flow → status **Owned** → if a version_id is known, set it in the collection item's version picker → save. Never guess a version — omit it when unknown. The flow has been walked and documented: see `docs/bgg-upload-flow.md` for the dialog structure, version-picker behavior (paginated, no search — match by canonical version NAME from the XML API), and observed automation gotchas (stale elements, hidden-not-removed dialogs, hydration races). -- A second copy of an owned game must be a NEW collection entry (new collid), not an edit of the existing item. +- A second copy of an owned game must be a NEW collection entry (new collid), not an edit of the existing item. Conversely, version UPGRADES from to_update.csv must edit the EXISTING item (same collid) — additive only: fill the empty version field, change nothing else, and skip any entry that already has a version. - Expect UI fragility: wrap each game in its own try/except, log the failure to `upload_log.csv`, and continue. `--retry-failed` re-attempts failures; `--dry-run` logs without touching the site. - Idempotency: skip IDs already logged `added`; `--verify` re-fetches the collection to confirm. diff --git a/bgg-shelf-pipeline-spec.md b/bgg-shelf-pipeline-spec.md index 95c36b4..8133b9d 100644 --- a/bgg-shelf-pipeline-spec.md +++ b/bgg-shelf-pipeline-spec.md @@ -77,13 +77,16 @@ Each stage reads the previous stage's artifact and writes its own. Re-running a - Fetch my current collection: `https://boardgamegeek.com/xmlapi2/collection?username=&own=1` (handle the 202-retry queue; also pass `&subtype=boardgameexpansion` in a second call — the collection endpoint excludes expansions from the default subtype). - Output `to_add.csv`: approved/auto matches whose IDs are **not** already in the collection. - **Multiple editions of the same game**: collection items are identified by `collid` (one per copy), not just `objectid`. If matches contain two entries for the same `bgg_id` with different `version_id`s, both belong in the collection as separate entries. Diff logic: a (bgg_id, version_id) pair is "already owned" only if a collection item matches both; a bare bgg_id with `version_unknown` is "already owned" if any copy of that game exists. -- Print a summary: N recognized, N already owned, N to add (including second editions), N rejected/unmatched. +- **Improvement pass (to_update)**: for games already owned whose collection entry has NO version set, where photo matching produced a `version_auto`/`version_approved` — emit `to_update.csv` (`collid, bgg_id, bgg_name, version_id, version_name`). This upgrades the hand-entered 2018 entries with edition data from the shelves. Strictly additive: only fill empty version fields; if the collection entry already has a version, never touch it (even if the photo disagrees — report the disagreement in the summary instead). +- Informational only: list collection entries not seen in any photo (possible missing/loaned/sold games) in the summary. No action taken. +- Print a summary: N recognized, N already owned, N to add (including second editions), N version updates, N rejected/unmatched. ### Stage 5 — `upload`: Add games via Playwright - Log in to boardgamegeek.com with credentials from env vars (`BGG_USERNAME`, `BGG_PASSWORD`). Never write credentials to disk or logs. Persist the browser session/storage state locally so repeat runs don't re-login. - For each row in `to_add.csv`: navigate to the game page, use the "Add to Collection" flow, set status **Owned**, and — when a `version_id` is present — set the specific version in the collection item's version picker before saving. Manually walk this flow once and document the selectors before automating; the version UI is the most fragile part. - Adding a second copy of an already-owned game must create a NEW collection entry, not edit the existing one. +- **Update mode** (rows from `to_update.csv`): open the EXISTING collection entry (keyed by `collid`) rather than the add flow, set the version, save. Must never create a duplicate entry and never change any other field of the entry. Verify the already-owned dialog behavior manually first — flagged as unverified in `docs/bgg-upload-flow.md`. - Log every attempt to `upload_log.csv`: `bgg_id, name, status (added|already_present|failed), timestamp, error`. - Idempotent: skip IDs already logged as `added`; re-verify against a fresh collection fetch on `--verify`. - Deliberately slow: 2–4 s randomized delay between games. This is a real account on a community site — behave like a polite human. @@ -103,7 +106,8 @@ All artifacts are flat files in a `data/` directory — human-readable, git-frie - `titles.json` — extraction output (stage 1) - `bgg_cache/` — cached XML API responses - `matches.csv` — the master matching table (stages 2–3) -- `to_add.csv` — upload queue (stage 4) +- `to_add.csv` — upload queue, new entries (stage 4) +- `to_update.csv` — version upgrades for existing version-less entries (stage 4) - `upload_log.csv` — audit trail (stage 5) - `games.json` — full game + version metadata (stage 6); seed data for the future frontend @@ -130,6 +134,7 @@ All artifacts are flat files in a `data/` directory — human-readable, git-frie 6. Credentials never appear in any file, log, or error message. 7. Where photos show legible edition cues, the matched version survives to the BGG collection entry; where they don't, the entry is added version-less rather than with a guessed version. 8. A game I own in two editions ends up as two distinct collection entries, and `games.json` contains full metadata for every game in the collection. +9. Version upgrades land on existing collection entries (same `collid`) with no duplicate entries created and no non-version fields changed; entries that already have a version are never modified. ## Suggested Build Order diff --git a/data/collection_snapshot_base.xml b/data/collection_snapshot_base.xml new file mode 100644 index 0000000..94832c3 --- /dev/null +++ b/data/collection_snapshot_base.xml @@ -0,0 +1,1038 @@ + + + + 5-Minute Dungeon + 2017 https://cf.geekdo-images.com/uR7RqGbua7h_Z74fmz_-ng__original/img/WXzrC9-ob09Qbxt9jh5_dLLjFGE=/0x0/filters:format(jpeg)/pic9630053.jpg + https://cf.geekdo-images.com/uR7RqGbua7h_Z74fmz_-ng__small/img/AFRWc9kb0CH17kGzrJEghKNlOnQ=/fit-in/200x150/filters:strip_icc()/pic9630053.jpg + + + + + + + + + 0 + + Advanced Civilization + 1991 https://cf.geekdo-images.com/9ROB7NpxefRUmpR9UroQ8w__original/img/--qlhvNNj8zF9cWLlihdTg0jzmE=/0x0/filters:format(jpeg)/pic87459.jpg + https://cf.geekdo-images.com/9ROB7NpxefRUmpR9UroQ8w__small/img/XDH667tVl2KjQ6szNjT7ceEmh5E=/fit-in/200x150/filters:strip_icc()/pic87459.jpg + + + + + + + + + 0 + + Age of Renaissance + 1996 https://cf.geekdo-images.com/hNg-cufowH-csaTfzC_nPw__original/img/FXsJRqYH2tFltJrLqSlWdoZaJs8=/0x0/filters:format(jpeg)/pic5682587.jpg + https://cf.geekdo-images.com/hNg-cufowH-csaTfzC_nPw__small/img/M3hGcwq2PbwUmWE8anROZLBckKc=/fit-in/200x150/filters:strip_icc()/pic5682587.jpg + + + + + + + + + 0 + + ...and then, we held hands. + 2015 https://cf.geekdo-images.com/Ft08woV-KG3HHfO-ET6S4Q__original/img/x7YkL7sqFAt2LAxgPx3MEv3ZMNI=/0x0/filters:format(jpeg)/pic2717772.jpg + https://cf.geekdo-images.com/Ft08woV-KG3HHfO-ET6S4Q__small/img/8NF5KOA3oPkiJkqtOrfi0anm5BI=/fit-in/200x150/filters:strip_icc()/pic2717772.jpg + + + + + + + + + 0 + + Bananagrams + 2006 https://cf.geekdo-images.com/1QjYPI4bXx4OUMJPlrsNBA__original/img/WA2NRNJx83xq81H2dnnwEDV2Ork=/0x0/filters:format(jpeg)/pic2463443.jpg + https://cf.geekdo-images.com/1QjYPI4bXx4OUMJPlrsNBA__small/img/nC_gG-4CYy7VBfYez2qSfTkU2ik=/fit-in/200x150/filters:strip_icc()/pic2463443.jpg + + + + + + + + + 0 + + Before I Kill You, Mister Spy... + 1996 https://cf.geekdo-images.com/CMYnGVcqpdlN8D8Fi64Dpg__original/img/MkRBpDEL4Hw-81uG-IvH9ZHLsk0=/0x0/filters:format(jpeg)/pic3051016.jpg + https://cf.geekdo-images.com/CMYnGVcqpdlN8D8Fi64Dpg__small/img/7rrSNbVpY5TOPBax-G6Pj4DesDA=/fit-in/200x150/filters:strip_icc()/pic3051016.jpg + + + + + + + + + + 0 + + Britannia + 1986 https://cf.geekdo-images.com/-M-1zs8oMttiUS2xd8qK4A__original/img/Hil6BWCATeo_bcRqRMHGhAsx_mw=/0x0/filters:format(jpeg)/pic106711.jpg + https://cf.geekdo-images.com/-M-1zs8oMttiUS2xd8qK4A__small/img/qjfnfPFYpTCgmvV9Yon2BDdy88Q=/fit-in/200x150/filters:strip_icc()/pic106711.jpg + + + + + + + + + 0 + + Bugs in the Kitchen + 2013 https://cf.geekdo-images.com/RyeZQU9LkyEUtEtlwjSM9w__original/img/u0lfUWc7-bREM7t_6YmX7i_ViUY=/0x0/filters:format(jpeg)/pic3891987.jpg + https://cf.geekdo-images.com/RyeZQU9LkyEUtEtlwjSM9w__small/img/VLWYy1d6eq09iA_wopAJy-8LKcM=/fit-in/200x150/filters:strip_icc()/pic3891987.jpg + + + + + + + + + 0 + + Carcassonne + 2000 https://cf.geekdo-images.com/peUgu3A20LRmAXAMyDQfpQ__original/img/bP18m_PYjyFOv1IBGgMOteQUneA=/0x0/filters:format(jpeg)/pic8621446.jpg + https://cf.geekdo-images.com/peUgu3A20LRmAXAMyDQfpQ__small/img/oEEslN-EGqh82sNI6Aj4_MFXYg0=/fit-in/200x150/filters:strip_icc()/pic8621446.jpg + + + + + + + + + 0 + + Castle Panic + 2009 https://cf.geekdo-images.com/ryPiCH15spkrdtvUI-utuA__original/img/RYiSrrenTejCl149T6tc2d9CuwA=/0x0/filters:format(jpeg)/pic6966125.jpg + https://cf.geekdo-images.com/ryPiCH15spkrdtvUI-utuA__small/img/2MMQHuG-dSRngk0E2EKeqyE8e9o=/fit-in/200x150/filters:strip_icc()/pic6966125.jpg + + + + + + + + + 0 + + Castle Panic: The Dark Titan + 2015 https://cf.geekdo-images.com/ne5GT5tNupCbGeN4maV0aw__original/img/Pe0unjKPwaO0cJPd9QI_Eo-xuRU=/0x0/filters:format(jpeg)/pic6967876.jpg + https://cf.geekdo-images.com/ne5GT5tNupCbGeN4maV0aw__small/img/RTQtsNpxLidMnDPDGTTf-AiP9OQ=/fit-in/200x150/filters:strip_icc()/pic6967876.jpg + + + + + + + + 0 + + Castle Panic: The Wizard's Tower + 2011 https://cf.geekdo-images.com/ZI_7riAQtSAb9T3bodOVKA__original/img/S5nr9djtA4cUDvi7dmtTiYhut1Y=/0x0/filters:format(jpeg)/pic6966120.jpg + https://cf.geekdo-images.com/ZI_7riAQtSAb9T3bodOVKA__small/img/VzbEp7j_wYr0KiXfvsYITTAhnSk=/fit-in/200x150/filters:strip_icc()/pic6966120.jpg + + + + + + + + + 0 + + The Cat Game + 2017 https://cf.geekdo-images.com/A07HOEIY81M961ejepCidA__original/img/LcynDDk9pp1zzzj2CsLybJGeZws=/0x0/filters:format(jpeg)/pic3641655.jpg + https://cf.geekdo-images.com/A07HOEIY81M961ejepCidA__small/img/kW_C_eVz7fURxeIzS9ifEKMwZ4M=/fit-in/200x150/filters:strip_icc()/pic3641655.jpg + + + + + + + + 0 + + Catan + 1995 https://cf.geekdo-images.com/0XODRpReiZBFUffEcqT5-Q__original/img/oRc0AomWA9ZtFqQDZiZbIyKE1j0=/0x0/filters:format(png)/pic9156909.png + https://cf.geekdo-images.com/0XODRpReiZBFUffEcqT5-Q__small/img/SNVfF23OQafv3u8xdFolJnMkBoM=/fit-in/200x150/filters:strip_icc()/pic9156909.png + + + + + + + + + + 0 + + Catan Dice Game + 2007 https://cf.geekdo-images.com/lNVa_4IQ3pBHuh5CRzSe-w__original/img/nDWd2-dY7D1ZoFPZhXvDqQs_BA8=/0x0/filters:format(jpeg)/pic3661032.jpg + https://cf.geekdo-images.com/lNVa_4IQ3pBHuh5CRzSe-w__small/img/ICEhSw8IrhG7i-zNf9k7E3I3rrs=/fit-in/200x150/filters:strip_icc()/pic3661032.jpg + + + + + + + + + 0 + + Catan Junior + 2014 https://cf.geekdo-images.com/3N4eCvJFqoygqP9qxMq5ZA__original/img/sd5RwvhEjTOklfap_8sCPyexZ78=/0x0/filters:format(jpeg)/pic2836284.jpg + https://cf.geekdo-images.com/3N4eCvJFqoygqP9qxMq5ZA__small/img/n8BHU43CbISCJ0ki6S-15nOv-uE=/fit-in/200x150/filters:strip_icc()/pic2836284.jpg + + + + + + + + + 0 + + Civilization + 1980 https://cf.geekdo-images.com/tUdVpt5daNITDrLXqN931Q__original/img/121amP5yjflTHIFW017EGPe5Rjk=/0x0/filters:format(jpeg)/pic114473.jpg + https://cf.geekdo-images.com/tUdVpt5daNITDrLXqN931Q__small/img/AI7xWgZxUCdXZHPH5WXCXWSAKUI=/fit-in/200x150/filters:strip_icc()/pic114473.jpg + + + + + + + + + 0 + + Consentacle + 2014 https://cf.geekdo-images.com/HxW4curp8PnTfAZpqMuEDQ__original/img/Qd6WvEQhwV3ST8sFgJjP_E6cgxg=/0x0/filters:format(jpeg)/pic4172245.jpg + https://cf.geekdo-images.com/HxW4curp8PnTfAZpqMuEDQ__small/img/WznGAoMLcG3BGUEmP37vktZ2G9A=/fit-in/200x150/filters:strip_icc()/pic4172245.jpg + + + + + + + + + 0 + + Cosmic Encounter + 1991 https://cf.geekdo-images.com/bFAM5SbKCMp7qdwQyj0uiA__original/img/anmO_7hg4QsU_kI3BVR1Wx2kckA=/0x0/filters:format(jpeg)/pic455214.jpg + https://cf.geekdo-images.com/bFAM5SbKCMp7qdwQyj0uiA__small/img/Fy6EL7tvz-Ng8RudwDEa_OXK6LI=/fit-in/200x150/filters:strip_icc()/pic455214.jpg + + + + + + + + + + 0 + + Curling Table Game + 2008 https://cf.geekdo-images.com/YHsEDxsR3OGt2dJg1cL9Fw__original/img/QnNU20nsXPsrqj4LROxz70lxqVw=/0x0/filters:format(jpeg)/pic428287.jpg + https://cf.geekdo-images.com/YHsEDxsR3OGt2dJg1cL9Fw__small/img/R7nknX7IlDGQ-mSiPGnGkGO48SU=/fit-in/200x150/filters:strip_icc()/pic428287.jpg + + + + + + + + 0 + + Dark Cults + 1983 https://cf.geekdo-images.com/1Yiabh6DNZcIn_1WJ_DnjQ__original/img/5plSWWkOlUtYe1nsD8MaJXQTmGc=/0x0/filters:format(jpeg)/pic4978.jpg + https://cf.geekdo-images.com/1Yiabh6DNZcIn_1WJ_DnjQ__small/img/KDoWL5IkgGLQhm9bM__20pBzwmE=/fit-in/200x150/filters:strip_icc()/pic4978.jpg + + + + + + + + + 0 + + Diplomacy + 1959 https://cf.geekdo-images.com/CGJihifkrZSqW40zElgXkQ__original/img/m38u19fIxQceN0fJtLU3O31MhXw=/0x0/filters:format(jpeg)/pic7376874.jpg + https://cf.geekdo-images.com/CGJihifkrZSqW40zElgXkQ__small/img/_Ar945YdaXSz3iFIR_aOCCcf6zc=/fit-in/200x150/filters:strip_icc()/pic7376874.jpg + + + + + + + + + + 0 + + Dixit + 2008 https://cf.geekdo-images.com/J0PlHArkZDJ57H-brXW2Fw__original/img/jt3kFCHJ3HJ2079dMLwipFZqdQg=/0x0/filters:format(jpeg)/pic6738336.jpg + https://cf.geekdo-images.com/J0PlHArkZDJ57H-brXW2Fw__small/img/QVwPXskFikQwBQlrdLJBAiRGgdg=/fit-in/200x150/filters:strip_icc()/pic6738336.jpg + + + + + + + + + 0 + + Doctor Who: The Card Game + 2012 https://cf.geekdo-images.com/abNcykgcvAIvyZpmZY9Lew__original/img/gt-hLDZIqUhCNJDfVyBqbcHb7m0=/0x0/filters:format(jpeg)/pic1327331.jpg + https://cf.geekdo-images.com/abNcykgcvAIvyZpmZY9Lew__small/img/l91104qfHunxC48wvhlD6zDqsgM=/fit-in/200x150/filters:strip_icc()/pic1327331.jpg + + + + + + + + + + 0 + + Doctor Who: The Game of Time & Space + 1980 https://cf.geekdo-images.com/3l-VQuk2dGc2Vjjz93wNVA__original/img/aJ9sEoCgiZIWHZ3cXATF8iayKhU=/0x0/filters:format(jpeg)/pic14058.jpg + https://cf.geekdo-images.com/3l-VQuk2dGc2Vjjz93wNVA__small/img/w82krrS4f639MQb2Qf2Eo8Bd1xg=/fit-in/200x150/filters:strip_icc()/pic14058.jpg + + + + + + + + + 0 + + The Doom That Came to Atlantic City + 2013 https://cf.geekdo-images.com/SRNm7BPGq1L0aFo4aEcBhA__original/img/5ZHqB34M-wHKGNMJF20U5waS-EA=/0x0/filters:format(jpeg)/pic2454377.jpg + https://cf.geekdo-images.com/SRNm7BPGq1L0aFo4aEcBhA__small/img/F8dAQlcGebZuPnA9TK4VN1X5F-w=/fit-in/200x150/filters:strip_icc()/pic2454377.jpg + + + + + + + + + 0 + + Dragonland + 2002 https://cf.geekdo-images.com/k4uY9E-Vo_u06P2opeuhFQ__original/img/VI3Suc-b6qmNxNP5b45iFBRY8Hw=/0x0/filters:format(jpeg)/pic4890287.jpg + https://cf.geekdo-images.com/k4uY9E-Vo_u06P2opeuhFQ__small/img/N1fV_A0YYlWBpqEuNlgKdiqovZM=/fit-in/200x150/filters:strip_icc()/pic4890287.jpg + + + + + + + + + 0 + + Dungeon! + 1975 https://cf.geekdo-images.com/fvhkcw4s6Q4-nMwwok1J6A__original/img/WJFmTRWQRzOInBnWAjH39F3RyMg=/0x0/filters:format(png)/pic6569894.png + https://cf.geekdo-images.com/fvhkcw4s6Q4-nMwwok1J6A__small/img/zXW1s2ZXq1dZkvbAzYdr9o1xRNQ=/fit-in/200x150/filters:strip_icc()/pic6569894.png + + + + + + + + + + 0 + + Evolution + 2014 https://cf.geekdo-images.com/wo_EYno7S66psGPMl_JtiQ__original/img/buKqUQr48Cb41noIhoaAJzWBLQA=/0x0/filters:format(jpeg)/pic3543505.jpg + https://cf.geekdo-images.com/wo_EYno7S66psGPMl_JtiQ__small/img/_30uXRkyUuk9vMeeedlSqQ3oJwA=/fit-in/200x150/filters:strip_icc()/pic3543505.jpg + + + + + + + + + 0 + + Exploding Kittens + 2015 https://cf.geekdo-images.com/N8bL53-pRU7zaXDTrEaYrw__original/img/0ciN1VZYifUd0qIDO0e8cGXmiss=/0x0/filters:format(png)/pic2691976.png + https://cf.geekdo-images.com/N8bL53-pRU7zaXDTrEaYrw__small/img/3tH4pIc1Udzkd0tXc6MgVQ59BC0=/fit-in/200x150/filters:strip_icc()/pic2691976.png + + + + + + + + + 0 + + Exploding Kittens: NSFW Edition + 2015 https://cf.geekdo-images.com/_9v_15rJjapltOr0I74uJQ__original/img/5-sylqMMDS3r8RelWDrcNQJiUSE=/0x0/filters:format(png)/pic9005066.png + https://cf.geekdo-images.com/_9v_15rJjapltOr0I74uJQ__small/img/RG3VraWEZaezik-9vAA0ksN4MZI=/fit-in/200x150/filters:strip_icc()/pic9005066.png + + + + + + + + + 0 + + Flat Top + 1977 https://cf.geekdo-images.com/U4aLOWpOLNtUjQ5BirlGLA__original/img/5m1hrtRgt6lst9tajA4o169D4wA=/0x0/filters:format(jpeg)/pic806423.jpg + https://cf.geekdo-images.com/U4aLOWpOLNtUjQ5BirlGLA__small/img/thPXwIIE3knD9igpLusCdeHVsMI=/fit-in/200x150/filters:strip_icc()/pic806423.jpg + + + + + + + + + 0 + + Fluxx + 1997 https://cf.geekdo-images.com/ZBQHRlhd32wt4F_zgeic6w__original/img/6-0pkob0RUXgRyxGPJ2ZKyYObxw=/0x0/filters:format(jpeg)/pic2405641.jpg + https://cf.geekdo-images.com/ZBQHRlhd32wt4F_zgeic6w__small/img/MjQ7iYoOXuU9AUrTojjYE8sdyTk=/fit-in/200x150/filters:strip_icc()/pic2405641.jpg + + + + + + + + + + 0 + + Forbidden Island + 2010 https://cf.geekdo-images.com/JgAkEBUaiHOsOS94iRMs2w__original/img/H5d4I5z_HSpPEu7EAl0DqLt9_pM=/0x0/filters:format(jpeg)/pic646458.jpg + https://cf.geekdo-images.com/JgAkEBUaiHOsOS94iRMs2w__small/img/5aPR8-KMbgucI_XkPE2PJaMQQsg=/fit-in/200x150/filters:strip_icc()/pic646458.jpg + + + + + + + + + 0 + + Give Me the Brain! + 1996 https://cf.geekdo-images.com/OlPw-qCHEgl-83A8rWf9IA__original/img/4ulSIYQhzgyhzzxlg6tKjis70kY=/0x0/filters:format(jpeg)/pic984692.jpg + https://cf.geekdo-images.com/OlPw-qCHEgl-83A8rWf9IA__small/img/uQwxOsY1lZ2D5T2OTQ0Q5t52MZo=/fit-in/200x150/filters:strip_icc()/pic984692.jpg + + + + + + + + + + 0 + + Go Fish Yourself + 2015 https://cf.geekdo-images.com/jfXGKha8QeY20sVRNCb3eQ__original/img/3tC9fwYOv0erI0w1KsKctWf4pR0=/0x0/filters:format(png)/pic9579726.png + https://cf.geekdo-images.com/jfXGKha8QeY20sVRNCb3eQ__small/img/r9bZLsBX19nqNIorrtuWbH4u0h4=/fit-in/200x150/filters:strip_icc()/pic9579726.png + + + + + + + + 0 + + Googly Eyes + 2008 https://cf.geekdo-images.com/D_SKR1RenJ-A96W4AcpVZw__original/img/AYoJl-zbL8OLzsx0xiC7FjvMIrQ=/0x0/filters:format(jpeg)/pic3052922.jpg + https://cf.geekdo-images.com/D_SKR1RenJ-A96W4AcpVZw__small/img/eJdxkVo28a-PvuEY5wBzbkuBAW4=/fit-in/200x150/filters:strip_icc()/pic3052922.jpg + + + + + + + + 0 + + History of the World + 1991 https://cf.geekdo-images.com/2pr-83ghWQUlwXSLuSTCtw__original/img/_MRG_pnmZQwScJWus84gwaXNflE=/0x0/filters:format(jpeg)/pic287451.jpg + https://cf.geekdo-images.com/2pr-83ghWQUlwXSLuSTCtw__small/img/4XPSkcdNf6CXGWsDGSRXrP7VUBc=/fit-in/200x150/filters:strip_icc()/pic287451.jpg + + + + + + + + + + + 0 + + Huggermugger + 1989 https://cf.geekdo-images.com/fPep3Ze_haawiA6wu979YQ__original/img/QlHSWYyF2JAXiPitbjELs_m4kkQ=/0x0/filters:format(jpeg)/pic353210.jpg + https://cf.geekdo-images.com/fPep3Ze_haawiA6wu979YQ__small/img/ACFXxWqeRMZ-lD5B1TuH28ZR9B8=/fit-in/200x150/filters:strip_icc()/pic353210.jpg + + + + + + + + + 0 + + Joking Hazard + 2016 https://cf.geekdo-images.com/ohrUtQ0FGHPSFxfSX2Ltmg__original/img/ksIb5Fgrn9Tka1FGVnL8iMlGAjA=/0x0/filters:format(png)/pic6411897.png + https://cf.geekdo-images.com/ohrUtQ0FGHPSFxfSX2Ltmg__small/img/r9PhVsbOjPDDLfVKBhwrPnqV4LI=/fit-in/200x150/filters:strip_icc()/pic6411897.png + + + + + + + + + 0 + + Kensington + 1979 https://cf.geekdo-images.com/SziKU_czapNhgznSS2J0Jg__original/img/BOwgrRde9S08t6GkITYnPozx1gQ=/0x0/filters:format(jpeg)/pic94595.jpg + https://cf.geekdo-images.com/SziKU_czapNhgznSS2J0Jg__small/img/qYKWfnTE8KoIsFB6GZjFQ8LD55o=/fit-in/200x150/filters:strip_icc()/pic94595.jpg + + + + + + + + + 0 + + Kill Doctor Lucky + 1996 https://cf.geekdo-images.com/HzSvdAtAiktVmdTfDEIayA__original/img/hdvDZLMGdx5EDOQFlKj8GcZkTp8=/0x0/filters:format(jpeg)/pic2923257.jpg + https://cf.geekdo-images.com/HzSvdAtAiktVmdTfDEIayA__small/img/fIMPwA6ZEVr9bSf7QFrsezXjafg=/fit-in/200x150/filters:strip_icc()/pic2923257.jpg + + + + + + + + + 0 + + KLASK + 2014 https://cf.geekdo-images.com/oPNuEm_dR987BKoYEF9zGQ__original/img/ZNqEkLMKkrIPxRduZWmWC6VBgoY=/0x0/filters:format(png)/pic7414566.png + https://cf.geekdo-images.com/oPNuEm_dR987BKoYEF9zGQ__small/img/JeO68IlD-DGB8zg2ozB-3MmpN2s=/fit-in/200x150/filters:strip_icc()/pic7414566.png + + + + + + + + + + 0 + + Labyrinth + 1986 https://cf.geekdo-images.com/qpL225YNN5iKRPotB7Q7MA__original/img/5ZGo501PquASeGxpQLBIglcVSYs=/0x0/filters:format(jpeg)/pic6173371.jpg + https://cf.geekdo-images.com/qpL225YNN5iKRPotB7Q7MA__small/img/JZR5MVC8xYrboBrYMsZmWtjJTu0=/fit-in/200x150/filters:strip_icc()/pic6173371.jpg + + + + + + + + + 0 + + Laser Chess + 2011 https://cf.geekdo-images.com/8VnQyYMQZGiTCO3e8CjBQg__original/img/AsLQ0q62L3fXJPcFqVadk4zqLx0=/0x0/filters:format(jpeg)/pic3950331.jpg + https://cf.geekdo-images.com/8VnQyYMQZGiTCO3e8CjBQg__small/img/4s5BaVmkKxcK2p8Zt9skfZOLOSQ=/fit-in/200x150/filters:strip_icc()/pic3950331.jpg + + + + + + + + + 0 + + Lil' Cthulhu + 2016 https://cf.geekdo-images.com/IAea2iylhELCRfoUyMcdPw__original/img/ahqDWvf1g5O69dIkRevW4E_MbPc=/0x0/filters:format(jpeg)/pic2839660.jpg + https://cf.geekdo-images.com/IAea2iylhELCRfoUyMcdPw__small/img/zSjYtpodp9sCy3qNMohEWZKZcR0=/fit-in/200x150/filters:strip_icc()/pic2839660.jpg + + + + + + + + 0 + + Mage Wars Academy + 2015 https://cf.geekdo-images.com/BXqdHw39CPenDAKWDm_Vxw__original/img/pzO7kVTqFPx5mGYQXPxC39x4kL8=/0x0/filters:format(png)/pic2555236.png + https://cf.geekdo-images.com/BXqdHw39CPenDAKWDm_Vxw__small/img/RgBmCUFY-rCCHNC3uWAE3u8lTmA=/fit-in/200x150/filters:strip_icc()/pic2555236.png + + + + + + + + + 0 + + Meteor + 2014 https://cf.geekdo-images.com/mVC1JCvb488GJFhNF1idsA__original/img/G1UroUSm25FSY7LQXpPu6f6--20=/0x0/filters:format(png)/pic2256875.png + https://cf.geekdo-images.com/mVC1JCvb488GJFhNF1idsA__small/img/Bx9UJsNZV8eF7kebFJlFoCqvtUw=/fit-in/200x150/filters:strip_icc()/pic2256875.png + + + + + + + + + 0 + + Munchkin + 2001 https://cf.geekdo-images.com/J-ts3MW0UhDzs621TR6cog__original/img/FbqPPCilgZKND2xmhWJgkfjZiYE=/0x0/filters:format(jpeg)/pic1871016.jpg + https://cf.geekdo-images.com/J-ts3MW0UhDzs621TR6cog__small/img/8hVkpMC5pDLr6ARI_4gI4N3aF5M=/fit-in/200x150/filters:strip_icc()/pic1871016.jpg + + + + + + + + + + 0 + + No Thank You, Evil! + 2016 https://cf.geekdo-images.com/b_Jftm8zKB2ItfIdDZSR-g__original/img/XPkfFiWXkGvqvpCqgbGhAt30tyM=/0x0/filters:format(jpeg)/pic3174067.jpg + https://cf.geekdo-images.com/b_Jftm8zKB2ItfIdDZSR-g__small/img/ECPrjPcNpwBZELxzwxX1usQe9f4=/fit-in/200x150/filters:strip_icc()/pic3174067.jpg + + + + + + + + + + 0 + + Onitama + 2014 https://cf.geekdo-images.com/GJKuOCy5HGAYgVH_Rei5mA__original/img/oRsIxp72iv58128KFdqvjG6Gz64=/0x0/filters:format(jpeg)/pic7070194.jpg + https://cf.geekdo-images.com/GJKuOCy5HGAYgVH_Rei5mA__small/img/Q3W4poMS4btD-HZLervgqbSCtmE=/fit-in/200x150/filters:strip_icc()/pic7070194.jpg + + + + + + + + + 0 + + Pie Face Showdown + 2016 https://cf.geekdo-images.com/5OUkDIq5mnGL2aLYIXIXmA__original/img/VCuxOesnLaPddH1B_OarM2_j0mA=/0x0/filters:format(jpeg)/pic3175723.jpg + https://cf.geekdo-images.com/5OUkDIq5mnGL2aLYIXIXmA__small/img/Epz7KLATSUCD5VbWcj-SE9Zh4Us=/fit-in/200x150/filters:strip_icc()/pic3175723.jpg + + + + + + + + 0 + + The Red Dragon Inn + 2007 https://cf.geekdo-images.com/RCXedcfgn5LSfH4-kOUvLA__original/img/Fr16k-_UzhrIB6_yre7SrMhkDxU=/0x0/filters:format(jpeg)/pic291048.jpg + https://cf.geekdo-images.com/RCXedcfgn5LSfH4-kOUvLA__small/img/fw7C7ruhaqXTqrWZFHCXdQpNKRs=/fit-in/200x150/filters:strip_icc()/pic291048.jpg + + + + + + + + + + 0 + + Risk: The Lord of the Rings + 2002 https://cf.geekdo-images.com/i8ryx8pqPonNNUXyRWjQaw__original/img/jD6_3u-Z2e54Szi3I8p6Ma74Wc4=/0x0/filters:format(jpeg)/pic265703.jpg + https://cf.geekdo-images.com/i8ryx8pqPonNNUXyRWjQaw__small/img/0-JW3OU-6XDoUKqhQudJIbRX0Bc=/fit-in/200x150/filters:strip_icc()/pic265703.jpg + + + + + + + + + 0 + + Rivals for Catan + 2010 https://cf.geekdo-images.com/n5x9eZiQ7Da4SQjB7M41-w__original/img/Y6dJpidB1624ox-QCAdiSVsCnf4=/0x0/filters:format(jpeg)/pic6877018.jpg + https://cf.geekdo-images.com/n5x9eZiQ7Da4SQjB7M41-w__small/img/dGMw2df-4gOwfLCdUeJceBeLCk8=/fit-in/200x150/filters:strip_icc()/pic6877018.jpg + + + + + + + + + 0 + + Robot Turtles + 2013 https://cf.geekdo-images.com/SRJcEXLEBnj5WxcSmW22hA__original/img/Dzz2RP84t8CLjMaLoLbGB5tbzFc=/0x0/filters:format(jpeg)/pic2047441.jpg + https://cf.geekdo-images.com/SRJcEXLEBnj5WxcSmW22hA__small/img/cpax1CjpG61IOX1zhXrKuW9Z7yU=/fit-in/200x150/filters:strip_icc()/pic2047441.jpg + + + + + + + + + 0 + + Rock Me Archimedes + 2012 https://cf.geekdo-images.com/aYy25Eg6tHOhdmqaa2MgFg__original/img/_pEiVGJru7TLHdTLwFzn_1PW0_o=/0x0/filters:format(jpeg)/pic2387634.jpg + https://cf.geekdo-images.com/aYy25Eg6tHOhdmqaa2MgFg__small/img/8W8piD3EZi4x1HyOFJs9_7DMLMA=/fit-in/200x150/filters:strip_icc()/pic2387634.jpg + + + + + + + + + 0 + + Royals + 2014 https://cf.geekdo-images.com/Un-yHPPUaH7IpTfiG7ffkw__original/img/rOD_UORh5dzMisuJFBP7548XbkU=/0x0/filters:format(jpeg)/pic3021582.jpg + https://cf.geekdo-images.com/Un-yHPPUaH7IpTfiG7ffkw__small/img/h9a43sj1YW-dZCKU9wKvHvFSy5U=/fit-in/200x150/filters:strip_icc()/pic3021582.jpg + + + + + + + + + + 0 + + Santorini + 2016 https://cf.geekdo-images.com/665Ply7Ho1WVf1v1iZlWeg__original/img/4q6RCxd7st-yW2MyrJwVC_d3ajk=/0x0/filters:format(png)/pic3283110.png + https://cf.geekdo-images.com/665Ply7Ho1WVf1v1iZlWeg__small/img/BKnSb6kAhpVFHV8cyUXrs3EF_dw=/fit-in/200x150/filters:strip_icc()/pic3283110.png + + + + + + + + + 0 + + Seven Dragons + 2011 https://cf.geekdo-images.com/Qc-1nXLd7Zpl2kpX1ga3Bg__original/img/Ee7DlC9nZTtHXA5TfqfEKEvTS18=/0x0/filters:format(jpeg)/pic1022004.jpg + https://cf.geekdo-images.com/Qc-1nXLd7Zpl2kpX1ga3Bg__small/img/AhwFa5lK5OuIhieeQ56KZrR09e8=/fit-in/200x150/filters:strip_icc()/pic1022004.jpg + + + + + + + + + 0 + + Sheriff of Nottingham + 2014 https://cf.geekdo-images.com/BBgLFKUzr6tcKtlIM2JSFw__original/img/fll2MuTBPVKb7fyBJ8D-4_c1XHM=/0x0/filters:format(jpeg)/pic2075830.jpg + https://cf.geekdo-images.com/BBgLFKUzr6tcKtlIM2JSFw__small/img/JD5L_XrtkaKINUj8ILZqFMGcTsE=/fit-in/200x150/filters:strip_icc()/pic2075830.jpg + + + + + + + + + + 0 + + Simon's Cat Card Game + 2016 https://cf.geekdo-images.com/1DW2I_hYs6l5BHuQPGj9dw__original/img/Lg0wZJUxF071jdWcRqOFno2FHgo=/0x0/filters:format(jpeg)/pic8089317.jpg + https://cf.geekdo-images.com/1DW2I_hYs6l5BHuQPGj9dw__small/img/Go_iakh-eYWSEIhz7Gkjmod2fE8=/fit-in/200x150/filters:strip_icc()/pic8089317.jpg + + + + + + + + + + 0 + + Skylanders Portal Master + 2013 https://cf.geekdo-images.com/nPwffbp8-RD4SWwwgwGIfg__original/img/WMxqMqdSTRVpuUAjjUVOIOLzBx4=/0x0/filters:format(jpeg)/pic9686810.jpg + https://cf.geekdo-images.com/nPwffbp8-RD4SWwwgwGIfg__small/img/aPiWIz7W1yg4ZWuMVjn7X4yzJpE=/fit-in/200x150/filters:strip_icc()/pic9686810.jpg + + + + + + + + 0 + + Small World + 2009 https://cf.geekdo-images.com/aoPM07XzoceB-RydLh08zA__original/img/bYLzrwZO9u-3h2wyU-PHc8aTOY4=/0x0/filters:format(jpeg)/pic428828.jpg + https://cf.geekdo-images.com/aoPM07XzoceB-RydLh08zA__small/img/o3Bw9heVDJRgPYlI_PksCvLAgnM=/fit-in/200x150/filters:strip_icc()/pic428828.jpg + + + + + + + + + + 0 + + Snappy Dressers + 2016 https://cf.geekdo-images.com/BWKD42FXZxyY3iGg0MdEhQ__original/img/eNk-qRaZg3d5RkrKiZcwZMu9s48=/0x0/filters:format(jpeg)/pic3619180.jpg + https://cf.geekdo-images.com/BWKD42FXZxyY3iGg0MdEhQ__small/img/_-qsvWQbJKc8SFFVIYURqyQEjlE=/fit-in/200x150/filters:strip_icc()/pic3619180.jpg + + + + + + + + 0 + + Sorcerer: The Game of Magical Conflict + 1975 https://cf.geekdo-images.com/NpauF7CJudER5H5nj-z-gA__original/img/eGfEPINMJA_0pAKWAYyjJaXmaQo=/0x0/filters:format(jpeg)/pic10078.jpg + https://cf.geekdo-images.com/NpauF7CJudER5H5nj-z-gA__small/img/Vo85InhIcQUg1myZBiHCL22uu8A=/fit-in/200x150/filters:strip_icc()/pic10078.jpg + + + + + + + + + + 0 + + Speechless + 2016 https://cf.geekdo-images.com/CGCYY9KMI4ohm5fYQH1n_g__original/img/1iIrbGykzNTIAsvNkCLxt9e-km4=/0x0/filters:format(png)/pic2944475.png + https://cf.geekdo-images.com/CGCYY9KMI4ohm5fYQH1n_g__small/img/V_azlMIVuWUW7vgGE1eMYULSzzY=/fit-in/200x150/filters:strip_icc()/pic2944475.png + + + + + + + + 0 + + StarForce 'Alpha Centauri': Interstellar Conflict in the 25th Century + 1974 https://cf.geekdo-images.com/8PIdXg87V8l-VuCZAplQlQ__original/img/JRuDUwwK8S1jG9gZISv_Hwz5Kog=/0x0/filters:format(jpeg)/pic567384.jpg + https://cf.geekdo-images.com/8PIdXg87V8l-VuCZAplQlQ__small/img/OTL4rEL5eQ-8jJ_JubPwIq9LBIQ=/fit-in/200x150/filters:strip_icc()/pic567384.jpg + + + + + + + + + 0 + + Super Mario Bros. Power Up Card Game + 2017 https://cf.geekdo-images.com/_tjh4A0MS2DK2fO3DaKj5w__original/img/JlMNj_kW9fXhKRB6VAZyKBxPgb4=/0x0/filters:format(jpeg)/pic3684810.jpg + https://cf.geekdo-images.com/_tjh4A0MS2DK2fO3DaKj5w__small/img/-j-mQ0mq6PCgL1C9NyqFwoDzA8E=/fit-in/200x150/filters:strip_icc()/pic3684810.jpg + + + + + + + + 0 + + Superfight + 2013 https://cf.geekdo-images.com/4ih18dd_9SZv3yn-YazMIw__original/img/VOTdHizWmvwJnOFMw6YMWj5sJSg=/0x0/filters:format(jpeg)/pic2933903.jpg + https://cf.geekdo-images.com/4ih18dd_9SZv3yn-YazMIw__small/img/i2BNig3lkYu3MZPhzKRIygg7RJU=/fit-in/200x150/filters:strip_icc()/pic2933903.jpg + + + + + + + + + 0 + + Tac Tac Jack + 2008 https://cf.geekdo-images.com/6TG4QXV3JmLsln11f72XXQ__original/img/Cd7AXhKDVniLOUYXdU1RZ26YH-0=/0x0/filters:format(png)/pic8499311.png + https://cf.geekdo-images.com/6TG4QXV3JmLsln11f72XXQ__small/img/g2GglyKXfnWFJnjS057wW1Fpm7U=/fit-in/200x150/filters:strip_icc()/pic8499311.png + + + + + + + + + 0 + + Tem-Purr-A + 2011 https://cf.geekdo-images.com/LWLRKZPO9B5ITz5f6Linhg__original/img/feTFDIvserg3DrmG6QnsDgtZrF0=/0x0/filters:format(jpeg)/pic2776998.jpg + https://cf.geekdo-images.com/LWLRKZPO9B5ITz5f6Linhg__small/img/beldZHdnD-u49LMy5X6fEJW2F_8=/fit-in/200x150/filters:strip_icc()/pic2776998.jpg + + + + + + + + + 0 + + Terror in Meeple City + 2013 https://cf.geekdo-images.com/loyFNu06XcKcRcoouNkn5Q__original/img/Dg5JwmmkDHJ4b4WDAU7WREHbBdw=/0x0/filters:format(jpeg)/pic2482302.jpg + https://cf.geekdo-images.com/loyFNu06XcKcRcoouNkn5Q__small/img/w5H9B8agVcPdAfNYgvN1qoFjLsc=/fit-in/200x150/filters:strip_icc()/pic2482302.jpg + + + + + + + + + 0 + + Ticket to Ride + 2004 https://cf.geekdo-images.com/kdWYkW-7AqG63HhqPL6ekA__original/img/rWF8r4JXXCQQ7QhiWHhmT-rQ3Pc=/0x0/filters:format(jpeg)/pic8937637.jpg + https://cf.geekdo-images.com/kdWYkW-7AqG63HhqPL6ekA__small/img/5G46jv8MFh_BfX67iMSouTMhKxc=/fit-in/200x150/filters:strip_icc()/pic8937637.jpg + + + + + + + + + 0 + + Town of Salem: The Card Game + 2017 https://cf.geekdo-images.com/twV5Z01K8K7AUgCBH9GShQ__original/img/U9vXw70nSJ94B-Ihe6WEuL1EEn8=/0x0/filters:format(jpeg)/pic3337089.jpg + https://cf.geekdo-images.com/twV5Z01K8K7AUgCBH9GShQ__small/img/-qdChbv8NvLH0d45iFl4bu2SCX4=/fit-in/200x150/filters:strip_icc()/pic3337089.jpg + + + + + + + + 0 + + Völuspá + 2012 https://cf.geekdo-images.com/0Sa8hpkdz947r104XjGijw__original/img/R5k-Fa4h1heKyv-q6InDW0nDio8=/0x0/filters:format(jpeg)/pic1591249.jpg + https://cf.geekdo-images.com/0Sa8hpkdz947r104XjGijw__small/img/8MrEnv-5IvQixU7aVIMmt2Y--Z4=/fit-in/200x150/filters:strip_icc()/pic1591249.jpg + + + + + + + + + + 0 + + Walk the Plank! + 2013 https://cf.geekdo-images.com/nWcihyfWeAXo9SuSANPepw__original/img/P77A3nELOXRHK3JxCRLCTsSqOFo=/0x0/filters:format(jpeg)/pic2196826.jpg + https://cf.geekdo-images.com/nWcihyfWeAXo9SuSANPepw__small/img/UeAabtDenC1sLH02VF30QK-DtmI=/fit-in/200x150/filters:strip_icc()/pic2196826.jpg + + + + + + + + + 0 + + Wiz-War (Eighth Edition) + 2012 https://cf.geekdo-images.com/yXbWhfIuwKFJfPNg5SgPOQ__original/img/C-3SceTz2k75LaIYt3sQWl7g7lU=/0x0/filters:format(jpeg)/pic1222733.jpg + https://cf.geekdo-images.com/yXbWhfIuwKFJfPNg5SgPOQ__small/img/PFBGm2T4kgP7_ARhb7Zcr5j_uZU=/fit-in/200x150/filters:strip_icc()/pic1222733.jpg + + + + + + + + + 0 + + The X-Files: Circle of Truth + 2018 https://cf.geekdo-images.com/0atFeJj4AQqlICeMi_8W0g__original/img/Pzi-phLQqtSqNxkwTCle8UYxeWM=/0x0/filters:format(jpeg)/pic5208706.jpg + https://cf.geekdo-images.com/0atFeJj4AQqlICeMi_8W0g__small/img/Zi1DUgVsUPka8DcOZgodMi7L_GU=/fit-in/200x150/filters:strip_icc()/pic5208706.jpg + + + + + + + + 0 + + diff --git a/data/collection_snapshot_expansions.xml b/data/collection_snapshot_expansions.xml new file mode 100644 index 0000000..6cd028e --- /dev/null +++ b/data/collection_snapshot_expansions.xml @@ -0,0 +1,65 @@ + + + +Advanced Civilization +1991 +https://cf.geekdo-images.com/9ROB7NpxefRUmpR9UroQ8w__original/img/--qlhvNNj8zF9cWLlihdTg0jzmE=/0x0/filters:format(jpeg)/pic87459.jpg +https://cf.geekdo-images.com/9ROB7NpxefRUmpR9UroQ8w__small/img/XDH667tVl2KjQ6szNjT7ceEmh5E=/fit-in/200x150/filters:strip_icc()/pic87459.jpg + + + + + + + + + + + + + + +0 + + +Castle Panic: The Dark Titan +2015 +https://cf.geekdo-images.com/ne5GT5tNupCbGeN4maV0aw__original/img/Pe0unjKPwaO0cJPd9QI_Eo-xuRU=/0x0/filters:format(jpeg)/pic6967876.jpg +https://cf.geekdo-images.com/ne5GT5tNupCbGeN4maV0aw__small/img/RTQtsNpxLidMnDPDGTTf-AiP9OQ=/fit-in/200x150/filters:strip_icc()/pic6967876.jpg + + + + + + + + + + + + + +0 + + +Castle Panic: The Wizard's Tower +2011 +https://cf.geekdo-images.com/ZI_7riAQtSAb9T3bodOVKA__original/img/S5nr9djtA4cUDvi7dmtTiYhut1Y=/0x0/filters:format(jpeg)/pic6966120.jpg +https://cf.geekdo-images.com/ZI_7riAQtSAb9T3bodOVKA__small/img/VzbEp7j_wYr0KiXfvsYITTAhnSk=/fit-in/200x150/filters:strip_icc()/pic6966120.jpg + + + + + + + + + + + + + + +0 + + diff --git a/src/bggpipe/cli.py b/src/bggpipe/cli.py index 704162b..b2d4d65 100644 --- a/src/bggpipe/cli.py +++ b/src/bggpipe/cli.py @@ -67,7 +67,10 @@ def review(config: ConfigOpt = None) -> None: @app.command() def diff(config: ConfigOpt = None) -> None: """Stage 4: diff approved matches against the existing BGG collection.""" - _not_implemented("diff", 4) + from bggpipe.diff import run_diff + + cfg = load_config(config) + run_diff(cfg) @app.command() diff --git a/src/bggpipe/diff.py b/src/bggpipe/diff.py new file mode 100644 index 0000000..8eb74c5 --- /dev/null +++ b/src/bggpipe/diff.py @@ -0,0 +1,213 @@ +"""Stage 4 — diff approved/auto matches against the existing BGG collection. + +Two collection sources: +- live API (default once BGG_API_TOKEN exists): /collection base + expansion + subtype calls, merged by collid; +- snapshot files (fallback): data/collection_snapshot_base.xml + + data/collection_snapshot_expansions.xml, pulled manually via the + logged-in-user exemption. + +Outputs both artifacts: +- to_add.csv — recognized games not in the collection (new entries); +- to_update.csv — owned, VERSION-LESS entries where matching produced a + confident version (version_auto/version_approved). Strictly additive: + entries that already carry a version are never touched — a photo/version + disagreement is reported in the summary instead. +""" + +from __future__ import annotations + +import csv +import os +from dataclasses import dataclass, field +from pathlib import Path + +import typer + +from bggpipe.bgg_client import BGGClient +from bggpipe.config import Config +from bggpipe.models import CollectionItem, parse_collection +from bggpipe.resolve import read_matches + +TO_ADD_COLUMNS = [ + "bgg_id", + "bgg_name", + "year", + "type", + "version_id", + "version_name", + "title_raw", + "source_photos", +] +TO_UPDATE_COLUMNS = ["collid", "bgg_id", "bgg_name", "version_id", "version_name"] + +SNAPSHOT_FILES = ("collection_snapshot_base.xml", "collection_snapshot_expansions.xml") +_CONFIDENT_VERSION = ("version_auto", "version_approved") + + +@dataclass +class DiffResult: + to_add: list[dict] = field(default_factory=list) + to_update: list[dict] = field(default_factory=list) + already_owned: list[str] = field(default_factory=list) # title_raw + disagreements: list[str] = field(default_factory=list) + unseen: list[CollectionItem] = field(default_factory=list) + pending: list[str] = field(default_factory=list) # ambiguous/unmatched titles + rejected: int = 0 + recognized: int = 0 + + +def load_snapshot_collection(data_dir: Path) -> list[CollectionItem]: + """Merge the base + expansions snapshot files, deduping by collid (the + same physical copy can appear in both responses).""" + items: list[CollectionItem] = [] + seen: set[int] = set() + for name in SNAPSHOT_FILES: + path = data_dir / name + if not path.exists(): + raise FileNotFoundError( + f"{path} not found — pull your collection while logged in " + "(no registration needed for your own collection) or set " + "BGG_API_TOKEN for live mode." + ) + for item in parse_collection(path.read_text()): + if item.own and item.coll_id not in seen: + seen.add(item.coll_id) + items.append(item) + return items + + +def compute_diff(rows: list[dict], collection: list[CollectionItem]) -> DiffResult: + by_object: dict[int, list[CollectionItem]] = {} + for item in collection: + by_object.setdefault(item.object_id, []).append(item) + + result = DiffResult() + seen_object_ids: set[int] = set() + consumed_collids: set[int] = set() + + for row in rows: + status = row["match_status"] + if status == "rejected": + result.rejected += 1 + continue + if status not in ("auto", "approved") or not row["bgg_id"]: + result.pending.append(row["title_raw"]) + continue + + result.recognized += 1 + bgg_id = int(row["bgg_id"]) + copies = by_object.get(bgg_id, []) + if copies: + seen_object_ids.add(bgg_id) + + confident = row["version_status"] in _CONFIDENT_VERSION and row["version_id"] + version_id = int(row["version_id"]) if confident else None + + if not copies: + result.to_add.append( + { + "bgg_id": row["bgg_id"], + "bgg_name": row["bgg_name"], + "year": row["year"], + "type": row["type"], + "version_id": row["version_id"] if confident else "", + "version_name": row["version_name"] if confident else "", + "title_raw": row["title_raw"], + "source_photos": row["source_photos"], + } + ) + continue + + if not confident: + # bare id with unknown version: owned if any copy exists + result.already_owned.append(row["title_raw"]) + continue + + if any(c.version_id == version_id for c in copies): + result.already_owned.append(row["title_raw"]) + continue + + versionless = [ + c + for c in copies + if c.version_id is None and c.coll_id not in consumed_collids + ] + if versionless: + target = versionless[0] + consumed_collids.add(target.coll_id) + result.already_owned.append(row["title_raw"]) + result.to_update.append( + { + "collid": str(target.coll_id), + "bgg_id": row["bgg_id"], + "bgg_name": row["bgg_name"] or target.name, + "version_id": row["version_id"], + "version_name": row["version_name"], + } + ) + else: + # every copy already carries a (different) version — never touch it + result.already_owned.append(row["title_raw"]) + result.disagreements.append( + f"{row['title_raw']}: photo suggests version " + f"{row['version_name']!r} ({row['version_id']}) but the " + "collection entry already has a version set — not changing it" + ) + + result.unseen = [ + item for item in collection if item.object_id not in seen_object_ids + ] + return result + + +def _write_csv(path: Path, columns: list[str], rows: list[dict]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("w", newline="") as f: + writer = csv.DictWriter(f, fieldnames=columns, extrasaction="ignore") + writer.writeheader() + writer.writerows(rows) + + +def run_diff(cfg: Config, *, client: BGGClient | None = None) -> DiffResult: + rows = read_matches(cfg.matches_path) + if not rows: + typer.echo(f"{cfg.matches_path} is empty — run `bggpipe resolve` first.") + raise typer.Exit(code=1) + + if os.environ.get("BGG_API_TOKEN") and cfg.bgg_username: + typer.echo("Fetching live collection from BGG…") + client = client or BGGClient(cfg.cache_dir, cfg.rate_limit_seconds) + collection = client.collection_full(cfg.bgg_username) + else: + typer.echo( + "No BGG_API_TOKEN — using collection snapshot files in " + f"{cfg.data_dir}/ (live mode takes over once the token exists)." + ) + collection = load_snapshot_collection(cfg.data_dir) + + result = compute_diff(rows, collection) + + _write_csv(cfg.data_dir / "to_add.csv", TO_ADD_COLUMNS, result.to_add) + _write_csv(cfg.data_dir / "to_update.csv", TO_UPDATE_COLUMNS, result.to_update) + + typer.echo( + f"\n{result.recognized} recognized · {len(result.already_owned)} already " + f"owned · {len(result.to_add)} to add · {len(result.to_update)} version " + f"update(s) · {len(result.pending)} pending review · " + f"{result.rejected} rejected" + ) + if result.disagreements: + typer.echo("\nVersion disagreements (left untouched):") + for line in result.disagreements: + typer.echo(f" - {line}") + if result.pending: + typer.echo("\nStill pending review: " + ", ".join(result.pending)) + if result.unseen: + typer.echo( + f"\nIn your collection but not seen in any photo " + f"({len(result.unseen)} — informational only):" + ) + for item in result.unseen: + typer.echo(f" - {item.name} ({item.object_id})") + return result diff --git a/tests/fixtures/collection_snapshot_base.xml b/tests/fixtures/collection_snapshot_base.xml new file mode 100644 index 0000000..94832c3 --- /dev/null +++ b/tests/fixtures/collection_snapshot_base.xml @@ -0,0 +1,1038 @@ + + + + 5-Minute Dungeon + 2017 https://cf.geekdo-images.com/uR7RqGbua7h_Z74fmz_-ng__original/img/WXzrC9-ob09Qbxt9jh5_dLLjFGE=/0x0/filters:format(jpeg)/pic9630053.jpg + https://cf.geekdo-images.com/uR7RqGbua7h_Z74fmz_-ng__small/img/AFRWc9kb0CH17kGzrJEghKNlOnQ=/fit-in/200x150/filters:strip_icc()/pic9630053.jpg + + + + + + + + + 0 + + Advanced Civilization + 1991 https://cf.geekdo-images.com/9ROB7NpxefRUmpR9UroQ8w__original/img/--qlhvNNj8zF9cWLlihdTg0jzmE=/0x0/filters:format(jpeg)/pic87459.jpg + https://cf.geekdo-images.com/9ROB7NpxefRUmpR9UroQ8w__small/img/XDH667tVl2KjQ6szNjT7ceEmh5E=/fit-in/200x150/filters:strip_icc()/pic87459.jpg + + + + + + + + + 0 + + Age of Renaissance + 1996 https://cf.geekdo-images.com/hNg-cufowH-csaTfzC_nPw__original/img/FXsJRqYH2tFltJrLqSlWdoZaJs8=/0x0/filters:format(jpeg)/pic5682587.jpg + https://cf.geekdo-images.com/hNg-cufowH-csaTfzC_nPw__small/img/M3hGcwq2PbwUmWE8anROZLBckKc=/fit-in/200x150/filters:strip_icc()/pic5682587.jpg + + + + + + + + + 0 + + ...and then, we held hands. + 2015 https://cf.geekdo-images.com/Ft08woV-KG3HHfO-ET6S4Q__original/img/x7YkL7sqFAt2LAxgPx3MEv3ZMNI=/0x0/filters:format(jpeg)/pic2717772.jpg + https://cf.geekdo-images.com/Ft08woV-KG3HHfO-ET6S4Q__small/img/8NF5KOA3oPkiJkqtOrfi0anm5BI=/fit-in/200x150/filters:strip_icc()/pic2717772.jpg + + + + + + + + + 0 + + Bananagrams + 2006 https://cf.geekdo-images.com/1QjYPI4bXx4OUMJPlrsNBA__original/img/WA2NRNJx83xq81H2dnnwEDV2Ork=/0x0/filters:format(jpeg)/pic2463443.jpg + https://cf.geekdo-images.com/1QjYPI4bXx4OUMJPlrsNBA__small/img/nC_gG-4CYy7VBfYez2qSfTkU2ik=/fit-in/200x150/filters:strip_icc()/pic2463443.jpg + + + + + + + + + 0 + + Before I Kill You, Mister Spy... + 1996 https://cf.geekdo-images.com/CMYnGVcqpdlN8D8Fi64Dpg__original/img/MkRBpDEL4Hw-81uG-IvH9ZHLsk0=/0x0/filters:format(jpeg)/pic3051016.jpg + https://cf.geekdo-images.com/CMYnGVcqpdlN8D8Fi64Dpg__small/img/7rrSNbVpY5TOPBax-G6Pj4DesDA=/fit-in/200x150/filters:strip_icc()/pic3051016.jpg + + + + + + + + + + 0 + + Britannia + 1986 https://cf.geekdo-images.com/-M-1zs8oMttiUS2xd8qK4A__original/img/Hil6BWCATeo_bcRqRMHGhAsx_mw=/0x0/filters:format(jpeg)/pic106711.jpg + https://cf.geekdo-images.com/-M-1zs8oMttiUS2xd8qK4A__small/img/qjfnfPFYpTCgmvV9Yon2BDdy88Q=/fit-in/200x150/filters:strip_icc()/pic106711.jpg + + + + + + + + + 0 + + Bugs in the Kitchen + 2013 https://cf.geekdo-images.com/RyeZQU9LkyEUtEtlwjSM9w__original/img/u0lfUWc7-bREM7t_6YmX7i_ViUY=/0x0/filters:format(jpeg)/pic3891987.jpg + https://cf.geekdo-images.com/RyeZQU9LkyEUtEtlwjSM9w__small/img/VLWYy1d6eq09iA_wopAJy-8LKcM=/fit-in/200x150/filters:strip_icc()/pic3891987.jpg + + + + + + + + + 0 + + Carcassonne + 2000 https://cf.geekdo-images.com/peUgu3A20LRmAXAMyDQfpQ__original/img/bP18m_PYjyFOv1IBGgMOteQUneA=/0x0/filters:format(jpeg)/pic8621446.jpg + https://cf.geekdo-images.com/peUgu3A20LRmAXAMyDQfpQ__small/img/oEEslN-EGqh82sNI6Aj4_MFXYg0=/fit-in/200x150/filters:strip_icc()/pic8621446.jpg + + + + + + + + + 0 + + Castle Panic + 2009 https://cf.geekdo-images.com/ryPiCH15spkrdtvUI-utuA__original/img/RYiSrrenTejCl149T6tc2d9CuwA=/0x0/filters:format(jpeg)/pic6966125.jpg + https://cf.geekdo-images.com/ryPiCH15spkrdtvUI-utuA__small/img/2MMQHuG-dSRngk0E2EKeqyE8e9o=/fit-in/200x150/filters:strip_icc()/pic6966125.jpg + + + + + + + + + 0 + + Castle Panic: The Dark Titan + 2015 https://cf.geekdo-images.com/ne5GT5tNupCbGeN4maV0aw__original/img/Pe0unjKPwaO0cJPd9QI_Eo-xuRU=/0x0/filters:format(jpeg)/pic6967876.jpg + https://cf.geekdo-images.com/ne5GT5tNupCbGeN4maV0aw__small/img/RTQtsNpxLidMnDPDGTTf-AiP9OQ=/fit-in/200x150/filters:strip_icc()/pic6967876.jpg + + + + + + + + 0 + + Castle Panic: The Wizard's Tower + 2011 https://cf.geekdo-images.com/ZI_7riAQtSAb9T3bodOVKA__original/img/S5nr9djtA4cUDvi7dmtTiYhut1Y=/0x0/filters:format(jpeg)/pic6966120.jpg + https://cf.geekdo-images.com/ZI_7riAQtSAb9T3bodOVKA__small/img/VzbEp7j_wYr0KiXfvsYITTAhnSk=/fit-in/200x150/filters:strip_icc()/pic6966120.jpg + + + + + + + + + 0 + + The Cat Game + 2017 https://cf.geekdo-images.com/A07HOEIY81M961ejepCidA__original/img/LcynDDk9pp1zzzj2CsLybJGeZws=/0x0/filters:format(jpeg)/pic3641655.jpg + https://cf.geekdo-images.com/A07HOEIY81M961ejepCidA__small/img/kW_C_eVz7fURxeIzS9ifEKMwZ4M=/fit-in/200x150/filters:strip_icc()/pic3641655.jpg + + + + + + + + 0 + + Catan + 1995 https://cf.geekdo-images.com/0XODRpReiZBFUffEcqT5-Q__original/img/oRc0AomWA9ZtFqQDZiZbIyKE1j0=/0x0/filters:format(png)/pic9156909.png + https://cf.geekdo-images.com/0XODRpReiZBFUffEcqT5-Q__small/img/SNVfF23OQafv3u8xdFolJnMkBoM=/fit-in/200x150/filters:strip_icc()/pic9156909.png + + + + + + + + + + 0 + + Catan Dice Game + 2007 https://cf.geekdo-images.com/lNVa_4IQ3pBHuh5CRzSe-w__original/img/nDWd2-dY7D1ZoFPZhXvDqQs_BA8=/0x0/filters:format(jpeg)/pic3661032.jpg + https://cf.geekdo-images.com/lNVa_4IQ3pBHuh5CRzSe-w__small/img/ICEhSw8IrhG7i-zNf9k7E3I3rrs=/fit-in/200x150/filters:strip_icc()/pic3661032.jpg + + + + + + + + + 0 + + Catan Junior + 2014 https://cf.geekdo-images.com/3N4eCvJFqoygqP9qxMq5ZA__original/img/sd5RwvhEjTOklfap_8sCPyexZ78=/0x0/filters:format(jpeg)/pic2836284.jpg + https://cf.geekdo-images.com/3N4eCvJFqoygqP9qxMq5ZA__small/img/n8BHU43CbISCJ0ki6S-15nOv-uE=/fit-in/200x150/filters:strip_icc()/pic2836284.jpg + + + + + + + + + 0 + + Civilization + 1980 https://cf.geekdo-images.com/tUdVpt5daNITDrLXqN931Q__original/img/121amP5yjflTHIFW017EGPe5Rjk=/0x0/filters:format(jpeg)/pic114473.jpg + https://cf.geekdo-images.com/tUdVpt5daNITDrLXqN931Q__small/img/AI7xWgZxUCdXZHPH5WXCXWSAKUI=/fit-in/200x150/filters:strip_icc()/pic114473.jpg + + + + + + + + + 0 + + Consentacle + 2014 https://cf.geekdo-images.com/HxW4curp8PnTfAZpqMuEDQ__original/img/Qd6WvEQhwV3ST8sFgJjP_E6cgxg=/0x0/filters:format(jpeg)/pic4172245.jpg + https://cf.geekdo-images.com/HxW4curp8PnTfAZpqMuEDQ__small/img/WznGAoMLcG3BGUEmP37vktZ2G9A=/fit-in/200x150/filters:strip_icc()/pic4172245.jpg + + + + + + + + + 0 + + Cosmic Encounter + 1991 https://cf.geekdo-images.com/bFAM5SbKCMp7qdwQyj0uiA__original/img/anmO_7hg4QsU_kI3BVR1Wx2kckA=/0x0/filters:format(jpeg)/pic455214.jpg + https://cf.geekdo-images.com/bFAM5SbKCMp7qdwQyj0uiA__small/img/Fy6EL7tvz-Ng8RudwDEa_OXK6LI=/fit-in/200x150/filters:strip_icc()/pic455214.jpg + + + + + + + + + + 0 + + Curling Table Game + 2008 https://cf.geekdo-images.com/YHsEDxsR3OGt2dJg1cL9Fw__original/img/QnNU20nsXPsrqj4LROxz70lxqVw=/0x0/filters:format(jpeg)/pic428287.jpg + https://cf.geekdo-images.com/YHsEDxsR3OGt2dJg1cL9Fw__small/img/R7nknX7IlDGQ-mSiPGnGkGO48SU=/fit-in/200x150/filters:strip_icc()/pic428287.jpg + + + + + + + + 0 + + Dark Cults + 1983 https://cf.geekdo-images.com/1Yiabh6DNZcIn_1WJ_DnjQ__original/img/5plSWWkOlUtYe1nsD8MaJXQTmGc=/0x0/filters:format(jpeg)/pic4978.jpg + https://cf.geekdo-images.com/1Yiabh6DNZcIn_1WJ_DnjQ__small/img/KDoWL5IkgGLQhm9bM__20pBzwmE=/fit-in/200x150/filters:strip_icc()/pic4978.jpg + + + + + + + + + 0 + + Diplomacy + 1959 https://cf.geekdo-images.com/CGJihifkrZSqW40zElgXkQ__original/img/m38u19fIxQceN0fJtLU3O31MhXw=/0x0/filters:format(jpeg)/pic7376874.jpg + https://cf.geekdo-images.com/CGJihifkrZSqW40zElgXkQ__small/img/_Ar945YdaXSz3iFIR_aOCCcf6zc=/fit-in/200x150/filters:strip_icc()/pic7376874.jpg + + + + + + + + + + 0 + + Dixit + 2008 https://cf.geekdo-images.com/J0PlHArkZDJ57H-brXW2Fw__original/img/jt3kFCHJ3HJ2079dMLwipFZqdQg=/0x0/filters:format(jpeg)/pic6738336.jpg + https://cf.geekdo-images.com/J0PlHArkZDJ57H-brXW2Fw__small/img/QVwPXskFikQwBQlrdLJBAiRGgdg=/fit-in/200x150/filters:strip_icc()/pic6738336.jpg + + + + + + + + + 0 + + Doctor Who: The Card Game + 2012 https://cf.geekdo-images.com/abNcykgcvAIvyZpmZY9Lew__original/img/gt-hLDZIqUhCNJDfVyBqbcHb7m0=/0x0/filters:format(jpeg)/pic1327331.jpg + https://cf.geekdo-images.com/abNcykgcvAIvyZpmZY9Lew__small/img/l91104qfHunxC48wvhlD6zDqsgM=/fit-in/200x150/filters:strip_icc()/pic1327331.jpg + + + + + + + + + + 0 + + Doctor Who: The Game of Time & Space + 1980 https://cf.geekdo-images.com/3l-VQuk2dGc2Vjjz93wNVA__original/img/aJ9sEoCgiZIWHZ3cXATF8iayKhU=/0x0/filters:format(jpeg)/pic14058.jpg + https://cf.geekdo-images.com/3l-VQuk2dGc2Vjjz93wNVA__small/img/w82krrS4f639MQb2Qf2Eo8Bd1xg=/fit-in/200x150/filters:strip_icc()/pic14058.jpg + + + + + + + + + 0 + + The Doom That Came to Atlantic City + 2013 https://cf.geekdo-images.com/SRNm7BPGq1L0aFo4aEcBhA__original/img/5ZHqB34M-wHKGNMJF20U5waS-EA=/0x0/filters:format(jpeg)/pic2454377.jpg + https://cf.geekdo-images.com/SRNm7BPGq1L0aFo4aEcBhA__small/img/F8dAQlcGebZuPnA9TK4VN1X5F-w=/fit-in/200x150/filters:strip_icc()/pic2454377.jpg + + + + + + + + + 0 + + Dragonland + 2002 https://cf.geekdo-images.com/k4uY9E-Vo_u06P2opeuhFQ__original/img/VI3Suc-b6qmNxNP5b45iFBRY8Hw=/0x0/filters:format(jpeg)/pic4890287.jpg + https://cf.geekdo-images.com/k4uY9E-Vo_u06P2opeuhFQ__small/img/N1fV_A0YYlWBpqEuNlgKdiqovZM=/fit-in/200x150/filters:strip_icc()/pic4890287.jpg + + + + + + + + + 0 + + Dungeon! + 1975 https://cf.geekdo-images.com/fvhkcw4s6Q4-nMwwok1J6A__original/img/WJFmTRWQRzOInBnWAjH39F3RyMg=/0x0/filters:format(png)/pic6569894.png + https://cf.geekdo-images.com/fvhkcw4s6Q4-nMwwok1J6A__small/img/zXW1s2ZXq1dZkvbAzYdr9o1xRNQ=/fit-in/200x150/filters:strip_icc()/pic6569894.png + + + + + + + + + + 0 + + Evolution + 2014 https://cf.geekdo-images.com/wo_EYno7S66psGPMl_JtiQ__original/img/buKqUQr48Cb41noIhoaAJzWBLQA=/0x0/filters:format(jpeg)/pic3543505.jpg + https://cf.geekdo-images.com/wo_EYno7S66psGPMl_JtiQ__small/img/_30uXRkyUuk9vMeeedlSqQ3oJwA=/fit-in/200x150/filters:strip_icc()/pic3543505.jpg + + + + + + + + + 0 + + Exploding Kittens + 2015 https://cf.geekdo-images.com/N8bL53-pRU7zaXDTrEaYrw__original/img/0ciN1VZYifUd0qIDO0e8cGXmiss=/0x0/filters:format(png)/pic2691976.png + https://cf.geekdo-images.com/N8bL53-pRU7zaXDTrEaYrw__small/img/3tH4pIc1Udzkd0tXc6MgVQ59BC0=/fit-in/200x150/filters:strip_icc()/pic2691976.png + + + + + + + + + 0 + + Exploding Kittens: NSFW Edition + 2015 https://cf.geekdo-images.com/_9v_15rJjapltOr0I74uJQ__original/img/5-sylqMMDS3r8RelWDrcNQJiUSE=/0x0/filters:format(png)/pic9005066.png + https://cf.geekdo-images.com/_9v_15rJjapltOr0I74uJQ__small/img/RG3VraWEZaezik-9vAA0ksN4MZI=/fit-in/200x150/filters:strip_icc()/pic9005066.png + + + + + + + + + 0 + + Flat Top + 1977 https://cf.geekdo-images.com/U4aLOWpOLNtUjQ5BirlGLA__original/img/5m1hrtRgt6lst9tajA4o169D4wA=/0x0/filters:format(jpeg)/pic806423.jpg + https://cf.geekdo-images.com/U4aLOWpOLNtUjQ5BirlGLA__small/img/thPXwIIE3knD9igpLusCdeHVsMI=/fit-in/200x150/filters:strip_icc()/pic806423.jpg + + + + + + + + + 0 + + Fluxx + 1997 https://cf.geekdo-images.com/ZBQHRlhd32wt4F_zgeic6w__original/img/6-0pkob0RUXgRyxGPJ2ZKyYObxw=/0x0/filters:format(jpeg)/pic2405641.jpg + https://cf.geekdo-images.com/ZBQHRlhd32wt4F_zgeic6w__small/img/MjQ7iYoOXuU9AUrTojjYE8sdyTk=/fit-in/200x150/filters:strip_icc()/pic2405641.jpg + + + + + + + + + + 0 + + Forbidden Island + 2010 https://cf.geekdo-images.com/JgAkEBUaiHOsOS94iRMs2w__original/img/H5d4I5z_HSpPEu7EAl0DqLt9_pM=/0x0/filters:format(jpeg)/pic646458.jpg + https://cf.geekdo-images.com/JgAkEBUaiHOsOS94iRMs2w__small/img/5aPR8-KMbgucI_XkPE2PJaMQQsg=/fit-in/200x150/filters:strip_icc()/pic646458.jpg + + + + + + + + + 0 + + Give Me the Brain! + 1996 https://cf.geekdo-images.com/OlPw-qCHEgl-83A8rWf9IA__original/img/4ulSIYQhzgyhzzxlg6tKjis70kY=/0x0/filters:format(jpeg)/pic984692.jpg + https://cf.geekdo-images.com/OlPw-qCHEgl-83A8rWf9IA__small/img/uQwxOsY1lZ2D5T2OTQ0Q5t52MZo=/fit-in/200x150/filters:strip_icc()/pic984692.jpg + + + + + + + + + + 0 + + Go Fish Yourself + 2015 https://cf.geekdo-images.com/jfXGKha8QeY20sVRNCb3eQ__original/img/3tC9fwYOv0erI0w1KsKctWf4pR0=/0x0/filters:format(png)/pic9579726.png + https://cf.geekdo-images.com/jfXGKha8QeY20sVRNCb3eQ__small/img/r9bZLsBX19nqNIorrtuWbH4u0h4=/fit-in/200x150/filters:strip_icc()/pic9579726.png + + + + + + + + 0 + + Googly Eyes + 2008 https://cf.geekdo-images.com/D_SKR1RenJ-A96W4AcpVZw__original/img/AYoJl-zbL8OLzsx0xiC7FjvMIrQ=/0x0/filters:format(jpeg)/pic3052922.jpg + https://cf.geekdo-images.com/D_SKR1RenJ-A96W4AcpVZw__small/img/eJdxkVo28a-PvuEY5wBzbkuBAW4=/fit-in/200x150/filters:strip_icc()/pic3052922.jpg + + + + + + + + 0 + + History of the World + 1991 https://cf.geekdo-images.com/2pr-83ghWQUlwXSLuSTCtw__original/img/_MRG_pnmZQwScJWus84gwaXNflE=/0x0/filters:format(jpeg)/pic287451.jpg + https://cf.geekdo-images.com/2pr-83ghWQUlwXSLuSTCtw__small/img/4XPSkcdNf6CXGWsDGSRXrP7VUBc=/fit-in/200x150/filters:strip_icc()/pic287451.jpg + + + + + + + + + + + 0 + + Huggermugger + 1989 https://cf.geekdo-images.com/fPep3Ze_haawiA6wu979YQ__original/img/QlHSWYyF2JAXiPitbjELs_m4kkQ=/0x0/filters:format(jpeg)/pic353210.jpg + https://cf.geekdo-images.com/fPep3Ze_haawiA6wu979YQ__small/img/ACFXxWqeRMZ-lD5B1TuH28ZR9B8=/fit-in/200x150/filters:strip_icc()/pic353210.jpg + + + + + + + + + 0 + + Joking Hazard + 2016 https://cf.geekdo-images.com/ohrUtQ0FGHPSFxfSX2Ltmg__original/img/ksIb5Fgrn9Tka1FGVnL8iMlGAjA=/0x0/filters:format(png)/pic6411897.png + https://cf.geekdo-images.com/ohrUtQ0FGHPSFxfSX2Ltmg__small/img/r9PhVsbOjPDDLfVKBhwrPnqV4LI=/fit-in/200x150/filters:strip_icc()/pic6411897.png + + + + + + + + + 0 + + Kensington + 1979 https://cf.geekdo-images.com/SziKU_czapNhgznSS2J0Jg__original/img/BOwgrRde9S08t6GkITYnPozx1gQ=/0x0/filters:format(jpeg)/pic94595.jpg + https://cf.geekdo-images.com/SziKU_czapNhgznSS2J0Jg__small/img/qYKWfnTE8KoIsFB6GZjFQ8LD55o=/fit-in/200x150/filters:strip_icc()/pic94595.jpg + + + + + + + + + 0 + + Kill Doctor Lucky + 1996 https://cf.geekdo-images.com/HzSvdAtAiktVmdTfDEIayA__original/img/hdvDZLMGdx5EDOQFlKj8GcZkTp8=/0x0/filters:format(jpeg)/pic2923257.jpg + https://cf.geekdo-images.com/HzSvdAtAiktVmdTfDEIayA__small/img/fIMPwA6ZEVr9bSf7QFrsezXjafg=/fit-in/200x150/filters:strip_icc()/pic2923257.jpg + + + + + + + + + 0 + + KLASK + 2014 https://cf.geekdo-images.com/oPNuEm_dR987BKoYEF9zGQ__original/img/ZNqEkLMKkrIPxRduZWmWC6VBgoY=/0x0/filters:format(png)/pic7414566.png + https://cf.geekdo-images.com/oPNuEm_dR987BKoYEF9zGQ__small/img/JeO68IlD-DGB8zg2ozB-3MmpN2s=/fit-in/200x150/filters:strip_icc()/pic7414566.png + + + + + + + + + + 0 + + Labyrinth + 1986 https://cf.geekdo-images.com/qpL225YNN5iKRPotB7Q7MA__original/img/5ZGo501PquASeGxpQLBIglcVSYs=/0x0/filters:format(jpeg)/pic6173371.jpg + https://cf.geekdo-images.com/qpL225YNN5iKRPotB7Q7MA__small/img/JZR5MVC8xYrboBrYMsZmWtjJTu0=/fit-in/200x150/filters:strip_icc()/pic6173371.jpg + + + + + + + + + 0 + + Laser Chess + 2011 https://cf.geekdo-images.com/8VnQyYMQZGiTCO3e8CjBQg__original/img/AsLQ0q62L3fXJPcFqVadk4zqLx0=/0x0/filters:format(jpeg)/pic3950331.jpg + https://cf.geekdo-images.com/8VnQyYMQZGiTCO3e8CjBQg__small/img/4s5BaVmkKxcK2p8Zt9skfZOLOSQ=/fit-in/200x150/filters:strip_icc()/pic3950331.jpg + + + + + + + + + 0 + + Lil' Cthulhu + 2016 https://cf.geekdo-images.com/IAea2iylhELCRfoUyMcdPw__original/img/ahqDWvf1g5O69dIkRevW4E_MbPc=/0x0/filters:format(jpeg)/pic2839660.jpg + https://cf.geekdo-images.com/IAea2iylhELCRfoUyMcdPw__small/img/zSjYtpodp9sCy3qNMohEWZKZcR0=/fit-in/200x150/filters:strip_icc()/pic2839660.jpg + + + + + + + + 0 + + Mage Wars Academy + 2015 https://cf.geekdo-images.com/BXqdHw39CPenDAKWDm_Vxw__original/img/pzO7kVTqFPx5mGYQXPxC39x4kL8=/0x0/filters:format(png)/pic2555236.png + https://cf.geekdo-images.com/BXqdHw39CPenDAKWDm_Vxw__small/img/RgBmCUFY-rCCHNC3uWAE3u8lTmA=/fit-in/200x150/filters:strip_icc()/pic2555236.png + + + + + + + + + 0 + + Meteor + 2014 https://cf.geekdo-images.com/mVC1JCvb488GJFhNF1idsA__original/img/G1UroUSm25FSY7LQXpPu6f6--20=/0x0/filters:format(png)/pic2256875.png + https://cf.geekdo-images.com/mVC1JCvb488GJFhNF1idsA__small/img/Bx9UJsNZV8eF7kebFJlFoCqvtUw=/fit-in/200x150/filters:strip_icc()/pic2256875.png + + + + + + + + + 0 + + Munchkin + 2001 https://cf.geekdo-images.com/J-ts3MW0UhDzs621TR6cog__original/img/FbqPPCilgZKND2xmhWJgkfjZiYE=/0x0/filters:format(jpeg)/pic1871016.jpg + https://cf.geekdo-images.com/J-ts3MW0UhDzs621TR6cog__small/img/8hVkpMC5pDLr6ARI_4gI4N3aF5M=/fit-in/200x150/filters:strip_icc()/pic1871016.jpg + + + + + + + + + + 0 + + No Thank You, Evil! + 2016 https://cf.geekdo-images.com/b_Jftm8zKB2ItfIdDZSR-g__original/img/XPkfFiWXkGvqvpCqgbGhAt30tyM=/0x0/filters:format(jpeg)/pic3174067.jpg + https://cf.geekdo-images.com/b_Jftm8zKB2ItfIdDZSR-g__small/img/ECPrjPcNpwBZELxzwxX1usQe9f4=/fit-in/200x150/filters:strip_icc()/pic3174067.jpg + + + + + + + + + + 0 + + Onitama + 2014 https://cf.geekdo-images.com/GJKuOCy5HGAYgVH_Rei5mA__original/img/oRsIxp72iv58128KFdqvjG6Gz64=/0x0/filters:format(jpeg)/pic7070194.jpg + https://cf.geekdo-images.com/GJKuOCy5HGAYgVH_Rei5mA__small/img/Q3W4poMS4btD-HZLervgqbSCtmE=/fit-in/200x150/filters:strip_icc()/pic7070194.jpg + + + + + + + + + 0 + + Pie Face Showdown + 2016 https://cf.geekdo-images.com/5OUkDIq5mnGL2aLYIXIXmA__original/img/VCuxOesnLaPddH1B_OarM2_j0mA=/0x0/filters:format(jpeg)/pic3175723.jpg + https://cf.geekdo-images.com/5OUkDIq5mnGL2aLYIXIXmA__small/img/Epz7KLATSUCD5VbWcj-SE9Zh4Us=/fit-in/200x150/filters:strip_icc()/pic3175723.jpg + + + + + + + + 0 + + The Red Dragon Inn + 2007 https://cf.geekdo-images.com/RCXedcfgn5LSfH4-kOUvLA__original/img/Fr16k-_UzhrIB6_yre7SrMhkDxU=/0x0/filters:format(jpeg)/pic291048.jpg + https://cf.geekdo-images.com/RCXedcfgn5LSfH4-kOUvLA__small/img/fw7C7ruhaqXTqrWZFHCXdQpNKRs=/fit-in/200x150/filters:strip_icc()/pic291048.jpg + + + + + + + + + + 0 + + Risk: The Lord of the Rings + 2002 https://cf.geekdo-images.com/i8ryx8pqPonNNUXyRWjQaw__original/img/jD6_3u-Z2e54Szi3I8p6Ma74Wc4=/0x0/filters:format(jpeg)/pic265703.jpg + https://cf.geekdo-images.com/i8ryx8pqPonNNUXyRWjQaw__small/img/0-JW3OU-6XDoUKqhQudJIbRX0Bc=/fit-in/200x150/filters:strip_icc()/pic265703.jpg + + + + + + + + + 0 + + Rivals for Catan + 2010 https://cf.geekdo-images.com/n5x9eZiQ7Da4SQjB7M41-w__original/img/Y6dJpidB1624ox-QCAdiSVsCnf4=/0x0/filters:format(jpeg)/pic6877018.jpg + https://cf.geekdo-images.com/n5x9eZiQ7Da4SQjB7M41-w__small/img/dGMw2df-4gOwfLCdUeJceBeLCk8=/fit-in/200x150/filters:strip_icc()/pic6877018.jpg + + + + + + + + + 0 + + Robot Turtles + 2013 https://cf.geekdo-images.com/SRJcEXLEBnj5WxcSmW22hA__original/img/Dzz2RP84t8CLjMaLoLbGB5tbzFc=/0x0/filters:format(jpeg)/pic2047441.jpg + https://cf.geekdo-images.com/SRJcEXLEBnj5WxcSmW22hA__small/img/cpax1CjpG61IOX1zhXrKuW9Z7yU=/fit-in/200x150/filters:strip_icc()/pic2047441.jpg + + + + + + + + + 0 + + Rock Me Archimedes + 2012 https://cf.geekdo-images.com/aYy25Eg6tHOhdmqaa2MgFg__original/img/_pEiVGJru7TLHdTLwFzn_1PW0_o=/0x0/filters:format(jpeg)/pic2387634.jpg + https://cf.geekdo-images.com/aYy25Eg6tHOhdmqaa2MgFg__small/img/8W8piD3EZi4x1HyOFJs9_7DMLMA=/fit-in/200x150/filters:strip_icc()/pic2387634.jpg + + + + + + + + + 0 + + Royals + 2014 https://cf.geekdo-images.com/Un-yHPPUaH7IpTfiG7ffkw__original/img/rOD_UORh5dzMisuJFBP7548XbkU=/0x0/filters:format(jpeg)/pic3021582.jpg + https://cf.geekdo-images.com/Un-yHPPUaH7IpTfiG7ffkw__small/img/h9a43sj1YW-dZCKU9wKvHvFSy5U=/fit-in/200x150/filters:strip_icc()/pic3021582.jpg + + + + + + + + + + 0 + + Santorini + 2016 https://cf.geekdo-images.com/665Ply7Ho1WVf1v1iZlWeg__original/img/4q6RCxd7st-yW2MyrJwVC_d3ajk=/0x0/filters:format(png)/pic3283110.png + https://cf.geekdo-images.com/665Ply7Ho1WVf1v1iZlWeg__small/img/BKnSb6kAhpVFHV8cyUXrs3EF_dw=/fit-in/200x150/filters:strip_icc()/pic3283110.png + + + + + + + + + 0 + + Seven Dragons + 2011 https://cf.geekdo-images.com/Qc-1nXLd7Zpl2kpX1ga3Bg__original/img/Ee7DlC9nZTtHXA5TfqfEKEvTS18=/0x0/filters:format(jpeg)/pic1022004.jpg + https://cf.geekdo-images.com/Qc-1nXLd7Zpl2kpX1ga3Bg__small/img/AhwFa5lK5OuIhieeQ56KZrR09e8=/fit-in/200x150/filters:strip_icc()/pic1022004.jpg + + + + + + + + + 0 + + Sheriff of Nottingham + 2014 https://cf.geekdo-images.com/BBgLFKUzr6tcKtlIM2JSFw__original/img/fll2MuTBPVKb7fyBJ8D-4_c1XHM=/0x0/filters:format(jpeg)/pic2075830.jpg + https://cf.geekdo-images.com/BBgLFKUzr6tcKtlIM2JSFw__small/img/JD5L_XrtkaKINUj8ILZqFMGcTsE=/fit-in/200x150/filters:strip_icc()/pic2075830.jpg + + + + + + + + + + 0 + + Simon's Cat Card Game + 2016 https://cf.geekdo-images.com/1DW2I_hYs6l5BHuQPGj9dw__original/img/Lg0wZJUxF071jdWcRqOFno2FHgo=/0x0/filters:format(jpeg)/pic8089317.jpg + https://cf.geekdo-images.com/1DW2I_hYs6l5BHuQPGj9dw__small/img/Go_iakh-eYWSEIhz7Gkjmod2fE8=/fit-in/200x150/filters:strip_icc()/pic8089317.jpg + + + + + + + + + + 0 + + Skylanders Portal Master + 2013 https://cf.geekdo-images.com/nPwffbp8-RD4SWwwgwGIfg__original/img/WMxqMqdSTRVpuUAjjUVOIOLzBx4=/0x0/filters:format(jpeg)/pic9686810.jpg + https://cf.geekdo-images.com/nPwffbp8-RD4SWwwgwGIfg__small/img/aPiWIz7W1yg4ZWuMVjn7X4yzJpE=/fit-in/200x150/filters:strip_icc()/pic9686810.jpg + + + + + + + + 0 + + Small World + 2009 https://cf.geekdo-images.com/aoPM07XzoceB-RydLh08zA__original/img/bYLzrwZO9u-3h2wyU-PHc8aTOY4=/0x0/filters:format(jpeg)/pic428828.jpg + https://cf.geekdo-images.com/aoPM07XzoceB-RydLh08zA__small/img/o3Bw9heVDJRgPYlI_PksCvLAgnM=/fit-in/200x150/filters:strip_icc()/pic428828.jpg + + + + + + + + + + 0 + + Snappy Dressers + 2016 https://cf.geekdo-images.com/BWKD42FXZxyY3iGg0MdEhQ__original/img/eNk-qRaZg3d5RkrKiZcwZMu9s48=/0x0/filters:format(jpeg)/pic3619180.jpg + https://cf.geekdo-images.com/BWKD42FXZxyY3iGg0MdEhQ__small/img/_-qsvWQbJKc8SFFVIYURqyQEjlE=/fit-in/200x150/filters:strip_icc()/pic3619180.jpg + + + + + + + + 0 + + Sorcerer: The Game of Magical Conflict + 1975 https://cf.geekdo-images.com/NpauF7CJudER5H5nj-z-gA__original/img/eGfEPINMJA_0pAKWAYyjJaXmaQo=/0x0/filters:format(jpeg)/pic10078.jpg + https://cf.geekdo-images.com/NpauF7CJudER5H5nj-z-gA__small/img/Vo85InhIcQUg1myZBiHCL22uu8A=/fit-in/200x150/filters:strip_icc()/pic10078.jpg + + + + + + + + + + 0 + + Speechless + 2016 https://cf.geekdo-images.com/CGCYY9KMI4ohm5fYQH1n_g__original/img/1iIrbGykzNTIAsvNkCLxt9e-km4=/0x0/filters:format(png)/pic2944475.png + https://cf.geekdo-images.com/CGCYY9KMI4ohm5fYQH1n_g__small/img/V_azlMIVuWUW7vgGE1eMYULSzzY=/fit-in/200x150/filters:strip_icc()/pic2944475.png + + + + + + + + 0 + + StarForce 'Alpha Centauri': Interstellar Conflict in the 25th Century + 1974 https://cf.geekdo-images.com/8PIdXg87V8l-VuCZAplQlQ__original/img/JRuDUwwK8S1jG9gZISv_Hwz5Kog=/0x0/filters:format(jpeg)/pic567384.jpg + https://cf.geekdo-images.com/8PIdXg87V8l-VuCZAplQlQ__small/img/OTL4rEL5eQ-8jJ_JubPwIq9LBIQ=/fit-in/200x150/filters:strip_icc()/pic567384.jpg + + + + + + + + + 0 + + Super Mario Bros. Power Up Card Game + 2017 https://cf.geekdo-images.com/_tjh4A0MS2DK2fO3DaKj5w__original/img/JlMNj_kW9fXhKRB6VAZyKBxPgb4=/0x0/filters:format(jpeg)/pic3684810.jpg + https://cf.geekdo-images.com/_tjh4A0MS2DK2fO3DaKj5w__small/img/-j-mQ0mq6PCgL1C9NyqFwoDzA8E=/fit-in/200x150/filters:strip_icc()/pic3684810.jpg + + + + + + + + 0 + + Superfight + 2013 https://cf.geekdo-images.com/4ih18dd_9SZv3yn-YazMIw__original/img/VOTdHizWmvwJnOFMw6YMWj5sJSg=/0x0/filters:format(jpeg)/pic2933903.jpg + https://cf.geekdo-images.com/4ih18dd_9SZv3yn-YazMIw__small/img/i2BNig3lkYu3MZPhzKRIygg7RJU=/fit-in/200x150/filters:strip_icc()/pic2933903.jpg + + + + + + + + + 0 + + Tac Tac Jack + 2008 https://cf.geekdo-images.com/6TG4QXV3JmLsln11f72XXQ__original/img/Cd7AXhKDVniLOUYXdU1RZ26YH-0=/0x0/filters:format(png)/pic8499311.png + https://cf.geekdo-images.com/6TG4QXV3JmLsln11f72XXQ__small/img/g2GglyKXfnWFJnjS057wW1Fpm7U=/fit-in/200x150/filters:strip_icc()/pic8499311.png + + + + + + + + + 0 + + Tem-Purr-A + 2011 https://cf.geekdo-images.com/LWLRKZPO9B5ITz5f6Linhg__original/img/feTFDIvserg3DrmG6QnsDgtZrF0=/0x0/filters:format(jpeg)/pic2776998.jpg + https://cf.geekdo-images.com/LWLRKZPO9B5ITz5f6Linhg__small/img/beldZHdnD-u49LMy5X6fEJW2F_8=/fit-in/200x150/filters:strip_icc()/pic2776998.jpg + + + + + + + + + 0 + + Terror in Meeple City + 2013 https://cf.geekdo-images.com/loyFNu06XcKcRcoouNkn5Q__original/img/Dg5JwmmkDHJ4b4WDAU7WREHbBdw=/0x0/filters:format(jpeg)/pic2482302.jpg + https://cf.geekdo-images.com/loyFNu06XcKcRcoouNkn5Q__small/img/w5H9B8agVcPdAfNYgvN1qoFjLsc=/fit-in/200x150/filters:strip_icc()/pic2482302.jpg + + + + + + + + + 0 + + Ticket to Ride + 2004 https://cf.geekdo-images.com/kdWYkW-7AqG63HhqPL6ekA__original/img/rWF8r4JXXCQQ7QhiWHhmT-rQ3Pc=/0x0/filters:format(jpeg)/pic8937637.jpg + https://cf.geekdo-images.com/kdWYkW-7AqG63HhqPL6ekA__small/img/5G46jv8MFh_BfX67iMSouTMhKxc=/fit-in/200x150/filters:strip_icc()/pic8937637.jpg + + + + + + + + + 0 + + Town of Salem: The Card Game + 2017 https://cf.geekdo-images.com/twV5Z01K8K7AUgCBH9GShQ__original/img/U9vXw70nSJ94B-Ihe6WEuL1EEn8=/0x0/filters:format(jpeg)/pic3337089.jpg + https://cf.geekdo-images.com/twV5Z01K8K7AUgCBH9GShQ__small/img/-qdChbv8NvLH0d45iFl4bu2SCX4=/fit-in/200x150/filters:strip_icc()/pic3337089.jpg + + + + + + + + 0 + + Völuspá + 2012 https://cf.geekdo-images.com/0Sa8hpkdz947r104XjGijw__original/img/R5k-Fa4h1heKyv-q6InDW0nDio8=/0x0/filters:format(jpeg)/pic1591249.jpg + https://cf.geekdo-images.com/0Sa8hpkdz947r104XjGijw__small/img/8MrEnv-5IvQixU7aVIMmt2Y--Z4=/fit-in/200x150/filters:strip_icc()/pic1591249.jpg + + + + + + + + + + 0 + + Walk the Plank! + 2013 https://cf.geekdo-images.com/nWcihyfWeAXo9SuSANPepw__original/img/P77A3nELOXRHK3JxCRLCTsSqOFo=/0x0/filters:format(jpeg)/pic2196826.jpg + https://cf.geekdo-images.com/nWcihyfWeAXo9SuSANPepw__small/img/UeAabtDenC1sLH02VF30QK-DtmI=/fit-in/200x150/filters:strip_icc()/pic2196826.jpg + + + + + + + + + 0 + + Wiz-War (Eighth Edition) + 2012 https://cf.geekdo-images.com/yXbWhfIuwKFJfPNg5SgPOQ__original/img/C-3SceTz2k75LaIYt3sQWl7g7lU=/0x0/filters:format(jpeg)/pic1222733.jpg + https://cf.geekdo-images.com/yXbWhfIuwKFJfPNg5SgPOQ__small/img/PFBGm2T4kgP7_ARhb7Zcr5j_uZU=/fit-in/200x150/filters:strip_icc()/pic1222733.jpg + + + + + + + + + 0 + + The X-Files: Circle of Truth + 2018 https://cf.geekdo-images.com/0atFeJj4AQqlICeMi_8W0g__original/img/Pzi-phLQqtSqNxkwTCle8UYxeWM=/0x0/filters:format(jpeg)/pic5208706.jpg + https://cf.geekdo-images.com/0atFeJj4AQqlICeMi_8W0g__small/img/Zi1DUgVsUPka8DcOZgodMi7L_GU=/fit-in/200x150/filters:strip_icc()/pic5208706.jpg + + + + + + + + 0 + + diff --git a/tests/fixtures/collection_snapshot_expansions.xml b/tests/fixtures/collection_snapshot_expansions.xml new file mode 100644 index 0000000..6cd028e --- /dev/null +++ b/tests/fixtures/collection_snapshot_expansions.xml @@ -0,0 +1,65 @@ + + + +Advanced Civilization +1991 +https://cf.geekdo-images.com/9ROB7NpxefRUmpR9UroQ8w__original/img/--qlhvNNj8zF9cWLlihdTg0jzmE=/0x0/filters:format(jpeg)/pic87459.jpg +https://cf.geekdo-images.com/9ROB7NpxefRUmpR9UroQ8w__small/img/XDH667tVl2KjQ6szNjT7ceEmh5E=/fit-in/200x150/filters:strip_icc()/pic87459.jpg + + + + + + + + + + + + + + +0 + + +Castle Panic: The Dark Titan +2015 +https://cf.geekdo-images.com/ne5GT5tNupCbGeN4maV0aw__original/img/Pe0unjKPwaO0cJPd9QI_Eo-xuRU=/0x0/filters:format(jpeg)/pic6967876.jpg +https://cf.geekdo-images.com/ne5GT5tNupCbGeN4maV0aw__small/img/RTQtsNpxLidMnDPDGTTf-AiP9OQ=/fit-in/200x150/filters:strip_icc()/pic6967876.jpg + + + + + + + + + + + + + +0 + + +Castle Panic: The Wizard's Tower +2011 +https://cf.geekdo-images.com/ZI_7riAQtSAb9T3bodOVKA__original/img/S5nr9djtA4cUDvi7dmtTiYhut1Y=/0x0/filters:format(jpeg)/pic6966120.jpg +https://cf.geekdo-images.com/ZI_7riAQtSAb9T3bodOVKA__small/img/VzbEp7j_wYr0KiXfvsYITTAhnSk=/fit-in/200x150/filters:strip_icc()/pic6966120.jpg + + + + + + + + + + + + + + +0 + + diff --git a/tests/test_diff.py b/tests/test_diff.py new file mode 100644 index 0000000..9696937 --- /dev/null +++ b/tests/test_diff.py @@ -0,0 +1,166 @@ +"""Diff-stage tests: pure compute_diff cases plus the real 2018 collection +snapshots as parsing fixtures. No network anywhere.""" + +from __future__ import annotations + +from pathlib import Path + +from bggpipe.diff import compute_diff, load_snapshot_collection +from bggpipe.models import CollectionItem + +FIXTURES = Path(__file__).parent / "fixtures" + + +def _item(object_id, coll_id, name="Game", version_id=None, own=True): + return CollectionItem( + object_id=object_id, + coll_id=coll_id, + name=name, + subtype="boardgame", + own=own, + year=None, + version_id=version_id, + ) + + +def _match( + title, bgg_id="", status="auto", vstatus="version_unknown", vid="", vname="" +): + return { + "title_raw": title, + "bgg_id": bgg_id, + "bgg_name": title.title(), + "year": "2000", + "type": "boardgame", + "match_status": status, + "version_id": vid, + "version_name": vname, + "version_status": vstatus, + "candidates_json": "[]", + "version_candidates_json": "[]", + "source_photos": "x.jpg", + } + + +# -- snapshot loading --------------------------------------------------- + + +def test_load_real_snapshots_merges_and_dedupes(): + collection = load_snapshot_collection(FIXTURES) + # 79 base + 3 expansions, but all 3 expansion collids also appear in + # the base file -> 79 unique physical copies + assert len(collection) == 79 + assert len({c.coll_id for c in collection}) == 79 + by_id = {c.object_id: c for c in collection} + assert by_id[207830].name == "5-Minute Dungeon" + assert by_id[177].name == "Advanced Civilization" + # hand-entered in 2018: every entry is version-less (parsed, not assumed) + assert all(c.version_id is None for c in collection) + + +# -- compute_diff ------------------------------------------------------- + + +def test_new_game_goes_to_add_with_version(): + result = compute_diff( + [ + _match( + "Cat Crimes", + "235096", + vstatus="version_auto", + vid="360982", + vname="ThinkFun edition", + ) + ], + [_item(13, 1)], + ) + (row,) = result.to_add + assert row["bgg_id"] == "235096" + assert row["version_id"] == "360982" + assert not result.to_update + + +def test_owned_versionless_plus_confident_version_goes_to_update(): + result = compute_diff( + [ + _match( + "Britannia", + "240", + vstatus="version_auto", + vid="55555", + vname="AH English edition", + ) + ], + [_item(240, 900001, name="Britannia")], + ) + assert result.already_owned == ["Britannia"] + (row,) = result.to_update + assert row == { + "collid": "900001", + "bgg_id": "240", + "bgg_name": "Britannia", + "version_id": "55555", + "version_name": "AH English edition", + } + assert not result.to_add + + +def test_owned_with_matching_version_is_just_owned(): + result = compute_diff( + [_match("Wingspan", "266192", vstatus="version_auto", vid="465063")], + [_item(266192, 5, version_id=465063)], + ) + assert result.already_owned == ["Wingspan"] + assert not result.to_update and not result.to_add + + +def test_owned_with_different_version_reports_disagreement_untouched(): + result = compute_diff( + [ + _match( + "Wingspan", + "266192", + vstatus="version_auto", + vid="521212", + vname="fourth printing", + ) + ], + [_item(266192, 5, version_id=465063)], + ) + assert result.already_owned == ["Wingspan"] + assert not result.to_update # additive only: never edit a set version + assert "fourth printing" in result.disagreements[0] + + +def test_version_unknown_owned_by_bare_id(): + result = compute_diff( + [_match("Catan", "13")], + [_item(13, 1, name="Catan")], + ) + assert result.already_owned == ["Catan"] + assert not result.to_add and not result.to_update + + +def test_two_photo_editions_consume_distinct_collids(): + matches = [ + _match("Cosmic A", "39", vstatus="version_auto", vid="111"), + _match("Cosmic B", "39", vstatus="version_auto", vid="222"), + ] + collection = [_item(39, 701), _item(39, 702)] + result = compute_diff(matches, collection) + assert {r["collid"] for r in result.to_update} == {"701", "702"} + assert {r["version_id"] for r in result.to_update} == {"111", "222"} + + +def test_pending_rejected_and_unseen_are_reported(): + matches = [ + _match("Mystery Spine", status="ambiguous"), + _match("Junk", status="rejected"), + _match("Catan", "13"), + ] + collection = [_item(13, 1, name="Catan"), _item(9209, 2, name="Ticket to Ride")] + result = compute_diff(matches, collection) + assert result.pending == ["Mystery Spine"] + assert result.rejected == 1 + assert [c.object_id for c in result.unseen] == [9209] # informational + assert result.recognized == 1