예제 #1
0
    def release_license(self, data=None):  # pylint: disable=unused-argument
        """Release the server license"""
        try:
            # When you try to play a video while another one is currently in playing,
            # a new license to be released will be queued, so the oldest license must be released
            url = self.licenses_release_url.pop()
            sid = self.licenses_session_id.pop()
            xid = self.licenses_xid.pop()

            LOG.debug('Requesting releasing license')
            params = [{
                'url': url,
                'params': {
                    'drmSessionId': sid,
                    'xid': xid
                },
                'echo': 'drmSessionId'
            }]

            response = self.msl_requests.chunked_request(
                ENDPOINTS['license'],
                self.msl_requests.build_request_data('/bundle', params),
                get_esn())
            LOG.debug('License release response: {}', response)
        except IndexError:
            # Example the supplemental media type have no license
            LOG.debug('No license to release')
예제 #2
0
 def _process_event_request(self, event):
     """Do the event post request"""
     event.status = Event.STATUS_REQUESTED
     # Request attempts can be made up to a maximum of 3 times per event
     LOG.info('EVENT [{}] - Executing request', event)
     endpoint_url = ENDPOINTS['events'] + create_req_params(
         20 if event.event_type == EVENT_START else 0,
         'events/{}'.format(event))
     try:
         response = self.chunked_request(endpoint_url,
                                         event.request_data,
                                         get_esn(),
                                         disable_msl_switch=False)
         # Malformed/wrong content in requests are ignored without returning error feedback in the response
         event.set_response(response)
     except Exception as exc:  # pylint: disable=broad-except
         LOG.error('EVENT [{}] - The request has failed: {}', event, exc)
         event.set_response('RequestError')
     if event.event_type == EVENT_STOP and event.status == Event.STATUS_SUCCESS:
         self.clear_queue()
         if event.event_data['allow_request_update_loco']:
             # Calls to nfsession
             common.make_http_call('update_loco_context',
                                   {'context_name': 'continueWatching'})
             common.make_http_call('update_videoid_bookmark',
                                   {'video_id': event.get_video_id()})
     return True
예제 #3
0
 def perform_key_handshake(self):
     """Perform a key handshake and initialize crypto keys"""
     esn = get_esn()
     if not esn:
         LOG.error('Cannot perform key handshake, missing ESN')
         return False
     LOG.info('Performing key handshake with ESN: {}',
              common.censure(esn) if len(esn) > 50 else esn)
     try:
         header, _ = _process_json_response(
             self._post(ENDPOINTS['manifest'], self.handshake_request(esn)))
         header_data = self.decrypt_header_data(header['headerdata'], False)
         self.crypto.parse_key_response(header_data, esn, True)
     except MSLError as exc:
         if exc.err_number == 207006 and common.get_system_platform(
         ) == 'android':
             msg = (
                 'Request failed validation during key exchange\r\n'
                 'To try to solve this problem read the Wiki FAQ on add-on GitHub.'
             )
             raise MSLError(msg) from exc
         raise
     # Delete all the user id tokens (are correlated to the previous mastertoken)
     self.crypto.clear_user_id_tokens()
     LOG.debug('Key handshake successful')
     return True
