#!/usr/bin/env python3 """Build the KW27 crowdfunding article HTML from KS and GF JSON data.""" import json from datetime import datetime, timezone # Load data with open("/home/hermes/workspace/ks_all_kw27_full.json") as f: ks_data = json.load(f) with open("/home/hermes/workspace/gf_all_kw27.json") as f: gf_data = json.load(f) gf_campaigns = gf_data["campaigns"] # Currency conversion rates (approximate, late June 2026) FX = { "USD": 1.0, "EUR": 1.08, "GBP": 1.28, "PLN": 0.25, "AUD": 0.65, "CAD": 0.73, "CHF": 1.12, "HKD": 0.128, "MXN": 0.055, "SGD": 0.74, } def fmt_usd(val): """Format USD value nicely.""" if val >= 1000000: return f"${val/1000000:.2f} Mio." elif val >= 1000: return f"${val/1000:,.0f}k".replace(",", ".") else: return f"${val:,.0f}" def fmt_eur(val): if val >= 1000000: return f"{val/1000000:.2f} Mio. €" elif val >= 1000: return f"{val/1000:,.0f}k €".replace(",", ".") else: return f"{val:,.0f} €" def fmt_native(amount, currency): """Format amount in native currency.""" if amount >= 1000000: return f"{amount/1000000:.2f} Mio. {currency}" elif amount >= 1000: return f"{amount/1000:,.0f}k {currency}".replace(",", ".") else: return f"{amount:,.0f} {currency}" # Build unified campaign list all_campaigns = [] for c in ks_data: pledged_usd = float(c["pledged_usd"]) all_campaigns.append({ "name": c["name"], "url": c["url"], "funding_usd": pledged_usd, "funding_native": c["pledged_native"], "currency": c["currency"], "goal_native": c["goal_native"], "backers": c["backers"], "deadline_unix": c["deadline_unix"], "percent_funded": c["percent_funded"], "creator": c["creator"], "platform": "Kickstarter", "blurb": c.get("blurb", ""), "staff_pick": c.get("staff_pick", False), }) for c in gf_campaigns: funding_native = c["funding"] currency = c["currency"] funding_usd = funding_native * FX.get(currency, 1.0) goal = c["goal"] if c["goal"] is not None else 0 pct = c["percent"] if c["percent"] is not None else 0 # Parse end_date end_date_str = c["end_date"] try: end_dt = datetime.fromisoformat(end_date_str.replace("Z", "+00:00")) deadline_unix = int(end_dt.timestamp()) except: deadline_unix = 0 all_campaigns.append({ "name": c["name"], "url": c["url"], "funding_usd": funding_usd, "funding_native": funding_native, "currency": currency, "goal_native": goal, "backers": c["backers"], "deadline_unix": deadline_unix, "percent_funded": pct, "creator": c["creator"], "platform": "Gamefound", "blurb": "", "staff_pick": False, }) # Sort by funding USD descending all_campaigns.sort(key=lambda x: x["funding_usd"], reverse=True) # Top 10 top10 = all_campaigns[:10] # This week ending: June 29 - July 5, 2026 kw27_start = int(datetime(2026, 6, 29, 0, 0, 0, tzinfo=timezone.utc).timestamp()) kw27_end = int(datetime(2026, 7, 5, 23, 59, 59, tzinfo=timezone.utc).timestamp()) ending_this_week = [c for c in all_campaigns if kw27_start <= c["deadline_unix"] <= kw27_end] ending_this_week.sort(key=lambda x: x["deadline_unix"]) # "Kleine Verlage - große Überraschungen": small/indie creators with high funding # Criteria: goal <= 5000, funding > 10000, not in top 10 small_surprises = [c for c in all_campaigns if c["goal_native"] <= 5000 and c["funding_usd"] > 10000 and c not in top10] small_surprises.sort(key=lambda x: x["funding_usd"], reverse=True) small_surprises = small_surprises[:8] # Build HTML html = """
Crowdfunding-Übersicht KW27: 115 Brettspiel-Kampagnen im Check

29. Juni 2026

Jede Woche: Alle aktiven Brettspiel-Kampagnen auf Kickstarter und Gamefound

