Ejemplo n.º 1
0
    def add(self,
            bucket,
            identifier,
            data,
            ttl=None,
            expires=None,
            delayed_db_op=False):
        """
        Add or update an item to a cache bucket

        :param bucket: bucket where save the data
        :param identifier: key identifier of the data
        :param data: the content
        :param ttl: override default expiration (in seconds)
        :param expires: override default expiration (in timestamp) if specified override also the 'ttl' value
        :param delayed_db_op: if True, queues the adding operation for the db, then is mandatory to call
                      'execute_pending_db_add' at end of all operations to apply the changes to the db
                      (only for persistent buckets)
        """
        call_args = {
            'bucket': bucket,
            'identifier': identifier,
            'data': data,
            'ttl': ttl,
            'expires': expires,
            'delayed_db_op': delayed_db_op
        }
        # make_call('add', call_args, IPC_ENDPOINT_CACHE)
        make_http_call(IPC_ENDPOINT_CACHE, 'add', call_args)
Ejemplo n.º 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
Ejemplo n.º 3
0
    def clear(self, buckets=None, clear_database=True):
        """
        Clear the cache

        :param buckets: list of buckets to clear, if not specified clear all the cache
        :param clear_database: if True clear also the database data
        """
        call_args = {'buckets': buckets, 'clear_database': clear_database}
        # make_call('clear', call_args, IPC_ENDPOINT_CACHE)
        make_http_call(IPC_ENDPOINT_CACHE, 'clear', call_args)
Ejemplo n.º 4
0
    def delete(self, bucket, identifier, including_suffixes=False):
        """
        Delete an item from cache bucket

        :param including_suffixes: if true will delete all items with the identifier that start with it
        """
        call_args = {
            'bucket': bucket,
            'identifier': identifier,
            'including_suffixes': including_suffixes
        }
        # make_call('delete', call_args, IPC_ENDPOINT_CACHE)
        make_http_call(IPC_ENDPOINT_CACHE, 'delete', call_args)
Ejemplo n.º 5
0
 def remove_watched_status(self, videoid):
     """Remove the watched status from the Netflix service"""
     if not ui.ask_for_confirmation(
             common.get_local_string(30168),
             common.get_local_string(30300).format(
                 xbmc.getInfoLabel('ListItem.Label'))):
         return
     if not api.remove_watched_status(videoid):
         ui.show_notification(
             'The operation was cancelled due to an unexpected error')
         return
     # Check if item is in the cache
     videoid_exists, list_id = common.make_http_call(
         'get_continuewatching_videoid_exists',
         {'video_id': str(videoid.value)})
     if videoid_exists:
         # Try to remove the videoid from the list in the cache
         try:
             video_list_sorted_data = G.CACHE.get(cache_utils.CACHE_COMMON,
                                                  list_id)
             del video_list_sorted_data.videos[videoid.value]
             G.CACHE.add(cache_utils.CACHE_COMMON, list_id,
                         video_list_sorted_data)
             common.json_rpc(
                 'Input.Down')  # Avoids selection back to the top
         except CacheMiss:
             pass
     common.container_refresh()
