d02c9906a9
- GET /review-builder: Upload-Formular (Word .docx + Bilder Drag/Drop + Metadaten)
- POST /review-builder/build: Word parsen → LLM (DeepSeek Flash) strukturiert
Teaser/Spielerklärung/Fazit → HTML bauen → im Workspace speichern
- Bild-Resize: 1920x1080 @ 72dpi (PIL), Bilderverzeichnis/01/{buchstabe}/{spiel}/
- review_config.json: 25+ Autoren, 5 Disclosures, 5 Rubriken, Komplexitätsstufen
- Live-Publish via Joomla-API optional (Button: Vorschau / Veröffentlichen)
- Link im Dashboard: 📝 Review-Builder
137 lines
4.1 KiB
Python
137 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Merge GF + KS data, compute rankings, generate HTML article."""
|
|
import json, os, sys
|
|
from datetime import datetime, timezone
|
|
|
|
# Load data
|
|
with open("/home/hermes/workspace/gf_filtered.json") as f:
|
|
gf_data = json.load(f)
|
|
with open("/home/hermes/workspace/ks_filtered.json") as f:
|
|
ks_data = json.load(f)
|
|
|
|
print(f"GF: {len(gf_data)}, KS: {len(ks_data)}")
|
|
|
|
# Convert both to common format
|
|
merged = []
|
|
now = datetime.now(timezone.utc)
|
|
|
|
# Process Gamefound
|
|
for p in gf_data:
|
|
name = p.get("projectName", "")
|
|
funds = float(p.get("fundsGathered", 0) or 0)
|
|
goal = float(p.get("campaignGoal", 0) or 0)
|
|
backers = int(p.get("backerCount", 0) or 0)
|
|
end_str = p.get("campaignEndDate", "")
|
|
|
|
if end_str:
|
|
try:
|
|
end_dt = datetime.fromisoformat(end_str.replace('Z', '+00:00'))
|
|
except:
|
|
end_dt = None
|
|
else:
|
|
end_dt = None
|
|
|
|
days_left = (end_dt - now).days + 1 if end_dt else 999
|
|
if days_left < 0:
|
|
days_left = 0
|
|
|
|
pct = round(funds / goal * 100, 1) if goal > 0 else 0
|
|
|
|
# EUR to USD for ranking consistency (1 EUR ≈ 1.08 USD)
|
|
usd_equiv = funds * 1.08
|
|
|
|
merged.append({
|
|
"name": name,
|
|
"url": p.get("projectHomeUrl", ""),
|
|
"platform": "Gamefound",
|
|
"funds": funds,
|
|
"goal": goal,
|
|
"funding_usd": usd_equiv,
|
|
"backers": backers,
|
|
"days_left": days_left,
|
|
"pct": pct,
|
|
"end_date": end_str,
|
|
"image": p.get("projectImageUrl", ""),
|
|
"blurb": p.get("shortDescription", ""),
|
|
"creator": p.get("creatorName", ""),
|
|
"currency": p.get("currencyShortName", "EUR"),
|
|
"state": "live",
|
|
})
|
|
|
|
# Process Kickstarter
|
|
for p in ks_data:
|
|
funds = float(p.get("pledged", 0) or 0)
|
|
goal = float(p.get("goal", 0) or 0)
|
|
currency = p.get("currency", "USD")
|
|
backers = int(p.get("backers_count", 0) or 0)
|
|
|
|
# KS is in USD by default
|
|
if currency == "USD":
|
|
usd_equiv = funds
|
|
elif currency == "EUR":
|
|
usd_equiv = funds * 1.08
|
|
else:
|
|
usd_equiv = funds * 1.0 # approximate
|
|
|
|
# Days left
|
|
deadline_str = p.get("deadline")
|
|
if deadline_str:
|
|
try:
|
|
end_dt = datetime.fromisoformat(deadline_str.replace('Z', '+00:00'))
|
|
except:
|
|
end_dt = None
|
|
else:
|
|
# Try timestamp
|
|
ts = p.get("deadline_ts")
|
|
if isinstance(ts, int):
|
|
end_dt = datetime.fromtimestamp(ts, tz=timezone.utc)
|
|
else:
|
|
end_dt = None
|
|
|
|
days_left = (end_dt - now).days + 1 if end_dt else 999
|
|
if days_left < 0:
|
|
days_left = 0
|
|
|
|
pct = round(funds / goal * 100, 1) if goal > 0 else 0
|
|
|
|
merged.append({
|
|
"name": p.get("name", ""),
|
|
"url": p.get("url", ""),
|
|
"platform": "Kickstarter",
|
|
"funds": funds,
|
|
"goal": goal,
|
|
"funding_usd": usd_equiv,
|
|
"backers": backers,
|
|
"days_left": days_left,
|
|
"pct": pct,
|
|
"end_date": deadline_str,
|
|
"image": p.get("photo", ""),
|
|
"blurb": p.get("blurb", ""),
|
|
"creator": p.get("creator", ""),
|
|
"currency": currency,
|
|
"state": p.get("state", "live"),
|
|
})
|
|
|
|
# Sort by funding (USD equivalent)
|
|
merged.sort(key=lambda x: x["funding_usd"], reverse=True)
|
|
|
|
# Save merged data
|
|
with open("/home/hermes/workspace/merged_data.json", "w") as f:
|
|
json.dump(merged, f, indent=2, ensure_ascii=False)
|
|
|
|
print(f"\nTotal merged: {len(merged)}")
|
|
print(f"\nTop 10 by funding:")
|
|
for i, p in enumerate(merged[:10]):
|
|
plat = p['platform'][:2]
|
|
funds_str = f"${p['funding_usd']:,.0f}" if p['currency'] == 'USD' else f"€{p['funds']:,.0f}"
|
|
print(f" {i+1}. [{plat}] {p['name']}: {funds_str} ({p['pct']}%) · {p['backers']} backers · {p['days_left']}d left")
|
|
|
|
# Save top 10, endspurts (≤3d), etc.
|
|
print(f"\nEndspurte (≤3d): {sum(1 for p in merged if p['days_left'] <= 3)}")
|
|
print(f"Geheimtipps (<$10k, >100% funded, >50 backers): {sum(1 for p in merged if p['funding_usd'] < 10000 and p['pct'] > 100 and p['backers'] > 50)}")
|
|
|
|
# Get KW number
|
|
kw = now.isocalendar()[1]
|
|
print(f"\nKW: {kw}")
|
|
print(f"\nDONE")
|