Created
October 25, 2025 12:14
-
-
Save thibaudcolas/fdd1c5b53fb7b95fe10f0cca748a226b to your computer and use it in GitHub Desktop.
frab_to_csv conference schedule pretalx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| """ | |
| Convert a frab/pretalx schedule JSON to CSV for Google Sheets. | |
| Usage: | |
| python frab_to_csv.py input.json > output.csv | |
| """ | |
| import sys, json, csv | |
| from datetime import datetime | |
| REQUIRED_ORDER = [ | |
| "Day", | |
| "Time", | |
| "Talk / slot title", | |
| "Speaker name(s)", | |
| "URL", | |
| "Full timestamp", | |
| "Venue", | |
| "Duration", | |
| "Slot type", | |
| "Speaker bio", | |
| "Speaker picture URL", | |
| ] | |
| def parse_iso(iso_str): | |
| try: | |
| # Handles "2025-09-19T11:00:00+01:00" | |
| return datetime.fromisoformat(iso_str) | |
| except Exception: | |
| return None | |
| def day_name(dt): | |
| return dt.strftime("%A") if dt else "" | |
| def time_24h(dt, fallback=""): | |
| return dt.strftime("%H:%M") if dt else fallback | |
| def pick_name(p): | |
| return p.get("public_name") or p.get("name") or "" | |
| def pick_bio(p): | |
| return p.get("biography") or "" | |
| def pick_avatar(p): | |
| return p.get("avatar") or "" | |
| def extract_rows(data): | |
| rows = [] | |
| schedule = data.get("schedule", {}) | |
| conference = schedule.get("conference", {}) | |
| for day in conference.get("days", []): | |
| day_date = day.get("date", "") | |
| rooms = day.get("rooms", {}) | |
| for room_name, items in rooms.items(): | |
| for it in items: | |
| iso = it.get("date") or "" | |
| dt = parse_iso(iso) | |
| persons = it.get("persons") or [] | |
| names = ", ".join([n for p in persons if (n := pick_name(p))]) | |
| bios = " | ".join([b for p in persons if (b := pick_bio(p))]) | |
| avatars = " | ".join([a for p in persons if (a := pick_avatar(p))]) | |
| row = { | |
| "Day": day_name(dt) or day_date, | |
| "Time": time_24h(dt, it.get("start") or ""), | |
| "Talk / slot title": it.get("title") or "", | |
| "Speaker name(s)": names, | |
| "URL": it.get("url") or it.get("origin_url") or "", | |
| "Full timestamp": iso, | |
| "Venue": it.get("room") or room_name or "", | |
| "Duration": it.get("duration") or "", | |
| "Slot type": it.get("type") or "", | |
| "Speaker bio": bios, | |
| "Speaker picture URL": avatars, | |
| } | |
| sort_key = dt.isoformat() if dt else f"{day_date}T{it.get('start','')}" | |
| rows.append((sort_key, row)) | |
| rows.sort(key=lambda x: x[0]) | |
| return [r for _, r in rows] | |
| def main(): | |
| if len(sys.argv) < 2: | |
| print("Usage: python frab_to_csv.py input.json > output.csv", file=sys.stderr) | |
| sys.exit(1) | |
| with open(sys.argv[1], "r", encoding="utf-8") as f: | |
| data = json.load(f) | |
| rows = extract_rows(data) | |
| writer = csv.DictWriter(sys.stdout, fieldnames=REQUIRED_ORDER) | |
| writer.writeheader() | |
| for r in rows: | |
| writer.writerow(r) | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment