示例#1
0
def add_info_list_item(list_item: ListItemW,
                       videoid,
                       item,
                       raw_data,
                       is_in_mylist,
                       common_data,
                       art_item=None):
    """Add infolabels and art to a ListItem"""
    infos, quality_infos = get_info(videoid,
                                    item,
                                    raw_data,
                                    delayed_db_op=True)
    list_item.addStreamInfoFromDict(quality_infos)
    # Use a deepcopy of dict to not reflect future changes to the dictionary also to the cache
    infos_copy = copy.deepcopy(infos)
    if 'Plot' not in infos_copy and 'PlotOutline' in infos_copy:
        # Not all skins support read value from PlotOutline
        infos_copy['Plot'] = infos_copy['PlotOutline']
    _add_supplemental_plot_info(infos_copy, item, common_data)
    if is_in_mylist and common_data.get('mylist_titles_color'):
        # Highlight ListItem title when the videoid is contained in my-list
        list_item.setLabel(
            _colorize_text(common_data['mylist_titles_color'],
                           list_item.getLabel()))
    infos_copy['title'] = list_item.getLabel()
    list_item.setInfo('video', infos_copy)
    list_item.setArt(
        get_art(videoid,
                art_item or item or {},
                common_data['profile_language_code'],
                delayed_db_op=True))
示例#2
0
def _create_video_item(videoid_value, video, video_list, perpetual_range_start,
                       common_data):  # pylint: disable=unused-argument
    videoid = common.VideoId.from_videolist_item(video)
    is_folder = videoid.mediatype == common.VideoId.SHOW
    is_playable = video['availability']['isPlayable']
    is_video_playable = not is_folder and is_playable
    is_in_mylist = videoid in common_data['mylist_items']
    list_item = ListItemW(label=video['title'])
    list_item.setProperties({
        'isPlayable':
        str(is_video_playable).lower(),
        'nf_videoid':
        videoid.to_string(),
        'nf_is_in_mylist':
        str(is_in_mylist),
        'nf_perpetual_range_start':
        str(perpetual_range_start)
    })
    add_info_list_item(list_item, videoid, video, video_list.data,
                       is_in_mylist, common_data)
    if not is_folder:
        set_watched_status(list_item, video, common_data)
    if is_playable:
        # The movie or tvshow (episodes) is playable
        url = common.build_url(
            videoid=videoid,
            mode=G.MODE_DIRECTORY if is_folder else G.MODE_PLAY,
            params=None if is_folder else common_data['params'])
        list_item.addContextMenuItems(
            generate_context_menu_items(
                videoid, is_in_mylist, perpetual_range_start,
                common_data['ctxmenu_remove_watched_status']))
    else:
        # The movie or tvshow (episodes) is not available
        # Try check if there is a availability date
        list_item.setProperty('nf_availability_message',
                              get_availability_message(video))
        # Check if the user has set "Remind Me" feature,
        try:
            #  Due to the add-on cache we can not change in easy way the value stored in database cache,
            #  then we temporary override the value (see 'remind_me' in navigation/actions.py)
            is_in_remind_me = G.CACHE.get(CACHE_BOOKMARKS,
                                          f'is_in_remind_me_{videoid}')
        except CacheMiss:
            #  The website check the "Remind Me" value on key "inRemindMeList" and also "queue"/"inQueue"
            is_in_remind_me = video['inRemindMeList'] or video['queue'][
                'inQueue']
        trackid = video['trackIds']['trackId_jaw']
        list_item.addContextMenuItems(
            generate_context_menu_remind_me(videoid, is_in_remind_me, trackid))
        url = common.build_url(['show_availability_message'],
                               videoid=videoid,
                               mode=G.MODE_ACTION)
    return url, list_item, is_folder and is_playable
