@@ -241,39 +241,51 @@ def _clean_social_input(text: str) -> str | None:
241241 removes "http://" or "https://",
242242 removes "www." prefix,
243243 removes "@" prefix,
244+ removes invisible Unicode control characters,
244245 and decodes URL-encoded characters.
245246 """
246247 if EuroPythonSpeaker ._is_blank_or_na (text ):
247248 print (f"Blank or N/A input: { text } " )
248249 return None
249250
251+ # Strip leading/trailing whitespace
250252 text = text .strip ()
251253
252- # Handle inputs like "LinkedIn: https://linkedin.com/in/username"
253- # or "GH: https://github.com/username"
254+ # Remove any text prefix like "LinkedIn: " or "GH: "
254255 text = text .split (" " , 1 )[1 ] if ": " in text else text
255256
257+ # Remove query strings and trailing commas or slashes
256258 text = text .split ("?" , 1 )[0 ]
257259 text = text .split ("," , 1 )[0 ]
258260 text = text .rstrip ("/" )
259261
262+ # Remove URL schemes
260263 if text .startswith ("https://" ):
261264 text = text [8 :]
262265 elif text .startswith ("http://" ):
263266 text = text [7 :]
264267
268+ # Remove "www." prefix
265269 if text .startswith ("www." ):
266270 text = text [4 :]
267271
268- # Remove @ if present
272+ # Remove leading @
269273 if text .startswith ("@" ):
270274 text = text [1 :]
271275
272- # Percent-encode non-ASCII characters
276+ # Remove invisible Unicode control characters (Bidi, LTR/RTL marks, etc.)
277+ invisible_chars = [
278+ '\u200e ' , '\u200f ' , # LTR / RTL marks
279+ '\u202a ' , '\u202b ' , '\u202c ' , '\u202d ' , '\u202e ' , # Directional overrides
280+ '\u2066 ' , '\u2067 ' , '\u2068 ' , '\u2069 ' , # Isolates
281+ ]
282+ text = re .sub (f"[{ '' .join (invisible_chars )} ]" , '' , text )
283+
284+ # Percent-encode if needed (e.g., non-ASCII chars)
273285 if not text .isascii ():
274286 text = quote (text , safe = "@/-_.+~#=:" )
275287
276- return text .lower ()
288+ return text .lower () if text else None
277289
278290
279291class EuroPythonSession (BaseModel ):
@@ -292,7 +304,7 @@ class EuroPythonSession(BaseModel):
292304 duration : str = ""
293305 level : str = ""
294306 delivery : str = ""
295- resources : list [dict [str , str ]] | None = None
307+ resources : list [dict [str , str | None ]] | None = None
296308 room : str | None = None
297309 start : datetime | None = None
298310 end : datetime | None = None
0 commit comments