예제 #4
0
 def _mastertoken_checks(self):
     """Perform checks to the MasterToken and executes a new key handshake when necessary"""
     is_handshake_required = False
     if self.crypto.mastertoken:
         if self.crypto.is_current_mastertoken_expired():
             LOG.debug(
                 'Stored MSL MasterToken is expired, a new key handshake will be performed'
             )
             is_handshake_required = True
         else:
             # Check if the current ESN is same of ESN bound to MasterToken
             if get_esn() != self.crypto.bound_esn:
                 LOG.debug(
                     'Stored MSL MasterToken is bound to a different ESN, '
                     'a new key handshake will be performed')
                 is_handshake_required = True
     else:
         LOG.debug(
             'MSL MasterToken is not available, a new key handshake will be performed'
         )
         is_handshake_required = True
     if is_handshake_required:
         if self.perform_key_handshake():
             msl_data = json.loads(common.load_file_def(MSL_DATA_FILENAME))
             self.crypto.load_msl_data(msl_data)
             self.crypto.load_crypto_session(msl_data)
 def _ensure_forced_subtitle_only_kodi18(self):
     """Ensures the display of forced subtitles only with the audio language set [KODI 18]"""
     # With Kodi 18 it is not possible to read the properties of the player streams,
     # so the only possible way is to read the data from the manifest file
     from resources.lib.common.cache_utils import CACHE_MANIFESTS
     from resources.lib.utils.esn import get_esn
     # Get the manifest
     cache_identifier = get_esn() + '_' + self.videoid.value
     manifest = G.CACHE.get(CACHE_MANIFESTS, cache_identifier)
     common.fix_locale_languages(manifest['timedtexttracks'])
     # Get the language
     audio_language = common.get_kodi_audio_language()
     if audio_language == 'mediadefault':
         # Netflix do not have a "Media default" track then we rely on the language of current nf profile,
         # although due to current Kodi locale problems could be not always accurate.
         profile_language_code = G.LOCAL_DB.get_profile_config('language')
         audio_language = profile_language_code[0:2]
     if audio_language == 'original':
         # Find the language of the original audio track
         stream = next((audio_track
                        for audio_track in manifest['audio_tracks']
                        if audio_track['isNative']), None)
         if not stream:
             return
         audio_language = stream['language']
     # Check in the manifest if there is a forced subtitle in the specified language
     if not any(
             text_track.get('isForcedNarrative', False)
             and text_track['language'] == audio_language
             for text_track in manifest['timedtexttracks']):
         self.sc_settings.update({'subtitleenabled': False})
예제 #6
0
 def bind_events(self):
     """Bind events"""
     # I don't know the real purpose of its use, it seems to be requested after the license and before starting
     # playback, and only the first time after a switch,
     # in the response you can also understand if the msl switch has worked
     LOG.debug('Requesting bind events')
     response = self.msl_requests.chunked_request(
         ENDPOINTS['manifest'],
         self.msl_requests.build_request_data('/bind', {}),
         get_esn(),
         disable_msl_switch=False)
     LOG.debug('Bind events response: {}', response)
예제 #7
0
 def __init__(self, *args, **kwargs):  # pylint: disable=unused-argument
     self.changes_applied = False
     self.esn = get_esn()
     self.esn_new = None
     self.wv_force_sec_lev = G.LOCAL_DB.get_value(
         'widevine_force_seclev',
         WidevineForceSecLev.DISABLED,
         table=TABLE_SESSION)
     self.wv_sec_lev_new = None
     self.is_android = common.get_system_platform() == 'android'
     self.action_exit_keys_id = [
         ACTION_PREVIOUS_MENU, ACTION_PLAYER_STOP, ACTION_NAV_BACK
     ]
     super().__init__(*args)