def _create_episode_item(seasonid, episodeid_value, episode, episodes_list,
                         common_data):
    is_playable = episode['summary']['isPlayable']
    episodeid = seasonid.derive_episode(episodeid_value)
    list_item = ListItemW(label=episode['title'])
    list_item.setProperties({
        'isPlayable': str(is_playable).lower(),
        'nf_videoid': episodeid.to_string()
    })
    add_info_list_item(list_item, episodeid, episode, episodes_list.data,
                       False, common_data)
    set_watched_status(list_item, episode, common_data)
    if is_playable:
        url = common.build_url(videoid=episodeid,
                               mode=G.MODE_PLAY,
                               params=common_data['params'])
        list_item.addContextMenuItems(
            generate_context_menu_items(episodeid, False, None))
    else:
        # The video is not playable, try check if there is a date
        list_item.setProperty('nf_availability_message',
                              get_availability_message(episode))
        url = common.build_url(['show_availability_message'],
                               mode=G.MODE_ACTION)
    return url, list_item, False
def _create_videolist_item(list_id,
                           video_list,
                           menu_data,
                           common_data,
                           static_lists=False):
    if static_lists and G.is_known_menu_context(video_list['context']):
        pathitems = list(menu_data['path'])  # Make a copy
        pathitems.append(video_list['context'])
    else:
        # It is a dynamic video list / menu context
        if menu_data.get('force_use_videolist_id', False):
            path = 'video_list'
        else:
            path = 'video_list_sorted'
        pathitems = [path, menu_data['path'][1], list_id]
    list_item = ListItemW(label=video_list['displayName'])
    add_info_list_item(list_item,
                       video_list.videoid,
                       video_list,
                       video_list.data,
                       False,
                       common_data,
                       art_item=video_list.artitem)
    # Add possibility to browse the sub-genres (see build_video_listing)
    sub_genre_id = video_list.get('genreId')
    params = {'sub_genre_id': str(sub_genre_id)} if sub_genre_id else None
    return common.build_url(pathitems, params=params,
                            mode=G.MODE_DIRECTORY), list_item, True
示例#5
0
def _create_category_item(list_id, video_list, menu_data, common_data,
                          summary_data):
    pathitems = ['video_list', menu_data['path'][1], list_id]
    list_item = ListItemW(label=summary_data['displayName'])
    add_info_list_item(list_item,
                       video_list.videoid,
                       video_list,
                       video_list.data,
                       False,
                       common_data,
                       art_item=video_list.artitem)
    return common.build_url(pathitems, mode=G.MODE_DIRECTORY), list_item, True
示例#6
0
def _create_season_item(tvshowid, seasonid_value, season, season_list, common_data):
    seasonid = tvshowid.derive_season(seasonid_value)
    list_item = ListItemW(label=season['summary']['name'])
    list_item.setProperty('nf_videoid', seasonid.to_string())
    add_info_list_item(list_item, seasonid, season, season_list.data, False, common_data,
                       art_item=season_list.artitem)
    list_item.addContextMenuItems(generate_context_menu_items(seasonid, False, None))
    return common.build_url(videoid=seasonid, mode=G.MODE_DIRECTORY), list_item, True
def _create_video_item(videoid_value, video, video_list, perpetual_range_start,
                       common_data):  # pylint: disable=unused-argument
    videoid = common.VideoId.from_videolist_item(video)
    is_folder = videoid.mediatype == common.VideoId.SHOW
    is_playable = video['availability']['isPlayable']
    is_video_playable = not is_folder and is_playable
    is_in_mylist = videoid in common_data['mylist_items']
    list_item = ListItemW(label=video['title'])
    list_item.setProperties({
        'isPlayable':
        str(is_video_playable).lower(),
        'nf_videoid':
        videoid.to_string(),
        'nf_is_in_mylist':
        str(is_in_mylist),
        'nf_perpetual_range_start':
        str(perpetual_range_start)
    })
    add_info_list_item(list_item, videoid, video, video_list.data,
                       is_in_mylist, common_data)
    if not is_folder:
        set_watched_status(list_item, video, common_data)
    if is_playable:
        url = common.build_url(
            videoid=videoid,
            mode=G.MODE_DIRECTORY if is_folder else G.MODE_PLAY,
            params=None if is_folder else common_data['params'])
        list_item.addContextMenuItems(
            generate_context_menu_items(
                videoid, is_in_mylist, perpetual_range_start,
                common_data['ctxmenu_remove_watched_status']))
    else:
        # The video is not playable, try check if there is a date
        list_item.setProperty('nf_availability_message',
                              get_availability_message(video))
        url = common.build_url(['show_availability_message'],
                               mode=G.MODE_ACTION)
    return url, list_item, is_folder and is_playable