Ejemplo n.º 6
0
def update_lolomo_context(context_name):
    """Update the lolomo list by context"""
    # 01/06/2020: refreshListByContext often return HTTP error 500, currently i have seen that in the website is
    #   performed only when the video played is not added to "my list", but with a strange mixed data:
    #     context_id: the id of continueWatching
    #     context_index: that seem to point to "My list" id context index
    #   This api is no more needed to update the continueWatching lolomo list
    lolomo_root = g.LOCAL_DB.get_value('lolomo_root_id', '', TABLE_SESSION)

    context_index = g.LOCAL_DB.get_value(
        'lolomo_{}_index'.format(context_name.lower()), '', TABLE_SESSION)
    context_id = g.LOCAL_DB.get_value(
        'lolomo_{}_id'.format(context_name.lower()), '', TABLE_SESSION)

    if not context_index:
        common.warn(
            'Update lolomo context {} skipped due to missing lolomo index',
            context_name)
        return
    path = [['lolomos', lolomo_root, 'refreshListByContext']]
    # The fourth parameter is like a request-id, but it doesn't seem to match to
    # serverDefs/date/requestId of reactContext (g.LOCAL_DB.get_value('request_id', table=TABLE_SESSION))
    # nor to request_id of the video event request
    # has a kind of relationship with renoMessageId suspect with the logblob but i'm not sure because my debug crashed,
    # and i am no longer able to trace the source.
    # I noticed also that this request can also be made with the fourth parameter empty,
    # but it still doesn't update the continueWatching list of lolomo, that is strange because of no error
    params = [
        common.enclose_quotes(context_id), context_index,
        common.enclose_quotes(context_name), ''
    ]
    # path_suffixs = [
    #    [['trackIds', 'context', 'length', 'genreId', 'videoId', 'displayName', 'isTallRow', 'isShowAsARow',
    #      'impressionToken', 'showAsARow', 'id', 'requestId']],
    #    [{'from': 0, 'to': 100}, 'reference', 'summary'],
    #    [{'from': 0, 'to': 100}, 'reference', 'title'],
    #    [{'from': 0, 'to': 100}, 'reference', 'titleMaturity'],
    #    [{'from': 0, 'to': 100}, 'reference', 'userRating'],
    #    [{'from': 0, 'to': 100}, 'reference', 'userRatingRequestId'],
    #    [{'from': 0, 'to': 100}, 'reference', 'boxarts', '_342x192', 'jpg'],
    #    [{'from': 0, 'to': 100}, 'reference', 'promoVideo']
    # ]
    callargs = {
        'callpaths': path,
        'params': params,
        # 'path_suffixs': path_suffixs
    }
    try:
        response = common.make_http_call('callpath_request', callargs)
        common.debug('refreshListByContext response: {}', response)
        # The call response return the new context id of the previous invalidated lolomo context_id
        # and if path_suffixs is added return also the new video list data
    except Exception:  # pylint: disable=broad-except
        if not common.is_debug_verbose():
            return
        ui.show_notification(
            title=common.get_local_string(30105),
            msg='An error prevented the update the lolomo context on netflix',
            time=10000)
Ejemplo n.º 7
0
def update_lolomo_context(context_name, video_id=None):
    """Update the lolomo list by context"""
    # Should update the context list but it doesn't, what is missing?
    # The remaining requests made on the website that are missing here are of logging type,
    # it seems strange that they use log data to finish the operations are almost impossible to reproduce here:
    # pbo_logblobs /logblob
    # personalization/cl2

    lolomo_data = common.make_call('path_request', [["lolomo", [context_name], ['context', 'id', 'index']]])
    # Note: lolomo root seem differs according to the profile in use
    lolomo_root = lolomo_data['lolomo'][1]
    context_index = lolomo_data['lolomos'][lolomo_root][context_name][2]
    context_id = lolomo_data['lolomos'][lolomo_root][context_index][1]

    path = [['lolomos', lolomo_root, 'refreshListByContext']]
    params = [common.enclose_quotes(context_id),
              context_index,
              common.enclose_quotes(context_name),
              common.enclose_quotes(g.LOCAL_DB.get_value('request_id', table=TABLE_SESSION))]
    # path_suffixs = [
    #    [['trackIds', 'context', 'length', 'genreId', 'videoId', 'displayName', 'isTallRow', 'isShowAsARow',
    #      'impressionToken', 'showAsARow', 'id', 'requestId']],
    #    [{'from': 0, 'to': 100}, 'reference', 'summary'],
    #    [{'from': 0, 'to': 100}, 'reference', 'title'],
    #    [{'from': 0, 'to': 100}, 'reference', 'titleMaturity'],
    #    [{'from': 0, 'to': 100}, 'reference', 'userRating'],
    #    [{'from': 0, 'to': 100}, 'reference', 'userRatingRequestId'],
    #    [{'from': 0, 'to': 100}, 'reference', 'boxarts', '_342x192', 'jpg'],
    #    [{'from': 0, 'to': 100}, 'reference', 'promoVideo']
    # ]
    callargs = {
        'callpaths': path,
        'params': params,
        # 'path_suffixs': path_suffixs
    }
    response = common.make_http_call('callpath_request', callargs)
    common.debug('refreshListByContext response: {}', response)

    callargs = {
        'callpaths': [['refreshVideoCurrentPositions']],
        'params': ['[' + video_id + ']', ''],
    }
    response = common.make_http_call('callpath_request', callargs)
    common.debug('refreshVideoCurrentPositions response: {}', response)
