@@ -32,6 +32,8 @@ class EuroPythonSpeaker(BaseModel):
3232 linkedin_url : str | None = None
3333 bluesky_url : str | None = None
3434 gitx_url : str | None = None
35+ instagram_url : str | None = None
36+ timezone : str | None = None
3537
3638 @computed_field
3739 def website_url (self ) -> str :
@@ -64,6 +66,12 @@ def extract_answers(cls, values) -> dict:
6466 if answer .question_text == SpeakerQuestion .gitx :
6567 values ["gitx_url" ] = cls .extract_gitx_url (answer .answer_text )
6668
69+ if answer .question_text == SpeakerQuestion .instagram :
70+ values ["instagram_url" ] = cls .extract_instagram_url (answer .answer_text )
71+
72+ if answer .question_text == SpeakerQuestion .timezone :
73+ values ["timezone" ] = answer .answer_text
74+
6775 return values
6876
6977 @staticmethod
@@ -221,6 +229,33 @@ def extract_gitx_url(text: str) -> str | None:
221229 print (f"Invalid GitHub/GitLab URL: { cleaned } " )
222230 return None
223231
232+ @staticmethod
233+ def extract_instagram_url (text : str ) -> str | None :
234+ """
235+ Extracts an Instagram profile URL from the given text.
236+ Cleans the input and handles following formats:
237+ - @username
238+ - username
239+ - instagram.com/username
240+ """
241+ cleaned = EuroPythonSpeaker ._clean_social_input (text )
242+ if cleaned is None :
243+ print (f"Invalid Instagram URL: { text } " )
244+ return None
245+
246+ # https://instagram.com/username (username max 30 chars)
247+ match = re .match (r"^instagram\.com/([\w\.]{1,30})$" , cleaned )
248+ if match :
249+ username = match .groups ()[0 ]
250+ return f"https://instagram.com/{ username } "
251+
252+ # only username
253+ if re .match (r"^[\w\.]{1,30}$" , cleaned ):
254+ return f"https://instagram.com/{ cleaned } "
255+
256+ print (f"Invalid Instagram URL: { cleaned } " )
257+ return None
258+
224259 @staticmethod
225260 def _is_blank_or_na (text : str ) -> bool :
226261 """
0 commit comments