예제 #8
0
 def _get_owner_user_id_token(self):
     """A way to get the user token id of owner profile"""
     # In order to get a user id token of another (non-owner) profile you must make a request with SWITCH_PROFILE
     # authentication scheme (a custom authentication for netflix), and this request can be directly included
     # in the MSL manifest request.
     # But in order to execute this switch profile, you need to have the user id token of the main (owner) profile.
     # The only way (found to now) to get it immediately, is send a logblob event request, and save the
     # user id token obtained in the response.
     LOG.debug('Requesting logblog')
     endpoint_url = ENDPOINTS['logblobs'] + create_req_params(0, 'bind')
     response = self.chunked_request(endpoint_url,
                                     self.build_request_data('/logblob', generate_logblobs_params()),
                                     get_esn(),
                                     force_auth_credential=True)
     LOG.debug('Response of logblob request: {}', response)
 def _show_only_forced_subtitle(self):
     # Forced stream not found, then fix Kodi bug if user chose to apply the workaround
     # Kodi bug???:
     # If the kodi player is set with "forced only" subtitle setting, Kodi use this behavior:
     # 1) try to select forced subtitle that matches audio language
     # 2) if missing the forced subtitle in language, then
     #    Kodi try to select: The first "forced" subtitle or the first "regular" subtitle
     #    that can respect the chosen language or not, depends on the available streams
     # So can cause a wrong subtitle language or in a permanent display of subtitles!
     # This does not reflect the setting chosen in the Kodi player and is very annoying!
     # There is no other solution than to disable the subtitles manually.
     if self.legacy_kodi_version:
         # --- ONLY FOR KODI VERSION 18 ---
         # NOTE: With Kodi 18 it is not possible to read the properties of the streams
         # so the only possible way is to read the data from the manifest file
         audio_language = common.get_kodi_audio_language()
         cache_identifier = get_esn() + '_' + self.videoid.value
         manifest_data = G.CACHE.get(CACHE_MANIFESTS, cache_identifier)
         common.fix_locale_languages(manifest_data['timedtexttracks'])
         if not any(
                 text_track.get('isForcedNarrative', False) is True
                 and text_track['language'] == audio_language
                 for text_track in manifest_data['timedtexttracks']):
             self.sc_settings.update({'subtitleenabled': False})
     else:
         # --- ONLY FOR KODI VERSION 19 ---
         audio_language = common.get_kodi_audio_language(
             iso_format=xbmc.ISO_639_2, use_fallback=False)
         if audio_language == 'mediadefault':
             # Find the language of the default audio track
             audio_list = self.player_state.get(STREAMS['audio']['list'])
             for audio_track in audio_list:
                 if audio_track['isdefault']:
                     audio_language = audio_track['language']
                     break
         player_stream = self.player_state.get(
             STREAMS['subtitle']['current'])
         if player_stream is None:
             return
         if audio_language == 'original':
             # Do nothing
             is_language_appropriate = True
         else:
             is_language_appropriate = player_stream[
                 'language'] == audio_language
         # Check if the current stream is forced and with an appropriate subtitle language
         if not player_stream['isforced'] or not is_language_appropriate:
             self.sc_settings.update({'subtitleenabled': False})
예제 #10
0
    def get_license(self, license_data):
        """
        Requests and returns a license for the given challenge and sid

        :param license_data: The license data provided by isa
        :return: Base64 representation of the license key or False unsuccessful
        """
        LOG.debug('Requesting license')
        challenge, sid = license_data.decode('utf-8').split('!')
        sid = base64.standard_b64decode(sid).decode('utf-8')
        timestamp = int(time.time() * 10000)
        xid = str(timestamp + 1610)
        params = [{
            'drmSessionId': sid,
            'clientTime': int(timestamp / 10000),
            'challengeBase64': challenge,
            'xid': xid
        }]
        self.manifest_challenge = challenge
        endpoint_url = ENDPOINTS['license'] + create_req_params(
            0, 'prefetch/license')
        try:
            response = self.msl_requests.chunked_request(
                endpoint_url,
                self.msl_requests.build_request_data(self.last_license_url,
                                                     params, 'drmSessionId'),
                get_esn())
        except MSLError as exc:
            if exc.err_number == '1044' and common.get_system_platform(
            ) == 'android':
                msg = (
                    'This title is not available to watch instantly. Please try another title.\r\n'
                    'To try to solve this problem you can force "Widevine L3" from the add-on Expert settings.\r\n'
                    'More info in the Wiki FAQ on add-on GitHub.')
                raise MSLError(msg) from exc
            raise
        # This xid must be used also for each future Event request, until playback stops
        G.LOCAL_DB.set_value('xid', xid, TABLE_SESSION)

        self.licenses_xid.insert(0, xid)
        self.licenses_session_id.insert(0, sid)
        self.licenses_release_url.insert(
            0, response[0]['links']['releaseLicense']['href'])

        if self.msl_requests.msl_switch_requested:
            self.msl_requests.msl_switch_requested = False
            self.bind_events()
        return base64.standard_b64decode(response[0]['licenseResponseBase64'])