Ejemplo n.º 8
0
 def get(self, bucket, identifier):
     """Get a item from cache bucket"""
     call_args = {
         'bucket': bucket,
         'identifier': identifier,
         'deserialize_data': False
     }
     # Todo: currently AddonSignals does not support serialization of objects
     # return make_call('get', call_args, IPC_ENDPOINT_CACHE)
     return make_http_call(IPC_ENDPOINT_CACHE, 'get', call_args)
 def on_playback_started(self, player_state):
     # Clear continue watching list data on the cache, to force loading of new data
     # but only when the videoid not exists in the continue watching list
     videoid_exists, list_id = common.make_http_call('get_continuewatching_videoid_exists',
                                                     {'video_id': str(self.videoid_parent.value)})
     if not videoid_exists:
         # Delete the cache of continueWatching list
         G.CACHE.delete(CACHE_COMMON, list_id, including_suffixes=True)
         # When the continueWatching context is invalidated from a refreshListByContext call
         # the LoCo need to be updated to obtain the new list id, so we delete the cache to get new data
         G.CACHE.delete(CACHE_COMMON, 'loco_list')
Ejemplo n.º 10
0
def update_lolomo_context(context_name):
    """Update the lolomo list by context"""
    lolomo_root = g.LOCAL_DB.get_value('lolomo_root_id', '', TABLE_SESSION)

    context_index = g.LOCAL_DB.get_value(
        'lolomo_{}_index'.format(context_name.lower()), '', TABLE_SESSION)
    context_id = g.LOCAL_DB.get_value(
        'lolomo_{}_id'.format(context_name.lower()), '', TABLE_SESSION)

    if not context_index:
        return
    path = [['lolomos', lolomo_root, 'refreshListByContext']]
    # The fourth parameter is like a request-id, but it doesn't seem to match to
    # serverDefs/date/requestId of reactContext (g.LOCAL_DB.get_value('request_id', table=TABLE_SESSION))
    # nor to request_id of the video event request
    # has a kind of relationship with renoMessageId suspect with the logblob but i'm not sure because my debug crashed,
    # and i am no longer able to trace the source.
    # I noticed also that this request can also be made with the fourth parameter empty,
    # but it still doesn't update the continueWatching list of lolomo, that is strange because of no error
    params = [
        common.enclose_quotes(context_id), context_index,
        common.enclose_quotes(context_name), ''
    ]
    # path_suffixs = [
    #    [['trackIds', 'context', 'length', 'genreId', 'videoId', 'displayName', 'isTallRow', 'isShowAsARow',
    #      'impressionToken', 'showAsARow', 'id', 'requestId']],
    #    [{'from': 0, 'to': 100}, 'reference', 'summary'],
    #    [{'from': 0, 'to': 100}, 'reference', 'title'],
    #    [{'from': 0, 'to': 100}, 'reference', 'titleMaturity'],
    #    [{'from': 0, 'to': 100}, 'reference', 'userRating'],
    #    [{'from': 0, 'to': 100}, 'reference', 'userRatingRequestId'],
    #    [{'from': 0, 'to': 100}, 'reference', 'boxarts', '_342x192', 'jpg'],
    #    [{'from': 0, 'to': 100}, 'reference', 'promoVideo']
    # ]
    callargs = {
        'callpaths': path,
        'params': params,
        # 'path_suffixs': path_suffixs
    }
    try:
        response = common.make_http_call('callpath_request', callargs)
        common.debug('refreshListByContext response: {}', response)
    except Exception:  # pylint: disable=broad-except
        # I do not know the reason yet, but sometimes continues to return error 401,
        # making it impossible to update the bookmark position
        if not common.is_debug_verbose():
            return
        ui.show_notification(
            title=common.get_local_string(30105),
            msg='An error prevented the update the lolomo context on netflix',
            time=10000)
