Esempio n. 1
0
 def monitor_userlist(self):
     monitor_userlist = self.params.get('monitor_userlist')
     with utils.busy_dialog():
         user_slug = TraktAPI().get_usernameslug()  # Get the user's slug
         user_lists = TraktAPI().get_response_json(
             'users', user_slug, 'lists')  # Get the user's lists
         if not user_lists:
             return
         user_list_labels = [i.get('name') for i in user_lists
                             ]  # Build select dialog to choose list
         user_list_labels.append(xbmc.getLocalizedString(231))
     user_choice = xbmcgui.Dialog().select(
         self.addon.getLocalizedString(32133),
         user_list_labels)  # Choose the list
     if user_choice == -1:  # User cancelled
         return
     elif user_list_labels[user_choice] == xbmc.getLocalizedString(
             231):  # User opted to clear setting
         self.addon.setSettingString(monitor_userlist, '')
         return
     user_list = user_lists[user_choice].get('ids', {}).get('slug')
     if not user_list:
         return
     self.addon.setSettingString(monitor_userlist, user_list)
     if xbmcgui.Dialog().yesno(xbmc.getLocalizedString(653),
                               self.addon.getLocalizedString(32132)):
         self.library_autoupdate(list_slug=user_list, user_slug=user_slug)
def play():
    with utils.busy_dialog():
        suffix = 'force_dialog=True'
        tmdb_id, season, episode = None, None, None
        dbtype = sys.listitem.getVideoInfoTag().getMediaType()

        if dbtype == 'episode':
            tmdb_id = sys.listitem.getProperty('tvshow.tmdb_id')
            season = sys.listitem.getVideoInfoTag().getSeason()
            episode = sys.listitem.getVideoInfoTag().getEpisode()
            suffix += ',season={},episode={}'.format(season, episode)

        elif dbtype == 'movie':
            tmdb_id = sys.listitem.getProperty('tmdb_id') or sys.listitem.getUniqueID('tmdb')

        # Try to lookup ID if we don't have it
        if not tmdb_id and dbtype == 'episode':
            id_details = TraktAPI().get_item_idlookup(
                'episode', parent=True, tvdb_id=sys.listitem.getUniqueID('tvdb'),
                tmdb_id=sys.listitem.getUniqueID('tmdb'), imdb_id=sys.listitem.getUniqueID('imdb'))
            tmdb_id = id_details.get('show', {}).get('ids', {}).get('tmdb')

        elif not tmdb_id and dbtype == 'movie':
            tmdb_id = Plugin().get_tmdb_id(
                itemtype='movie', imdb_id=sys.listitem.getUniqueID('imdb'),
                query=sys.listitem.getVideoInfoTag().getTitle(), year=sys.listitem.getVideoInfoTag().getYear())

        if not tmdb_id or not dbtype:
            return xbmcgui.Dialog().ok('TheMovieDb Helper', _addon.getLocalizedString(32157))

        xbmc.executebuiltin('RunScript(plugin.video.themoviedb.helper,play={},tmdb_id={},{})'.format(dbtype, tmdb_id, suffix))
Esempio n. 3
0
def get_userlist(user_slug=None, list_slug=None, confirm=True, busy_dialog=True):
    if busy_dialog:
        with utils.busy_dialog():
            request = TraktAPI().get_response_json('users', user_slug, 'lists', list_slug, 'items')
    else:
        request = TraktAPI().get_response_json('users', user_slug, 'lists', list_slug, 'items')

    if not request:
        return

    if confirm:
        d_head = _addon.getLocalizedString(32125)
        i_check_limits = check_overlimit(request)
        if i_check_limits:
            # List over limit so inform user that it is too large to add
            d_body = [
                _addon.getLocalizedString(32168).format(list_slug, user_slug),
                _addon.getLocalizedString(32170).format(i_check_limits.get('shows'), i_check_limits.get('movies')),
                '',
                _addon.getLocalizedString(32164).format(LIBRARY_ADD_LIMIT_TVSHOWS, LIBRARY_ADD_LIMIT_MOVIES)]
            xbmcgui.Dialog().ok(d_head, '\n'.join(d_body))
            return
        elif confirm != 2:  # Set confirm param to 2 to only check limits
            # List is within limits so ask for confirmation before adding it
            d_body = [
                _addon.getLocalizedString(32168).format(list_slug, user_slug),
                _addon.getLocalizedString(32171).format(len(request)) if len(request) > 20 else '',
                '',
                _addon.getLocalizedString(32126)]
            if not xbmcgui.Dialog().yesno(d_head, '\n'.join(d_body)):
                return

    return request
def action(action, tmdb_id=None, tmdb_type=None, season=None, episode=None, label=None, cache_refresh=False):
    _traktapi = TraktAPI()

    if action == 'history':
        func = _traktapi.sync_history
    elif action == 'collection':
        func = _traktapi.sync_collection
    elif action == 'watchlist':
        func = _traktapi.sync_watchlist
    elif action == 'add_to_userlist':
        return sync_userlist()
    elif action == 'remove_from_userlist':
        return sync_userlist(remove_item=True)
    elif action == 'library_userlist':
        return library_userlist()
    elif action == 'library':
        return library()
    elif action == 'play':
        return play()
    elif action == 'open':
        return browse()
    else:
        return

    with utils.busy_dialog():
        if tmdb_type == 'episode' and (not season or not episode):
            return
        elif tmdb_id and tmdb_type:
            dbtype = utils.type_convert(tmdb_type, 'dbtype')
            label = label or 'this {}'.format(utils.type_convert(tmdb_type, 'trakt'))
        else:
            label = sys.listitem.getLabel()
            dbtype = sys.listitem.getVideoInfoTag().getMediaType()
            tmdb_id = sys.listitem.getProperty('tmdb_id') if not dbtype == 'episode' else sys.listitem.getProperty('tvshow.tmdb_id')
            season = sys.listitem.getVideoInfoTag().getSeason() if dbtype == 'episode' else None
            episode = sys.listitem.getVideoInfoTag().getEpisode() if dbtype == 'episode' else None
        tmdb_type = 'movie' if dbtype == 'movie' else 'tv'
        trakt_ids = func(utils.type_convert(tmdb_type, 'trakt'), 'tmdb', cache_refresh=cache_refresh)
        boolean = 'remove' if int(tmdb_id) in trakt_ids else 'add'

    dialog_header = 'Trakt {0}'.format(action.capitalize())
    dialog_text = xbmcaddon.Addon().getLocalizedString(32065) if boolean == 'add' else xbmcaddon.Addon().getLocalizedString(32064)
    dialog_text = dialog_text.format(utils.try_decode_string(label), action.capitalize(), tmdb_type, tmdb_id)
    dialog_text = dialog_text + ' Season: {}  Episode: {}'.format(season, episode) if dbtype == 'episode' else dialog_text
    if not xbmcgui.Dialog().yesno(dialog_header, dialog_text):
        return

    with utils.busy_dialog():
        trakt_type = 'episode' if dbtype == 'episode' else utils.type_convert(tmdb_type, 'trakt')
        slug_type = 'show' if dbtype == 'episode' else trakt_type
        slug = _traktapi.get_traktslug(slug_type, 'tmdb', tmdb_id)
        item = _traktapi.get_details(slug_type, slug, season=season, episode=episode)
        items = {trakt_type + 's': [item]}
        func(slug_type, mode=boolean, items=items)

    dialog_header = 'Trakt {0}'.format(action.capitalize())
    dialog_text = xbmcaddon.Addon().getLocalizedString(32062) if boolean == 'add' else xbmcaddon.Addon().getLocalizedString(32063)
    dialog_text = dialog_text.format(tmdb_id, action.capitalize())
    xbmcgui.Dialog().ok(dialog_header, dialog_text)
    xbmc.executebuiltin('Container.Refresh')
Esempio n. 5
0
 def __init__(self):
     super(Player, self).__init__()
     self.traktapi = TraktAPI()
     self.search_movie, self.search_episode, self.play_movie, self.play_episode = [], [], [], []
     self.item = defaultdict(lambda: '+')
     self.itemlist = []
     self.actions = []
     self.players = {}
Esempio n. 6
0
 def router(self):
     if not self.params:
         """ If no params assume user wants to run plugin """
         # TODO: Maybe restart service here too?
         self.params = {
             'call_path': 'plugin://plugin.video.themoviedb.helper/'
         }
     if self.params.get('authenticate_trakt'):
         TraktAPI(force=True)
     elif self.params.get('revoke_trakt'):
         TraktAPI().logout()
     elif self.params.get('split_value'):
         self.split_value()
     elif self.params.get('discover_rename'):
         self.discover_modify('discover_rename')
     elif self.params.get('discover_delete'):
         self.discover_modify('discover_delete')
     elif self.params.get('discover_edit'):
         self.discover_modify('discover_edit')
     elif self.params.get('kodi_setting'):
         self.kodi_setting()
     elif self.params.get('blur_image'):
         self.blur_image()
     elif self.params.get('image_colors'):
         self.image_colors()
     elif self.params.get('monitor_userlist'):
         self.monitor_userlist()
     elif self.params.get('library_userlist'):
         self.library_userlist()
     elif self.params.get('update_players'):
         self.update_players()
     elif self.params.get('set_defaultplayer'):
         self.set_defaultplayer()
     elif self.params.get('clear_defaultplayers'):
         self.clear_defaultplayers()
     elif self.params.get('library_autoupdate'):
         self.library_autoupdate()
     elif self.params.get('sync_trakt'):
         self.sync_trakt()
     elif self.params.get('add_path'):
         self.add_path()
     elif self.params.get('add_query') and self.params.get('type'):
         self.add_query()
     elif self.params.get('add_prop') and self.params.get('prop_id'):
         self.add_prop()
     elif self.params.get('del_path'):
         self.del_path()
     elif self.params.get('close_dialog'):
         self.close_dialog()
     elif self.params.get('reset_path'):
         self.reset_props()
     elif self.params.get('play'):
         self.player_play()
     elif self.params.get('restart_service'):
         self.restart_service()
     else:
         self.call_window()