예제 #11
0
    def perform_key_handshake(self, data=None):  # pylint: disable=unused-argument
        """Perform a key handshake and initialize crypto keys"""
        esn = get_esn()
        if not esn:
            LOG.warn('Cannot perform key handshake, missing ESN')
            return False

        LOG.info('Performing key handshake with ESN: {}',
                 common.censure(esn) if G.ADDON.getSetting('esn') else esn)
        response = _process_json_response(
            self._post(ENDPOINTS['manifest'], self.handshake_request(esn)))
        header_data = self.decrypt_header_data(response['headerdata'], False)
        self.crypto.parse_key_response(header_data, esn, True)

        # Delete all the user id tokens (are correlated to the previous mastertoken)
        self.crypto.clear_user_id_tokens()
        LOG.debug('Key handshake successful')
        return True
예제 #12
0
    def load_manifest(self, viewable_id):
        """
        Loads the manifests for the given viewable_id and returns a mpd-XML-Manifest

        :param viewable_id: The id of of the viewable
        :return: MPD XML Manifest or False if no success
        """
        try:
            manifest = self._load_manifest(viewable_id, get_esn())
        except MSLError as exc:
            if 'Email or password is incorrect' in G.py2_decode(str(exc)):
                # Known cases when MSL error "Email or password is incorrect." can happen:
                # - If user change the password when the nf session was still active
                # - Netflix has reset the password for suspicious activity when the nf session was still active
                # Then clear the credentials and also user tokens.
                common.purge_credentials()
                self.msl_requests.crypto.clear_user_id_tokens()
            raise
        return self.__tranform_to_dash(manifest)
예제 #13
0
 def _process_event_request(self, event_type, event_data, player_state):
     """Build and make the event post request"""
     if event_type == EVENT_START:
         # We get at every new video playback a fresh LoCo data
         self.loco_data = self.nfsession.get_loco_data()
     url = event_data['manifest']['links']['events']['href']
     from resources.lib.services.nfsession.msl.msl_request_builder import MSLRequestBuilder
     request_data = MSLRequestBuilder.build_request_data(
         url,
         self._build_event_params(event_type, event_data, player_state,
                                  event_data['manifest'], self.loco_data))
     # Request attempts can be made up to a maximum of 3 times per event
     LOG.info('EVENT [{}] - Executing request', event_type)
     endpoint_url = ENDPOINTS['events'] + create_req_params(
         20 if event_type == EVENT_START else 0, f'events/{event_type}')
     try:
         response = self.chunked_request(endpoint_url,
                                         request_data,
                                         get_esn(),
                                         disable_msl_switch=False)
         # Malformed/wrong content in requests are ignored without returning any error in the response or exception
         LOG.debug('EVENT [{}] - Request response: {}', event_type,
                   response)
         if event_type == EVENT_STOP:
             if event_data['allow_request_update_loco']:
                 if 'list_context_name' in self.loco_data:
                     self.nfsession.update_loco_context(
                         self.loco_data['root_id'],
                         self.loco_data['list_context_name'],
                         self.loco_data['list_id'],
                         self.loco_data['list_index'])
                 else:
                     LOG.warn(
                         'EventsHandler: LoCo list not updated due to missing list context data'
                     )
                 video_id = request_data['params']['sessionParams'][
                     'uiplaycontext']['video_id']
                 self.nfsession.update_videoid_bookmark(video_id)
             self.loco_data = None
     except Exception as exc:  # pylint: disable=broad-except
         LOG.error('EVENT [{}] - The request has failed: {}', event_type,
                   exc)