Ejemplo n.º 11
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():
         common.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,
                                             G.get_esn(),
                                             disable_msl_switch=False)
             event.set_response(response)
             break
         except Exception as exc:  # pylint: disable=broad-except
             common.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
 def on_playback_started(self, player_state):
     # Clear continue watching list data on the cache, to force loading of new data
     # but only when the videoid not exists in the continue watching list
     try:
         videoid_exists, list_id = common.make_http_call('get_continuewatching_videoid_exists',
                                                         {'video_id': str(self.videoid_parent.value)})
         if not videoid_exists:
             # Delete the cache of continueWatching list
             G.CACHE.delete(CACHE_COMMON, list_id, including_suffixes=True)
             # When the continueWatching context is invalidated from a refreshListByContext call
             # the LoCo need to be updated to obtain the new list id, so we delete the cache to get new data
             G.CACHE.delete(CACHE_COMMON, 'loco_list')
     except InvalidVideoListTypeError:
         # Ignore possible "No lists with context xxx available" exception due to a new profile without data
         pass
Ejemplo n.º 13
0
 def on_playback_started(self, player_state):
     # Clear continue watching list data on the cache, to force loading of new data
     # but only when the videoid not exists in the continue watching list
     current_videoid = (self.videoid
                        if self.videoid.mediatype == common.VideoId.MOVIE
                        else self.videoid.derive_parent(0))
     videoid_exists, list_id = common.make_http_call(
         'get_continuewatching_videoid_exists',
         {'video_id': str(current_videoid.value)})
     if not videoid_exists:
         # Delete the cache of continueWatching list
         g.CACHE.delete(CACHE_COMMON, list_id, including_suffixes=True)
         # When the continueWatching context is invalidated from a refreshListByContext call
         # the lolomo need to be updated to obtain the new list id, so we delete the cache to get new data
         g.CACHE.delete(CACHE_COMMON, 'lolomo_list')
Ejemplo n.º 14
0
def update_videoid_bookmark(video_id):
    """Update the videoid bookmark position"""
    # You can check if this function works through the official android app
    # by checking if the status bar watched of the video will be updated
    callargs = {
        'callpaths': [['refreshVideoCurrentPositions']],
        'params': ['[' + video_id + ']', '[]'],
    }
    try:
        response = common.make_http_call('callpath_request', callargs)
        common.debug('refreshVideoCurrentPositions response: {}', response)
    except Exception:  # pylint: disable=broad-except
        ui.show_notification(
            title=common.get_local_string(30105),
            msg='An error prevented the update the status watched on netflix',
            time=10000)
def update_loco_context(context_name):
    """Update a loco list by context"""
    # This api seem no more needed to update the continueWatching loco list
    loco_root = g.LOCAL_DB.get_value('loco_root_id', '', TABLE_SESSION)

    context_index = g.LOCAL_DB.get_value(
        'loco_{}_index'.format(context_name.lower()), '', TABLE_SESSION)
    context_id = g.LOCAL_DB.get_value(
        'loco_{}_id'.format(context_name.lower()), '', TABLE_SESSION)

    if not context_index:
        common.warn('Update loco context {} skipped due to missing loco index',
                    context_name)
        return
    path = [['locos', loco_root, 'refreshListByContext']]
    # After the introduction of LoCo, the following notes are to be reviewed (refers to old LoLoMo):
    #   The fourth parameter is like a request-id, but it doesn't seem to match to
    #   serverDefs/date/requestId of reactContext (g.LOCAL_DB.get_value('request_id', table=TABLE_SESSION))
    #   nor to request_id of the video event request,
    #   has a kind of relationship with renoMessageId suspect with the logblob but i'm not sure because my debug crashed
    #   and i am no longer able to trace the source.
    #   I noticed also that this request can also be made with the fourth parameter empty.
    params = [
        common.enclose_quotes(context_id), context_index,
        common.enclose_quotes(context_name), ''
    ]
    # path_suffixs = [
    #    [{'from': 0, 'to': 100}, 'itemSummary'],
    #    [['componentSummary']]
    # ]
    callargs = {
        'callpaths': path,
        'params': params,
        # 'path_suffixs': path_suffixs
    }
    try:
        response = common.make_http_call('callpath_request', callargs)
        common.debug('refreshListByContext response: {}', response)
        # The call response return the new context id of the previous invalidated loco context_id
        # and if path_suffixs is added return also the new video list data
    except Exception:  # pylint: disable=broad-except
        if not common.is_debug_verbose():
            return
        ui.show_notification(
            title=common.get_local_string(30105),
            msg='An error prevented the update the loco context on netflix',
            time=10000)
