def extract_parental_control_data(content, current_maturity): """Extract the content of parental control data""" try: react_context = extract_json(content, 'reactContext') # Extract country max maturity value max_maturity = common.get_path(['models', 'parentalControls', 'data', 'accountProps', 'countryMaxMaturity'], react_context) # Extract rating levels rc_rating_levels = common.get_path(['models', 'memberContext', 'data', 'userInfo', 'ratingLevels'], react_context) rating_levels = [] levels_count = len(rc_rating_levels) - 1 current_level_index = levels_count for index, rating_level in enumerate(rc_rating_levels): if index == levels_count: # Last level must use the country max maturity level level_value = max_maturity else: level_value = int(rating_level['level']) rating_levels.append({'level': index, 'value': level_value, 'label': rating_level['labels'][0]['label'], 'description': parse_html(rating_level['labels'][0]['description'])}) if level_value == current_maturity: current_level_index = index except KeyError as exc: raise_from(WebsiteParsingError('Unable to get path in to reactContext data'), exc) if not rating_levels: raise WebsiteParsingError('Unable to get maturity rating levels') return {'rating_levels': rating_levels, 'current_level_index': current_level_index}
def validate_login(react_context): path_code_list = PAGE_ITEM_ERROR_CODE_LIST.split('\\') path_error_code = PAGE_ITEM_ERROR_CODE.split('/') if common.check_path_exists(path_error_code, react_context): # If the path exists, a login error occurs try: error_code_list = common.get_path(path_code_list, react_context) error_code = common.get_path(path_error_code, react_context) LOG.error('Login not valid, error code {}', error_code) error_description = common.get_local_string(30102) + error_code if error_code in error_code_list: error_description = error_code_list[error_code] if 'email_' + error_code in error_code_list: error_description = error_code_list['email_' + error_code] if 'login_' + error_code in error_code_list: error_description = error_code_list['login_' + error_code] raise LoginValidateError(common.remove_html_tags(error_description)) except (AttributeError, KeyError) as exc: import traceback LOG.error(G.py2_decode(traceback.format_exc(), 'latin-1')) error_msg = ( 'Something is wrong in PAGE_ITEM_ERROR_CODE or PAGE_ITEM_ERROR_CODE_LIST paths.' 'react_context data may have changed.') LOG.error(error_msg) raise_from(WebsiteParsingError(error_msg), exc)
def extract_json(content, name): """Extract json from netflix content page""" LOG.debug('Extracting {} JSON', name) json_str = None try: json_array = recompile(JSON_REGEX.format(name), DOTALL).findall(content.decode('utf-8')) json_str = json_array[0] json_str_replace = json_str.replace(r'\"', r'\\"') # Escape \" json_str_replace = json_str_replace.replace( r'\s', r'\\s') # Escape whitespace json_str_replace = json_str_replace.replace(r'\r', r'\\r') # Escape return json_str_replace = json_str_replace.replace(r'\n', r'\\n') # Escape line feed json_str_replace = json_str_replace.replace(r'\t', r'\\t') # Escape tab json_str_replace = json_str_replace.encode().decode( 'unicode_escape') # Decode the string as unicode json_str_replace = sub( r'\\(?!["])', r'\\\\', json_str_replace ) # Escape backslash (only when is not followed by double quotation marks \") return json.loads(json_str_replace) except Exception as exc: # pylint: disable=broad-except if json_str: # For testing purposes remember to add raw prefix to the string to test: json_str = r'string to test' LOG.error('JSON string trying to load: {}', json_str) import traceback LOG.error(traceback.format_exc()) raise WebsiteParsingError('Unable to extract {}'.format(name)) from exc
def extract_json(content, name): """Extract json from netflix content page""" LOG.debug('Extracting {} JSON', name) json_str = None try: json_array = recompile(JSON_REGEX.format(name), DOTALL).findall(content.decode('utf-8')) json_str = json_array[0] json_str_replace = json_str.replace('\\"', '\\\\"') # Escape double-quotes json_str_replace = json_str_replace.replace('\\s', '\\\\s') # Escape \s json_str_replace = json_str_replace.replace( '\\n', '\\\\n') # Escape line feed json_str_replace = json_str_replace.replace('\\t', '\\\\t') # Escape tab json_str_replace = json_str_replace.encode().decode( 'unicode_escape') # Decode the string as unicode json_str_replace = sub( r'\\(?!["])', r'\\\\', json_str_replace ) # Escape backslash (only when is not followed by double quotation marks \") return json.loads(json_str_replace) except Exception as exc: # pylint: disable=broad-except if json_str: LOG.error('JSON string trying to load: {}', json_str) import traceback LOG.error(G.py2_decode(traceback.format_exc(), 'latin-1')) raise_from(WebsiteParsingError('Unable to extract {}'.format(name)), exc)
def login_auth_data(self, data=None, password=None): """Perform account login with authentication data""" from requests import exceptions LOG.debug('Logging in with authentication data') # Add the cookies to the session self.session.cookies.clear() for cookie in data['cookies']: self.session.cookies.set(cookie[0], cookie[1], **cookie[2]) cookies.log_cookie(self.session.cookies) # Try access to website try: website.extract_session_data(self.get('browse'), validate=True, update_profiles=True) except MbrStatusAnonymousError: # Access not valid return False # Get the account e-mail page_response = self.get('your_account').decode('utf-8') email_match = re.search(r'account-email[^<]+>([^<]+@[^</]+)</', page_response) email = email_match.group(1).strip() if email_match else None if not email: raise WebsiteParsingError('E-mail field not found') # Verify the password (with parental control api) try: response = self.post_safe('profile_hub', data={ 'destination': 'contentRestrictions', 'guid': G.LOCAL_DB.get_active_profile_guid(), 'password': password, 'task': 'auth' }) if response.get('status') != 'ok': raise LoginError(common.get_local_string( 12344)) # 12344=Passwords entered did not match. except exceptions.HTTPError as exc: if exc.response.status_code == 500: # This endpoint raise HTTP error 500 when the password is wrong raise LoginError(common.get_local_string(12344)) from exc raise common.set_credentials({'email': email, 'password': password}) LOG.info('Login successful') ui.show_notification(common.get_local_string(30109)) cookies.save(self.session.cookies) return True
def login_auth_data(self, data=None, password=None): """Perform account login with authentication data""" LOG.debug('Logging in with authentication data') # Add the cookies to the session self.session.cookies.clear() for cookie in data['cookies']: # The code below has been adapted from httpx.Cookies.set() method kwargs = { 'version': 0, 'name': cookie['name'], 'value': cookie['value'], 'port': None, 'port_specified': False, 'domain': cookie['domain'], 'domain_specified': bool(cookie['domain']), 'domain_initial_dot': cookie['domain'].startswith('.'), 'path': cookie['path'], 'path_specified': bool(cookie['path']), 'secure': cookie['secure'], 'expires': cookie['expires'], 'discard': True, 'comment': None, 'comment_url': None, 'rest': cookie['rest'], 'rfc2109': False, } cookie = Cookie(**kwargs) self.session.cookies.jar.set_cookie(cookie) cookies.log_cookie(self.session.cookies.jar) # Try access to website try: website.extract_session_data(self.get('browse'), validate=True, update_profiles=True) except MbrStatusAnonymousError: # Access not valid return False # Get the account e-mail page_response = self.get('your_account').decode('utf-8') email_match = re.search(r'account-email[^<]+>([^<]+@[^</]+)</', page_response) email = email_match.group(1).strip() if email_match else None if not email: raise WebsiteParsingError('E-mail field not found') # Verify the password (with parental control api) try: response = self.post_safe('profile_hub', data={ 'destination': 'contentRestrictions', 'guid': G.LOCAL_DB.get_active_profile_guid(), 'password': password, 'task': 'auth' }) if response.get('status') != 'ok': raise LoginError(common.get_local_string( 12344)) # 12344=Passwords entered did not match. except httpx.HTTPStatusError as exc: if exc.response.status_code == 500: # This endpoint raise HTTP error 500 when the password is wrong raise LoginError(common.get_local_string(12344)) from exc raise common.set_credentials({'email': email, 'password': password}) LOG.info('Login successful') ui.show_notification(common.get_local_string(30109)) cookies.save(self.session.cookies.jar) return True