Esempio n. 7
0
    def monitor_userlist(self):
        with utils.busy_dialog():
            user_slug = TraktAPI().get_usernameslug()  # Get the user's slug
            user_lists = TraktAPI().get_response_json(
                'users', user_slug, 'lists') or [
                ]  # Get the user's custom lists
            user_lists += [
                i.get('list') for i in TraktAPI().get_response_json(
                    'users', 'likes', 'lists') if i.get('type') == 'list'
            ]  # Get the user's liked lists

            if not user_lists:
                return

            monitor_userlist = self.addon.getSettingString(
                'monitor_userlist') or ''
            monitor_userlist = monitor_userlist.split(' | ')
            user_list_labels, preselect = [], []
            for idx, i in enumerate(user_lists):
                user_list_labels.append(i.get('name'))
                preselect.append(idx) if i.get(
                    'ids', {}).get('slug') in monitor_userlist else None

        # Choose lists
        user_choice = xbmcgui.Dialog().multiselect(
            self.addon.getLocalizedString(32133),
            user_list_labels,
            preselect=preselect)
        if not user_choice:  # User cancelled
            return

        # Check lists are within limits before adding
        selected_slugs, selected_lists = [], []
        for i in user_choice:
            i_slug = user_lists[i].get('user', {}).get('ids', {}).get('slug')
            i_list = user_lists[i].get('ids', {}).get('slug')
            if libraryupdate.get_userlist(
                    user_slug=i_slug, list_slug=i_list,
                    confirm=2):  # Set confirm(2) to only check within limits
                selected_lists.append(i_list)
                selected_slugs.append(i_slug)
        user_list = ' | '.join(selected_lists)
        user_slug = ' | '.join(selected_slugs)
        if not user_list or not user_slug:
            return

        self.addon.setSettingString('monitor_userlist', user_list)
        self.addon.setSettingString('monitor_userslug', user_slug)

        if xbmcgui.Dialog().yesno(xbmc.getLocalizedString(653),
                                  self.addon.getLocalizedString(32132)):
            self.library_autoupdate(list_slug=user_list, user_slug=user_slug)
 def __init__(self):
     super(Player, self).__init__()
     self.traktapi = TraktAPI()
     self.search_movie, self.search_episode, self.play_movie, self.play_episode = [], [], [], []
     self.item = defaultdict(lambda: '+')
     self.itemlist, self.actions, self.players, self.identifierlist = [], [], {}, []
     self.is_local = None
     self.dp_movies = self.addon.getSettingString('default_player_movies')
     self.dp_episodes = self.addon.getSettingString(
         'default_player_episodes')
     self.dp_movies_id = None
     self.dp_episodes_id = None
     self.fallbacks = {}
Esempio n. 9
0
 def router(self):
     if not self.params:
         """ If no params assume user wants to run plugin """
         # TODO: Maybe restart service here too?
         self.params = {'call_path': 'plugin://plugin.video.themoviedb.helper/'}
     if self.params.get('authenticate_trakt'):
         TraktAPI(force=True)
     elif self.params.get('update_players'):
         self.update_players()
     elif self.params.get('set_defaultplayer'):
         self.set_defaultplayer()
     elif self.params.get('clear_defaultplayers'):
         self.clear_defaultplayers()
     elif self.params.get('library_autoupdate'):
         self.library_autoupdate()
     elif self.params.get('add_path'):
         self.add_path()
     elif self.params.get('add_query') and self.params.get('type'):
         self.add_query()
     elif self.params.get('add_prop') and self.params.get('prop_id'):
         self.add_prop()
     elif self.params.get('del_path'):
         self.del_path()
     elif self.params.get('close_dialog'):
         self.close_dialog()
     elif self.params.get('reset_path'):
         self.reset_props()
     elif self.params.get('play'):
         self.play()
     elif self.params.get('restart_service'):
         self.restart_service()
     else:
         self.call_window()
Esempio n. 10
0
 def get_trakt_ratings(self, item, tmdbtype=None, tmdb_id=None, season=None, episode=None):
     imdb_id = self.tmdb.get_item_externalid(itemtype=tmdbtype, tmdb_id=tmdb_id, external_id='imdb_id')
     if tmdbtype and imdb_id:
         ratings = TraktAPI().get_ratings(tmdbtype=tmdbtype, imdb_id=imdb_id, season=season, episode=episode)
         if ratings:
             item['infoproperties'] = utils.merge_two_dicts(item.get('infoproperties', {}), ratings)
     return item
    def library_autoupdate(self, list_slug=None, user_slug=None):
        busy_dialog = True if self.params.get('busy_dialog') else False
        utils.kodi_log(u'UPDATING TV SHOWS LIBRARY', 1)
        xbmcgui.Dialog().notification('TMDbHelper', 'Auto-Updating Library...')
        basedir_tv = self.addon.getSettingString(
            'tvshows_library'
        ) or 'special://profile/addon_data/plugin.video.themoviedb.helper/tvshows/'

        list_slug = list_slug or self.addon.getSettingString(
            'monitor_userlist') or ''
        user_slug = user_slug or TraktAPI().get_usernameslug()
        if user_slug and list_slug:
            for i in list_slug.split(' | '):
                context.library_userlist(user_slug=user_slug,
                                         list_slug=i,
                                         confirmation_dialog=False,
                                         allow_update=False,
                                         busy_dialog=busy_dialog)

        p_dialog = xbmcgui.DialogProgressBG() if busy_dialog else None
        p_dialog.create('TMDbHelper',
                        'Adding items to library...') if p_dialog else None
        for f in xbmcvfs.listdir(basedir_tv)[0]:
            try:
                folder = basedir_tv + f + '/'
                # Get nfo file
                nfo = None
                for x in xbmcvfs.listdir(folder)[1]:
                    if x.endswith('.nfo'):
                        nfo = x
                if not nfo:
                    continue

                # Read nfo file
                vfs_file = xbmcvfs.File(folder + nfo)
                content = ''
                try:
                    content = vfs_file.read()
                finally:
                    vfs_file.close()
                tmdb_id = content.replace('https://www.themoviedb.org/tv/', '')
                tmdb_id = tmdb_id.replace('&islocal=True', '')
                if not tmdb_id:
                    continue

                # Get the tvshow
                url = 'plugin://plugin.video.themoviedb.helper/?info=seasons&tmdb_id={}&type=tv'.format(
                    tmdb_id)
                context.library_addtvshow(basedir=basedir_tv,
                                          folder=f,
                                          url=url,
                                          tmdb_id=tmdb_id,
                                          p_dialog=p_dialog)
            except Exception as exc:
                utils.kodi_log(u'LIBRARY AUTO UPDATE ERROR:\n{}'.format(exc))
        p_dialog.close() if p_dialog else None
        if self.addon.getSettingBool('auto_update'):
            xbmc.executebuiltin('UpdateLibrary(video)')
 def library_userlist(self):
     user_slug = self.params.get('user_slug') or TraktAPI(
     ).get_usernameslug()  # Get the user's slug
     list_slug = self.params.get('library_userlist')
     if user_slug and list_slug:
         context.library_userlist(user_slug=user_slug,
                                  list_slug=list_slug,
                                  confirmation_dialog=False,
                                  allow_update=True,
                                  busy_dialog=False)
Esempio n. 13
0
def action(action):
    _traktapi = TraktAPI()

    if action == 'history':
        func = _traktapi.sync_history
    elif action == 'collection':
        func = _traktapi.sync_collection
    elif action == 'watchlist':
        func = _traktapi.sync_watchlist
    elif action == 'library':
        return library()
    else:
        return

    with utils.busy_dialog():
        label = sys.listitem.getLabel()
        dbtype = sys.listitem.getVideoInfoTag().getMediaType()
        tmdb_id = sys.listitem.getProperty('tmdb_id')
        tmdb_type = 'movie' if dbtype == 'movie' else 'tv'
        trakt_ids = func(utils.type_convert(tmdb_type, 'trakt'), 'tmdb')
        boolean = 'remove' if int(tmdb_id) in trakt_ids else 'add'

    dialog_header = 'Trakt {0}'.format(action.capitalize())
    dialog_text = xbmcaddon.Addon().getLocalizedString(32065) if boolean == 'add' else xbmcaddon.Addon().getLocalizedString(32064)
    dialog_text = dialog_text.format(label, action.capitalize(), dbtype.capitalize(), tmdb_id)
    if not xbmcgui.Dialog().yesno(dialog_header, dialog_text):
        return

    with utils.busy_dialog():
        trakt_type = utils.type_convert(tmdb_type, 'trakt')
        slug_type = 'show' if dbtype == 'episode' else trakt_type
        slug = _traktapi.get_traktslug(slug_type, 'tmdb', tmdb_id)
        season = sys.listitem.getVideoInfoTag().getSeason() if dbtype == 'episode' else None
        episode = sys.listitem.getVideoInfoTag().getEpisode() if dbtype == 'episode' else None
        item = _traktapi.get_details(slug_type, slug, season=season, episode=episode)
        items = {trakt_type + 's': [item]}
        func(slug_type, mode=boolean, items=items)

    dialog_header = 'Trakt {0}'.format(action.capitalize())
    dialog_text = xbmcaddon.Addon().getLocalizedString(32062) if boolean == 'add' else xbmcaddon.Addon().getLocalizedString(32063)
    dialog_text = dialog_text.format(tmdb_id, action.capitalize())
    xbmcgui.Dialog().ok(dialog_header, dialog_text)
    xbmc.executebuiltin('Container.Refresh')
Esempio n. 14
0
 def get_top250_rank(self, item):
     if not self.imdb_top250:
         self.imdb_top250 = [
             i.get('movie', {}).get('ids', {}).get('tmdb')
             for i in TraktAPI().get_imdb_top250()
         ]
     try:
         item['infolabels']['top250'] = self.imdb_top250.index(
             item.get('infoproperties', {}).get('tmdb_id')) + 1
     except Exception:
         pass
     return item
    def monitor_userlist(self):
        with utils.busy_dialog():
            user_slug = TraktAPI().get_usernameslug()  # Get the user's slug
            user_lists = TraktAPI().get_response_json(
                'users', user_slug, 'lists')  # Get the user's lists

            if not user_lists:
                return

            monitor_userlist = self.addon.getSettingString(
                'monitor_userlist') or ''
            monitor_userlist = monitor_userlist.split(' | ')
            user_list_labels, preselect = [], []
            for idx, i in enumerate(user_lists):
                user_list_labels.append(i.get('name'))
                preselect.append(idx) if i.get(
                    'ids', {}).get('slug') in monitor_userlist else None

        user_choice = xbmcgui.Dialog().multiselect(
            self.addon.getLocalizedString(32133),
            user_list_labels,
            preselect=preselect)  # Choose the list

        if not user_choice:  # User cancelled
            return

        user_list = ''
        for i in user_choice:
            user_list += ' | ' if user_list else ''
            user_list += user_lists[i].get('ids', {}).get('slug')

        if not user_list:
            return

        self.addon.setSettingString('monitor_userlist', user_list)

        if xbmcgui.Dialog().yesno(xbmc.getLocalizedString(653),
                                  self.addon.getLocalizedString(32132)):
            self.library_autoupdate(list_slug=user_list, user_slug=user_slug)
