diff --git a/data/examples/pretalx/speakers.json b/data/examples/pretalx/speakers.json index fa3e0ff..b5f5161 100644 --- a/data/examples/pretalx/speakers.json +++ b/data/examples/pretalx/speakers.json @@ -6,7 +6,7 @@ "submissions": [ "A8CD3F" ], - "avatar": "https://pretalx.com/media/avatars/picture.jpg", + "avatar_url": "https://pretalx.com/media/avatars/picture.jpg", "answers": [ { "id": 272244, diff --git a/data/examples/pretalx/submissions.json b/data/examples/pretalx/submissions.json index d3b2759..ac4d835 100644 --- a/data/examples/pretalx/submissions.json +++ b/data/examples/pretalx/submissions.json @@ -2,26 +2,16 @@ { "code": "A8CD3F", "speakers": [ - { - "code": "F3DC8A", - "name": "A Speaker", - "biography": "This is a biography of F3D speaker", - "avatar": "https://pretalx.com/media/avatars/picture.jpg", - "email": "f3dc8a@example.com" - }, - { - "code": "ZXCVBN", - "name": "ZXC Speaker", - "biography": "This is a biography of ZXC speaker", - "avatar": "https://pretalx.com/media/avatars/picture.jpg", - "email": "zxcvbn@example.com" - } + "F3DC8A", + "ZXCVBN" ], "title": "This is a test talk from a test speaker about a test topic.", "submission_type": "Talk (long session)", "submission_type_id": 3961, "track": { - "en": "Software Engineering & Architecture" + "name": { + "en": "Software Engineering & Architecture" + } }, "track_id": 4493, "state": "confirmed", @@ -125,19 +115,15 @@ { "code": "B8CD4F", "speakers": [ - { - "code": "G3DC8A", - "name": "Another Speaker", - "biography": "This is a biography of F3D speaker", - "avatar": "https://pretalx.com/media/avatars/picture.jpg", - "email": "g3dc8a@example.com" - } + "G3DC8A" ], "title": "A talk with shorter title", "submission_type": "Talk", "submission_type_id": 3961, "track": { - "en": "PyData: LLMs" + "name": { + "en": "PyData: LLMs" + } }, "track_id": 4493, "state": "confirmed", diff --git a/src/download.py b/src/download.py index 847f751..4eab58a 100644 --- a/src/download.py +++ b/src/download.py @@ -25,12 +25,16 @@ } base_url = f"https://pretalx.com/api/events/{Config.event}/" -schedule_url = base_url + "schedules/latest/" +schedule_url = ( + base_url + + "schedules/latest?expand=" + + "slots,slots.submission,slots.submission.submission_type,slots.submission.track,slots.room" +) # Build resource list dynamically based on exclusions resources = [ - "submissions?questions=all&state=confirmed", - "speakers?questions=all", + "submissions?state=confirmed&expand=answers.question,submission_type,track,slots.room,resources", + "speakers?expand=answers.question", ] if "youtube" not in exclude: diff --git a/src/models/pretalx.py b/src/models/pretalx.py index 0a3cce5..a925930 100644 --- a/src/models/pretalx.py +++ b/src/models/pretalx.py @@ -33,7 +33,7 @@ class PretalxSlot(BaseModel): @classmethod def handle_localized(cls, v) -> str | None: if isinstance(v, dict): - return v.get("en") + return v["name"].get("en") return v @@ -45,7 +45,7 @@ class PretalxSpeaker(BaseModel): code: str name: str biography: str | None = None - avatar: str + avatar_url: str submissions: list[str] answers: list[PretalxAnswer] @@ -77,7 +77,7 @@ class PretalxSubmission(BaseModel): @classmethod def handle_localized(cls, v) -> str | None: if isinstance(v, dict): - return v.get("en") + return v["name"].get("en") return v @field_validator("duration", mode="before") @@ -95,11 +95,18 @@ def handle_resources(cls, v) -> list[dict[str, str]] | None: @model_validator(mode="before") @classmethod def process_values(cls, values) -> dict: - values["speakers"] = sorted([s["code"] for s in values["speakers"]]) + # Transform resource information + if raw_resources := values.get("resources"): + resources = [ + {"description": res["description"], "resource": res["resource"]} + for res in raw_resources + ] + values["resources"] = resources # Set slot information - if values.get("slot"): - slot = PretalxSlot.model_validate(values["slot"]) + if values.get("slots"): + slot = PretalxSlot.model_validate(values["slots"][0]) + values["slot"] = slot values["room"] = slot.room values["start"] = slot.start values["end"] = slot.end @@ -146,3 +153,31 @@ class PretalxSchedule(BaseModel): slots: list[PretalxSubmission] breaks: list[PretalxScheduleBreak] + + @model_validator(mode="before") + @classmethod + def process_values(cls, values) -> dict: + submission_slots = [] + break_slots = [] + for slot_dict in values["slots"]: + # extract nested slot fields into slot + slot_object = PretalxSlot.model_validate(slot_dict) + slot_dict["slot"] = slot_object + slot_dict["room"] = slot_object.room + slot_dict["start"] = slot_object.start + slot_dict["end"] = slot_object.end + + if slot_dict.get("submission") is None: + break_slots.append(slot_dict) + else: + # merge submission fields into slot + slot_dict.update(slot_dict.get("submission", {})) + + # remove resource IDs (not expandable with API, not required for schedule) + slot_dict.pop("resources", None) + + submission_slots.append(slot_dict) + + values["slots"] = submission_slots + values["breaks"] = break_slots + return values diff --git a/src/utils/parse.py b/src/utils/parse.py index cfe53e4..efb6289 100644 --- a/src/utils/parse.py +++ b/src/utils/parse.py @@ -34,12 +34,12 @@ def publishable_speakers( js = json.load(fd) all_speakers = [PretalxSpeaker.model_validate(s) for s in js] - speakers_with_publishable_sessions: list[PretalxSubmission] = [] + speakers_with_publishable_sessions: list[PretalxSpeaker] = [] for speaker in all_speakers: if publishable_sessions := Utils.publishable_sessions_of_speaker( speaker, publishable_sessions_keys ): - speaker.submissions = publishable_sessions + speaker.submissions = sorted(publishable_sessions) speakers_with_publishable_sessions.append(speaker) publishable_speakers_by_code = { diff --git a/src/utils/transform.py b/src/utils/transform.py index ac7d6d9..066e43b 100644 --- a/src/utils/transform.py +++ b/src/utils/transform.py @@ -83,7 +83,7 @@ def pretalx_speakers_to_europython_speakers( code=speaker.code, name=speaker.name, biography=speaker.biography, - avatar=speaker.avatar, + avatar=speaker.avatar_url, slug=speaker_code_to_slug[speaker.code], answers=speaker.answers, submissions=speaker.submissions,