def extract_session_data(content, validate=False, update_profiles=False):
    """
    Call all the parsers we need to extract all
    the session relevant data from the HTML page
    """
    common.debug('Extracting session data...')
    react_context = extract_json(content, 'reactContext')
    if validate:
        validate_login(react_context)

    user_data = extract_userdata(react_context)
    _check_membership_status(user_data.get('membershipStatus'))

    api_data = extract_api_data(react_context)
    # Note: Falcor cache does not exist if membershipStatus is not CURRENT_MEMBER
    falcor_cache = extract_json(content, 'falcorCache')

    if update_profiles:
        parse_profiles(falcor_cache)

    # 21/05/2020 - Netflix has introduced a new paging type called "loco" similar to the old "lolomo"
    # Extract loco root id
    loco_root = falcor_cache['loco']['value'][1]
    G.LOCAL_DB.set_value('loco_root_id', loco_root, TABLE_SESSION)

    # Save only some info of the current profile from user data
    G.LOCAL_DB.set_value('build_identifier', user_data.get('BUILD_IDENTIFIER'),
                         TABLE_SESSION)
    if not G.LOCAL_DB.get_value('esn', table=TABLE_SESSION):
        G.LOCAL_DB.set_value('esn',
                             common.generate_android_esn() or user_data['esn'],
                             TABLE_SESSION)
    G.LOCAL_DB.set_value('locale_id',
                         user_data.get('preferredLocale').get('id', 'en-US'))
    # Extract the client version from assets core
    result = search(r'-([0-9\.]+)\.js$', api_data.pop('asset_core'))
    if not result:
        common.error('It was not possible to extract the client version!')
        api_data['client_version'] = '6.0023.976.011'
    else:
        api_data['client_version'] = result.groups()[0]
    # Save api urls
    for key, path in list(api_data.items()):
        G.LOCAL_DB.set_value(key, path, TABLE_SESSION)
    return api_data
def _esn_checks():
    # Check if the custom esn is changed
    custom_esn = g.ADDON.getSetting('esn')
    custom_esn_old = g.LOCAL_DB.get_value('custom_esn', '',
                                          TABLE_SETTINGS_MONITOR)
    if custom_esn != custom_esn_old:
        g.LOCAL_DB.set_value('custom_esn', custom_esn, TABLE_SETTINGS_MONITOR)
        common.send_signal(signal=common.Signals.ESN_CHANGED)

    if not custom_esn:
        # Check if "Force identification as L3 Widevine device" is changed (ANDROID ONLY)
        is_l3_forced = bool(g.ADDON.getSettingBool('force_widevine_l3'))
        is_l3_forced_old = g.LOCAL_DB.get_value('force_widevine_l3', False,
                                                TABLE_SETTINGS_MONITOR)
        if is_l3_forced != is_l3_forced_old:
            g.LOCAL_DB.set_value('force_widevine_l3', is_l3_forced,
                                 TABLE_SETTINGS_MONITOR)
            # If user has changed setting is needed clear previous ESN and perform a new handshake with the new one
            g.LOCAL_DB.set_value('esn',
                                 common.generate_android_esn() or '',
                                 TABLE_SESSION)
            common.send_signal(signal=common.Signals.ESN_CHANGED)