def auto_update_library(sync_with_mylist, silent):
    """
    Perform an auto update of the exported items to Kodi library,
    so check if there is new seasons/episodes.
    If sync_with_mylist is enabled the Kodi library will be also synchronized
    with the Netflix "My List".
    :param sync_with_mylist: True to enable sync with My List
    :param silent: don't display user interface while performing an operation
    :return: None
    """
    if _is_auto_update_library_running():
        return
    execute_lib_tasks_method = execute_library_tasks_silently if silent else execute_library_tasks
    common.info(
        'Starting auto update library - check updates for tv shows (sync with My List is {})',
        'ENABLED' if sync_with_mylist else 'DISABLED')
    g.SHARED_DB.set_value('library_auto_update_is_running', True)
    g.SHARED_DB.set_value('library_auto_update_start_time', datetime.now())
    try:
        videoids_to_update = []

        # Get the list of the exported items to Kodi library
        exported_tvshows_videoids_values = g.SHARED_DB.get_tvshows_id_list()
        exported_movies_videoids_values = g.SHARED_DB.get_movies_id_list()

        if sync_with_mylist:
            # Get My List videoids of the chosen profile
            # Use make_http_call instead make_http because call AddonSignals on same instance makes problems
            mylist_video_id_list, mylist_video_id_list_type = common.make_http_call(
                'get_mylist_videoids_profile_switch', None)

            # Check if tv shows have been removed from the My List
            for videoid_value in exported_tvshows_videoids_values:
                if unicode(videoid_value) in mylist_video_id_list:
                    continue
                # The tv show no more exist in My List so remove it from library
                videoid = common.VideoId.from_path(
                    [common.VideoId.SHOW, videoid_value])
                execute_lib_tasks_method(videoid, [remove_item])

            # Check if movies have been removed from the My List
            for videoid_value in exported_movies_videoids_values:
                if unicode(videoid_value) in mylist_video_id_list:
                    continue
                # The movie no more exist in My List so remove it from library
                videoid = common.VideoId.from_path(
                    [common.VideoId.MOVIE, videoid_value])
                execute_lib_tasks_method(videoid, [remove_item])

            # Add missing tv shows / movies of My List to library
            for index, video_id in enumerate(mylist_video_id_list):
                if (int(video_id) not in exported_tvshows_videoids_values and
                        int(video_id) not in exported_movies_videoids_values):
                    videoids_to_update.append(
                        common.VideoId(
                            **{
                                ('movieid' if (mylist_video_id_list_type[index] == 'movie') else 'tvshowid'):
                                video_id
                            }))

        # Add the exported tv shows to be updated to the list..
        tvshows_videoids_to_upd = [
            common.VideoId.from_path([common.VideoId.SHOW, videoid_value])
            for videoid_value in g.SHARED_DB.get_tvshows_id_list(
                VidLibProp['exclude_update'], False)
        ]
        # ..and avoids any duplication caused by possible unexpected errors
        videoids_to_update.extend(
            list(set(tvshows_videoids_to_upd) - set(videoids_to_update)))

        # Add missing tv shows/movies or update existing tv shows
        _update_library(videoids_to_update, exported_tvshows_videoids_values,
                        silent)

        common.debug('Auto update of the library completed')
        g.SHARED_DB.set_value('library_auto_update_is_running', False)
        if not g.ADDON.getSettingBool('lib_auto_upd_disable_notification'):
            ui.show_notification(common.get_local_string(30220), time=5000)
        common.debug(
            'Notify service to communicate to Kodi of update the library')
        common.send_signal(common.Signals.LIBRARY_UPDATE_REQUESTED)
    except Exception:  # pylint: disable=broad-except
        import traceback
        common.error('An error has occurred in the library auto update')
        common.error(traceback.format_exc())
        g.SHARED_DB.set_value('library_auto_update_is_running', False)