From 9b96b516c366de8b90f0489894643259483a5cb2 Mon Sep 17 00:00:00 2001 From: Rob Hand <146272+sinon@users.noreply.github.com> Date: Wed, 17 Sep 2025 19:22:33 +0100 Subject: [PATCH 1/3] Add a boardgames collection page --- config.toml | 3 +- content/pages/boardgames.md | 7 + sass/boardgames.sass | 77 +++ scripts/boardgames.py | 122 +++++ static/boardgames_collection.json | 795 ++++++++++++++++++++++++++++++ templates/boardgames.html | 51 ++ 6 files changed, 1054 insertions(+), 1 deletion(-) create mode 100644 content/pages/boardgames.md create mode 100644 sass/boardgames.sass create mode 100755 scripts/boardgames.py create mode 100644 static/boardgames_collection.json create mode 100644 templates/boardgames.html diff --git a/config.toml b/config.toml index 99c8fe1..877bdf1 100644 --- a/config.toml +++ b/config.toml @@ -4,7 +4,7 @@ default_language = "en" title = "Rob's Blog | Python • Rust • Ramblings?" # Whether to automatically compile all Sass files in the sass directory -compile_sass = false +compile_sass = true # Whether to build a search index to be used later on by a JavaScript library build_search_index = false @@ -29,6 +29,7 @@ after_dark_menu = [ { name = "Home", url = "$BASE_URL" }, { name = "About", url = "$BASE_URL/about/" }, { name = "Now", url = "$BASE_URL/now/" }, + { name = "Boardgames", url = "$BASE_URL/boardgames" }, { name = "TILs", url = "$BASE_URL/tils/" }, { name = "Tags", url = "$BASE_URL/tags" }, { name = "Source", url = "https://github.com/sinon/sinon.github.io" }, diff --git a/content/pages/boardgames.md b/content/pages/boardgames.md new file mode 100644 index 0000000..8bcbae0 --- /dev/null +++ b/content/pages/boardgames.md @@ -0,0 +1,7 @@ ++++ +title = "Boardgames" +date = 2025-08-27 +template = "boardgames.html" +sort_by = "none" +path = "boardgames" ++++ diff --git a/sass/boardgames.sass b/sass/boardgames.sass new file mode 100644 index 0000000..c719665 --- /dev/null +++ b/sass/boardgames.sass @@ -0,0 +1,77 @@ +.boardgames-container + max-width: 1200px + margin: 0 auto + padding: 20px + +.games-grid + display: grid + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)) + gap: 20px + margin-top: 20px + +.game-card + border: 1px solid #404040 + border-radius: 8px + padding: 16px + background: var(--bg-primary) + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3) + transition: transform 0.2s, box-shadow 0.2s + + &:hover + transform: translateY(-2px) + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4) + border-color: var(--note-color) + +.game-header + display: flex + gap: 12px + margin-bottom: 12px + +.game-thumbnail + width: 60px + height: 45px + object-fit: cover + border-radius: 4px + border: 1px solid #404040 + +.game-info + flex: 1 + +.game-title + font-weight: bold + margin: 0 0 4px 0 + color: #ffffff + +.game-year + color: #cccccc + font-size: 0.9em + margin: 0 + +.game-stats + display: flex + gap: 16px + margin-bottom: 8px + font-size: 0.9em + color: #aaaaaa + +.game-rating + font-weight: bold + color: var(--note-color) + + &.rating-high + color: #27ae60 + + &.rating-medium + color: #f39c12 + + &.rating-low + color: #e74c3c + + &.rating-unrated + color: #999999 + +.game-comment + color: #cccccc + font-size: 0.9em + margin-top: 8px + font-style: italic diff --git a/scripts/boardgames.py b/scripts/boardgames.py new file mode 100755 index 0000000..c05e66d --- /dev/null +++ b/scripts/boardgames.py @@ -0,0 +1,122 @@ +#!/usr/bin/env -S uv run +# /// script +# requires-python = ">=3.13" +# dependencies = [ +# "requests", +# ] +# /// + +import requests +import xml.etree.ElementTree as ET +import json +import time +import logging +from typing import List, Dict, Any + +logging.basicConfig( + level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s" +) +logger = logging.getLogger(__name__) + + +def fetch_boardgame_collection(username: str) -> str: + url = f"https://boardgamegeek.com/xmlapi2/collection?username={username}&own=1&stats=1&excludesubtype=boardgameexpansion" + + max_retries = 5 + retry_delay = 2 + + for attempt in range(max_retries): + response = requests.get(url) + + if response.status_code == 202: + logger.info( + f"Collection still processing, retrying in {retry_delay} seconds... (attempt {attempt + 1}/{max_retries})" + ) + time.sleep(retry_delay) + retry_delay *= 2 + continue + + response.raise_for_status() + return response.text + + raise Exception(f"Failed to fetch collection after {max_retries} attempts") + + +def parse_collection_xml(xml_content: str) -> List[Dict[str, Any]]: + root = ET.fromstring(xml_content) + games = [] + + for item in root.findall("item"): + game = { + "objectid": item.get("objectid"), + "name": None, + "yearpublished": None, + "my_rating": None, + "stats": {}, + "comment": None, + } + + name_elem = item.find("name") + if name_elem is not None: + game["name"] = name_elem.text + + year_elem = item.find("yearpublished") + if year_elem is not None: + game["yearpublished"] = year_elem.text + + thumbnail_elem = item.find("thumbnail") + if thumbnail_elem is not None: + game["thumbnail"] = thumbnail_elem.text + comment_elem = item.find("comment") + if comment_elem is not None: + game["comment"] = comment_elem.text + + stats_elem = item.find("stats") + if stats_elem is not None: + rating_elem = stats_elem.find("rating") + if rating_elem is not None: + game["stats"] = { + "minplayers": stats_elem.get("minplayers"), + "maxplayers": stats_elem.get("maxplayers"), + "playingtime": stats_elem.get("playingtime"), + } + if rating_elem.get("value") != "N/A": + game["my_rating"] = float(rating_elem.get("value")) + games.append(game) + games = sorted(games, key=lambda x: x["my_rating"] or 0, reverse=True) + return games + + +def save_to_json(data: List[Dict[str, Any]], filename: str) -> None: + with open(filename, "w", encoding="utf-8") as f: + json.dump(data, f, indent=2, ensure_ascii=False) + + +def main(): + username = "sinon88" + output_file = "../static/boardgames_collection.json" + + try: + logger.info(f"Fetching board game collection for user: {username}") + xml_content = fetch_boardgame_collection(username) + + logger.info("Parsing XML content...") + games_list = parse_collection_xml(xml_content) + + logger.info(f"Found {len(games_list)} games in collection") + + logger.info(f"Saving to {output_file}...") + save_to_json(games_list, output_file) + + logger.info(f"Successfully saved board game collection to {output_file}") + + except requests.exceptions.RequestException as e: + logger.error(f"Error fetching data: {e}") + except ET.ParseError as e: + logger.error(f"Error parsing XML: {e}") + except Exception as e: + logger.error(f"Unexpected error: {e}") + + +if __name__ == "__main__": + main() diff --git a/static/boardgames_collection.json b/static/boardgames_collection.json new file mode 100644 index 0000000..b0beb06 --- /dev/null +++ b/static/boardgames_collection.json @@ -0,0 +1,795 @@ +[ + { + "objectid": "373106", + "name": "Sky Team", + "yearpublished": "2023", + "my_rating": 9.0, + "stats": { + "minplayers": "2", + "maxplayers": "2", + "playingtime": "20" + }, + "comment": "Excellent, the perfect light easy to setup game that is tense and engaging throughout. The modules add interesting new worries to each game, meaning it still hasn't gotten stale after 10+ plays.", + "thumbnail": "https://cf.geekdo-images.com/uXMeQzNenHb3zK7Hoa6b2w__small/img/WyPClajMWU9lV5BdCXiZnqdZgmU=/fit-in/200x150/filters:strip_icc()/pic7398904.jpg" + }, + { + "objectid": "28143", + "name": "Race for the Galaxy", + "yearpublished": "2007", + "my_rating": 8.55, + "stats": { + "minplayers": "2", + "maxplayers": "4", + "playingtime": "60" + }, + "comment": "Excellent tableau builder, quick once players internalise the symbolic language. Never overstays it's welcome and still come across new combinations with each play.", + "thumbnail": "https://cf.geekdo-images.com/-DOqixs8uwKUvvWPKI4f9w__small/img/xLs-ldTPwaADbvzkOpF0sgWzwck=/fit-in/200x150/filters:strip_icc()/pic5261714.jpg" + }, + { + "objectid": "124361", + "name": "Concordia", + "yearpublished": "2013", + "my_rating": 8.5, + "stats": { + "minplayers": "2", + "maxplayers": "5", + "playingtime": "100" + }, + "comment": "Simple to teach with a nice strategic depth.", + "thumbnail": "https://cf.geekdo-images.com/CzwSm8i7tkLz6cBnrILZBg__small/img/ESPSltYYSFK-aJw6jOTdQrJGpOc=/fit-in/200x150/filters:strip_icc()/pic3453267.jpg" + }, + { + "objectid": "161936", + "name": "Pandemic Legacy: Season 1", + "yearpublished": "2015", + "my_rating": 8.5, + "stats": { + "minplayers": "2", + "maxplayers": "4", + "playingtime": "60" + }, + "comment": "4p, never finished. The theme and novelty are probably what keeps this rating so high.", + "thumbnail": "https://cf.geekdo-images.com/-Qer2BBPG7qGGDu6KcVDIw__small/img/NQQcjS31TO0DE246N9rpt0hd9eo=/fit-in/200x150/filters:strip_icc()/pic2452831.png" + }, + { + "objectid": "162886", + "name": "Spirit Island", + "yearpublished": "2017", + "my_rating": 8.5, + "stats": { + "minplayers": "1", + "maxplayers": "4", + "playingtime": "120" + }, + "comment": "Great theme, great variety in spirits/difficulty/scenarios.", + "thumbnail": "https://cf.geekdo-images.com/kjCm4ZvPjIZxS-mYgSPy1g__small/img/aUlIih2_R7P8IYKeyNl2heLQbu8=/fit-in/200x150/filters:strip_icc()/pic7013651.jpg" + }, + { + "objectid": "503", + "name": "Through the Desert", + "yearpublished": "1998", + "my_rating": 8.2, + "stats": { + "minplayers": "2", + "maxplayers": "5", + "playingtime": "45" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/Rq_hJIAO7jDgIpAW943hJA__small/img/blKEV5US-j7v3VDceGF1CIUb-lE=/fit-in/200x150/filters:strip_icc()/pic7697747.jpg" + }, + { + "objectid": "386937", + "name": "Lacuna", + "yearpublished": "2023", + "my_rating": 8.1, + "stats": { + "minplayers": "2", + "maxplayers": "2", + "playingtime": "15" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/kYZoWRZUfVD_g4TefiBu-Q__small/img/u1WZAzQstXpCSvXCbQA87R0xeTM=/fit-in/200x150/filters:strip_icc()/pic7488897.png" + }, + { + "objectid": "93", + "name": "El Grande", + "yearpublished": "1995", + "my_rating": 8.0, + "stats": { + "minplayers": "2", + "maxplayers": "5", + "playingtime": "120" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/RRKDHaYtFPHhczkUDcHOmg__small/img/XPcVtsZPITv5qe3IXpzMKa5RSYA=/fit-in/200x150/filters:strip_icc()/pic7906240.jpg" + }, + { + "objectid": "204493", + "name": "Sakura Arms", + "yearpublished": "2016", + "my_rating": 8.0, + "stats": { + "minplayers": "2", + "maxplayers": "2", + "playingtime": "30" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/IMslo9J8RnWXQospAjO6Dw__small/img/72su9RSHg1kxt9MApnodqc76f6Y=/fit-in/200x150/filters:strip_icc()/pic3545811.jpg" + }, + { + "objectid": "424975", + "name": "Wilmot's Warehouse", + "yearpublished": "2024", + "my_rating": 8.0, + "stats": { + "minplayers": "2", + "maxplayers": "6", + "playingtime": "30" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/me8N7vrfzBRD83d0VcRM-g__small/img/9pTYnER8A_J83WcRJHvAB8TeVlI=/fit-in/200x150/filters:strip_icc()/pic8327408.png" + }, + { + "objectid": "368061", + "name": "Zoo Vadis", + "yearpublished": "2023", + "my_rating": 8.0, + "stats": { + "minplayers": "3", + "maxplayers": "7", + "playingtime": "40" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/Kl3NjtNKpuJNPjdBQtdsow__small/img/Or2YcwIFnCP84aWJ_63HMwRJDis=/fit-in/200x150/filters:strip_icc()/pic6988937.jpg" + }, + { + "objectid": "200680", + "name": "Agricola (Revised Edition)", + "yearpublished": "2016", + "my_rating": 7.9, + "stats": { + "minplayers": "1", + "maxplayers": "4", + "playingtime": "120" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/YCGWJMFwOI5efji2RJ2mSw__small/img/h_Rp2XYqaNElM2hrYxUSzMxRRgM=/fit-in/200x150/filters:strip_icc()/pic8093340.jpg" + }, + { + "objectid": "73439", + "name": "Troyes", + "yearpublished": "2010", + "my_rating": 7.9, + "stats": { + "minplayers": "1", + "maxplayers": "4", + "playingtime": "90" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/fBIe-aEPtJKC-ceNlspK6A__small/img/Npv5mrWBkjnlKjl_8hGLNk9CCwc=/fit-in/200x150/filters:strip_icc()/pic750583.jpg" + }, + { + "objectid": "84876", + "name": "The Castles of Burgundy", + "yearpublished": "2011", + "my_rating": 7.8, + "stats": { + "minplayers": "2", + "maxplayers": "4", + "playingtime": "90" + }, + "comment": "Go to game with Wife for a non-confrontational resource gathering game. Not too headsdown, still a lot of focus on what moves the opponent is making. \n\nOnly played 2 player", + "thumbnail": "https://cf.geekdo-images.com/sH2YTQ10dHj1ibfS-KKtGA__small/img/f5zFXdTcH9RNY0iMNBppd8D-_r0=/fit-in/200x150/filters:strip_icc()/pic8745814.jpg" + }, + { + "objectid": "124742", + "name": "Android: Netrunner", + "yearpublished": "2012", + "my_rating": 7.5, + "stats": { + "minplayers": "2", + "maxplayers": "2", + "playingtime": "45" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/2ewHIIG_TRq8bYlqk0jIMw__small/img/IJaOyyQ7Y59tW6nbKbjTMTFt-Ls=/fit-in/200x150/filters:strip_icc()/pic3738560.jpg" + }, + { + "objectid": "178900", + "name": "Codenames", + "yearpublished": "2015", + "my_rating": 7.5, + "stats": { + "minplayers": "2", + "maxplayers": "8", + "playingtime": "15" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/nC6ifPCDnAItwoKSKXVrnw__small/img/1iZav_8ZqurrDbvkZA9GcFhB5x0=/fit-in/200x150/filters:strip_icc()/pic8907965.jpg" + }, + { + "objectid": "207016", + "name": "Flick 'em Up!: Dead of Winter", + "yearpublished": "2017", + "my_rating": 7.5, + "stats": { + "minplayers": "1", + "maxplayers": "10", + "playingtime": "45" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/P7W3dCZliN22VxH7JPUG3A__small/img/m-ZmSf0iL8fgEb2BmVhqhqmWzLQ=/fit-in/200x150/filters:strip_icc()/pic3365608.jpg" + }, + { + "objectid": "339924", + "name": "Hot Lead", + "yearpublished": "2022", + "my_rating": 7.5, + "stats": { + "minplayers": "2", + "maxplayers": "5", + "playingtime": "15" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/yM17m8v87Gj_kIpc3hBQXw__small/img/y5fP40O-e68gx5WW-c6fKStPI8E=/fit-in/200x150/filters:strip_icc()/pic6231247.png" + }, + { + "objectid": "118", + "name": "Modern Art", + "yearpublished": "2021", + "my_rating": 7.5, + "stats": { + "minplayers": "3", + "maxplayers": "5", + "playingtime": "45" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/DHO7YSykDvUQqLMRJL37BQ__small/img/sbt5IqhoR6ysf3lvvXr9_y92I8k=/fit-in/200x150/filters:strip_icc()/pic7161137.jpg" + }, + { + "objectid": "141572", + "name": "Paperback", + "yearpublished": "2014", + "my_rating": 7.5, + "stats": { + "minplayers": "2", + "maxplayers": "5", + "playingtime": "45" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/iZl2U-2BjftbWfLw5y25Vg__small/img/36X5ESX-n44TFPf8V97Cvr1yPao=/fit-in/200x150/filters:strip_icc()/pic7069377.jpg" + }, + { + "objectid": "237182", + "name": "Root", + "yearpublished": "2018", + "my_rating": 7.5, + "stats": { + "minplayers": "2", + "maxplayers": "4", + "playingtime": "90" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/JUAUWaVUzeBgzirhZNmHHw__small/img/ACovMZzGGIsBRyEQXFnsT8282NM=/fit-in/200x150/filters:strip_icc()/pic4254509.jpg" + }, + { + "objectid": "372", + "name": "Schotten Totten", + "yearpublished": "1999", + "my_rating": 7.3, + "stats": { + "minplayers": "2", + "maxplayers": "2", + "playingtime": "20" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/69mwXe7c6HNYmT6S35Y4zg__small/img/97DW-2XWDrSSkgy3XnUJ7f7tLiQ=/fit-in/200x150/filters:strip_icc()/pic2932872.jpg" + }, + { + "objectid": "12333", + "name": "Twilight Struggle", + "yearpublished": "2005", + "my_rating": 7.3, + "stats": { + "minplayers": "2", + "maxplayers": "2", + "playingtime": "180" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/pNCiUUphnoeWOYfsWq0kng__small/img/p7alNkNy8Avm8UISmhYHCiMz5bE=/fit-in/200x150/filters:strip_icc()/pic3530661.jpg" + }, + { + "objectid": "36218", + "name": "Dominion", + "yearpublished": "2008", + "my_rating": 7.1, + "stats": { + "minplayers": "2", + "maxplayers": "4", + "playingtime": "30" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/j6iQpZ4XkemZP07HNCODBA__small/img/B2u2ghwlmI_qsUtCwuvcbnBcIqU=/fit-in/200x150/filters:strip_icc()/pic394356.jpg" + }, + { + "objectid": "163412", + "name": "Patchwork", + "yearpublished": "2014", + "my_rating": 7.1, + "stats": { + "minplayers": "2", + "maxplayers": "2", + "playingtime": "30" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/RDOwMRBnIb3Ehl6GyXj9xg__small/img/nxex9ASN99exPLXEc9E4s08qZzc=/fit-in/200x150/filters:strip_icc()/pic8669620.jpg" + }, + { + "objectid": "70919", + "name": "Takenoko", + "yearpublished": "2011", + "my_rating": 7.1, + "stats": { + "minplayers": "2", + "maxplayers": "4", + "playingtime": "45" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/uvz-5V6A2R6dp2oWIXmj_g__small/img/vz9Ec1xB2b4JJQlZFijUsuCvfkQ=/fit-in/200x150/filters:strip_icc()/pic1912529.jpg" + }, + { + "objectid": "227224", + "name": "The Red Cathedral", + "yearpublished": "2020", + "my_rating": 7.05, + "stats": { + "minplayers": "1", + "maxplayers": "4", + "playingtime": "80" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/-PuiCnbxlBzMSjnUegp9AQ__small/img/CKamYUPlBDXav4A1AEqMRy976fY=/fit-in/200x150/filters:strip_icc()/pic5556025.jpg" + }, + { + "objectid": "247367", + "name": "Air, Land, & Sea", + "yearpublished": "2019", + "my_rating": 7.0, + "stats": { + "minplayers": "2", + "maxplayers": "2", + "playingtime": "20" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/3wpYeNwO7k_yjpIN7IQwaw__small/img/kfzWQvTxwcVx_ljICqhu5Coq53Q=/fit-in/200x150/filters:strip_icc()/pic4387681.jpg" + }, + { + "objectid": "219475", + "name": "Axio", + "yearpublished": "2017", + "my_rating": 7.0, + "stats": { + "minplayers": "1", + "maxplayers": "4", + "playingtime": "45" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/wROIUYusbdD2Lov5cnMCNw__small/img/HWL8-wSYeAFltK3OfSAKhnKtIso=/fit-in/200x150/filters:strip_icc()/pic3742268.jpg" + }, + { + "objectid": "147151", + "name": "Concept", + "yearpublished": "2013", + "my_rating": 7.0, + "stats": { + "minplayers": "4", + "maxplayers": "12", + "playingtime": "40" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/hHFs0_KRoW_FJ0cMIVgZcw__small/img/1MmGQvJVNw8TA7eWAJ8oIK-ZENc=/fit-in/200x150/filters:strip_icc()/pic4991925.jpg" + }, + { + "objectid": "98778", + "name": "Hanabi", + "yearpublished": "2010", + "my_rating": 7.0, + "stats": { + "minplayers": "2", + "maxplayers": "5", + "playingtime": "25" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/JDVksMwfcqoem1k_xtZrOA__small/img/amCeCcEKhYGbVtDvpvIMnu3qTg0=/fit-in/200x150/filters:strip_icc()/pic2007286.jpg" + }, + { + "objectid": "161882", + "name": "Irish Gauge", + "yearpublished": "2014", + "my_rating": 7.0, + "stats": { + "minplayers": "3", + "maxplayers": "5", + "playingtime": "60" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/BZW9WTKwGMfb3R4EELel3w__small/img/FowoMM52tGgX2JSUsKFaeuTsM2s=/fit-in/200x150/filters:strip_icc()/pic7628587.jpg" + }, + { + "objectid": "54043", + "name": "Jaipur", + "yearpublished": "2009", + "my_rating": 7.0, + "stats": { + "minplayers": "2", + "maxplayers": "2", + "playingtime": "30" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/_LTujSe_o16nvjDC-J0seA__small/img/82vhODfpxIT03BzW4NkisJ5Unzs=/fit-in/200x150/filters:strip_icc()/pic5100947.jpg" + }, + { + "objectid": "253399", + "name": "Journal 29: Interactive Book Game", + "yearpublished": "2017", + "my_rating": 7.0, + "stats": { + "minplayers": "1", + "maxplayers": "10", + "playingtime": "120" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/Y1dibOE_gxTh9wEfThT55w__small/img/jKe4qo5VtODdMzeU0ErVirMzeDA=/fit-in/200x150/filters:strip_icc()/pic4675327.jpg" + }, + { + "objectid": "181304", + "name": "Mysterium", + "yearpublished": "2015", + "my_rating": 7.0, + "stats": { + "minplayers": "2", + "maxplayers": "7", + "playingtime": "42" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/1nQ3ZKudtDeAP7IiKE-kNg__small/img/sW38512N2r1ZuuPE2TUD2LNfoxM=/fit-in/200x150/filters:strip_icc()/pic8625343.jpg" + }, + { + "objectid": "147949", + "name": "One Night Ultimate Werewolf", + "yearpublished": "2014", + "my_rating": 7.0, + "stats": { + "minplayers": "3", + "maxplayers": "10", + "playingtime": "10" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/rqLju4uaZq-G9z4g91aPPQ__small/img/viW0s_SZmeEo53dKbM84WbVjIaY=/fit-in/200x150/filters:strip_icc()/pic8783294.png" + }, + { + "objectid": "30549", + "name": "Pandemic", + "yearpublished": "2008", + "my_rating": 7.0, + "stats": { + "minplayers": "2", + "maxplayers": "4", + "playingtime": "45" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/S3ybV1LAp-8SnHIXLLjVqA__small/img/oqViRj6nVxK3m36NluTxU1PZkrk=/fit-in/200x150/filters:strip_icc()/pic1534148.jpg" + }, + { + "objectid": "25669", + "name": "Qwirkle", + "yearpublished": "2006", + "my_rating": 7.0, + "stats": { + "minplayers": "2", + "maxplayers": "4", + "playingtime": "45" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/k7zHj8j_a6uUAtXUt5Fvuw__small/img/APPui4zwBuwAIHXSTW6UxYcY6Ow=/fit-in/200x150/filters:strip_icc()/pic309353.jpg" + }, + { + "objectid": "92415", + "name": "Skull", + "yearpublished": "2011", + "my_rating": 7.0, + "stats": { + "minplayers": "3", + "maxplayers": "6", + "playingtime": "45" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/OPrd2iXm43dir7BwKAMOuQ__small/img/yEnb4YWN-Cp41KWTQ2EeNkrqlZI=/fit-in/200x150/filters:strip_icc()/pic6097488.jpg" + }, + { + "objectid": "14996", + "name": "Ticket to Ride: Europe", + "yearpublished": "2005", + "my_rating": 7.0, + "stats": { + "minplayers": "2", + "maxplayers": "5", + "playingtime": "60" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/0K1AOciqlMVUWFPLTJSiww__small/img/RDvu2FvsYVVH8icp1VsilUlqUGI=/fit-in/200x150/filters:strip_icc()/pic66668.jpg" + }, + { + "objectid": "822", + "name": "Carcassonne", + "yearpublished": "2000", + "my_rating": 6.99, + "stats": { + "minplayers": "2", + "maxplayers": "5", + "playingtime": "45" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/okM0dq_bEXnbyQTOvHfwRA__small/img/88274KiOg94wziybVHyW8AeOiXg=/fit-in/200x150/filters:strip_icc()/pic6544250.png" + }, + { + "objectid": "131357", + "name": "Coup", + "yearpublished": "2012", + "my_rating": 6.9, + "stats": { + "minplayers": "2", + "maxplayers": "6", + "playingtime": "15" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/MWhSY_GOe2-bmlQ2rntSVg__small/img/vuR_0PCX1w2EkjO_LbchOHZPOwU=/fit-in/200x150/filters:strip_icc()/pic2016054.jpg" + }, + { + "objectid": "148203", + "name": "Dutch Blitz", + "yearpublished": "1960", + "my_rating": 6.9, + "stats": { + "minplayers": "2", + "maxplayers": "4", + "playingtime": "15" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/ipuSaHTjxDpXAee-3vttiA__small/img/jw5BDMVYqffzOcB4F_MU2XC4BRI=/fit-in/200x150/filters:strip_icc()/pic336418.jpg" + }, + { + "objectid": "118048", + "name": "Targi", + "yearpublished": "2012", + "my_rating": 6.7, + "stats": { + "minplayers": "2", + "maxplayers": "2", + "playingtime": "60" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/wHg4fOf48cs1kw1PDOk1tQ__small/img/6l-jqYlfECK1SVSsUs7FXUheKzQ=/fit-in/200x150/filters:strip_icc()/pic3958793.jpg" + }, + { + "objectid": "41114", + "name": "The Resistance", + "yearpublished": "2009", + "my_rating": 6.5, + "stats": { + "minplayers": "5", + "maxplayers": "10", + "playingtime": "30" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/cAPTkL2BR3snLO71dkH8rw__small/img/5lDn1W82rlLXtVG7nPIYR9Orn-4=/fit-in/200x150/filters:strip_icc()/pic2576459.jpg" + }, + { + "objectid": "133473", + "name": "Sushi Go!", + "yearpublished": "2013", + "my_rating": 6.5, + "stats": { + "minplayers": "2", + "maxplayers": "5", + "playingtime": "15" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/Fn3PSPZVxa3YurlorITQ1Q__small/img/6XF493O0tSyLyZP5ArlcZrOTMXQ=/fit-in/200x150/filters:strip_icc()/pic1900075.jpg" + }, + { + "objectid": "16992", + "name": "Tsuro", + "yearpublished": "2005", + "my_rating": 6.5, + "stats": { + "minplayers": "2", + "maxplayers": "8", + "playingtime": "20" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/2V3d4ryhxkS3RoPtDrvpUw__small/img/NWgNhoxUIF7Lmj1apRkZQhFL6NU=/fit-in/200x150/filters:strip_icc()/pic875761.jpg" + }, + { + "objectid": "157969", + "name": "Sheriff of Nottingham", + "yearpublished": "2014", + "my_rating": 6.3, + "stats": { + "minplayers": "3", + "maxplayers": "5", + "playingtime": "60" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/BBgLFKUzr6tcKtlIM2JSFw__small/img/JD5L_XrtkaKINUj8ILZqFMGcTsE=/fit-in/200x150/filters:strip_icc()/pic2075830.jpg" + }, + { + "objectid": "110327", + "name": "Lords of Waterdeep", + "yearpublished": "2012", + "my_rating": 6.1, + "stats": { + "minplayers": "2", + "maxplayers": "5", + "playingtime": "120" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/-hk8f8iGk_DyWyMrfiPBkg__small/img/dBqYOO8uLXAumxUGuYtuiRGQ1Y8=/fit-in/200x150/filters:strip_icc()/pic1116080.jpg" + }, + { + "objectid": "129622", + "name": "Love Letter", + "yearpublished": "2012", + "my_rating": 6.0, + "stats": { + "minplayers": "2", + "maxplayers": "4", + "playingtime": "20" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/T1ltXwapFUtghS9A7_tf4g__small/img/GtNX7gCmGpw39Tr6JApWC3Aga5U=/fit-in/200x150/filters:strip_icc()/pic1401448.jpg" + }, + { + "objectid": "150312", + "name": "Welcome to the Dungeon", + "yearpublished": "2013", + "my_rating": 6.0, + "stats": { + "minplayers": "2", + "maxplayers": "4", + "playingtime": "30" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/6eQXDEMIWldaut9w7jXihg__small/img/CpRGL9nRUlwYERQzds6WyXRvJ4Y=/fit-in/200x150/filters:strip_icc()/pic6771265.jpg" + }, + { + "objectid": "6249", + "name": "Alhambra", + "yearpublished": "2003", + "my_rating": 5.9, + "stats": { + "minplayers": "2", + "maxplayers": "6", + "playingtime": "60" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/OiqKsYDh7pqeRYKG__kMSw__small/img/Pj2FP8bV-BHofcDS0eGLh8gzTmI=/fit-in/200x150/filters:strip_icc()/pic4893652.jpg" + }, + { + "objectid": "295949", + "name": "Adventure Games: The Grand Hotel Abaddon", + "yearpublished": "2020", + "my_rating": 5.1, + "stats": { + "minplayers": "1", + "maxplayers": "4", + "playingtime": "270" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/dKRPsLgTrkFVAwUqU4BBqQ__small/img/u2VDEylxdcE3AJlrVL3iWzYatFQ=/fit-in/200x150/filters:strip_icc()/pic6210950.jpg" + }, + { + "objectid": "342207", + "name": "echoes: The Dancer", + "yearpublished": "2021", + "my_rating": 5.0, + "stats": { + "minplayers": "1", + "maxplayers": "6", + "playingtime": "60" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/znvaTlswIC23fYH5oHMrGg__small/img/KZ5NrUS-hJPQG68k_6Gp1iW6p14=/fit-in/200x150/filters:strip_icc()/pic6306043.jpg" + }, + { + "objectid": "62871", + "name": "Zombie Dice", + "yearpublished": "2010", + "my_rating": 5.0, + "stats": { + "minplayers": "2", + "maxplayers": "99", + "playingtime": "20" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/iPy584JMAJYrupqRdQp8gA__small/img/0qjQ2T0wXNZDVvMie54bEVmKeT8=/fit-in/200x150/filters:strip_icc()/pic4991962.jpg" + }, + { + "objectid": "1269", + "name": "Skip-Bo", + "yearpublished": "1967", + "my_rating": 4.5, + "stats": { + "minplayers": "2", + "maxplayers": "6", + "playingtime": "20" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/aaUJua2zRXA6lqbVbNcBGg__small/img/81Ix-m3uliKZ43ouEhnOzUivMj4=/fit-in/200x150/filters:strip_icc()/pic8204244.jpg" + }, + { + "objectid": "2593", + "name": "Pass the Pigs", + "yearpublished": "1977", + "my_rating": 4.0, + "stats": { + "minplayers": "2", + "maxplayers": "10", + "playingtime": "30" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/blW_a3O5Md5bE1jFygJ6SA__small/img/s9q6W3Z7i4uW8x9CYZuL8wHzesE=/fit-in/200x150/filters:strip_icc()/pic697422.jpg" + }, + { + "objectid": "292032", + "name": "Funkoverse Strategy Game: Harry Potter 100", + "yearpublished": "2019", + "my_rating": null, + "stats": { + "minplayers": "2", + "maxplayers": "4", + "playingtime": "60" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/9JmZzK_PuB_1OT0YCpvlbg__small/img/hn3JeVpFbEtOSoCmRK5QW1XPso8=/fit-in/200x150/filters:strip_icc()/pic5008393.png" + }, + { + "objectid": "174430", + "name": "Gloomhaven", + "yearpublished": "2017", + "my_rating": null, + "stats": { + "minplayers": "1", + "maxplayers": "4", + "playingtime": "120" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/sZYp_3BTDGjh2unaZfZmuA__small/img/veqFeP4d_3zNhFc3GNBkV95rBEQ=/fit-in/200x150/filters:strip_icc()/pic2437871.jpg" + }, + { + "objectid": "54138", + "name": "Imperial 2030", + "yearpublished": "2009", + "my_rating": null, + "stats": { + "minplayers": "2", + "maxplayers": "6", + "playingtime": "180" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/YSopSx1x5iea7qI21ogYBw__small/img/9pIX4JJydy15FHCDrdwtdbXRAFk=/fit-in/200x150/filters:strip_icc()/pic586346.jpg" + }, + { + "objectid": "338353", + "name": "Soda Smugglers", + "yearpublished": "2022", + "my_rating": null, + "stats": { + "minplayers": "3", + "maxplayers": "8", + "playingtime": "20" + }, + "comment": null, + "thumbnail": "https://cf.geekdo-images.com/zRdItFkzzgkuSn-Ix8PwWA__small/img/-fJHCP4bCWCNrmcrWBcOKbDKaew=/fit-in/200x150/filters:strip_icc()/pic6231245.png" + } +] \ No newline at end of file diff --git a/templates/boardgames.html b/templates/boardgames.html new file mode 100644 index 0000000..3dccbf8 --- /dev/null +++ b/templates/boardgames.html @@ -0,0 +1,51 @@ +{% extends "after-dark/templates/page.html" %} +{% block css %} +{{ super() }} + +{% endblock css %} + +{% block content %} +{% block header %} +{{ super() }} +{% endblock header %} +
{{game.yearpublished}}
+{{game.yearpublished}}
From 1863634ec56742ef5687af876e9e2b5d56016144 Mon Sep 17 00:00:00 2001 From: Rob Hand <146272+sinon@users.noreply.github.com> Date: Wed, 17 Sep 2025 19:42:16 +0100 Subject: [PATCH 3/3] fix spacing in template --- templates/boardgames.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/templates/boardgames.html b/templates/boardgames.html index e90df2e..a238fc9 100644 --- a/templates/boardgames.html +++ b/templates/boardgames.html @@ -27,21 +27,21 @@{{game.yearpublished}}
+{{ game.yearpublished }}