@@ -78,14 +78,10 @@ def __init__(
7878 if not enable_logging :
7979 logger .remove ()
8080 logger .add (lambda msg : None , level = "CRITICAL" ) # Disable most logging
81- # Parse SSID if it's a complete auth message
81+
82+ # Validate and parse SSID
8283 self ._original_demo = None # Store original demo value from SSID
83- if ssid .startswith ('42["auth",' ):
84- self ._parse_complete_ssid (ssid )
85- else :
86- # Treat as raw session ID
87- self .session_id = ssid
88- self ._complete_ssid = None
84+ self ._validate_and_parse_ssid (ssid )
8985
9086 # Core components
9187 self ._websocket = AsyncWebSocketClient ()
@@ -656,6 +652,39 @@ def get_connection_stats(self) -> Dict[str, Any]:
656652
657653 return stats # Private methods
658654
655+ def _validate_and_parse_ssid (self , ssid : str ) -> None :
656+ """Validate and parse SSID format"""
657+ if not ssid or not isinstance (ssid , str ):
658+ raise InvalidParameterError (
659+ "SSID must be a non-empty string. "
660+ "Expected format: 42[\" auth\" ,{\" session\" :\" ...\" ,\" isDemo\" :1,\" uid\" :0,\" platform\" :1}]"
661+ )
662+
663+ ssid = ssid .strip ()
664+
665+ # Check if it's a complete SSID format
666+ if ssid .startswith ('42["auth",' ):
667+ self ._parse_complete_ssid (ssid )
668+ # Validate that we got a session ID
669+ if not self .session_id or len (self .session_id ) < 10 :
670+ raise InvalidParameterError (
671+ f"Invalid SSID format - session ID is too short or missing. "
672+ f"Please ensure your SSID is in the correct format: "
673+ f"42[\" auth\" ,{{\" session\" :\" your_session_id\" ,\" isDemo\" :1,\" uid\" :12345,\" platform\" :1}}]. "
674+ f"You can get this from browser DevTools (F12) -> Network tab -> WS filter -> "
675+ f"look for authentication message starting with 42[\" auth\" ,"
676+ )
677+ else :
678+ # Treat as raw session ID
679+ if len (ssid ) < 10 :
680+ logger .warning (
681+ f"Raw session ID appears to be too short ({ len (ssid )} chars). "
682+ f"If you're having connection issues, please use the complete SSID format: "
683+ f"42[\" auth\" ,{{\" session\" :\" your_session\" ,\" isDemo\" :1,\" uid\" :12345,\" platform\" :1}}]"
684+ )
685+ self .session_id = ssid
686+ self ._complete_ssid = None
687+
659688 def _format_session_message (self ) -> str :
660689 """Format session authentication message"""
661690 # Always create auth message from components using constructor parameters
@@ -683,41 +712,80 @@ def _parse_complete_ssid(self, ssid: str) -> None:
683712 data = json .loads (json_part )
684713
685714 self .session_id = data .get ("session" , "" )
715+ if not self .session_id :
716+ raise InvalidParameterError (
717+ "SSID is missing the 'session' field. "
718+ "Expected format: 42[\" auth\" ,{\" session\" :\" your_session\" ,\" isDemo\" :1,\" uid\" :12345,\" platform\" :1}]"
719+ )
720+
686721 # Store original demo value from SSID, but don't override the constructor parameter
687722 self ._original_demo = bool (data .get ("isDemo" , 1 ))
688723 # Keep the is_demo value from constructor - don't override it
689724 self .uid = data .get ("uid" , 0 )
690725 self .platform = data .get ("platform" , 1 )
691726 # Don't store complete SSID - we'll reconstruct it with correct demo value
692727 self ._complete_ssid = None
728+ else :
729+ raise InvalidParameterError (
730+ "Could not parse SSID - JSON object not found. "
731+ "Expected format: 42[\" auth\" ,{\" session\" :\" your_session\" ,\" isDemo\" :1,\" uid\" :12345,\" platform\" :1}]"
732+ )
733+ except json .JSONDecodeError as e :
734+ raise InvalidParameterError (
735+ f"Invalid SSID format - JSON parsing failed: { e } . "
736+ f"Expected format: 42[\" auth\" ,{{\" session\" :\" your_session\" ,\" isDemo\" :1,\" uid\" :12345,\" platform\" :1}}]"
737+ )
738+ except InvalidParameterError :
739+ raise # Re-raise our custom errors
693740 except Exception as e :
694- logger .warning (f"Failed to parse SSID: { e } " )
695- self .session_id = ssid
696- self ._complete_ssid = None
741+ raise InvalidParameterError (
742+ f"Failed to parse SSID: { e } . "
743+ f"Expected format: 42[\" auth\" ,{{\" session\" :\" your_session\" ,\" isDemo\" :1,\" uid\" :12345,\" platform\" :1}}]"
744+ )
697745
698746 async def _wait_for_authentication (self , timeout : float = 10.0 ) -> None :
699747 """Wait for authentication to complete (like old API)"""
700748 auth_received = False
749+ auth_error = None
701750
702751 def on_auth (data ):
703752 nonlocal auth_received
704753 auth_received = True
754+
755+ def on_auth_error (data ):
756+ nonlocal auth_error
757+ auth_error = data .get ("message" , "Unknown authentication error" )
705758
706- # Add temporary handler
759+ # Add temporary handlers
707760 self ._websocket .add_event_handler ("authenticated" , on_auth )
761+ self ._websocket .add_event_handler ("auth_error" , on_auth_error )
708762
709763 try :
710764 # Wait for authentication
711765 start_time = time .time ()
712- while not auth_received and (time .time () - start_time ) < timeout :
766+ while not auth_received and not auth_error and (time .time () - start_time ) < timeout :
713767 await asyncio .sleep (0.1 )
714768
769+ if auth_error :
770+ raise AuthenticationError (
771+ f"Authentication failed: { auth_error } . "
772+ f"Please verify your SSID is correct. "
773+ f"SSID should be in format: 42[\" auth\" ,{{\" session\" :\" your_session\" ,\" isDemo\" :1,\" uid\" :12345,\" platform\" :1}}]. "
774+ f"Get it from browser DevTools (F12) -> Network tab -> WS filter -> look for message starting with 42[\" auth\" ,"
775+ )
776+
715777 if not auth_received :
716- raise AuthenticationError ("Authentication timeout" )
778+ raise AuthenticationError (
779+ "Authentication timeout - server did not respond to authentication request. "
780+ "This usually means your SSID is invalid or expired. "
781+ "Please get a fresh SSID from browser DevTools (F12) -> Network tab -> WS filter -> "
782+ "look for authentication message starting with 42[\" auth\" ,{\" session\" :\" ...\" ,..."
783+ )
717784
718785 finally :
719- # Remove temporary handler
786+ # Remove temporary handlers
720787 self ._websocket .remove_event_handler ("authenticated" , on_auth )
788+ self ._websocket .remove_event_handler ("auth_error" , on_auth_error )
721789
722790 async def _initialize_data (self ) -> None :
723791 """Initialize client data after connection"""
0 commit comments