Die 27. Kalenderwoche 2026 bringt eine geballte Ladung Crowdfunding: Insgesamt 115 aktive Brettspiel-Kampagnen haben wir diese Woche identifiziert – 72 auf Kickstarter und 43 auf Gamefound. Von millionenschweren Schwergewichten bis zu kleinen Geheimtipps ist alles dabei. Wir haben alle Kampagnen für euch gecheckt und nach Funding sortiert.


Top 10 nach Funding (KW27)

Die zehn aktuell am höchsten finanzierten Brettspiel-Kampagnen – gemischt über beide Plattformen:

""" for i, c in enumerate(top10, 1): platform_label = "GF" if c["platform"] == "Gamefound" else "KS" funding_str = fmt_native(c["funding_native"], c["currency"]) html += f""" """ html += """
#KampagnePlattformFundingBackersVerlag
{i} {c['name']} {platform_label} {funding_str} {c['backers']:,} {c['creator']}

Diese Woche endende Kampagnen

Folgende Kampagnen laufen in KW27 (29. Juni – 5. Juli 2026) aus. Schnell sein lohnt sich!

""" for c in ending_this_week: platform_label = "GF" if c["platform"] == "Gamefound" else "KS" funding_str = fmt_native(c["funding_native"], c["currency"]) end_date = datetime.fromtimestamp(c["deadline_unix"], tz=timezone.utc) end_str = end_date.strftime("%d.%m.%Y") html += f""" """ html += """
KampagnePlattformFundingEndetVerlag
{c['name']} {platform_label} {funding_str} {end_str} {c['creator']}

Kleine Verlage – große Überraschungen

Nicht nur die großen Namen liefern ab. Diese Kampagnen kleiner Verlage haben mit bescheidenen Zielen gestartet und wurden zu echten Überraschungserfolgen:

""" for c in small_surprises: platform_label = "GF" if c["platform"] == "Gamefound" else "KS" funding_str = fmt_native(c["funding_native"], c["currency"]) goal_str = fmt_native(c["goal_native"], c["currency"]) pct_str = f"{c['percent_funded']:,.0f}%" if c['percent_funded'] else "—" html += f""" """ html += """
KampagnePlattformFundingZiel%BackersVerlag
{c['name']} {platform_label} {funding_str} {goal_str} {pct_str} {c['backers']:,} {c['creator']}

Alle 115 Kampagnen nach Funding sortiert

Die vollständige Liste aller aktiven Brettspiel-Kampagnen der KW27 – sortiert nach Funding (höchstes zuerst):

""" for i, c in enumerate(all_campaigns, 1): platform_label = "GF" if c["platform"] == "Gamefound" else "KS" funding_str = fmt_native(c["funding_native"], c["currency"]) goal_str = fmt_native(c["goal_native"], c["currency"]) if c["goal_native"] > 0 else "—" pct_str = f"{c['percent_funded']:,.0f}%" if c['percent_funded'] else "—" html += f""" """ html += """
#KampagnePlattformFundingZiel%BackersVerlag
{i} {c['name']} {platform_label} {funding_str} {goal_str} {pct_str} {c['backers']:,} {c['creator']}

Quellen

  1. Gamefound
  2. Kickstarter

Recherchestand: 29. Juni 2026

""" with open("/home/hermes/workspace/artikel_crowdfunding_kw27.html", "w") as f: f.write(html) # Print stats print(f"Total campaigns: {len(all_campaigns)}") print(f" Kickstarter: {sum(1 for c in all_campaigns if c['platform'] == 'Kickstarter')}") print(f" Gamefound: {sum(1 for c in all_campaigns if c['platform'] == 'Gamefound')}") print(f"Top 10: {len(top10)}") print(f"Ending this week: {len(ending_this_week)}") print(f"Small surprises: {len(small_surprises)}") print(f"\nTop 10 list:") for i, c in enumerate(top10, 1): print(f" {i}. {c['name']} ({c['platform']}) - {fmt_native(c['funding_native'], c['currency'])}") print(f"\nEnding this week:") for c in ending_this_week: end_date = datetime.fromtimestamp(c["deadline_unix"], tz=timezone.utc) print(f" {c['name']} ({c['platform']}) - ends {end_date.strftime('%d.%m.%Y')}") print(f"\nSmall surprises:") for c in small_surprises: print(f" {c['name']} ({c['platform']}) - {fmt_native(c['funding_native'], c['currency'])} (goal: {fmt_native(c['goal_native'], c['currency'])})")