예제 #14
0
 def _process_event_request(self, event):
     """Do the event post request"""
     event.status = Event.STATUS_REQUESTED
     # Request attempts can be made up to a maximum of 3 times per event
     while event.is_attempts_granted():
         LOG.info('EVENT [{}] - Executing request (attempt {})', event,
                  event.req_attempt)
         params = {
             'reqAttempt': event.req_attempt,
             'reqPriority': 20 if event.event_type == EVENT_START else 0,
             'reqName': 'events/{}'.format(event)
         }
         url = ENDPOINTS['events'] + '?' + urlencode(params).replace(
             '%2F', '/')
         try:
             response = self.chunked_request(url,
                                             event.request_data,
                                             get_esn(),
                                             disable_msl_switch=False)
             event.set_response(response)
             break
         except Exception as exc:  # pylint: disable=broad-except
             LOG.error('EVENT [{}] - The request has failed: {}', event,
                       exc)
     if event.event_type == EVENT_STOP:
         self.clear_queue()
         if event.event_data['allow_request_update_loco']:
             # Calls to nfsession
             common.make_http_call('update_loco_context',
                                   {'context_name': 'continueWatching'})
             common.make_http_call('update_videoid_bookmark',
                                   {'video_id': event.get_video_id()})
     # Below commented lines: let future requests continue to be sent, unstable connections like wi-fi cause problems
     # if not event.is_response_success():
     # The event request is unsuccessful then there is some problem,
     # no longer make any future requests from this event id
     #     return False
     return True
예제 #15
0
    def get_manifest(self, viewable_id):
        """
        Get the manifests for the given viewable_id and returns a mpd-XML-Manifest

        :param viewable_id: The id of of the viewable
        :return: MPD XML Manifest or False if no success
        """
        try:
            esn = get_esn()
            # When the add-on is installed from scratch or you logout the account the ESN will be empty
            if not esn:
                esn = set_esn()
            manifest = self._get_manifest(viewable_id, esn)
        except MSLError as exc:
            if 'Email or password is incorrect' in str(exc):
                # Known cases when MSL error "Email or password is incorrect." can happen:
                # - If user change the password when the nf session was still active
                # - Netflix has reset the password for suspicious activity when the nf session was still active
                # Then clear the credentials and also user tokens.
                common.purge_credentials()
                self.msl_requests.crypto.clear_user_id_tokens()
            raise
        return self.__tranform_to_dash(manifest)
예제 #16
0
    def get_license(self, challenge, sid):
        """
        Requests and returns a license for the given challenge and sid

        :param challenge: The base64 encoded challenge
        :param sid: The sid paired to the challenge
        :return: Base64 representation of the license key or False unsuccessful
        """
        LOG.debug('Requesting license')

        timestamp = int(time.time() * 10000)
        xid = str(timestamp + 1610)
        params = [{
            'drmSessionId': sid,
            'clientTime': int(timestamp / 10000),
            'challengeBase64': challenge,
            'xid': xid
        }]
        self.manifest_challenge = challenge
        endpoint_url = ENDPOINTS[
            'license'] + '?reqAttempt=1&reqPriority=0&reqName=prefetch/license'
        response = self.msl_requests.chunked_request(
            endpoint_url,
            self.msl_requests.build_request_data(self.last_license_url, params,
                                                 'drmSessionId'), get_esn())
        # This xid must be used also for each future Event request, until playback stops
        G.LOCAL_DB.set_value('xid', xid, TABLE_SESSION)

        self.licenses_xid.insert(0, xid)
        self.licenses_session_id.insert(0, sid)
        self.licenses_release_url.insert(
            0, response[0]['links']['releaseLicense']['href'])

        if self.msl_requests.msl_switch_requested:
            self.msl_requests.msl_switch_requested = False
            self.bind_events()
        return response[0]['licenseResponseBase64']