示例#8
0
def set_watched_status(list_item: ListItemW, video_data, common_data):
    """Check and set progress status (watched and resume)"""
    if not common_data['set_watched_status']:
        return
    video_id = str(video_data['summary']['id'])
    # Check from db if user has manually changed the watched status
    is_watched_user_overrided = G.SHARED_DB.get_watched_status(
        common_data['active_profile_guid'], video_id, None, bool)
    resume_time = 0
    if is_watched_user_overrided is None:
        # Note to shakti properties:
        # 'watched':  unlike the name this value is used to other purposes, so not to set a video as watched
        # 'watchedToEndOffset':  this value is used to determine if a video is watched but
        #                        is available only with the metadata api and only for "episode" video type
        # 'creditsOffset' :  this value is used as position where to show the (play) "Next" (episode) button
        #                    on the website, but it may not be always available with the "movie" video type
        if 'creditsOffset' in video_data:
            # To better ensure that a video is marked as watched also when a user do not reach the ending credits
            # we generally lower the watched threshold by 50 seconds for 50 minutes of video (3000 secs)
            lower_value = video_data['runtime'] / 3000 * 50
            watched_threshold = video_data['creditsOffset'] - lower_value
        else:
            # When missing the value should be only a video of movie type,
            # then we simulate the default Kodi playcount behaviour (playcountminimumpercent)
            watched_threshold = video_data['runtime'] / 100 * 90
        # To avoid asking to the server again the entire list of titles (after watched a video)
        # to get the updated value, we override the value with the value saved in memory (see am_video_events.py)
        try:
            bookmark_position = G.CACHE.get(CACHE_BOOKMARKS, video_id)
        except CacheMiss:
            # NOTE shakti 'bookmarkPosition' tag when it is not set have -1 value
            bookmark_position = video_data['bookmarkPosition']
        playcount = '1' if bookmark_position >= watched_threshold else '0'
        if playcount == '0' and bookmark_position > 0:
            resume_time = bookmark_position
    else:
        playcount = '1' if is_watched_user_overrided else '0'
    # We have to set playcount with setInfo(), because the setProperty('PlayCount', ) have a bug
    # when a item is already watched and you force to set again watched, the override do not work
    list_item.updateInfo({'PlayCount': playcount})
    list_item.setProperty('TotalTime', str(video_data['runtime']))
    list_item.setProperty('ResumeTime', str(resume_time))