def extract_session_data(content, validate=False, update_profiles=False):
    """
    Call all the parsers we need to extract all
    the session relevant data from the HTML page
    """
    common.debug('Extracting session data...')
    react_context = extract_json(content, 'reactContext')
    if validate:
        validate_login(react_context)

    user_data = extract_userdata(react_context)
    if user_data.get('membershipStatus') == 'ANONYMOUS':
        # Possible known causes:
        # -Login password has been changed
        # -In the login request, 'Content-Type' specified is not compliant with data passed or no more supported
        # -Expired profiles cookies!? (not verified)
        # In these cases it is mandatory to login again
        raise InvalidMembershipStatusAnonymous
    if user_data.get('membershipStatus') != 'CURRENT_MEMBER':
        # When NEVER_MEMBER it is possible that the account has not been confirmed or renewed
        common.error('Can not login, the Membership status is {}',
                     user_data.get('membershipStatus'))
        raise InvalidMembershipStatusError(user_data.get('membershipStatus'))

    api_data = extract_api_data(react_context)
    # Note: Falcor cache does not exist if membershipStatus is not CURRENT_MEMBER
    falcor_cache = extract_json(content, 'falcorCache')

    if update_profiles:
        parse_profiles(falcor_cache)

    if common.is_debug_verbose():
        # Only for debug purpose not sure if can be useful
        try:
            common.debug(
                'ReactContext profileGateState {} ({})', PROFILE_GATE_STATES[
                    react_context['models']['profileGateState']['data']],
                react_context['models']['profileGateState']['data'])
        except KeyError:
            common.error('ReactContext unknown profileGateState {}',
                         react_context['models']['profileGateState']['data'])

    # Profile idle timeout (not sure if will be useful, to now for documentation purpose)
    # NOTE: On the website this value is used to update the profilesNewSession cookie expiration after a profile switch
    #       and also to update the expiration of this cookie on each website interaction.
    #       When the session is expired the 'profileGateState' will be 0 and the website return auto. to profiles page
    # g.LOCAL_DB.set_value('profile_gate_idle_timer', user_data.get('idle_timer', 30), TABLE_SESSION)

    # 21/05/2020 - Netflix has introduced a new paging type called "loco" similar to the old "lolomo"
    # Extract loco root id
    loco_root = falcor_cache['loco']['value'][1]
    g.LOCAL_DB.set_value('loco_root_id', loco_root, TABLE_SESSION)

    # Check if the profile session is still active
    #  (when a session expire in the website, the screen return automatically to the profiles page)
    is_profile_session_active = 'componentSummary' in falcor_cache['locos'][
        loco_root]

    # Extract loco root request id
    if is_profile_session_active:
        component_summary = falcor_cache['locos'][loco_root][
            'componentSummary']['value']
        # Note: 18/06/2020 now the request id is the equal to reactContext models/serverDefs/data/requestId
        g.LOCAL_DB.set_value('loco_root_requestid',
                             component_summary['requestId'], TABLE_SESSION)
    else:
        g.LOCAL_DB.set_value('loco_root_requestid', '', TABLE_SESSION)

    # Extract loco continueWatching id and index
    #   The following commented code was needed for update_loco_context in api_requests.py, but currently
    #   seem not more required to update the continueWatching list then we keep this in case of future nf changes
    # -- INIT --
    # cw_list_data = jgraph_get('continueWatching', falcor_cache['locos'][loco_root], falcor_cache)
    # if cw_list_data:
    #     context_index = falcor_cache['locos'][loco_root]['continueWatching']['value'][2]
    #     g.LOCAL_DB.set_value('loco_continuewatching_index', context_index, TABLE_SESSION)
    #     g.LOCAL_DB.set_value('loco_continuewatching_id',
    #                          jgraph_get('componentSummary', cw_list_data)['id'], TABLE_SESSION)
    # elif is_profile_session_active:
    #     # Todo: In the new profiles, there is no 'continueWatching' context
    #     #  How get or generate the continueWatching context?
    #     #  NOTE: it was needed for update_loco_context in api_requests.py
    #     cur_profile = jgraph_get_path(['profilesList', 'current'], falcor_cache)
    #     common.warn('Context continueWatching not found in locos for profile guid {}.',
    #                 jgraph_get('summary', cur_profile)['guid'])
    #     g.LOCAL_DB.set_value('loco_continuewatching_index', '', TABLE_SESSION)
    #     g.LOCAL_DB.set_value('loco_continuewatching_id', '', TABLE_SESSION)
    # else:
    #     common.warn('Is not possible to find the context continueWatching, the profile session is no more active')
    #     g.LOCAL_DB.set_value('loco_continuewatching_index', '', TABLE_SESSION)
    #     g.LOCAL_DB.set_value('loco_continuewatching_id', '', TABLE_SESSION)
    # -- END --

    # Save only some info of the current profile from user data
    g.LOCAL_DB.set_value('build_identifier', user_data.get('BUILD_IDENTIFIER'),
                         TABLE_SESSION)
    if not g.LOCAL_DB.get_value('esn', table=TABLE_SESSION):
        g.LOCAL_DB.set_value('esn',
                             common.generate_android_esn() or user_data['esn'],
                             TABLE_SESSION)
    g.LOCAL_DB.set_value('locale_id',
                         user_data.get('preferredLocale').get('id', 'en-US'))
    # Save api urls
    for key, path in list(api_data.items()):
        g.LOCAL_DB.set_value(key, path, TABLE_SESSION)

    api_data['is_profile_session_active'] = is_profile_session_active
    return api_data