예제 #17
0
def _save_system_info():
    # Ask to save to a file
    filename = 'NFSystemInfo.txt'
    path = ui.show_browse_dialog(
        f'{common.get_local_string(30603)} - {filename}')
    if not path:
        return
    # This collect the main data to allow verification checks for problems
    data = f'Netflix add-on version: {G.VERSION}'
    data += f'\nDebug enabled: {LOG.is_enabled}'
    data += f'\nSystem platform: {common.get_system_platform()}'
    data += f'\nMachine architecture: {common.get_machine()}'
    data += f'\nUser agent string: {common.get_user_agent()}'
    data += '\n\n#### Widevine info ####\n'
    if common.get_system_platform() == 'android':
        data += f'\nSystem ID: {G.LOCAL_DB.get_value("drm_system_id", "--not obtained--", TABLE_SESSION)}'
        data += f'\nSecurity level: {G.LOCAL_DB.get_value("drm_security_level", "--not obtained--", TABLE_SESSION)}'
        data += f'\nHDCP level: {G.LOCAL_DB.get_value("drm_hdcp_level", "--not obtained--", TABLE_SESSION)}'
        wv_force_sec_lev = G.LOCAL_DB.get_value('widevine_force_seclev',
                                                WidevineForceSecLev.DISABLED,
                                                TABLE_SESSION)
        data += f'\nForced security level setting is: {wv_force_sec_lev}'
    else:
        try:
            from ctypes import (CDLL, c_char_p)
            cdm_lib_file_path = _get_cdm_file_path()
            try:
                lib = CDLL(cdm_lib_file_path)
                data += '\nLibrary status: Correctly loaded'
                try:
                    lib.GetCdmVersion.restype = c_char_p
                    data += f'\nVersion: {lib.GetCdmVersion().decode("utf-8")}'
                except Exception:  # pylint: disable=broad-except
                    # This can happen if the endpoint 'GetCdmVersion' is changed
                    data += '\nVersion: Reading error'
            except Exception as exc:  # pylint: disable=broad-except
                # This should not happen but currently InputStream Helper does not perform any verification checks on
                # downloaded and installed files, so if due to an problem it installs a CDM for a different architecture
                # or the files are corrupted, the user can no longer play videos and does not know what to do
                data += '\nLibrary status: Error loading failed'
                data += '\n>>> It is possible that is installed a CDM of a wrong architecture or is corrupted'
                data += '\n>>> Suggested solutions:'
                data += '\n>>> - Restore a previous version of Widevine library from InputStream Helper add-on settings'
                data += '\n>>> - Report the problem to the GitHub of InputStream Helper add-on'
                data += f'\n>>> Error details: {exc}'
        except Exception as exc:  # pylint: disable=broad-except
            data += f'\nThe data could not be obtained. Error details: {exc}'
    data += '\n\n#### ESN ####\n'
    esn = get_esn() or '--not obtained--'
    data += f'\nUsed ESN: {common.censure(esn) if len(esn) > 50 else esn}'
    data += f'\nWebsite ESN: {get_website_esn() or "--not obtained--"}'
    data += f'\nAndroid generated ESN: {(generate_android_esn() or "--not obtained--")}'
    if common.get_system_platform() == 'android':
        data += '\n\n#### Device system info ####\n'
        try:
            import subprocess
            info = subprocess.check_output(['/system/bin/getprop'
                                            ]).decode('utf-8')
            data += f'\n{info}'
        except Exception as exc:  # pylint: disable=broad-except
            data += f'\nThe data could not be obtained. Error: {exc}'
    data += '\n'
    try:
        common.save_file(common.join_folders_paths(path, filename),
                         data.encode('utf-8'))
        ui.show_notification(
            f'{xbmc.getLocalizedString(35259)}: {filename}')  # 35259=Saved
    except Exception as exc:  # pylint: disable=broad-except
        LOG.error('save_file error: {}', exc)
        ui.show_notification('Error! Try another path')