示例#9
0
def build_video_listing(video_list, menu_data, sub_genre_id=None, pathitems=None, perpetual_range_start=None,
                        mylist_items=None):
    """Build a video listing"""
    common_data = {
        'params': get_param_watched_status_by_profile(),
        'mylist_items': mylist_items,
        'set_watched_status': G.ADDON.getSettingBool('sync_watched_status'),
        'supplemental_info_color': get_color_name(G.ADDON.getSettingInt('supplemental_info_color')),
        'mylist_titles_color': (get_color_name(G.ADDON.getSettingInt('mylist_titles_color'))
                                if menu_data['path'][1] != 'myList'
                                else None),
        'profile_language_code': G.LOCAL_DB.get_profile_config('language', ''),
        'ctxmenu_remove_watched_status': menu_data['path'][1] == 'continueWatching',
        'active_profile_guid': G.LOCAL_DB.get_active_profile_guid()
    }
    directory_items = [_create_video_item(videoid_value, video, video_list, perpetual_range_start, common_data)
                       for videoid_value, video
                       in video_list.videos.items()]
    # If genre_id exists add possibility to browse LoCo sub-genres
    if sub_genre_id and sub_genre_id != 'None':
        # Create dynamic sub-menu info in MAIN_MENU_ITEMS
        menu_id = 'subgenre_' + sub_genre_id
        sub_menu_data = menu_data.copy()
        sub_menu_data['path'] = [menu_data['path'][0], menu_id, sub_genre_id]
        sub_menu_data['loco_known'] = False
        sub_menu_data['loco_contexts'] = None
        sub_menu_data['content_type'] = menu_data.get('content_type', G.CONTENT_SHOW)
        sub_menu_data.update({'title': common.get_local_string(30089)})
        sub_menu_data['initial_menu_id'] = menu_data.get('initial_menu_id', menu_data['path'][1])
        G.LOCAL_DB.set_value(menu_id, sub_menu_data, TABLE_MENU_DATA)
        # Create the folder for the access to sub-genre
        folder_list_item = ListItemW(label=common.get_local_string(30089))
        folder_list_item.setArt({'icon': 'DefaultVideoPlaylists.png'})
        folder_list_item.setInfo('video', {'plot': common.get_local_string(30088)})  # The description
        directory_items.insert(0, (common.build_url(['genres', menu_id, sub_genre_id], mode=G.MODE_DIRECTORY),
                                   folder_list_item,
                                   True))
    # add_items_previous_next_page use the new value of perpetual_range_selector
    add_items_previous_next_page(directory_items, pathitems, video_list.perpetual_range_selector, sub_genre_id)
    G.CACHE_MANAGEMENT.execute_pending_db_ops()
    return directory_items, {}
def _create_profile_item(profile_guid, is_selected, is_autoselect,
                         is_library_playback, detailed_info):
    profile_name = G.LOCAL_DB.get_profile_config('profileName',
                                                 '???',
                                                 guid=profile_guid)
    profile_attributes = []
    if G.LOCAL_DB.get_profile_config('isPinLocked', False, guid=profile_guid):
        profile_attributes.append('[COLOR red]' +
                                  common.get_local_string(20068) + '[/COLOR]')
    if G.LOCAL_DB.get_profile_config('isAccountOwner',
                                     False,
                                     guid=profile_guid):
        profile_attributes.append(common.get_local_string(30221))
    if G.LOCAL_DB.get_profile_config('isKids', False, guid=profile_guid):
        profile_attributes.append(common.get_local_string(30222))
    if is_autoselect and detailed_info:
        profile_attributes.append(common.get_local_string(30054))
    if is_library_playback and detailed_info:
        profile_attributes.append(common.get_local_string(30051))
    attributes_desc = '[CR]'.join(
        profile_attributes) + '[CR]' if profile_attributes else ''
    description = attributes_desc + '[' + G.LOCAL_DB.get_profile_config(
        'language_desc', '', guid=profile_guid) + ']'

    if detailed_info:
        menu_items = generate_context_menu_profile(profile_guid, is_autoselect,
                                                   is_library_playback)
    else:
        menu_items = []
    list_item = ListItemW(label=profile_name)
    list_item.setProperties({
        'nf_guid':
        profile_guid,
        'nf_description':
        description.replace('[CR]', ' - ')
    })
    list_item.setArt({
        'icon':
        G.LOCAL_DB.get_profile_config('avatar', '', guid=profile_guid)
    })
    list_item.setInfo('video', {'plot': description})
    list_item.select(is_selected)
    list_item.addContextMenuItems(menu_items)
    return (common.build_url(pathitems=['home'],
                             params={'switch_profile_guid': profile_guid},
                             mode=G.MODE_DIRECTORY), list_item, True)
def _create_subgenre_item(video_list_id, subgenre_data, menu_data):
    pathitems = ['video_list_sorted', menu_data['path'][1], video_list_id]
    list_item = ListItemW(label=subgenre_data['name'])
    return common.build_url(pathitems, mode=G.MODE_DIRECTORY), list_item, True