def sync_userlist(remove_item=False):
    dbtype = sys.listitem.getVideoInfoTag().getMediaType()
    user_list = sys.listitem.getProperty('container.list_slug') if remove_item else None
    tmdb_id = sys.listitem.getProperty('tvshow.tmdb_id')
    imdb_id = sys.listitem.getUniqueID('imdb')
    tvdb_id = None
    if not dbtype == 'episode':
        tmdb_id = sys.listitem.getProperty('tmdb_id') or sys.listitem.getUniqueID('tmdb')
        tvdb_id = sys.listitem.getUniqueID('tvdb')
    if dbtype == 'movie':
        item_type = 'movie'
    elif dbtype in ['tvshow', 'season', 'episode']:
        item_type = 'show'
    else:  # Not the right type of item so lets exit
        return
    TraktAPI().sync_userlist(item_type, tmdb_id=tmdb_id, tvdb_id=tvdb_id, imdb_id=imdb_id, remove_item=remove_item, user_list=user_list)
    xbmc.executebuiltin('Container.Refresh')
    def library_autoupdate(self, list_slug=None, user_slug=None):
        utils.kodi_log(u'UPDATING TV SHOWS LIBRARY', 1)
        basedir_tv = self.addon.getSettingString('tvshows_library') or 'special://profile/addon_data/plugin.video.skin.info.provider/tvshows/'
        list_slug = list_slug or self.addon.getSettingString('monitor_userlist')
        if list_slug:
            user_slug = user_slug or TraktAPI().get_usernameslug()
            if user_slug:
                context.library_userlist(user_slug=user_slug, list_slug=list_slug, confirmation_dialog=False)
            list_slug_2 = self.addon.getSettingString('monitor_userlist_2')
            if list_slug_2 and list_slug_2 != list_slug:
                context.library_userlist(user_slug=user_slug, list_slug=list_slug_2, confirmation_dialog=False)
        for f in xbmcvfs.listdir(basedir_tv)[0]:
            try:
                folder = basedir_tv + f + '/'
                # Get nfo file
                nfo = None
                for x in xbmcvfs.listdir(folder)[1]:
                    if x.endswith('.nfo'):
                        nfo = x
                if not nfo:
                    continue

                # Read nfo file
                vfs_file = xbmcvfs.File(folder + nfo)
                content = ''
                try:
                    content = vfs_file.read()
                finally:
                    vfs_file.close()
                tmdb_id = content.replace('https://www.themoviedb.org/tv/', '')
                tmdb_id = tmdb_id.replace('&islocal=True', '')
                if not tmdb_id:
                    continue

                # Get the tvshow
                url = 'plugin://plugin.video.skin.info.provider/?info=seasons&tmdb_id={}&type=tv'.format(tmdb_id)
                context.library_addtvshow(basedir=basedir_tv, folder=f, url=url, tmdb_id=tmdb_id)
            except Exception as exc:
                utils.kodi_log(u'LIBRARY AUTO UPDATE ERROR:\n{}'.format(exc))
        if self.addon.getSettingBool('auto_update'):
            xbmc.executebuiltin('UpdateLibrary(video, {})'.format(basedir_tv))
Esempio n. 18
0
class Player(Plugin):
    def __init__(self):
        super(Player, self).__init__()
        self.traktapi = TraktAPI()
        self.search_movie, self.search_episode, self.play_movie, self.play_episode = [], [], [], []
        self.item = defaultdict(lambda: '+')
        self.itemlist = []
        self.actions = []
        self.players = {}

    def setup_players(self, tmdbtype=None, details=False, clearsetting=False):
        self.build_players(tmdbtype)
        if details:
            self.build_details()
        self.build_selectbox(clearsetting)

    def get_itemindex(self, force_dialog=False):
        default_player_movies = self.addon.getSettingString(
            'default_player_movies')
        default_player_episodes = self.addon.getSettingString(
            'default_player_episodes')
        if force_dialog or (self.itemtype == 'movie'
                            and not default_player_movies) or (
                                self.itemtype == 'episode'
                                and not default_player_episodes):
            return xbmcgui.Dialog().select(
                self.addon.getLocalizedString(32042), self.itemlist)
        itemindex = -1
        with utils.busy_dialog():
            for index in range(0, len(self.itemlist)):
                label = self.itemlist[index].getLabel()
                if (label == default_player_movies and self.itemtype
                        == 'movie') or (label == default_player_episodes
                                        and self.itemtype == 'episode'):
                    return index
        return itemindex

    def play_external(self, force_dialog=False):
        itemindex = self.get_itemindex(force_dialog=force_dialog)

        # User cancelled dialog
        if not itemindex > -1:
            return False

        player = self.actions[itemindex]
        if not player or not player[1]:
            return False

        # External player has list of actions so let's iterate through them to find our item
        resolve_url = False
        if isinstance(player[1], list):
            actionlist = player[1]
            player = (False, actionlist[0])
            with utils.busy_dialog():
                for d in actionlist[1:]:
                    if player[0]:
                        break  # Playable item was found in last action so let's break and play it
                    folder = KodiLibrary().get_directory(
                        string_format_map(
                            player[1],
                            self.item))  # Get the next folder from the plugin
                    x = 0
                    for f in folder:  # Iterate through plugin folder looking for a matching item
                        x += 1  # Keep an index for position matching
                        for k, v in d.items(
                        ):  # Iterate through our key (infolabel) / value (infolabel must match) pairs of our action
                            if k == 'position':  # We're looking for an item position not an infolabel
                                if utils.try_parse_int(
                                        string_format_map(v, self.item)
                                ) != x:  # Format our position value
                                    break  # Not the item position we want so let's go to next item in folder
                            elif not f.get(k) or string_format_map(
                                    v, self.item
                            ) not in u'{}'.format(
                                    f.get(k, '')
                            ):  # Format our value and check if it matches the infolabel key
                                break  # Item's key value doesn't match value we are looking for so let's got to next item in folder
                        else:  # Item matched our criteria so let's open it up
                            resolve_url = True if f.get(
                                'filetype'
                            ) == 'file' else False  # Set true for files so we can play
                            player = (resolve_url, f.get('file')
                                      )  # Get ListItem.FolderPath for item
                            break  # Move onto next action (either open next folder or play file)
                    else:
                        xbmcgui.Dialog().notification(
                            self.itemlist[itemindex].getLabel(),
                            self.addon.getLocalizedString(32040))
                        del self.actions[
                            itemindex]  # Item not found so remove the player's action list
                        del self.itemlist[
                            itemindex]  # Item not found so remove the player's select dialog entry
                        return self.play_external(
                            force_dialog=True
                        )  # Ask user to select a different player

        # Play/Search found item
        if player and player[1]:
            action = string_format_map(player[1], self.item)
            if player[0]:  # Action is play so let's play the item and return
                xbmc.Player().play(
                    action,
                    ListItem(library='video', **self.details).set_listitem())
                return action
            # Action is search so let's load the plugin path
            action = u'Container.Update({0})'.format(
                action) if xbmc.getCondVisibility(
                    "Window.IsMedia"
                ) else u'ActivateWindow(videos,{0},return)'.format(action)
            xbmc.executebuiltin(utils.try_decode_string(action))
            return action

    def play(self, itemtype, tmdb_id, season=None, episode=None):
        """ Entry point for player method """
        if not tmdb_id or not itemtype:
            return

        # Get the details for the item
        self.itemtype, self.tmdb_id, self.season, self.episode = itemtype, tmdb_id, season, episode
        self.tmdbtype = 'tv' if self.itemtype in ['episode', 'tv'] else 'movie'
        self.details = self.tmdb.get_detailed_item(self.tmdbtype,
                                                   tmdb_id,
                                                   season=season,
                                                   episode=episode)
        self.item['imdb_id'] = self.details.get('infolabels',
                                                {}).get('imdbnumber')
        self.item['originaltitle'] = self.details.get('infolabels',
                                                      {}).get('originaltitle')
        self.item['title'] = self.details.get(
            'infolabels', {}).get('tvshowtitle') or self.details.get(
                'infolabels', {}).get('title')
        self.item['year'] = self.details.get('infolabels', {}).get('year')

        # Attempt to play local file first
        is_local = False
        if self.details and self.itemtype == 'movie':
            is_local = self.playmovie()
        if self.details and self.itemtype == 'episode':
            is_local = self.playepisode()
        if is_local:
            return is_local

        with utils.busy_dialog():
            self.setup_players(details=True)

        if not self.itemlist:
            return False

        return self.play_external()

    def build_details(self):
        self.item['id'] = self.tmdb_id
        self.item['tmdb'] = self.tmdb_id
        self.item['imdb'] = self.details.get('infolabels',
                                             {}).get('imdbnumber')
        self.item['name'] = u'{0} ({1})'.format(self.item.get('title'),
                                                self.item.get('year'))
        self.item['firstaired'] = self.details.get('infolabels',
                                                   {}).get('premiered')
        self.item['premiered'] = self.details.get('infolabels',
                                                  {}).get('premiered')
        self.item['released'] = self.details.get('infolabels',
                                                 {}).get('premiered')
        self.item['showname'] = self.item.get('title')
        self.item['clearname'] = self.item.get('title')
        self.item['tvshowtitle'] = self.item.get('title')
        self.item['title'] = self.item.get('title')
        self.item['thumbnail'] = self.details.get('thumb')
        self.item['poster'] = self.details.get('poster')
        self.item['fanart'] = self.details.get('fanart')
        self.item['now'] = datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')

        if self.traktapi:
            slug_type = utils.type_convert(self.tmdbtype, 'trakt')
            trakt_details = self.traktapi.get_details(
                slug_type,
                self.traktapi.get_traktslug(slug_type, 'tmdb', self.tmdb_id))
            self.item['trakt'] = trakt_details.get('ids', {}).get('trakt')
            self.item['imdb'] = trakt_details.get('ids', {}).get('imdb')
            self.item['tvdb'] = trakt_details.get('ids', {}).get('tvdb')
            self.item['slug'] = trakt_details.get('ids', {}).get('slug')

        if self.itemtype == 'episode':  # Do some special episode stuff
            self.item['id'] = self.item.get('tvdb')
            self.item['title'] = self.details.get('infolabels', {}).get(
                'title')  # Set Episode Title
            self.item['name'] = u'{0} S{1:02d}E{2:02d}'.format(
                self.item.get('showname'), int(self.season), int(self.episode))
            self.item['season'] = self.season
            self.item['episode'] = self.episode

        if self.traktapi and self.itemtype == 'episode':
            trakt_details = self.traktapi.get_details(slug_type,
                                                      self.item.get('slug'),
                                                      season=self.season,
                                                      episode=self.episode)
            self.item['epid'] = trakt_details.get('ids', {}).get('tvdb')
            self.item['epimdb'] = trakt_details.get('ids', {}).get('imdb')
            self.item['eptmdb'] = trakt_details.get('ids', {}).get('tmdb')
            self.item['eptrakt'] = trakt_details.get('ids', {}).get('trakt')

        for k, v in self.item.copy().items():
            v = u'{0}'.format(v)
            self.item[k] = v.replace(',', '')
            self.item[k + '_+'] = v.replace(' ', '+')
            self.item[k + '_-'] = v.replace(' ', '-')
            self.item[k + '_escaped'] = v.replace(' ', '%2520')
            self.item[k + '_escaped+'] = v.replace(' ', '%252B')

    def build_players(self, tmdbtype=None):
        basedirs = [
            'special://profile/addon_data/plugin.video.themoviedb.helper/players/'
        ]
        if self.addon.getSettingBool('bundled_players'):
            basedirs.append(
                'special://home/addons/plugin.video.themoviedb.helper/resources/players/'
            )
        for basedir in basedirs:
            files = [
                x for x in xbmcvfs.listdir(basedir)[1] if x.endswith('.json')
            ]
            for file in files:
                vfs_file = xbmcvfs.File(basedir + file)
                try:
                    content = vfs_file.read()
                    meta = loads(content) or {}
                finally:
                    vfs_file.close()
                if not meta.get('plugin') or not xbmc.getCondVisibility(
                        u'System.HasAddon({0})'.format(meta.get('plugin'))):
                    continue  # Don't have plugin so skip

                tmdbtype = tmdbtype or self.tmdbtype
                priority = utils.try_parse_int(meta.get('priority')) or 1000
                if tmdbtype == 'movie' and meta.get('search_movie'):
                    self.search_movie.append((vfs_file, priority))
                if tmdbtype == 'movie' and meta.get('play_movie'):
                    self.play_movie.append((vfs_file, priority))
                if tmdbtype == 'tv' and meta.get('search_episode'):
                    self.search_episode.append((vfs_file, priority))
                if tmdbtype == 'tv' and meta.get('play_episode'):
                    self.play_episode.append((vfs_file, priority))
                self.players[vfs_file] = meta

    def build_selectbox(self, clearsetting=False):
        self.itemlist, self.actions = [], []
        if clearsetting:
            self.itemlist.append(
                xbmcgui.ListItem(
                    xbmc.getLocalizedString(13403)))  # Clear Default
        for i in sorted(self.play_movie, key=lambda x: x[1]):
            self.itemlist.append(
                xbmcgui.ListItem(u'{0} {1}'.format(
                    self.addon.getLocalizedString(32061),
                    self.players.get(i[0], {}).get('name', ''))))
            self.actions.append(
                (True, self.players.get(i[0], {}).get('play_movie', '')))
        for i in sorted(self.search_movie, key=lambda x: x[1]):
            self.itemlist.append(
                xbmcgui.ListItem(u'{0} {1}'.format(
                    xbmc.getLocalizedString(137),
                    self.players.get(i[0], {}).get('name', ''))))
            self.actions.append(
                (False, self.players.get(i[0], {}).get('search_movie', '')))
        for i in sorted(self.play_episode, key=lambda x: x[1]):
            self.itemlist.append(
                xbmcgui.ListItem(u'{0} {1}'.format(
                    self.addon.getLocalizedString(32061),
                    self.players.get(i[0], {}).get('name', ''))))
            self.actions.append(
                (True, self.players.get(i[0], {}).get('play_episode', '')))
        for i in sorted(self.search_episode, key=lambda x: x[1]):
            self.itemlist.append(
                xbmcgui.ListItem(u'{0} {1}'.format(
                    xbmc.getLocalizedString(137),
                    self.players.get(i[0], {}).get('name', ''))))
            self.actions.append(
                (False, self.players.get(i[0], {}).get('search_episode', '')))

    def playfile(self, file):
        if not file:
            return
        if file.endswith('.strm'):
            f = xbmcvfs.File(file)
            contents = f.read()
            f.close()
            if contents.startswith('plugin://plugin.video.themoviedb.helper'):
                return
        xbmc.executebuiltin(u'PlayMedia({0})'.format(file))
        return file

    def playmovie(self):
        fuzzy_match = self.addon.getSettingBool('fuzzymatch_movie')
        return self.playfile(
            KodiLibrary(dbtype='movie').get_info('file',
                                                 fuzzy_match=fuzzy_match,
                                                 **self.item))

    def playepisode(self):
        fuzzy_match = self.addon.getSettingBool('fuzzymatch_tv')
        dbid = KodiLibrary(dbtype='tvshow').get_info('dbid',
                                                     fuzzy_match=fuzzy_match,
                                                     **self.item)
        return self.playfile(
            KodiLibrary(dbtype='episode',
                        tvshowid=dbid).get_info('file',
                                                season=self.season,
                                                episode=self.episode))