def extract_session_data(content, validate=False, update_profiles=False):
    """
    Call all the parsers we need to extract all
    the session relevant data from the HTML page
    """
    common.debug('Extracting session data...')
    react_context = extract_json(content, 'reactContext')
    if validate:
        validate_login(react_context)

    user_data = extract_userdata(react_context)
    if user_data.get('membershipStatus') == 'ANONYMOUS':
        # Possible known causes:
        # -Login password has been changed
        # -In the login request, 'Content-Type' specified is not compliant with data passed or no more supported
        # -Expired profiles cookies!? (not verified)
        # In these cases it is mandatory to login again
        raise InvalidMembershipStatusAnonymous
    if user_data.get('membershipStatus') != 'CURRENT_MEMBER':
        # When NEVER_MEMBER it is possible that the account has not been confirmed or renewed
        common.error('Can not login, the Membership status is {}',
                     user_data.get('membershipStatus'))
        raise InvalidMembershipStatusError(user_data.get('membershipStatus'))

    api_data = extract_api_data(react_context)
    # Note: Falcor cache does not exist if membershipStatus is not CURRENT_MEMBER
    falcor_cache = extract_json(content, 'falcorCache')

    if update_profiles:
        parse_profiles(falcor_cache)

    g.LOCAL_DB.set_value('is_loco_supported', user_data.get('isLocoSupported'), TABLE_SESSION)
    if user_data.get('isLocoSupported'):
        # 21/05/2020 - Netflix is introducing a new paging type called "loco", it is similar to "lolomo"
        # The lolomo data here is obtained by a separated request from update_lolomo_data in nfsession.py

        # Extract loco root id
        # NOTE: loco root ID is not same of lolomo root id
        loco_root = falcor_cache['loco']['value'][1]
        # g.LOCAL_DB.set_value('lolomo_root_id', loco_root, TABLE_SESSION)

        # Check if current 'profile session' is still active
        # Todo: 25/05/2020 - This not works, currently the "locos" list is always empty
        is_profile_session_active = 'componentSummary' in falcor_cache['locos'][loco_root]

        # Extract loco continueWatching id and index
        # Todo: 25/05/2020 - Without the "locos" list is not possible get this data here
        # g.LOCAL_DB.set_value('lolomo_continuewatching_index', '', TABLE_SESSION)
        # g.LOCAL_DB.set_value('lolomo_continuewatching_id', '', TABLE_SESSION)
    else:
        # Extract lolomo root id
        lolomo_root = falcor_cache['lolomo']['value'][1]
        g.LOCAL_DB.set_value('lolomo_root_id', lolomo_root, TABLE_SESSION)

        # Check if current 'profile session' is still active
        # What means 'profile session':
        # In web browser, after you select a profile and then you close the browse page,
        #   when you reopen it you will not be asked to select a profile again, this means that the same profile session
        #   still active, and the lolomo root id (and child contexts id's) are still the same.
        #   Here one way to understand this, is checking if there is an 'summary' entry in the lolomos dictionary.
        is_profile_session_active = 'summary' in falcor_cache['lolomos'][lolomo_root]

        # Extract lolomo continueWatching id and index
        cw_list_data = jgraph_get('continueWatching', falcor_cache['lolomos'][lolomo_root], falcor_cache)
        if cw_list_data:
            context_index = falcor_cache['lolomos'][lolomo_root]['continueWatching']['value'][2]
            g.LOCAL_DB.set_value('lolomo_continuewatching_index', context_index, TABLE_SESSION)
            g.LOCAL_DB.set_value('lolomo_continuewatching_id', jgraph_get('id', cw_list_data), TABLE_SESSION)
        elif is_profile_session_active:
            # Todo: In the new profiles, there is no 'continueWatching' context
            #  How get or generate the continueWatching context?
            #  (needed to update lolomo list for watched state sync, see update_lolomo_context in api_requests.py)
            cur_profile = jgraph_get_path(['profilesList', 'current'], falcor_cache)
            common.warn('Context continueWatching not found in lolomos for profile guid {}.',
                        jgraph_get('summary', cur_profile)['guid'])
            g.LOCAL_DB.set_value('lolomo_continuewatching_index', '', TABLE_SESSION)
            g.LOCAL_DB.set_value('lolomo_continuewatching_id', '', TABLE_SESSION)
        else:
            common.warn('Is not possible to find the context continueWatching, the profile session is no more active')

    # Save only some info of the current profile from user data
    g.LOCAL_DB.set_value('build_identifier', user_data.get('BUILD_IDENTIFIER'), TABLE_SESSION)
    if not g.LOCAL_DB.get_value('esn', table=TABLE_SESSION):
        g.LOCAL_DB.set_value('esn', common.generate_android_esn() or user_data['esn'], TABLE_SESSION)
    g.LOCAL_DB.set_value('locale_id', user_data.get('preferredLocale').get('id', 'en-US'))
    # Save api urls
    for key, path in list(api_data.items()):
        g.LOCAL_DB.set_value(key, path, TABLE_SESSION)

    api_data['is_profile_session_active'] = is_profile_session_active
    return api_data