def build_mainmenu_listing(loco_list):
    """Builds the main menu listing (my list, continue watching, etc.)"""
    from resources.lib.kodi.context_menu import generate_context_menu_mainmenu
    directory_items = []
    common_data = {
        'profile_language_code':
        G.LOCAL_DB.get_profile_config('language', ''),
        'supplemental_info_color':
        get_color_name(G.ADDON.getSettingInt('supplemental_info_color'))
    }
    for menu_id, data in G.MAIN_MENU_ITEMS.items():
        if data.get('has_show_setting',
                    True) and not G.ADDON.getSettingBool('_'.join(
                        ('show_menu', menu_id))):
            continue
        if data['loco_known']:
            list_id, video_list = loco_list.find_by_context(
                data['loco_contexts'][0])
            if not list_id:
                continue
            menu_title = video_list['displayName']
            directory_item = _create_videolist_item(list_id,
                                                    video_list,
                                                    data,
                                                    common_data,
                                                    static_lists=True)
            directory_item[1].addContextMenuItems(
                generate_context_menu_mainmenu(menu_id))
            directory_items.append(directory_item)
        else:
            menu_title = common.get_local_string(data['label_id']) if data.get(
                'label_id') else 'Missing menu title'
            menu_description = (common.get_local_string(data['description_id'])
                                if data['description_id'] is not None else '')
            list_item = ListItemW(label=menu_title)
            list_item.setArt({'icon': data['icon']})
            list_item.setInfo('video', {'plot': menu_description})
            list_item.addContextMenuItems(
                generate_context_menu_mainmenu(menu_id))
            directory_items.append(
                (common.build_url(data['path'],
                                  mode=G.MODE_DIRECTORY), list_item, True))
        # Save the menu titles, to reuse it when will be open the content of menus
        G.LOCAL_DB.set_value(menu_id, {'title': menu_title}, TABLE_MENU_DATA)
    # Add "Profiles" menu
    pfl_list_item = ListItemW(label=common.get_local_string(13200))
    pfl_list_item.setArt({'icon': 'DefaultUser.png'})
    directory_items.append(
        (common.build_url(['profiles'],
                          mode=G.MODE_DIRECTORY), pfl_list_item, True))
    G.CACHE_MANAGEMENT.execute_pending_db_ops()
    return directory_items, {}
示例#13
0
def add_items_previous_next_page(directory_items, pathitems, perpetual_range_selector, sub_genre_id=None,
                                 path_params=None):
    if pathitems and perpetual_range_selector:
        if 'previous_start' in perpetual_range_selector:
            params = {'perpetual_range_start': perpetual_range_selector.get('previous_start'),
                      'sub_genre_id': sub_genre_id if perpetual_range_selector.get('previous_start') == 0 else None}
            if path_params:
                params.update(path_params)
            previous_page_item = ListItemW(label=common.get_local_string(30148))
            previous_page_item.setProperty('specialsort', 'top')  # Force an item to stay on top
            previous_page_item.setArt({'thumb': _get_custom_thumb_path('FolderPagePrevious.png')})
            directory_items.insert(0, (common.build_url(pathitems=pathitems, params=params, mode=G.MODE_DIRECTORY),
                                       previous_page_item,
                                       True))
        if 'next_start' in perpetual_range_selector:
            params = {'perpetual_range_start': perpetual_range_selector.get('next_start')}
            if path_params:
                params.update(path_params)
            next_page_item = ListItemW(label=common.get_local_string(30147))
            next_page_item.setProperty('specialsort', 'bottom')  # Force an item to stay on bottom
            next_page_item.setArt({'thumb': _get_custom_thumb_path('FolderPageNext.png')})
            directory_items.append((common.build_url(pathitems=pathitems, params=params, mode=G.MODE_DIRECTORY),
                                    next_page_item,
                                    True))