Esempio n. 19
0
 def get_trakt_usernameslug(self, login=False):
     return TraktAPI().get_usernameslug(login=login)
def library_userlist(user_slug=None, list_slug=None, confirmation_dialog=True):
    user_slug = user_slug or sys.listitem.getProperty('Item.user_slug')
    list_slug = list_slug or sys.listitem.getProperty('Item.list_slug')

    with utils.busy_dialog():
        request = TraktAPI().get_response_json('users', user_slug, 'lists', list_slug, 'items')
        if not request:
            return

    i_count = 0
    i_total = len(request)

    if confirmation_dialog:
        d_head = _addon.getLocalizedString(32125)
        d_body = _addon.getLocalizedString(32126)
        d_body += '\n[B]{}[/B] {} [B]{}[/B]'.format(list_slug, _addon.getLocalizedString(32127), user_slug)
        d_body += '\n\n[B][COLOR=red]{}[/COLOR][/B] '.format(xbmc.getLocalizedString(14117)) if i_total > 20 else '\n\n'
        d_body += '{} [B]{}[/B] {}.'.format(_addon.getLocalizedString(32128), i_total, _addon.getLocalizedString(32129))
        if not xbmcgui.Dialog().yesno(d_head, d_body):
            return

    p_dialog = xbmcgui.DialogProgressBG()
    p_dialog.create('TMDbHelper', 'Adding items to library...')
    basedir_movie = _addon.getSettingString('movies_library') or 'special://profile/addon_data/plugin.video.skin.info.provider/movies/'
    basedir_tv = _addon.getSettingString('tvshows_library') or 'special://profile/addon_data/plugin.video.skin.info.provider/tvshows/'
    auto_update = _addon.getSettingBool('auto_update') or False
    all_movies = []
    all_tvshows = []

    for i in request:
        i_count += 1
        i_type = i.get('type')
        if i_type not in ['movie', 'show']:
            continue  # Only get movies or tvshows

        item = i.get(i_type, {})
        tmdb_id = item.get('ids', {}).get('tmdb')
        imdb_id = item.get('ids', {}).get('imdb')
        tvdb_id = item.get('ids', {}).get('tvdb')
        if not tmdb_id:
            continue  # Don't bother if there isn't a tmdb_id as lookup is too expensive for long lists

        if i_type == 'movie':  # Add any movies
            all_movies.append(item.get('title'))
            content = 'plugin://plugin.video.skin.info.provider/?info=play&tmdb_id={}&type=movie'.format(tmdb_id)
            folder = u'{} ({})'.format(item.get('title'), item.get('year'))
            movie_name = u'{} ({})'.format(item.get('title'), item.get('year'))
            db_file = _plugin.get_db_info(info='file', tmdbtype='movie', imdb_id=imdb_id, tmdb_id=tmdb_id)
            if db_file:
                all_movies.append(('filename', db_file.replace('\\', '/').split('/')[-1]))
                p_dialog.update((i_count * 100) // i_total, message=u'Found {} in library. Skipping...'.format(movie_name))
                utils.kodi_log(u'Trakt List Add to Library\nFound {} in library. Skipping...'.format(movie_name), 0)
                continue
            p_dialog.update((i_count * 100) // i_total, message=u'Adding {} to library...'.format(movie_name))
            utils.kodi_log(u'Adding {} to library...'.format(movie_name), 0)
            db_file = library_createfile(movie_name, content, folder, basedir=basedir_movie)
            library_create_nfo('movie', tmdb_id, folder, basedir=basedir_movie)
            all_movies.append(('filename', db_file.split('/')[-1]))

        if i_type == 'show':  # Add whole tvshows
            all_tvshows.append(('title', item.get('title')))
            content = 'plugin://plugin.video.skin.info.provider/?info=seasons&nextpage=True&tmdb_id={}&type=tv'.format(tmdb_id)
            folder = u'{}'.format(item.get('title'))
            p_dialog.update((i_count * 100) // i_total, message=u'Adding {} to library...'.format(item.get('title')))
            library_addtvshow(basedir=basedir_tv, folder=folder, url=content, tmdb_id=tmdb_id, imdb_id=imdb_id, tvdb_id=tvdb_id, p_dialog=p_dialog)

    p_dialog.close()
    create_playlist(all_movies, 'movies', user_slug, list_slug) if all_movies else None
    create_playlist(all_tvshows, 'tvshows', user_slug, list_slug) if all_tvshows else None
    xbmc.executebuiltin('UpdateLibrary(video)') if auto_update else None
Esempio n. 21
0
class Player(Plugin):
    def __init__(self):
        super(Player, self).__init__()
        self.traktapi = TraktAPI()
        self.search_movie, self.search_episode, self.play_movie, self.play_episode = [], [], [], []
        self.item = defaultdict(lambda: '+')
        self.itemlist, self.actions, self.players, self.identifierlist = [], [], {}, []
        self.is_local = None
        self.autoplay_single = self.addon.getSettingBool('autoplay_single')
        self.dp_local = self.addon.getSettingBool('default_player_local')
        self.dp_movies = self.addon.getSettingString('default_player_movies')
        self.dp_episodes = self.addon.getSettingString(
            'default_player_episodes')
        self.dp_movies_id = None
        self.dp_episodes_id = None
        self.fallbacks = {}
        self.playerstring = None

    def setup_players(self,
                      tmdbtype=None,
                      details=False,
                      clearsetting=False,
                      assertplayers=True):
        self.build_players(tmdbtype)
        if details:
            self.build_details()
        self.build_selectbox(clearsetting, assertplayers)

    def get_fallback(self, dp_file, dp_action):
        fallback = self.players.get(dp_file, {}).get('fallback',
                                                     {}).get(dp_action)
        if not fallback:  # No fallback so prompt dialog
            utils.kodi_log(
                u'Player -- {} {}\nFallback not set!'.format(
                    dp_file, dp_action), 2)
            return xbmcgui.Dialog().select(
                self.addon.getLocalizedString(32042), self.itemlist)
        if fallback in self.identifierlist:  # Found a fallback in list so play that
            utils.kodi_log(
                u'Player -- {} {}\nFallback found: {}'.format(
                    dp_file, dp_action, fallback), 2)
            return self.identifierlist.index(fallback)
        fb_file, fb_action = fallback.split()
        utils.kodi_log(
            u'Player -- {} {}\nFallback NOT found!\n{}'.format(
                dp_file, dp_action, fallback), 2)
        return self.get_fallback(
            fb_file, fb_action
        )  # Fallback not in list so let's check fallback's fallback

    def get_playerindex(self, force_dialog=False):
        if not self.itemlist:
            return -1  # No players left so cancel

        if (force_dialog
                or (self.itemtype == 'movie' and not self.dp_movies and
                    (not self.is_local or not self.dp_local))
                or (self.itemtype == 'episode' and not self.dp_episodes and
                    (not self.is_local or not self.dp_local))):
            idx = xbmcgui.Dialog().select(
                self.addon.getLocalizedString(32042),
                self.itemlist)  # Ask user to select player
            if self.itemtype == 'movie':
                self.dp_movies = self.itemlist[idx].getLabel()
                self.dp_movies_id = self.identifierlist[idx]
                utils.kodi_log(
                    u'Player -- User selected {}\n{}'.format(
                        self.dp_movies, self.dp_movies_id), 2)
            elif self.itemtype == 'episode':
                self.dp_episodes = self.itemlist[idx].getLabel()
                self.dp_episodes_id = self.identifierlist[idx]
                utils.kodi_log(
                    u'Player -- User selected {}\n{}'.format(
                        self.dp_episodes, self.dp_episodes_id), 2)
            return idx

        for i in range(0, len(self.itemlist)):
            label = self.itemlist[i].getLabel()
            if ((label == self.dp_movies and self.itemtype == 'movie') or
                (label == self.dp_episodes and self.itemtype == 'episode')
                    or (label == u'{0} {1}'.format(
                        self.addon.getLocalizedString(32061), 'Kodi')
                        and self.dp_local)):
                utils.kodi_log(
                    u'Player -- Attempting to Play with Default Player:\n {}'.
                    format(label), 2)
                return i  # Play local or with default player if found

        # Check for fallbacks
        utils.kodi_log(u'Player -- Checking for Fallbacks', 2)
        if self.itemtype == 'movie' and self.dp_movies_id:
            dp_file, dp_action = self.dp_movies_id.split()
            return self.get_fallback(dp_file, dp_action)
        if self.itemtype == 'episode' and self.dp_episodes_id:
            dp_file, dp_action = self.dp_episodes_id.split()
            return self.get_fallback(dp_file, dp_action)

        return -1

    def player_getnewindex(self, playerindex=-1, force_dialog=False):
        if playerindex > -1:  # Previous iteration didn't find an item to play so remove it and retry
            xbmcgui.Dialog().notification(
                self.itemlist[playerindex].getLabel(),
                self.addon.getLocalizedString(32040))
            del self.actions[
                playerindex]  # Item not found so remove the player's action list
            del self.itemlist[
                playerindex]  # Item not found so remove the player's select dialog entry
            del self.identifierlist[
                playerindex]  # Item not found so remove the player's index
        playerindex = 0 if len(
            self.itemlist
        ) == 1 and self.autoplay_single else self.get_playerindex(
            force_dialog=force_dialog)
        return playerindex

    def player_dialogselect(self, folder, auto=False):
        d_items = []
        for f in folder:

            # Skip items without labels as probably not worth playing
            if not f.get('label') or f.get('label') == 'None':
                continue

            # Get the label of the item
            label_a = f.get('label')

            # Add year to our label if exists and not special value of 1601
            if f.get('year') and f.get('year') != 1601:
                label_a = u'{} ({})'.format(label_a, f.get('year'))

            # Add season and episode numbers to label
            if utils.try_parse_int(f.get('season',
                                         0)) > 0 and utils.try_parse_int(
                                             f.get('episode', 0)) > 0:
                label_a = u'{}x{}. {}'.format(f.get('season'),
                                              f.get('episode'), label_a)

            # Add various stream details to ListItem.Label2 (aka label_b)
            label_b_list = []
            if f.get('streamdetails'):
                sdv_list = f.get('streamdetails', {}).get('video',
                                                          [{}]) or [{}]
                sda_list = f.get('streamdetails', {}).get('audio',
                                                          [{}]) or [{}]
                sdv, sda = sdv_list[0], sda_list[0]
                if sdv.get('width') or sdv.get('height'):
                    label_b_list.append(u'{}x{}'.format(
                        sdv.get('width'), sdv.get('height')))
                if sdv.get('codec'):
                    label_b_list.append(u'{}'.format(
                        sdv.get('codec', '').upper()))
                if sda.get('codec'):
                    label_b_list.append(u'{}'.format(
                        sda.get('codec', '').upper()))
                if sda.get('channels'):
                    label_b_list.append(u'{} CH'.format(sda.get(
                        'channels', '')))
                for i in sda_list:
                    if i.get('language'):
                        label_b_list.append(u'{}'.format(
                            i.get('language', '').upper()))
                if sdv.get('duration'):
                    label_b_list.append(u'{} mins'.format(
                        utils.try_parse_int(sdv.get('duration', 0)) // 60))
            if f.get('size'):
                label_b_list.append(u'{}'.format(
                    utils.normalise_filesize(f.get('size', 0))))
            label_b = ' | '.join(label_b_list) if label_b_list else ''

            # Add item to select dialog list
            d_items.append(
                ListItem(label=label_a,
                         label2=label_b,
                         icon=f.get('thumbnail')).set_listitem())

        if not d_items:
            return -1  # No items so ask user to select new player

        # If autoselect enabled and only 1 item choose that otherwise ask user to choose
        idx = 0 if auto and len(d_items) == 1 else xbmcgui.Dialog().select(
            'Select Item', d_items, useDetails=True)

        if idx == -1:
            return  # User exited the dialog so return nothing

        resolve_url = True if folder[idx].get(
            'filetype'
        ) == 'file' else False  # Set true for files so we can play
        return (resolve_url, folder[idx].get('file'))  # Return the player

    def player_applyrules(self, folder, action):
        for x, f in enumerate(folder):
            for k, v in action.items(
            ):  # Iterate through our key (infolabel) / value (infolabel must match) pairs of our action
                if k == 'position':  # We're looking for an item position not an infolabel
                    if utils.try_parse_int(
                            string_format_map(v, self.item)
                    ) != x + 1:  # Format our position value and add one since people are dumb and don't know that arrays start at 0
                        break  # Not the item position we want so let's go to next item in folder
                elif not f.get(k) or not re.match(
                        string_format_map(v, self.item), u'{}'.format(
                            f.get(k, ''))
                ):  # Format our value and check if it regex matches the infolabel key
                    break  # Item's key value doesn't match value we are looking for so let's got to next item in folder
            else:  # Item matched our criteria so let's return it
                utils.kodi_log('Player -- Found Match!\n{}'.format(f), 2)
                resolve_url = True if f.get(
                    'filetype'
                ) == 'file' else False  # Set true for files so we can play
                return (
                    resolve_url, f.get('file')
                )  # Get ListItem.FolderPath for item and return as player
        utils.kodi_log('Player -- Failed to find match!\n{}'.format(action), 2)
        return -1  # Got through the entire folder without a match so ask user to select new player

    def player_resolveurl(self, player=None):
        if not player or not player[1] or not isinstance(player[1], list):
            return player  # No player configured or not a list of actions so return

        keyboard_input = None
        player_actions = player[1]
        player = (False, player_actions[0]
                  )  # player tuple is: isPlayable flag; path URI to call.

        for action in player_actions[1:]:

            # If playable item was found in last action then let's break and play it
            if player[0]:
                break

            # Start thread with keyboard inputter if needed
            if action.get('keyboard'):
                if action.get('keyboard') in [
                        'Up', 'Down', 'Left', 'Right', 'Select'
                ]:
                    keyboard_input = KeyboardInputter(
                        action="Input.{}".format(action.get('keyboard')))
                else:
                    keyboard_input = KeyboardInputter(text=string_format_map(
                        action.get('keyboard', ''), self.item))
                keyboard_input.setName('keyboard_input')
                keyboard_input.start()
                continue  # Go to next action

            # Get the next folder from the plugin
            with utils.busy_dialog():
                folder = KodiLibrary().get_directory(
                    string_format_map(player[1], self.item))

            # Kill our keyboard inputter thread
            if keyboard_input:
                keyboard_input.exit = True
                keyboard_input = None

            # Special option to show dialog of items to select from
            if action.get('dialog'):
                auto = True if action.get('dialog',
                                          '').lower() == 'auto' else False
                return self.player_dialogselect(folder, auto=auto)

            utils.kodi_log(
                'Player -- Retrieved Folder\n{}'.format(
                    string_format_map(player[1], self.item)), 2)

            # Iterate through plugin folder looking for item that matches rules
            player = self.player_applyrules(folder, action) or player

            if player == -1:
                break

        return player

    def play_external(self, playerindex=-1, force_dialog=False):
        playerindex = self.player_getnewindex(playerindex,
                                              force_dialog=force_dialog)

        # User cancelled dialog
        if not playerindex > -1:
            utils.kodi_log(u'Player -- User cancelled', 2)
            return False

        # Run through player actions
        player = self.player_resolveurl(self.actions[playerindex])

        # Previous player failed so ask user to select a new one
        if player == -1:
            return self.play_external(playerindex, force_dialog=force_dialog)

        # Play/Search found item
        if player and player[1]:
            action = string_format_map(player[1], self.item)
            if player[0] and (
                    action.endswith('.strm')
                    or self.identifierlist[playerindex] == 'play_kodi'
            ):  # Action is play and is a strm/local so PlayMedia
                utils.kodi_log(
                    u'Player -- Found strm or local.\nAttempting PLAYMEDIA({})'
                    .format(action), 1)
                xbmc.executebuiltin(
                    utils.try_decode_string(
                        u'PlayMedia(\"{0}\")'.format(action)))
            elif player[
                    0]:  # Action is play and not a strm so play with player
                utils.kodi_log(
                    u'Player -- Found file.\nAttempting to PLAY: {}'.format(
                        action), 2)
                xbmcgui.Window(10000).setProperty(
                    'TMDbHelper.PlayerInfoString',
                    self.playerstring) if self.playerstring else None
                xbmc.Player().play(
                    action,
                    ListItem(library='video', **self.details).set_listitem())
            else:
                action = u'Container.Update({0})'.format(
                    action) if xbmc.getCondVisibility(
                        "Window.IsMedia"
                    ) else u'ActivateWindow(videos,{0},return)'.format(action)
                utils.kodi_log(
                    u'Player -- Found folder.\nAttempting to OPEN: {}'.format(
                        action), 2)
                xbmc.executebuiltin(
                    utils.try_encode_string(utils.try_decode_string(action)))
            return action

    def play(self,
             itemtype,
             tmdb_id,
             season=None,
             episode=None,
             force_dialog=False,
             kodi_db=False):
        """ Entry point for player method """
        if not tmdb_id or not itemtype:
            return

        xbmcgui.Window(10000).clearProperty('TMDbHelper.PlayerInfoString')

        with utils.busy_dialog():
            # Get the details for the item
            self.itemtype, self.tmdb_id, self.season, self.episode = itemtype, tmdb_id, season, episode
            self.tmdbtype = 'tv' if self.itemtype in ['episode', 'tv'
                                                      ] else 'movie'
            self.details = self.tmdb.get_detailed_item(self.tmdbtype,
                                                       tmdb_id,
                                                       season=season,
                                                       episode=episode)
            self.item['tmdb_id'] = self.tmdb_id
            self.item['imdb_id'] = self.details.get(
                'infoproperties',
                {}).get('tvshow.imdb_id') or self.details.get(
                    'infoproperties', {}).get('imdb_id')
            self.item['tvdb_id'] = self.details.get(
                'infoproperties',
                {}).get('tvshow.tvdb_id') or self.details.get(
                    'infoproperties', {}).get('tvdb_id')
            self.item['originaltitle'] = self.details.get(
                'infolabels', {}).get('originaltitle')
            self.item['title'] = self.details.get(
                'infolabels', {}).get('tvshowtitle') or self.details.get(
                    'infolabels', {}).get('title')
            self.item['year'] = self.details.get('infolabels', {}).get('year')

            # Check if we have a local file
            # TODO: Add option to auto play local
            if self.details and self.itemtype == 'movie':
                self.is_local = self.localmovie()
            if self.details and self.itemtype == 'episode':
                self.is_local = self.localepisode()

            self.setup_players(details=True)

        if not self.itemlist:
            return False

        if kodi_db:
            self.playerstring = dumps({
                'tmdbtype':
                'episode' if itemtype in ['episode', 'tv'] else 'movie',
                'season':
                season,
                'episode':
                episode,
                'tmdb_id':
                self.tmdb_id,
                'tvdb_id':
                self.item.get('tvdb_id'),
                'imdb_id':
                self.item.get('imdb_id')
            })

        return self.play_external(force_dialog=force_dialog)

    def build_details(self):
        self.item['id'] = self.tmdb_id
        self.item['tmdb'] = self.tmdb_id
        self.item['imdb'] = self.details.get('infolabels',
                                             {}).get('imdbnumber')
        self.item['name'] = u'{0} ({1})'.format(self.item.get('title'),
                                                self.item.get('year'))
        self.item['premiered'] = self.item['firstaired'] = self.item[
            'released'] = self.details.get('infolabels', {}).get('premiered')
        self.item['plot'] = self.details.get('infolabels', {}).get('plot')
        self.item['cast'] = self.item['actors'] = " / ".join([
            i.get('name') for i in self.details.get('cast', [])
            if i.get('name')
        ])
        self.item['showname'] = self.item['clearname'] = self.item[
            'tvshowtitle'] = self.item['title'] = self.item.get('title')
        self.item['thumbnail'] = self.details.get('thumb')
        self.item['poster'] = self.details.get('poster')
        self.item['fanart'] = self.details.get('fanart')
        self.item['now'] = datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')

        if self.traktapi:
            slug_type = utils.type_convert(self.tmdbtype, 'trakt')
            trakt_details = self.traktapi.get_details(
                slug_type,
                self.traktapi.get_traktslug(slug_type, 'tmdb', self.tmdb_id))
            self.item['trakt'] = trakt_details.get('ids', {}).get('trakt')
            self.item['imdb'] = self.details.get(
                'infoproperties',
                {}).get('tvshow.imdb_id') or trakt_details.get('ids',
                                                               {}).get('imdb')
            self.item['tvdb'] = self.details.get(
                'infoproperties',
                {}).get('tvshow.tvdb_id') or trakt_details.get('ids',
                                                               {}).get('tvdb')
            self.item['slug'] = trakt_details.get('ids', {}).get('slug')

        if self.itemtype == 'episode':  # Do some special episode stuff
            self.item['id'] = self.item.get('tvdb')
            self.item['title'] = self.details.get('infolabels', {}).get(
                'title')  # Set Episode Title
            self.item['name'] = u'{0} S{1:02d}E{2:02d}'.format(
                self.item.get('showname'),
                int(utils.try_parse_int(self.season)),
                int(utils.try_parse_int(self.episode)))
            self.item['season'] = self.season
            self.item['episode'] = self.episode
            self.item['showpremiered'] = self.details.get(
                'infoproperties', {}).get('tvshow.premiered')
            self.item['showyear'] = self.details.get('infoproperties',
                                                     {}).get('tvshow.year')

        if self.traktapi and self.itemtype == 'episode':
            trakt_details = self.traktapi.get_details(slug_type,
                                                      self.item.get('slug'),
                                                      season=self.season,
                                                      episode=self.episode)
            self.item['epid'] = self.details.get(
                'infoproperties', {}).get('tvdb_id') or trakt_details.get(
                    'ids', {}).get('tvdb')
            self.item['epimdb'] = trakt_details.get('ids', {}).get('imdb')
            self.item['eptmdb'] = self.details.get(
                'infoproperties', {}).get('tmdb_id') or trakt_details.get(
                    'ids', {}).get('tmdb')
            self.item['eptrakt'] = trakt_details.get('ids', {}).get('trakt')

        utils.kodi_log(u'Player Details - Item:\n{}'.format(self.item), 2)

        for k, v in self.item.copy().items():
            if k not in constants.PLAYER_URLENCODE:
                continue
            v = u'{0}'.format(v)
            for key, value in {k: v, '{}_meta'.format(k): dumps(v)}.items():
                self.item[key] = value.replace(',', '')
                self.item[key + '_+'] = value.replace(',',
                                                      '').replace(' ', '+')
                self.item[key + '_-'] = value.replace(',',
                                                      '').replace(' ', '-')
                self.item[key + '_escaped'] = quote(
                    quote(utils.try_encode_string(value)))
                self.item[key + '_escaped+'] = quote(
                    quote_plus(utils.try_encode_string(value)))
                self.item[key + '_url'] = quote(utils.try_encode_string(value))
                self.item[key + '_url+'] = quote_plus(
                    utils.try_encode_string(value))

    def build_players(self, tmdbtype=None):
        basedirs = [
            'special://profile/addon_data/plugin.video.themoviedb.helper/players/'
        ]
        if self.addon.getSettingBool('bundled_players'):
            basedirs.append(
                'special://home/addons/plugin.video.themoviedb.helper/resources/players/'
            )
        for basedir in basedirs:
            files = [
                x for x in xbmcvfs.listdir(basedir)[1] if x.endswith('.json')
            ]
            for file in files:
                meta = loads(utils.read_file(basedir + file)) or {}

                self.players[file] = meta

                plugins = meta.get(
                    'plugin'
                ) or 'plugin.undefined'  # Give dummy name to undefined plugins so that they fail the check
                plugins = plugins if isinstance(plugins, list) else [
                    plugins
                ]  # Listify for simplicity of code
                for plugin in plugins:
                    if not xbmc.getCondVisibility(
                            u'System.HasAddon({0})'.format(plugin)):
                        break  # System doesn't have a required plugin so skip this player
                else:  # If the system has all the listed addons then build the player
                    tmdbtype = tmdbtype or self.tmdbtype
                    priority = utils.try_parse_int(
                        meta.get('priority')) or 1000
                    if tmdbtype == 'movie' and meta.get('search_movie'):
                        self.search_movie.append((file, priority))
                    if tmdbtype == 'movie' and meta.get('play_movie'):
                        self.play_movie.append((file, priority))
                    if tmdbtype == 'tv' and meta.get('search_episode'):
                        self.search_episode.append((file, priority))
                    if tmdbtype == 'tv' and meta.get('play_episode'):
                        self.play_episode.append((file, priority))

    def build_playeraction(self, playerfile, action, assertplayers=True):
        player = self.players.get(playerfile, {})
        isplay = True if action.startswith('play_') else False
        prefix = self.addon.getLocalizedString(32061) if action.startswith(
            'play_') else xbmc.getLocalizedString(137)
        label = u'{0} {1}'.format(prefix, player.get('name', ''))

        # Check if matches default player and set default player id
        if label == self.dp_movies:
            self.dp_movies_id = '{} {}'.format(playerfile, action)
        if label == self.dp_episodes:
            self.dp_episodes_id = '{} {}'.format(playerfile, action)

        # Check that asserted values exist
        if assertplayers:
            for i in player.get('assert', {}).get(action, []):
                if i.startswith('!'):
                    if self.item.get(i[1:]) and self.item.get(i[1:]) != 'None':
                        return  # inverted assert - has value but we don't want it so don't build that player
                else:
                    if not self.item.get(i) or self.item.get(i) == 'None':
                        return  # missing / empty asserted value so don't build that player

        # Add player action to list for dialog
        self.append_playeraction(label=label,
                                 action=player.get(action, ''),
                                 isplay=isplay,
                                 identifier='{} {}'.format(playerfile, action))

    def append_playeraction(self, label, action, isplay=True, identifier=''):
        self.itemlist.append(xbmcgui.ListItem(label))
        self.actions.append((isplay, action))
        self.identifierlist.append(identifier)

    def build_selectbox(self, clearsetting=False, assertplayers=True):
        self.itemlist, self.actions = [], []
        if clearsetting:
            self.itemlist.append(
                xbmcgui.ListItem(
                    xbmc.getLocalizedString(13403)))  # Clear Default
        if self.is_local:
            self.append_playeraction(u'{0} {1}'.format(
                self.addon.getLocalizedString(32061), 'Kodi'),
                                     self.is_local,
                                     identifier='play_kodi')
        for i in sorted(self.play_movie, key=lambda x: x[1]):
            self.build_playeraction(i[0],
                                    'play_movie',
                                    assertplayers=assertplayers)
        for i in sorted(self.search_movie, key=lambda x: x[1]):
            self.build_playeraction(i[0],
                                    'search_movie',
                                    assertplayers=assertplayers)
        for i in sorted(self.play_episode, key=lambda x: x[1]):
            self.build_playeraction(i[0],
                                    'play_episode',
                                    assertplayers=assertplayers)
        for i in sorted(self.search_episode, key=lambda x: x[1]):
            self.build_playeraction(i[0],
                                    'search_episode',
                                    assertplayers=assertplayers)
        utils.kodi_log(
            u'Player -- Built {} Players!\n{}'.format(len(self.itemlist),
                                                      self.identifierlist), 2)

    def localfile(self, file):
        if not file:
            return
        if file.endswith('.strm'):
            f = xbmcvfs.File(file)
            contents = f.read()
            f.close()
            if contents.startswith('plugin://plugin.video.themoviedb.helper'):
                return
        return file

    def localmovie(self):
        # fuzzy_match = self.addon.getSettingBool('fuzzymatch_movie')
        return self.localfile(
            KodiLibrary(dbtype='movie').get_info(
                'file',
                fuzzy_match=False,
                tmdb_id=self.item.get('tmdb_id'),
                imdb_id=self.item.get('imdb_id')))

    def localepisode(self):
        # fuzzy_match = self.addon.getSettingBool('fuzzymatch_tv')
        dbid = KodiLibrary(dbtype='tvshow').get_info(
            'dbid',
            fuzzy_match=False,
            tmdb_id=self.item.get('tmdb_id'),
            tvdb_id=self.item.get('tvdb_id'),
            imdb_id=self.item.get('imdb_id'))
        return self.localfile(
            KodiLibrary(dbtype='episode',
                        tvshowid=dbid).get_info('file',
                                                season=self.season,
                                                episode=self.episode))
class Player(Plugin):
    def __init__(self):
        super(Player, self).__init__()
        self.traktapi = TraktAPI()
        self.search_movie, self.search_episode, self.play_movie, self.play_episode = [], [], [], []
        self.item = defaultdict(lambda: '+')
        self.itemlist, self.actions, self.players, self.identifierlist = [], [], {}, []
        self.is_local = None
        self.dp_movies = self.addon.getSettingString('default_player_movies')
        self.dp_episodes = self.addon.getSettingString(
            'default_player_episodes')
        self.dp_movies_id = None
        self.dp_episodes_id = None
        self.fallbacks = {}

    def setup_players(self,
                      tmdbtype=None,
                      details=False,
                      clearsetting=False,
                      assertplayers=True):
        self.build_players(tmdbtype)
        if details:
            self.build_details()
        self.build_selectbox(clearsetting, assertplayers)

    def get_fallback(self, dp_file, dp_action):
        fallback = self.players.get(dp_file, {}).get('fallback',
                                                     {}).get(dp_action)
        if not fallback:  # No fallback so prompt dialog
            return xbmcgui.Dialog().select(
                self.addon.getLocalizedString(32042), self.itemlist)
        if fallback in self.identifierlist:  # Found a fallback in list so play that
            return self.identifierlist.index(fallback)
        fb_file, fb_action = fallback.split()
        return self.get_fallback(
            fb_file, fb_action
        )  # Fallback not in list so let's check fallback's fallback

    def get_playerindex(self, force_dialog=False):
        if force_dialog or (self.itemtype == 'movie' and
                            not self.dp_movies) or (self.itemtype == 'episode'
                                                    and not self.dp_episodes):
            return xbmcgui.Dialog().select(
                self.addon.getLocalizedString(32042), self.itemlist)
        for i in range(0, len(self.itemlist)):
            label = self.itemlist[i].getLabel()
            if ((label == self.dp_movies and self.itemtype == 'movie') or
                (label == self.dp_episodes and self.itemtype == 'episode')
                    or (label == u'{0} {1}'.format(
                        self.addon.getLocalizedString(32061), 'Kodi'))):
                return i  # Play local or with default player if found

        # Check for fallbacks
        if self.itemtype == 'movie' and self.dp_movies_id:
            dp_file, dp_action = self.dp_movies_id.split()
            return self.get_fallback(dp_file, dp_action)
        if self.itemtype == 'episode' and self.dp_episodes_id:
            dp_file, dp_action = self.dp_episodes_id.split()
            return self.get_fallback(dp_file, dp_action)

        return -1

    def play_external(self, force_dialog=False, playerindex=-1):
        if playerindex > -1:  # Previous iteration didn't find an item to play so remove it and retry
            xbmcgui.Dialog().notification(
                self.itemlist[playerindex].getLabel(),
                self.addon.getLocalizedString(32040))
            del self.actions[
                playerindex]  # Item not found so remove the player's action list
            del self.itemlist[
                playerindex]  # Item not found so remove the player's select dialog entry
            del self.identifierlist[
                playerindex]  # Item not found so remove the player's index

        playerindex = self.get_playerindex(force_dialog=force_dialog)

        # User cancelled dialog
        if not playerindex > -1:
            return False

        player = self.actions[playerindex]
        if not player or not player[1]:
            return False

        # External player has list of actions so let's iterate through them to find our item
        resolve_url = False
        if isinstance(player[1], list):
            actionlist = player[1]
            player = (False, actionlist[0])
            for d in actionlist[1:]:
                if player[0]:
                    break  # Playable item was found in last action so let's break and play it
                folder = KodiLibrary().get_directory(
                    string_format_map(
                        player[1],
                        self.item))  # Get the next folder from the plugin

                if d.get(
                        'dialog'
                ):  # Special option to show dialog of items to select from
                    d_items = []
                    for f in folder:  # Create our list of items
                        if not f.get('label') or f.get('label') == 'None':
                            continue
                        lb_list = []
                        label_a = f.get('label')
                        if f.get('year') and f.get('year') != 1601:
                            label_a = u'{} ({})'.format(label_a, f.get('year'))
                        if utils.try_parse_int(f.get(
                                'season', 0)) > 0 and utils.try_parse_int(
                                    f.get('episode', 0)) > 0:
                            label_a = u'{}x{}. {}'.format(
                                f.get('season'), f.get('episode'), label_a)
                        if f.get('streamdetails'):
                            sdv_list = f.get('streamdetails', {}).get(
                                'video', [{}]) or [{}]
                            sda_list = f.get('streamdetails', {}).get(
                                'audio', [{}]) or [{}]
                            sdv, sda = sdv_list[0], sda_list[0]
                            if sdv.get('width') or sdv.get('height'):
                                lb_list.append(u'{}x{}'.format(
                                    sdv.get('width'), sdv.get('height')))
                            if sdv.get('codec'):
                                lb_list.append(u'{}'.format(
                                    sdv.get('codec', '').upper()))
                            if sda.get('codec'):
                                lb_list.append(u'{}'.format(
                                    sda.get('codec', '').upper()))
                            if sda.get('channels'):
                                lb_list.append(u'{} CH'.format(
                                    sda.get('channels', '')))
                            for i in sda_list:
                                if i.get('language'):
                                    lb_list.append(u'{}'.format(
                                        i.get('language', '').upper()))
                            if sdv.get('duration'):
                                lb_list.append(u'{} mins'.format(
                                    utils.try_parse_int(sdv.get('duration', 0))
                                    // 60))
                        if f.get('size'):
                            lb_list.append(u'{}'.format(
                                utils.normalise_filesize(f.get('size', 0))))
                        label_b = ' | '.join(lb_list) if lb_list else ''
                        d_items.append(
                            ListItem(label=label_a,
                                     label2=label_b,
                                     icon=f.get('thumbnail')).set_listitem())
                    if d_items:
                        idx = 0
                        if d.get('dialog',
                                 '').lower() != 'auto' or len(d_items) != 1:
                            idx = xbmcgui.Dialog().select('Select Item',
                                                          d_items,
                                                          useDetails=True)
                        if idx == -1:  # User exited the dialog so return and do nothing
                            return
                        resolve_url = True if folder[idx].get(
                            'filetype'
                        ) == 'file' else False  # Set true for files so we can play
                        player = (resolve_url, folder[idx].get('file')
                                  )  # Set the folder path to open/play
                        break  # Move onto next action
                    else:  # Ask user to select a different player if no items in dialog
                        return self.play_external(force_dialog=force_dialog,
                                                  playerindex=playerindex)

                x = 0
                for f in folder:  # Iterate through plugin folder looking for a matching item
                    x += 1  # Keep an index for position matching
                    for k, v in d.items(
                    ):  # Iterate through our key (infolabel) / value (infolabel must match) pairs of our action
                        if k == 'position':  # We're looking for an item position not an infolabel
                            if utils.try_parse_int(
                                    string_format_map(v, self.item)
                            ) != x:  # Format our position value
                                break  # Not the item position we want so let's go to next item in folder
                        elif not f.get(k) or string_format_map(
                                v, self.item
                        ) not in u'{}'.format(
                                f.get(k, '')
                        ):  # Format our value and check if it matches the infolabel key
                            break  # Item's key value doesn't match value we are looking for so let's got to next item in folder
                    else:  # Item matched our criteria so let's open it up
                        resolve_url = True if f.get(
                            'filetype'
                        ) == 'file' else False  # Set true for files so we can play
                        player = (resolve_url, f.get('file')
                                  )  # Get ListItem.FolderPath for item
                        break  # Move onto next action (either open next folder or play file)
                else:
                    return self.play_external(
                        force_dialog=force_dialog, playerindex=playerindex
                    )  # Ask user to select a different player

        # Play/Search found item
        if player and player[1]:
            action = string_format_map(player[1], self.item)
            if player[0] and action.endswith(
                    '.strm'):  # Action is play and is a strm so PlayMedia
                xbmc.executebuiltin(
                    utils.try_decode_string(u'PlayMedia({0})'.format(action)))
            elif player[
                    0]:  # Action is play and not a strm so play with player
                xbmc.Player().play(
                    action,
                    ListItem(library='video', **self.details).set_listitem())
            else:
                action = u'Container.Update({0})'.format(
                    action) if xbmc.getCondVisibility(
                        "Window.IsMedia"
                    ) else u'ActivateWindow(videos,{0},return)'.format(action)
                xbmc.executebuiltin(utils.try_decode_string(action))
            return action

    def play(self,
             itemtype,
             tmdb_id,
             season=None,
             episode=None,
             force_dialog=False):
        """ Entry point for player method """
        if not tmdb_id or not itemtype:
            return

        # Get the details for the item
        self.itemtype, self.tmdb_id, self.season, self.episode = itemtype, tmdb_id, season, episode
        self.tmdbtype = 'tv' if self.itemtype in ['episode', 'tv'] else 'movie'
        self.details = self.tmdb.get_detailed_item(self.tmdbtype,
                                                   tmdb_id,
                                                   season=season,
                                                   episode=episode)
        self.item['imdb_id'] = self.details.get('infolabels',
                                                {}).get('imdbnumber')
        self.item['originaltitle'] = self.details.get('infolabels',
                                                      {}).get('originaltitle')
        self.item['title'] = self.details.get(
            'infolabels', {}).get('tvshowtitle') or self.details.get(
                'infolabels', {}).get('title')
        self.item['year'] = self.details.get('infolabels', {}).get('year')

        # Check if we have a local file
        # TODO: Add option to auto play local
        if self.details and self.itemtype == 'movie':
            self.is_local = self.localmovie()
        if self.details and self.itemtype == 'episode':
            self.is_local = self.localepisode()

        self.setup_players(details=True)

        if not self.itemlist:
            return False

        return self.play_external(force_dialog=force_dialog)

    def build_details(self):
        self.item['id'] = self.tmdb_id
        self.item['tmdb'] = self.tmdb_id
        self.item['imdb'] = self.details.get('infolabels',
                                             {}).get('imdbnumber')
        self.item['name'] = u'{0} ({1})'.format(self.item.get('title'),
                                                self.item.get('year'))
        self.item['firstaired'] = self.details.get('infolabels',
                                                   {}).get('premiered')
        self.item['premiered'] = self.details.get('infolabels',
                                                  {}).get('premiered')
        self.item['released'] = self.details.get('infolabels',
                                                 {}).get('premiered')
        self.item['showname'] = self.item.get('title')
        self.item['clearname'] = self.item.get('title')
        self.item['tvshowtitle'] = self.item.get('title')
        self.item['title'] = self.item.get('title')
        self.item['thumbnail'] = self.details.get('thumb')
        self.item['poster'] = self.details.get('poster')
        self.item['fanart'] = self.details.get('fanart')
        self.item['now'] = datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')

        if self.traktapi:
            slug_type = utils.type_convert(self.tmdbtype, 'trakt')
            trakt_details = self.traktapi.get_details(
                slug_type,
                self.traktapi.get_traktslug(slug_type, 'tmdb', self.tmdb_id))
            self.item['trakt'] = trakt_details.get('ids', {}).get('trakt')
            self.item['imdb'] = trakt_details.get('ids', {}).get('imdb')
            self.item['tvdb'] = trakt_details.get('ids', {}).get('tvdb')
            self.item['slug'] = trakt_details.get('ids', {}).get('slug')

        if self.itemtype == 'episode':  # Do some special episode stuff
            self.item['id'] = self.item.get('tvdb')
            self.item['title'] = self.details.get('infolabels', {}).get(
                'title')  # Set Episode Title
            self.item['name'] = u'{0} S{1:02d}E{2:02d}'.format(
                self.item.get('showname'),
                int(utils.try_parse_int(self.season)),
                int(utils.try_parse_int(self.episode)))
            self.item['season'] = self.season
            self.item['episode'] = self.episode

        if self.traktapi and self.itemtype == 'episode':
            trakt_details = self.traktapi.get_details(slug_type,
                                                      self.item.get('slug'),
                                                      season=self.season,
                                                      episode=self.episode)
            self.item['epid'] = trakt_details.get('ids', {}).get('tvdb')
            self.item['epimdb'] = trakt_details.get('ids', {}).get('imdb')
            self.item['eptmdb'] = trakt_details.get('ids', {}).get('tmdb')
            self.item['eptrakt'] = trakt_details.get('ids', {}).get('trakt')

        for k, v in self.item.copy().items():
            v = u'{0}'.format(v)
            self.item[k] = v.replace(',', '')
            self.item[k + '_+'] = v.replace(' ', '+')
            self.item[k + '_-'] = v.replace(' ', '-')
            self.item[k + '_escaped'] = v.replace(' ', '%2520')
            self.item[k + '_escaped+'] = v.replace(' ', '%252B')
            self.item[k + '_url'] = quote_plus(utils.try_encode_string(v))

    def build_players(self, tmdbtype=None):
        basedirs = [
            'special://profile/addon_data/plugin.video.themoviedb.helper/players/'
        ]
        if self.addon.getSettingBool('bundled_players'):
            basedirs.append(
                'special://home/addons/plugin.video.themoviedb.helper/resources/players/'
            )
        for basedir in basedirs:
            files = [
                x for x in xbmcvfs.listdir(basedir)[1] if x.endswith('.json')
            ]
            for file in files:
                vfs_file = xbmcvfs.File(basedir + file)
                try:
                    content = vfs_file.read()
                    meta = loads(content) or {}
                finally:
                    vfs_file.close()

                self.players[file] = meta
                if not meta.get('plugin') or not xbmc.getCondVisibility(
                        u'System.HasAddon({0})'.format(meta.get('plugin'))):
                    continue  # Don't have plugin so skip

                tmdbtype = tmdbtype or self.tmdbtype
                priority = utils.try_parse_int(meta.get('priority')) or 1000
                if tmdbtype == 'movie' and meta.get('search_movie'):
                    self.search_movie.append((file, priority))
                if tmdbtype == 'movie' and meta.get('play_movie'):
                    self.play_movie.append((file, priority))
                if tmdbtype == 'tv' and meta.get('search_episode'):
                    self.search_episode.append((file, priority))
                if tmdbtype == 'tv' and meta.get('play_episode'):
                    self.play_episode.append((file, priority))

    def build_playeraction(self, playerfile, action, assertplayers=True):
        player = self.players.get(playerfile, {})
        isplay = True if action.startswith('play_') else False
        prefix = self.addon.getLocalizedString(32061) if action.startswith(
            'play_') else xbmc.getLocalizedString(137)
        label = u'{0} {1}'.format(prefix, player.get('name', ''))

        # Check if matches default player and set default player id
        if label == self.dp_movies:
            self.dp_movies_id = '{} {}'.format(playerfile, action)
        if label == self.dp_episodes:
            self.dp_episodes_id = '{} {}'.format(playerfile, action)

        # Check that asserted values exist
        if assertplayers:
            for i in player.get('assert', {}).get(action, []):
                if i.startswith('!'):
                    if self.item.get(i[1:]) and self.item.get(i[1:]) != 'None':
                        return  # inverted assert - has value but we don't want it so don't build that player
                else:
                    if not self.item.get(i) or self.item.get(i) == 'None':
                        return  # missing / empty asserted value so don't build that player

        # Add player action to list for dialog
        self.append_playeraction(label=label,
                                 action=player.get(action, ''),
                                 isplay=isplay,
                                 identifier='{} {}'.format(playerfile, action))

    def append_playeraction(self, label, action, isplay=True, identifier=''):
        self.itemlist.append(xbmcgui.ListItem(label))
        self.actions.append((isplay, action))
        self.identifierlist.append(identifier)

    def build_selectbox(self, clearsetting=False, assertplayers=True):
        self.itemlist, self.actions = [], []
        if clearsetting:
            self.itemlist.append(
                xbmcgui.ListItem(
                    xbmc.getLocalizedString(13403)))  # Clear Default
        if self.is_local:
            self.append_playeraction(u'{0} {1}'.format(
                self.addon.getLocalizedString(32061), 'Kodi'),
                                     self.is_local,
                                     identifier='play_kodi')
        for i in sorted(self.play_movie, key=lambda x: x[1]):
            self.build_playeraction(i[0],
                                    'play_movie',
                                    assertplayers=assertplayers)
        for i in sorted(self.search_movie, key=lambda x: x[1]):
            self.build_playeraction(i[0],
                                    'search_movie',
                                    assertplayers=assertplayers)
        for i in sorted(self.play_episode, key=lambda x: x[1]):
            self.build_playeraction(i[0],
                                    'play_episode',
                                    assertplayers=assertplayers)
        for i in sorted(self.search_episode, key=lambda x: x[1]):
            self.build_playeraction(i[0],
                                    'search_episode',
                                    assertplayers=assertplayers)

    def localfile(self, file):
        if not file:
            return
        if file.endswith('.strm'):
            f = xbmcvfs.File(file)
            contents = f.read()
            f.close()
            if contents.startswith('plugin://plugin.video.themoviedb.helper'):
                return
        return file

    def localmovie(self):
        fuzzy_match = self.addon.getSettingBool('fuzzymatch_movie')
        return self.localfile(
            KodiLibrary(dbtype='movie').get_info('file',
                                                 fuzzy_match=fuzzy_match,
                                                 **self.item))

    def localepisode(self):
        fuzzy_match = self.addon.getSettingBool('fuzzymatch_tv')
        fuzzy_match = True  # TODO: Get tvshow year to match against but for now force fuzzy match
        dbid = KodiLibrary(dbtype='tvshow').get_info('dbid',
                                                     fuzzy_match=fuzzy_match,
                                                     **self.item)
        return self.localfile(
            KodiLibrary(dbtype='episode',
                        tvshowid=dbid).get_info('file',
                                                season=self.season,
                                                episode=self.episode))
def action(action, tmdb_id=None, tmdb_type=None, season=None, episode=None, label=None):
    _traktapi = TraktAPI()

    if action == 'history':
        func = _traktapi.sync_history
    elif action == 'collection':
        func = _traktapi.sync_collection
    elif action == 'watchlist':
        func = _traktapi.sync_watchlist
    elif action == 'add_to_userlist':
        return sync_userlist()
    elif action == 'remove_from_userlist':
        return sync_userlist(remove_item=True)
    elif action == 'library_userlist':
        return library_userlist()
    elif action == 'library':
        return library()
    elif action == 'refresh_item':
        return refresh_item()
    elif action == 'play':
        return play()
    elif action == 'open':
        return browse()
    else:
        return

    with utils.busy_dialog():
        if tmdb_id and tmdb_type:  # Passed details via script
            dbtype = utils.type_convert(tmdb_type, 'dbtype')
            label = label or 'this {}'.format(utils.type_convert(tmdb_type, 'trakt'))
            parent_tmdb_id = tmdb_id
        else:  # Context menu so retrieve details from listitem
            label = sys.listitem.getLabel()
            dbtype = sys.listitem.getVideoInfoTag().getMediaType()
            tmdb_id = sys.listitem.getProperty('tmdb_id')
            parent_tmdb_id = sys.listitem.getProperty('tvshow.tmdb_id') if dbtype == 'episode' else tmdb_id
            season = sys.listitem.getVideoInfoTag().getSeason() if dbtype == 'episode' else None
            episode = sys.listitem.getVideoInfoTag().getEpisode() if dbtype == 'episode' else None

        if tmdb_type == 'episode':  # Passed episode details via script
            if not season or not episode:  # Need season and episode for episodes
                return  # Need season and episode if run from script so leave
            # Retrieve episode details so that we can get tmdb_id for episode
            episode_details = _plugin.tmdb.get_detailed_item(tmdb_type, parent_tmdb_id, season=season, episode=episode)
            tmdb_id = episode_details.get('infoproperties', {}).get('imdb_id')

        if dbtype == 'movie':
            tmdb_type = 'movie'
        elif dbtype == 'tvshow':
            tmdb_type = 'tv'
        elif dbtype == 'episode':
            tmdb_type = 'episode'
        else:
            return

        # Check if we're adding or removing the item and confirm with the user that they want to do that
        trakt_ids = func(utils.type_convert(tmdb_type, 'trakt'), 'tmdb', cache_refresh=True)
        boolean = 'remove' if int(tmdb_id) in trakt_ids else 'add'
        dialog_header = 'Trakt {0}'.format(action.capitalize())
        dialog_text = xbmcaddon.Addon().getLocalizedString(32065) if boolean == 'add' else xbmcaddon.Addon().getLocalizedString(32064)
        dialog_text = dialog_text.format(utils.try_decode_string(label), action.capitalize(), tmdb_type, tmdb_id)
        dialog_text = dialog_text + ' Season: {}  Episode: {}'.format(season, episode) if dbtype == 'episode' else dialog_text
        if not xbmcgui.Dialog().yesno(dialog_header, dialog_text):
            return

        with utils.busy_dialog():
            slug_type = 'show' if tmdb_type == 'episode' else utils.type_convert(tmdb_type, 'trakt')
            trakt_type = utils.type_convert(tmdb_type, 'trakt')
            slug = _traktapi.get_traktslug(slug_type, 'tmdb', parent_tmdb_id)
            item = _traktapi.get_details(slug_type, slug, season=season, episode=episode)
            items = {trakt_type + 's': [item]}
            func(slug_type, mode=boolean, items=items)

        dialog_header = 'Trakt {0}'.format(action.capitalize())
        dialog_text = xbmcaddon.Addon().getLocalizedString(32062) if boolean == 'add' else xbmcaddon.Addon().getLocalizedString(32063)
        dialog_text = dialog_text.format(tmdb_id, action.capitalize())
        xbmcgui.Dialog().ok(dialog_header, dialog_text)
        xbmc.executebuiltin('Container.Refresh')
Esempio n. 24
0
    def library_autoupdate(self, list_slug=None, user_slug=None):
        utils.kodi_log(u'UPDATING TV SHOWS LIBRARY', 1)
        xbmcgui.Dialog().notification(
            'TMDbHelper',
            u'{}...'.format(self.addon.getLocalizedString(32167)))

        busy_dialog = True if self.params.get('busy_dialog') else False
        basedir_tv = self.addon.getSettingString(
            'tvshows_library'
        ) or 'special://profile/addon_data/plugin.video.themoviedb.helper/tvshows/'

        # Update library from Trakt lists
        user_name = TraktAPI().get_usernameslug()
        list_slug = list_slug or self.addon.getSettingString(
            'monitor_userlist') or ''
        user_slug = user_slug or self.addon.getSettingString(
            'monitor_userslug') or ''
        if list_slug:
            list_slugs = list_slug.split(' | ')
            user_slugs = user_slug.split(' | ') if user_slug else [
                user_name for i in list_slugs
            ]  # List comprehension in else condition for backwards compatibility. Previous versions didnt store user slugs because could only be the main user.
            for idx, i in enumerate(list_slugs):
                libraryupdate.add_userlist(user_slug=user_slugs[idx],
                                           list_slug=i,
                                           confirm=False,
                                           allow_update=False,
                                           busy_dialog=busy_dialog,
                                           force=self.params.get(
                                               'force', False))

        # Create our extended progress bg dialog
        p_dialog = xbmcgui.DialogProgressBG() if busy_dialog else None
        p_dialog.create('TMDbHelper', u'{}...'.format(
            self.addon.getLocalizedString(32167))) if p_dialog else None

        # Get TMDb IDs from .nfo files in the basedir
        nfos = []
        for f in xbmcvfs.listdir(basedir_tv)[0]:
            tmdb_id = utils.get_tmdbid_nfo(basedir_tv, f)
            if tmdb_id:
                nfos.append({'tmdb_id': tmdb_id, 'folder': f})

        for n_count, nfo in enumerate(nfos):
            if not nfo.get('folder') or not nfo.get('tmdb_id'):
                continue
            if p_dialog:
                p_dialog_val = ((n_count + 1) * 100) // len(nfos)
                p_dialog_msg = u'{} {}...'.format(
                    self.addon.getLocalizedString(32167), nfo.get('folder'))
                p_dialog.update(p_dialog_val, message=p_dialog_msg)
            url = 'plugin://plugin.video.themoviedb.helper/?info=seasons&tmdb_id={}&type=tv'.format(
                nfo.get('tmdb_id'))
            libraryupdate.add_tvshow(basedir=basedir_tv,
                                     folder=nfo.get('folder'),
                                     url=url,
                                     tmdb_id=nfo.get('tmdb_id'),
                                     p_dialog=p_dialog)

        if p_dialog:
            p_dialog.close()

        self.addon.setSettingString(
            'last_autoupdate',
            'Last updated {}'.format(utils.get_currentdatetime()))

        if self.addon.getSettingBool('auto_update'):
            xbmc.executebuiltin('UpdateLibrary(video)')