예제 #18
0
 def load_msl_data(self, msl_data=None):
     self._msl_data = msl_data if msl_data else {}
     if msl_data:
         self.set_mastertoken(msl_data['tokens']['mastertoken'])
         self.bound_esn = msl_data.get('bound_esn', get_esn())
예제 #19
0
def generate_logblobs_params():
    """Generate the initial log blog"""
    # It seems that this log is sent when logging in to a profile the first time
    # i think it is the easiest to reproduce, the others contain too much data
    screen_size = f'{xbmcgui.getScreenWidth()}x{xbmcgui.getScreenHeight()}'
    timestamp_utc = time.time()
    timestamp = int(timestamp_utc * 1000)
    app_id = int(time.time()) * 10000 + random.SystemRandom().randint(
        1, 10001)  # Should be used with all log requests

    # Here you have to enter only the real data, falsifying the data would cause repercussions in netflix server logs
    # therefore since it is possible to exclude data, we avoid entering data that we do not have
    blob = {
        'browserua':
        common.get_user_agent().replace(' ', '#'),
        'browserhref':
        'https://www.netflix.com/browse',
        # 'initstart': 988,
        # 'initdelay': 268,
        'screensize':
        screen_size,  # '1920x1080',
        'screenavailsize':
        screen_size,  # '1920x1040',
        'clientsize':
        screen_size,  # '1920x944',
        # 'pt_navigationStart': -1880,
        # 'pt_fetchStart': -1874,
        # 'pt_secureConnectionStart': -1880,
        # 'pt_requestStart': -1853,
        # 'pt_domLoading': -638,
        # 'm_asl_start': 990,
        # 'm_stf_creat': 993,
        # 'm_idb_open': 993,
        # 'm_idb_succ': 1021,
        # 'm_msl_load_no_data': 1059,
        # 'm_asl_comp': 1256,
        'type':
        'startup',
        'sev':
        'info',
        'devmod':
        'chrome-cadmium',
        'clver':
        G.LOCAL_DB.get_value('client_version', '',
                             table=TABLE_SESSION),  # e.g. '6.0021.220.051'
        'osplatform':
        G.LOCAL_DB.get_value('browser_info_os_name', '', table=TABLE_SESSION),
        'osver':
        G.LOCAL_DB.get_value('browser_info_os_version',
                             '',
                             table=TABLE_SESSION),
        'browsername':
        'Chrome',
        'browserver':
        G.LOCAL_DB.get_value('browser_info_version', '', table=TABLE_SESSION),
        'appLogSeqNum':
        0,
        'uniqueLogId':
        common.get_random_uuid(),
        'appId':
        app_id,
        'esn':
        get_esn(),
        'lver':
        '',
        # 'jssid': '15822792997793',  # Same value of appId
        # 'jsoffms': 1261,
        'clienttime':
        timestamp,
        'client_utc':
        int(timestamp_utc),
        'uiver':
        G.LOCAL_DB.get_value('ui_version', '', table=TABLE_SESSION)
    }

    blobs_container = {'entries': [blob]}
    blobs_dump = json.dumps(blobs_container)
    blobs_dump = blobs_dump.replace('"', '\"').replace(' ',
                                                       '').replace('#', ' ')
    return {'logblobs': blobs_dump}
예제 #20
0
def get_manifest(videoid):
    """Get the manifest from cache"""
    cache_identifier = get_esn() + '_' + videoid.value
    return G.CACHE.get(CACHE_MANIFESTS, cache_identifier)
예제 #21
0
 def view_esn(self, pathitems=None):  # pylint: disable=unused-argument
     """Show the ESN in use"""
     ui.show_ok_dialog(common.get_local_string(30016), get_esn())
예제 #22
0
 def _verify_esn_existence():
     return bool(get_esn())