示例#1
0
    def addShowToBlacklist(self, seriesid):
        # URL parameters
        data = {'shows': [{'ids': {'tvdb': seriesid}}]}

        trakt_settings = {
            'trakt_api_secret': app.TRAKT_API_SECRET,
            'trakt_api_key': app.TRAKT_API_KEY,
            'trakt_access_token': app.TRAKT_ACCESS_TOKEN,
            'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN
        }

        show_name = get_showname_from_indexer(INDEXER_TVDBV2, seriesid)
        try:
            trakt_api = TraktApi(timeout=app.TRAKT_TIMEOUT,
                                 ssl_verify=app.SSL_VERIFY,
                                 **trakt_settings)
            trakt_api.request('users/{0}/lists/{1}/items'.format(
                app.TRAKT_USERNAME, app.TRAKT_BLACKLIST_NAME),
                              data,
                              method='POST')
            ui.notifications.message(
                'Success!', "Added show '{0}' to blacklist".format(show_name))
        except Exception as e:
            ui.notifications.error(
                'Error!',
                "Unable to add show '{0}' to blacklist. Check logs.".format(
                    show_name))
            logger.log(
                "Error while adding show '{0}' to trakt blacklist: {1}".format(
                    show_name, e), logger.WARNING)
示例#2
0
    def test_notify(username, blacklist_name=None):
        """
        Sends a test notification to trakt with the given authentication info and returns a boolean
        representing success.

        api: The api string to use
        username: The username to use
        blacklist_name: slug of trakt list used to hide not interested show

        Returns: True if the request succeeded, False otherwise
        """
        try:
            trakt_settings = {'trakt_api_secret': app.TRAKT_API_SECRET,
                              'trakt_api_key': app.TRAKT_API_KEY,
                              'trakt_access_token': app.TRAKT_ACCESS_TOKEN}

            trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT, **trakt_settings)
            trakt_api.validate_account()
            if blacklist_name and blacklist_name is not None:
                trakt_lists = trakt_api.request('users/' + username + '/lists')
                found = False
                for trakt_list in trakt_lists:
                    if trakt_list['ids']['slug'] == blacklist_name:
                        return 'Test notice sent successfully to Trakt'
                if not found:
                    return "Trakt blacklist doesn't exists"
            else:
                return 'Test notice sent successfully to Trakt'
        except (TraktException, AuthException, ServerBusy) as trakt_ex:
            logger.log('Could not connect to Trakt service: {0}'.format(ex(trakt_ex)), logger.WARNING)
            return 'Test notice failed to Trakt: {0}'.format(ex(trakt_ex))
示例#3
0
    def test_notify(username, blacklist_name=None):
        """Send a test notification to trakt with the given authentication info and returns a boolean.

        api: The api string to use
        username: The username to use
        blacklist_name: slug of trakt list used to hide not interested show
        Returns: True if the request succeeded, False otherwise
        """
        try:
            trakt_settings = {
                'trakt_api_secret': app.TRAKT_API_SECRET,
                'trakt_api_key': app.TRAKT_API_KEY,
                'trakt_access_token': app.TRAKT_ACCESS_TOKEN,
                'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN
            }

            trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT,
                                 **trakt_settings)
            trakt_api.validate_account()
            if blacklist_name and blacklist_name is not None:
                trakt_lists = trakt_api.request('users/' + username + '/lists')
                found = False
                for trakt_list in trakt_lists:
                    if trakt_list['ids']['slug'] == blacklist_name:
                        return 'Test notice sent successfully to Trakt'
                if not found:
                    return "Trakt blacklist doesn't exists"
            else:
                return 'Test notice sent successfully to Trakt'
        except (TokenExpiredException, TraktException, AuthException) as error:
            log.warning('Unable to test TRAKT: {0}', error.message)
            return 'Test notice failed to Trakt: {0}'.format(error.message)
示例#4
0
    def addShowToBlacklist(self, seriesid):
        # URL parameters
        data = {'shows': [{'ids': {'tvdb': seriesid}}]}

        trakt_settings = {'trakt_api_secret': app.TRAKT_API_SECRET,
                          'trakt_api_key': app.TRAKT_API_KEY,
                          'trakt_access_token': app.TRAKT_ACCESS_TOKEN,
                          'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN}

        show_name = get_showname_from_indexer(INDEXER_TVDBV2, seriesid)
        try:
            trakt_api = TraktApi(timeout=app.TRAKT_TIMEOUT, ssl_verify=app.SSL_VERIFY, **trakt_settings)
            trakt_api.request('users/{0}/lists/{1}/items'.format
                              (app.TRAKT_USERNAME, app.TRAKT_BLACKLIST_NAME), data, method='POST')
            ui.notifications.message('Success!',
                                     "Added show '{0}' to blacklist".format(show_name))
        except Exception as e:
            ui.notifications.error('Error!',
                                   "Unable to add show '{0}' to blacklist. Check logs.".format(show_name))
            log.warning("Error while adding show '{name}' to trakt blacklist: {error}",
                        {'name': show_name, 'error': e})
示例#5
0
    def update_library(ep_obj):
        """
        Sends a request to trakt indicating that the given episode is part of our library.

        ep_obj: The TVEpisode object to add to trakt
        """

        trakt_id = app.indexerApi(ep_obj.show.indexer).config['trakt_id']
        # Create a trakt settings dict
        trakt_settings = {'trakt_api_secret': app.TRAKT_API_SECRET,
                          'trakt_api_key': app.TRAKT_API_KEY,
                          'trakt_access_token': app.TRAKT_ACCESS_TOKEN}

        trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT, **trakt_settings)

        if app.USE_TRAKT:
            try:
                # URL parameters
                data = {
                    'shows': [
                        {
                            'title': ep_obj.show.name,
                            'year': ep_obj.show.startyear,
                            'ids': {},
                        }
                    ]
                }

                if trakt_id == 'tvdb_id':
                    data['shows'][0]['ids']['tvdb'] = ep_obj.show.indexerid
                else:
                    data['shows'][0]['ids']['tvrage'] = ep_obj.show.indexerid

                if app.TRAKT_SYNC_WATCHLIST:
                    if app.TRAKT_REMOVE_SERIESLIST:
                        trakt_api.request('sync/watchlist/remove', data, method='POST')

                # Add Season and Episode + Related Episodes
                data['shows'][0]['seasons'] = [{'number': ep_obj.season, 'episodes': []}]

                for relEp_Obj in [ep_obj] + ep_obj.related_episodes:
                    data['shows'][0]['seasons'][0]['episodes'].append({'number': relEp_Obj.episode})

                if app.TRAKT_SYNC_WATCHLIST:
                    if app.TRAKT_REMOVE_WATCHLIST:
                        trakt_api.request('sync/watchlist/remove', data, method='POST')

                # update library
                trakt_api.request('sync/collection', data, method='POST')

            except (TraktException, AuthException, ServerBusy) as trakt_ex:
                logger.log('Could not connect to Trakt service: {0}'.format(ex(trakt_ex)), logger.WARNING)
示例#6
0
class TraktChecker(object):
    def __init__(self):
        trakt_settings = {'trakt_api_key': app.TRAKT_API_KEY,
                          'trakt_api_secret': app.TRAKT_API_SECRET,
                          'trakt_access_token': app.TRAKT_ACCESS_TOKEN}
        self.trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT, **trakt_settings)
        self.todoWanted = []
        self.show_watchlist = {}
        self.episode_watchlist = {}
        self.collection_list = {}
        self.amActive = False

    def run(self, force=False):  # pylint: disable=unused-argument
        self.amActive = True

        # add shows from Trakt watchlist
        if app.TRAKT_SYNC_WATCHLIST:
            self.todoWanted = []  # its about to all get re-added
            if len(app.ROOT_DIRS.split('|')) < 2:
                logger.log('No default root directory', logger.WARNING)
                ui.notifications.error('Unable to add show',
                                       'You do not have any default root directory configured. '
                                       'Please configure in general settings!')
                return

            try:
                self.sync_watchlist()
            except Exception:
                logger.log(traceback.format_exc(), logger.DEBUG)

            try:
                # sync Trakt library with medusa library
                self.sync_library()
            except Exception:
                logger.log(traceback.format_exc(), logger.DEBUG)

        self.amActive = False

    def find_show(self, indexerid):

        try:
            trakt_library = self.trakt_api.request('sync/collection/shows') or []
            if self.trakt_api.access_token_refreshed:
                app.TRAKT_ACCESS_TOKEN = self.trakt_api.access_token

            if not trakt_library:
                logger.log('No shows found in your library, aborting library update', logger.DEBUG)
                return

            trakt_show = [x for x in trakt_library if int(indexerid) in [int(x['show']['ids']['tvdb'] or 0), int(x['show']['ids']['tvrage'] or 0)]]
        except TraktException as e:
            logger.log('Could not connect to Trakt. Aborting library check. Error: {0}'.format(repr(e)), logger.WARNING)

        return trakt_show if trakt_show else None

    def remove_show_trakt_library(self, show_obj):
        """Remove Show from trakt collections"""
        if self.find_show(show_obj.indexerid):
            trakt_id = app.indexerApi(show_obj.indexer).config['trakt_id']

            # URL parameters
            data = {
                'shows': [
                    {
                        'title': show_obj.name,
                        'year': show_obj.startyear,
                        'ids': {}
                    }
                ]
            }

            if trakt_id == 'tvdb_id':
                data['shows'][0]['ids']['tvdb'] = show_obj.indexerid
            else:
                data['shows'][0]['ids']['tvrage'] = show_obj.indexerid

            logger.log('Removing {0} from Trakt library'.format(show_obj.name), logger.DEBUG)

            # Remove all episodes from the Trakt collection for this show
            try:
                self.remove_episode_trakt_collection(filter_show=show_obj)
            except TraktException as e:
                logger.log('Could not connect to Trakt. Aborting removing episodes for show {0} from Trakt library. Error: {1}'.
                           format(show_obj.name, repr(e)), logger.WARNING)

            try:
                self.trakt_api.request('sync/collection/remove', data, method='POST')
            except TraktException as e:
                logger.log('Could not connect to Trakt. Aborting removing show {0} from Trakt library. Error: {1}'.
                           format(show_obj.name, repr(e)), logger.WARNING)

    def add_show_trakt_library(self, show_obj):
        """
        Sends a request to trakt indicating that the given show and all its episodes is part of our library.

        show_obj: The TVShow object to add to trakt
        """
        data = {}

        if not self.find_show(show_obj.indexerid):
            trakt_id = app.indexerApi(show_obj.indexer).config['trakt_id']
            # URL parameters
            data = {
                'shows': [
                    {
                        'title': show_obj.name,
                        'year': show_obj.startyear,
                        'ids': {}
                    }
                ]
            }

            if trakt_id == 'tvdb_id':
                data['shows'][0]['ids']['tvdb'] = show_obj.indexerid
            else:
                data['shows'][0]['ids']['tvrage'] = show_obj.indexerid

        if data:
            logger.log('Adding {0} to Trakt library'.format(show_obj.name), logger.DEBUG)

            try:
                self.trakt_api.request('sync/collection', data, method='POST')
            except TraktException as e:
                logger.log('Could not connect to Trakt. Aborting adding show {0} to Trakt library. Error: {1}'.format(show_obj.name, repr(e)), logger.WARNING)
                return

    def sync_library(self):
        if app.TRAKT_SYNC and app.USE_TRAKT:
            logger.log('Starting to sync Medusa with Trakt collection', logger.DEBUG)

            if self._get_show_collection():
                self.add_episode_trakt_collection()
                if app.TRAKT_SYNC_REMOVE:
                    self.remove_episode_trakt_collection()

    def remove_episode_trakt_collection(self, filter_show=None):
        if app.TRAKT_SYNC_REMOVE and app.TRAKT_SYNC and app.USE_TRAKT:

            params = []
            main_db_con = db.DBConnection()
            sql_selection = b'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode, tv_episodes.status,' \
                            b'tv_episodes.location from tv_episodes, tv_shows where tv_shows.indexer_id = tv_episodes.showid'
            if filter_show:
                sql_selection += b' AND tv_shows.indexer_id = ? AND tv_shows.indexer = ?'
                params = [filter_show.indexerid, filter_show.indexer]

            episodes = main_db_con.select(sql_selection, params)

            if episodes:
                trakt_data = []

                for cur_episode in episodes:
                    trakt_id = app.indexerApi(cur_episode[b'indexer']).config['trakt_id']

                    if self._check_list(trakt_id, cur_episode[b'showid'], cur_episode[b'season'], cur_episode[b'episode'],
                                        List='Collection'):

                        if cur_episode[b'location'] == '':
                            logger.log('Removing Episode {show} {ep} from collection'.format
                                       (show=cur_episode[b'show_name'],
                                        ep=episode_num(cur_episode[b'season'], cur_episode[b'episode'])),
                                       logger.DEBUG)
                            trakt_data.append((cur_episode[b'showid'], cur_episode[b'indexer'], cur_episode[b'show_name'],
                                               cur_episode[b'startyear'], cur_episode[b'season'], cur_episode[b'episode']))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self.trakt_api.request('sync/collection/remove', data, method='POST')
                        self._get_show_collection()
                    except TraktException as e:
                        logger.log('Could not connect to Trakt. Error: {0}'.format(ex(e)), logger.WARNING)

    def add_episode_trakt_collection(self):
        """Add all episodes from local library to Trakt collections. Enabled through app.TRAKT_SYNC_WATCHLIST setting"""
        if app.TRAKT_SYNC and app.USE_TRAKT:

            main_db_con = db.DBConnection()
            selection_status = ['?' for _ in Quality.DOWNLOADED + Quality.ARCHIVED]
            sql_selection = b'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, ' \
                            b'episode from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid ' \
                            b"and tv_episodes.status in ({0}) and tv_episodes.location <> ''".format(','.join(selection_status))
            episodes = main_db_con.select(sql_selection, Quality.DOWNLOADED + Quality.ARCHIVED)

            if episodes:
                trakt_data = []

                for cur_episode in episodes:
                    trakt_id = app.indexerApi(cur_episode[b'indexer']).config['trakt_id']

                    if not self._check_list(trakt_id, cur_episode[b'showid'], cur_episode[b'season'], cur_episode[b'episode'], List='Collection'):
                        logger.log('Adding Episode {show} {ep} to collection'.format
                                   (show=cur_episode[b'show_name'],
                                    ep=episode_num(cur_episode[b'season'], cur_episode[b'episode'])),
                                   logger.DEBUG)
                        trakt_data.append((cur_episode[b'showid'], cur_episode[b'indexer'], cur_episode[b'show_name'], cur_episode[b'startyear'], cur_episode[b'season'], cur_episode[b'episode']))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self.trakt_api.request('sync/collection', data, method='POST')
                        self._get_show_collection()
                    except TraktException as e:
                        logger.log('Could not connect to Trakt. Error: {0}'.format(ex(e)), logger.WARNING)

    def sync_watchlist(self):
        if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT:
            logger.log('Starting to sync Medusa with Trakt Watchlist', logger.DEBUG)

            self.remove_from_library()

            if self._get_show_watchlist():
                logger.log('Syncing shows with Trakt watchlist', logger.DEBUG)
                self.add_show_watchlist()
                self.fetch_trakt_shows()

            if self._get_episode_watchlist():
                logger.log('Syncing episodes with Trakt watchlist', logger.DEBUG)
                self.remove_episode_watchlist()
                self.add_episode_watchlist()
                self.fetch_trakt_episodes()

            logger.log('Medusa is synced with Trakt watchlist', logger.DEBUG)

    def remove_episode_watchlist(self):
        if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT:

            main_db_con = db.DBConnection()
            sql_selection = b'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode, ' \
                            b'tv_episodes.status from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid'
            episodes = main_db_con.select(sql_selection)

            if episodes:
                trakt_data = []

                for cur_episode in episodes:
                    trakt_id = app.indexerApi(cur_episode[b'indexer']).config['trakt_id']

                    if self._check_list(trakt_id, cur_episode[b'showid'], cur_episode[b'season'], cur_episode[b'episode']):
                        if cur_episode[b'status'] not in Quality.SNATCHED + Quality.SNATCHED_PROPER + [UNKNOWN] + [WANTED]:
                            logger.log('Removing Episode {show} {ep} from watchlist'.format
                                       (show=cur_episode[b'show_name'],
                                        ep=episode_num(cur_episode[b'season'], cur_episode[b'episode'])),
                                       logger.DEBUG)
                            trakt_data.append((cur_episode[b'showid'], cur_episode[b'indexer'], cur_episode[b'show_name'], cur_episode[b'startyear'], cur_episode[b'season'], cur_episode[b'episode']))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self.trakt_api.request('sync/watchlist/remove', data, method='POST')
                        self._get_episode_watchlist()
                    except TraktException as e:
                        logger.log('Could not connect to Trakt. Error: {0}'.format(ex(e)), logger.WARNING)

    def add_episode_watchlist(self):
        if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT:

            main_db_con = db.DBConnection()
            selection_status = [b'?' for _ in Quality.SNATCHED + Quality.SNATCHED_PROPER + [WANTED]]
            sql_selection = b'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode from tv_episodes, ' \
                            b'tv_shows where tv_shows.indexer_id = tv_episodes.showid and tv_episodes.status in ({0})'.format(b','.join(selection_status))
            episodes = main_db_con.select(sql_selection, Quality.SNATCHED + Quality.SNATCHED_PROPER + [WANTED])

            if episodes:
                trakt_data = []

                for cur_episode in episodes:
                    trakt_id = app.indexerApi(cur_episode[b'indexer']).config['trakt_id']

                    if not self._check_list(trakt_id, cur_episode[b'showid'], cur_episode[b'season'], cur_episode[b'episode']):
                        logger.log('Adding Episode {show} {ep} to watchlist'.format
                                   (show=cur_episode[b'show_name'],
                                    ep=episode_num(cur_episode[b'season'], cur_episode[b'episode'])),
                                   logger.DEBUG)
                        trakt_data.append((cur_episode[b'showid'], cur_episode[b'indexer'], cur_episode[b'show_name'], cur_episode[b'startyear'], cur_episode[b'season'],
                                           cur_episode[b'episode']))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self.trakt_api.request('sync/watchlist', data, method='POST')
                        self._get_episode_watchlist()
                    except TraktException as e:
                        logger.log('Could not connect to Trakt. Error: {0}'.format(ex(e)), logger.WARNING)

    def add_show_watchlist(self):
        if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT:
            logger.log('Syncing shows to Trakt watchlist', logger.DEBUG)

            if app.showList:
                trakt_data = []

                for show_obj in app.showList:
                    trakt_id = app.indexerApi(show_obj.indexer).config['trakt_id']

                    if not self._check_list(trakt_id, show_obj.indexerid, 0, 0, List='Show'):
                        logger.log('Adding Show {0} with ID: {1} to Trakt watchlist'.format(show_obj.name, show_obj.indexerid), logger.DEBUG)
                        show_el = {'title': show_obj.name, 'year': show_obj.startyear, 'ids': {}}
                        if trakt_id == 'tvdb_id':
                            show_el['ids']['tvdb'] = show_obj.indexerid
                        else:
                            show_el['ids']['tvrage'] = show_obj.indexerid
                        trakt_data.append(show_el)

                if trakt_data:
                    try:
                        data = {'shows': trakt_data}
                        self.trakt_api.request('sync/watchlist', data, method='POST')
                        self._get_show_watchlist()
                    except TraktException as e:
                        logger.log('Could not connect to Trakt. Error: {0}'.format(ex(e)), logger.WARNING)

    def remove_from_library(self):
        if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT and app.TRAKT_REMOVE_SHOW_FROM_APPLICATION:
            logger.log('Retrieving ended/completed shows to remove from Medusa', logger.DEBUG)

            if app.showList:
                for show in app.showList:
                    if show.status == 'Ended':
                        if not show.imdbid:
                            logger.log('Could not check trakt progress for {0} because the imdb id is missing from tvdb data, skipping'.format
                                       (show.name), logger.WARNING)
                            continue

                        try:
                            progress = self.trakt_api.request('shows/{0}/progress/watched'.format(show.imdbid)) or []
                            if self.trakt_api.access_token_refreshed:
                                app.TRAKT_ACCESS_TOKEN = self.trakt_api.access_token
                        except TraktException as e:
                            logger.log('Could not connect to Trakt. Aborting removing show {0} from Medusa. Error: {1}'.format(show.name, repr(e)), logger.WARNING)
                            continue

                        if not progress:
                            continue

                        if progress.get('aired', True) == progress.get('completed', False):
                            app.showQueueScheduler.action.removeShow(show, full=True)
                            logger.log('Show {0} has been removed from Medusa'.format(show.name), logger.DEBUG)

    def fetch_trakt_shows(self):

        if not self.show_watchlist:
            logger.log('No shows found in your watchlist, aborting watchlist update', logger.DEBUG)
        else:
            indexer = int(app.TRAKT_DEFAULT_INDEXER)
            trakt_id = app.indexerApi(indexer).config['trakt_id']

            for watchlisted_show in self.show_watchlist[trakt_id]:
                indexer_id = int(watchlisted_show)
                show_obj = self.show_watchlist[trakt_id][watchlisted_show]
                if show_obj['year'] and show_obj['slug'].endswith(str(show_obj['year'])):
                    show_name = '{0} ({1})'.format(show_obj['title'], show_obj['year'])
                else:
                    show_name = show_obj['title']

                if int(app.TRAKT_METHOD_ADD) != 2:
                    self.add_show(indexer, indexer_id, show_name, SKIPPED)
                else:
                    self.add_show(indexer, indexer_id, show_name, WANTED)

                if int(app.TRAKT_METHOD_ADD) == 1:
                    new_show = Show.find(app.showList, indexer_id)

                    if new_show:
                        setEpisodeToWanted(new_show, 1, 1)
                    else:
                        self.todoWanted.append(indexer_id, 1, 1)

    def fetch_trakt_episodes(self):
        """
        Sets episodes to wanted that are in trakt watchlist
        """
        logger.log(u"Retrieving episodes to sync with Trakt episode's watchlist", logger.DEBUG)

        if not self.episode_watchlist:
            logger.log('No episode found in your watchlist, aborting episode update', logger.DEBUG)
            return

        managed_show = []

        indexer = int(app.TRAKT_DEFAULT_INDEXER)
        trakt_id = app.indexerApi(indexer).config['trakt_id']

        for watchlist_item in self.episode_watchlist[trakt_id]:
            indexer_id = int(watchlist_item)
            show = self.episode_watchlist[trakt_id][watchlist_item]

            new_show = Show.find(app.showList, indexer_id)

            try:
                if not new_show:
                    if indexer_id not in managed_show:
                        self.add_show(indexer, indexer_id, show['title'], SKIPPED)
                        managed_show.append(indexer_id)

                        for season_item in show['seasons']:
                            season = int(season_item)

                            for episode_item in show['seasons'][season_item]['episodes']:
                                self.todoWanted.append((indexer_id, season, int(episode_item)))
                else:
                    if new_show.indexer == indexer:
                        for season_item in show['seasons']:
                            season = int(season_item)

                            for episode_item in show['seasons'][season_item]['episodes']:
                                setEpisodeToWanted(new_show, season, int(episode_item))
            except TypeError:
                logger.log('Could not parse the output from trakt for {0} '.format(show['title']), logger.DEBUG)

    @staticmethod
    def add_show(indexer, indexer_id, show_name, status):
        """
        Adds a new show with the default settings
        """
        if not Show.find(app.showList, int(indexer_id)):
            root_dirs = app.ROOT_DIRS.split('|')

            location = root_dirs[int(root_dirs[0]) + 1] if root_dirs else None

            if location:
                logger.log('Adding show {0} with ID: {1}'.format(show_name, indexer_id))

                app.showQueueScheduler.action.addShow(indexer, indexer_id, None,
                                                      default_status=status,
                                                      quality=int(app.QUALITY_DEFAULT),
                                                      flatten_folders=int(app.FLATTEN_FOLDERS_DEFAULT),
                                                      paused=app.TRAKT_START_PAUSED,
                                                      default_status_after=status, root_dir=location)
            else:
                logger.log('There was an error creating the show, no root directory setting found', logger.WARNING)
                return

    def manage_new_show(self, show):
        logger.log('Checking if trakt watchlist wants to search for episodes from new show {0}'.format(show.name), logger.DEBUG)
        episodes = [i for i in self.todoWanted if i[0] == show.indexerid]

        for episode in episodes:
            self.todoWanted.remove(episode)
            setEpisodeToWanted(show, episode[1], episode[2])

    def _check_list(self, trakt_id, showid, season, episode, List=None): # pylint: disable=too-many-arguments
        """
         Check in the Watchlist or collection list for Show
         Is the Show, Season and Episode in the trakt_id list (tvdb / tvrage)
        """

        if 'Collection' == List:
            try:
                if self.collection_list[trakt_id][showid]['seasons'][season]['episodes'][episode] == episode:
                    return True
            except KeyError:
                return False
        elif 'Show' == List:
            try:
                if self.show_watchlist[trakt_id][showid]['id'] == showid:
                    return True
            except KeyError:
                return False
        else:
            try:
                if self.episode_watchlist[trakt_id][showid]['seasons'][season]['episodes'][episode] == episode:
                    return True
            except KeyError:
                return False

    def _get_show_watchlist(self):
        """
        Get Watchlist and parse once into addressable structure
        """
        try:
            self.show_watchlist = {'tvdb_id': {}, 'tvrage_id': {}}
            trakt_show_watchlist = self.trakt_api.request('sync/watchlist/shows')
            if self.trakt_api.access_token_refreshed:
                app.TRAKT_ACCESS_TOKEN = self.trakt_api.access_token

            tvdb_id = 'tvdb'
            tvrage_id = 'tvrage'

            for watchlist_item in trakt_show_watchlist:
                tvdb = True if watchlist_item['show']['ids']['tvdb'] else False
                tvrage = True if watchlist_item['show']['ids']['tvrage'] else False
                title = watchlist_item['show']['title']
                year = watchlist_item['show']['year']
                slug = watchlist_item['show']['ids']['slug']

                if tvdb:
                    showid = watchlist_item['show']['ids'][tvdb_id]
                    self.show_watchlist['{0}_id'.format(tvdb_id)][showid] = {'id': showid, 'title': title, 'year': year, 'slug': slug}

                if tvrage:
                    showid = watchlist_item['show']['ids'][tvrage_id]
                    self.show_watchlist['{0}_id'.format(tvrage_id)][showid] = {'id': showid, 'title': title, 'year': year, 'slug': slug}
        except TraktException as e:
            logger.log(u"Could not connect to Trakt. Unable to retrieve show's watchlist: {0!r}".format(e), logger.WARNING)
            return False
        return True

    def _get_episode_watchlist(self):
        """
         Get Watchlist and parse once into addressable structure
        """
        try:
            self.episode_watchlist = {'tvdb_id': {}, 'tvrage_id': {}}
            trakt_episode_watchlist = self.trakt_api.request('sync/watchlist/episodes')
            if self.trakt_api.access_token_refreshed:
                app.TRAKT_ACCESS_TOKEN = self.trakt_api.access_token

            tvdb_id = 'tvdb'
            tvrage_id = 'tvrage'

            for watchlist_item in trakt_episode_watchlist:
                tvdb = True if watchlist_item['show']['ids']['tvdb'] else False
                tvrage = True if watchlist_item['show']['ids']['tvrage'] else False
                title = watchlist_item['show']['title']
                year = watchlist_item['show']['year']
                season = watchlist_item['episode']['season']
                episode = watchlist_item['episode']['number']

                if tvdb:
                    showid = watchlist_item['show']['ids'][tvdb_id]

                    if showid not in self.episode_watchlist['{0}_id'.format(tvdb_id)].keys():
                        self.episode_watchlist['{0}_id'.format(tvdb_id)][showid] = {'id': showid, 'title': title, 'year': year, 'seasons': {}}

                    if season not in self.episode_watchlist['{0}_id'.format(tvdb_id)][showid]['seasons'].keys():
                        self.episode_watchlist['{0}_id'.format(tvdb_id)][showid]['seasons'][season] = {'s': season, 'episodes': {}}

                    if episode not in self.episode_watchlist['{0}_id'.format(tvdb_id)][showid]['seasons'][season]['episodes'].keys():
                        self.episode_watchlist['{0}_id'.format(tvdb_id)][showid]['seasons'][season]['episodes'][episode] = episode

                if tvrage:
                    showid = watchlist_item['show']['ids'][tvrage_id]

                    if showid not in self.episode_watchlist['{0}_id'.format(tvrage_id)].keys():
                        self.episode_watchlist['{0}_id'.format(tvrage_id)][showid] = {'id': showid, 'title': title, 'year': year, 'seasons': {}}

                    if season not in self.episode_watchlist['{0}_id'.format(tvrage_id)][showid]['seasons'].keys():
                        self.episode_watchlist['{0}_id'.format(tvrage_id)][showid]['seasons'][season] = {'s': season, 'episodes': {}}

                    if episode not in self.episode_watchlist['{0}_id'.format(tvrage_id)][showid]['seasons'][season]['episodes'].keys():
                        self.episode_watchlist['{0}_id'.format(tvrage_id)][showid]['seasons'][season]['episodes'][episode] = episode
        except TraktException as e:
            logger.log(u"Could not connect to Trakt. Unable to retrieve episode's watchlist: {0!r}".format(e), logger.WARNING)
            return False
        return True

    def _get_show_collection(self): # pylint: disable=too-many-branches
        """
        Get Collection and parse once into addressable structure
        """
        try:
            self.collection_list = {'tvdb_id': {}, 'tvrage_id': {}}
            logger.log('Getting Show Collection', logger.DEBUG)
            trakt_collection = self.trakt_api.request('sync/collection/shows')
            if self.trakt_api.access_token_refreshed:
                app.TRAKT_ACCESS_TOKEN = self.trakt_api.access_token

            tvdb_id = 'tvdb'
            tvrage_id = 'tvrage'

            for watchlist_item in trakt_collection:
                tvdb = True if watchlist_item['show']['ids']['tvdb'] else False
                tvrage = True if watchlist_item['show']['ids']['tvrage'] else False
                title = watchlist_item['show']['title']
                year = watchlist_item['show']['year']

                if 'seasons' in watchlist_item:
                    for season_item in watchlist_item['seasons']:
                        for episode_item in season_item['episodes']:
                            season = season_item['number']
                            episode = episode_item['number']

                            if tvdb:
                                showid = watchlist_item['show']['ids'][tvdb_id]

                                if showid not in self.collection_list['{0}_id'.format(tvdb_id)].keys():
                                    self.collection_list['{0}_id'.format(tvdb_id)][showid] = {'id': showid, 'title': title, 'year': year, 'seasons': {}}

                                if season not in self.collection_list['{0}_id'.format(tvdb_id)][showid]['seasons'].keys():
                                    self.collection_list['{0}_id'.format(tvdb_id)][showid]['seasons'][season] = {'s': season, 'episodes': {}}

                                if episode not in self.collection_list['{0}_id'.format(tvdb_id)][showid]['seasons'][season]['episodes'].keys():
                                    self.collection_list['{0}_id'.format(tvdb_id)][showid]['seasons'][season]['episodes'][episode] = episode

                            if tvrage:
                                showid = watchlist_item['show']['ids'][tvrage_id]

                                if showid not in self.collection_list[tvrage_id + '_id'].keys():
                                    self.collection_list[tvrage_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year, 'seasons': {}}

                                if season not in self.collection_list[tvrage_id + '_id'][showid]['seasons'].keys():
                                    self.collection_list[tvrage_id + '_id'][showid]['seasons'][season] = {'s': season, 'episodes': {}}

                                if episode not in self.collection_list[tvrage_id + '_id'][showid]['seasons'][season]['episodes'].keys():
                                    self.collection_list[tvrage_id + '_id'][showid]['seasons'][season]['episodes'][episode] = episode
        except TraktException as e:
            logger.log(u"Could not connect to Trakt. Unable to retrieve show's collection: {0!r}".format(e), logger.WARNING)
            return False
        return True

    @staticmethod
    def trakt_bulk_data_generate(data): # pylint: disable=too-many-locals
        """
        Build the JSON structure to send back to Trakt
        """
        uniqueShows = {}
        uniqueSeasons = {}

        for showid, indexerid, show_name, startyear, season, episode in data:
            if showid not in uniqueShows:
                uniqueShows[showid] = {'title': show_name, 'year': startyear, 'ids': {}, 'seasons': []}
                trakt_id = app.indexerApi(indexerid).config['trakt_id']

                if trakt_id == 'tvdb_id':
                    uniqueShows[showid]['ids']['tvdb'] = showid
                else:
                    uniqueShows[showid]['ids']['tvrage'] = showid
                uniqueSeasons[showid] = []

        # Get the unique seasons per Show
        for showid, indexerid, show_name, startyear, season, episode in data:
            if season not in uniqueSeasons[showid]:
                uniqueSeasons[showid].append(season)

        # build the query
        showList = []
        seasonsList = {}

        for searchedShow in uniqueShows:
            seasonsList[searchedShow] = []

            for searchedSeason in uniqueSeasons[searchedShow]:
                episodesList = []

                for showid, indexerid, show_name, startyear, season, episode in data:
                    if season == searchedSeason and showid == searchedShow:
                        episodesList.append({'number': episode})
                show = uniqueShows[searchedShow]
                show['seasons'].append({'number': searchedSeason, 'episodes': episodesList})
            showList.append(show)
        post_data = {'shows': showList}
        return post_data
示例#7
0
文件: trakt.py 项目: ngosang/Medusa
    def fetch_popular_shows(self, page_url=None, trakt_list=None):
        """Get a list of popular shows from different Trakt lists based on a provided trakt_list.

        :param page_url: the page url opened to the base api url, for retreiving a specific list
        :param trakt_list: a description of the trakt list
        :return: A list of RecommendedShow objects, an empty list of none returned
        :throw: ``Exception`` if an Exception is thrown not handled by the libtrats exceptions
        """
        trending_shows = []
        removed_from_medusa = []

        # Create a trakt settings dict
        trakt_settings = {
            'trakt_api_secret': app.TRAKT_API_SECRET,
            'trakt_api_key': app.TRAKT_API_KEY,
            'trakt_access_token': app.TRAKT_ACCESS_TOKEN,
            'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN
        }

        trakt_api = TraktApi(timeout=app.TRAKT_TIMEOUT,
                             ssl_verify=app.SSL_VERIFY,
                             **trakt_settings)

        try:
            not_liked_show = ''
            if app.TRAKT_ACCESS_TOKEN != '':
                library_shows = self.fetch_and_refresh_token(trakt_api, 'sync/watched/shows?extended=noseasons') + \
                    self.fetch_and_refresh_token(trakt_api, 'sync/collection/shows?extended=full')

                medusa_shows = [
                    show.indexerid for show in app.showList if show.indexerid
                ]
                removed_from_medusa = [
                    lshow['show']['ids']['tvdb'] for lshow in library_shows
                    if lshow['show']['ids']['tvdb'] not in medusa_shows
                ]

                if app.TRAKT_BLACKLIST_NAME is not None and app.TRAKT_BLACKLIST_NAME:
                    not_liked_show = trakt_api.request(
                        'users/' + app.TRAKT_USERNAME + '/lists/' +
                        app.TRAKT_BLACKLIST_NAME + '/items') or []
                else:
                    log.debug('Trakt blacklist name is empty')

            if trakt_list not in ['recommended', 'newshow', 'newseason']:
                limit_show = '?limit=' + text_type(100 +
                                                   len(not_liked_show)) + '&'
            else:
                limit_show = '?'

            series = self.fetch_and_refresh_token(
                trakt_api,
                page_url + limit_show + 'extended=full,images') or []

            # Let's trigger a cache cleanup.
            missing_posters.clean()

            for show in series:
                try:
                    if 'show' not in show:
                        show['show'] = show

                    if not_liked_show:
                        if show['show']['ids']['tvdb'] in (
                                s['show']['ids']['tvdb']
                                for s in not_liked_show
                                if s['type'] == 'show'):
                            continue
                    else:
                        trending_shows.append(
                            self._create_recommended_show(
                                show,
                                storage_key=b'trakt_{0}'.format(
                                    show['show']['ids']['trakt'])))

                except MultipleShowObjectsException:
                    continue

            # Update the dogpile index. This will allow us to retrieve all stored dogpile shows from the dbm.
            update_recommended_series_cache_index(
                'trakt', [binary_type(s.series_id) for s in trending_shows])
            blacklist = app.TRAKT_BLACKLIST_NAME not in ''

        except TraktException as error:
            log.warning('Could not connect to Trakt service: {0}', error)
            raise

        return blacklist, trending_shows, removed_from_medusa
示例#8
0
    def update_library(ep_obj):
        """Send a request to trakt indicating that the given episode is part of our library.

        ep_obj: The Episode object to add to trakt
        """
        # Check if TRAKT supports that indexer
        if not get_trakt_indexer(ep_obj.series.indexer):
            return

        # Create a trakt settings dict
        trakt_settings = {
            'trakt_api_secret': app.TRAKT_API_SECRET,
            'trakt_api_key': app.TRAKT_API_KEY,
            'trakt_access_token': app.TRAKT_ACCESS_TOKEN,
            'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN
        }

        trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT,
                             **trakt_settings)

        if app.USE_TRAKT:
            try:
                # URL parameters
                title = get_title_without_year(ep_obj.series.name,
                                               ep_obj.series.start_year)
                data = {
                    'shows': [{
                        'title': title,
                        'year': ep_obj.series.start_year,
                        'ids': {},
                    }]
                }

                data['shows'][0]['ids'][get_trakt_indexer(
                    ep_obj.series.indexer)] = ep_obj.series.indexerid

                if app.TRAKT_SYNC_WATCHLIST:
                    if app.TRAKT_REMOVE_SERIESLIST:
                        trakt_api.request('sync/watchlist/remove',
                                          data,
                                          method='POST')

                # Add Season and Episode + Related Episodes
                data['shows'][0]['seasons'] = [{
                    'number': ep_obj.season,
                    'episodes': []
                }]

                for relEp_Obj in [ep_obj] + ep_obj.related_episodes:
                    data['shows'][0]['seasons'][0]['episodes'].append(
                        {'number': relEp_Obj.episode})

                if app.TRAKT_SYNC_WATCHLIST:
                    if app.TRAKT_REMOVE_WATCHLIST:
                        trakt_api.request('sync/watchlist/remove',
                                          data,
                                          method='POST')

                # update library
                trakt_api.request('sync/collection', data, method='POST')

            except (TokenExpiredException, TraktException,
                    AuthException) as error:
                log.debug('Unable to update Trakt: {0}', error.message)
示例#9
0
    def update_watchlist(show_obj=None,
                         s=None,
                         e=None,
                         data_show=None,
                         data_episode=None,
                         update='add'):
        """Send a request to trakt indicating that the given episode is part of our library.

        show_obj: The Series object to add to trakt
        s: season number
        e: episode number
        data_show: structured object of shows trakt type
        data_episode: structured object of episodes trakt type
        update: type o action add or remove
        """
        # Check if TRAKT supports that indexer
        if not get_trakt_indexer(show_obj.indexer):
            return

        trakt_settings = {
            'trakt_api_secret': app.TRAKT_API_SECRET,
            'trakt_api_key': app.TRAKT_API_KEY,
            'trakt_access_token': app.TRAKT_ACCESS_TOKEN,
            'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN
        }

        trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT,
                             **trakt_settings)

        if app.USE_TRAKT:

            data = {}
            try:
                # URL parameters
                if show_obj is not None:
                    title = get_title_without_year(show_obj.name,
                                                   show_obj.start_year)
                    data = {
                        'shows': [{
                            'title': title,
                            'year': show_obj.start_year,
                            'ids': {},
                        }]
                    }
                    data['shows'][0]['ids'][get_trakt_indexer(
                        show_obj.indexer)] = show_obj.indexerid
                elif data_show is not None:
                    data.update(data_show)
                else:
                    log.warning(
                        "There's a coding problem contact developer. It's needed to be provided at"
                        " least one of the two: data_show or show_obj", )
                    return False

                if data_episode is not None:
                    data['shows'][0].update(data_episode)

                elif s is not None:
                    # trakt URL parameters
                    season = {
                        'season': [{
                            'number': s,
                        }]
                    }

                    if e is not None:
                        # trakt URL parameters
                        episode = {'episodes': [{'number': e}]}

                        season['season'][0].update(episode)

                    data['shows'][0].update(season)

                trakt_url = 'sync/watchlist'
                if update == 'remove':
                    trakt_url += '/remove'

                trakt_api.request(trakt_url, data, method='POST')

            except (TokenExpiredException, TraktException,
                    AuthException) as error:
                log.debug('Unable to update Trakt watchlist: {0}',
                          error.message)
                return False

        return True
示例#10
0
class TraktChecker(object):
    """Trakt checker class."""
    def __init__(self):
        """Initialize the class."""
        trakt_settings = {
            'trakt_api_key': app.TRAKT_API_KEY,
            'trakt_api_secret': app.TRAKT_API_SECRET,
            'trakt_access_token': app.TRAKT_ACCESS_TOKEN,
            'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN
        }
        self.trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT,
                                  **trakt_settings)
        self.todoWanted = []
        self.show_watchlist = {}
        self.episode_watchlist = {}
        self.collection_list = {}
        self.amActive = False

    def run(self, force=False):
        """Run Trakt Checker."""
        self.amActive = True

        # add shows from Trakt watchlist
        if app.TRAKT_SYNC_WATCHLIST:
            self.todoWanted = []  # its about to all get re-added
            if len(app.ROOT_DIRS) < 2:
                log.warning('No default root directory')
                ui.notifications.error(
                    'Unable to add show',
                    'You do not have any default root directory. '
                    'Please configure in general settings!')
                return

            self.sync_watchlist()
            self.sync_library()

        self.amActive = False

    def _request(self, path, data=None, method='GET'):
        """Fetch shows from trakt and store the refresh token when needed."""
        try:
            library_shows = self.trakt_api.request(path, data,
                                                   method=method) or []
            if self.trakt_api.access_token_refreshed:
                app.TRAKT_ACCESS_TOKEN = self.trakt_api.access_token
                app.TRAKT_REFRESH_TOKEN = self.trakt_api.refresh_token
                app.instance.save_config()
        except TokenExpiredException:
            log.warning(u'You need to get a PIN and authorize Medusa app')
            app.TRAKT_ACCESS_TOKEN = ''
            app.TRAKT_REFRESH_TOKEN = ''
            app.instance.save_config()
            raise TokenExpiredException(
                'You need to get a PIN and authorize Medusa app')

        return library_shows

    def find_show(self, indexerid, indexer):
        """Find show in Trakt library."""
        trakt_library = []
        try:
            trakt_library = self._request('sync/collection/shows')
        except (TraktException, AuthException, TokenExpiredException) as e:
            log.info(
                'Unable to retrieve shows from Trakt collection. Error: {error}',
                {'error': e.message})

        if not trakt_library:
            log.info('No shows found in your Trakt library. Nothing to sync')
            return
        trakt_show = [
            x for x in trakt_library
            if get_trakt_indexer(indexer) and int(indexerid) in
            [int(x['show']['ids'].get(get_trakt_indexer(indexer)))]
        ]

        return trakt_show if trakt_show else None

    def remove_show_trakt_library(self, show_obj):
        """Remove show from trakt library."""
        if self.find_show(show_obj.indexerid, show_obj.indexer):

            # Check if TRAKT supports that indexer
            if not get_trakt_indexer(show_obj.indexer):
                return

            # URL parameters
            title = get_title_without_year(show_obj.name, show_obj.start_year)
            data = {
                'shows': [{
                    'title': title,
                    'year': show_obj.start_year,
                    'ids': {}
                }]
            }

            data['shows'][0]['ids'][get_trakt_indexer(
                show_obj.indexer)] = show_obj.indexerid

            log.info("Removing '{show}' from Trakt library",
                     {'show': show_obj.name})

            # Remove all episodes from the Trakt collection for this show
            try:
                self.remove_episode_trakt_collection(filter_show=show_obj)
            except (TraktException, AuthException, TokenExpiredException) as e:
                log.info(
                    "Unable to remove all episodes from show '{show}' from Trakt library. Error: {error}",
                    {
                        'show': show_obj.name,
                        'error': e.message
                    })

            try:
                self._request('sync/collection/remove', data, method='POST')
            except (TraktException, AuthException, TokenExpiredException) as e:
                log.info(
                    "Unable to remove show '{show}' from Trakt library. Error: {error}",
                    {
                        'show': show_obj.name,
                        'error': e.message
                    })

    def add_show_trakt_library(self, show_obj):
        """Add show to trakt library."""
        data = {}

        if not self.find_show(show_obj.indexerid, show_obj.indexer):

            # Check if TRAKT supports that indexer
            if not get_trakt_indexer(show_obj.indexer):
                return

            # URL parameters
            title = get_title_without_year(show_obj.name, show_obj.start_year)
            data = {
                'shows': [{
                    'title': title,
                    'year': show_obj.start_year,
                    'ids': {}
                }]
            }

            data['shows'][0]['ids'][get_trakt_indexer(
                show_obj.indexer)] = show_obj.indexerid

        if data:
            log.info("Adding show '{show}' to Trakt library",
                     {'show': show_obj.name})

            try:
                self._request('sync/collection', data, method='POST')
            except (TraktException, AuthException, TokenExpiredException) as e:
                log.info(
                    "Unable to add show '{show}' to Trakt library. Error: {error}",
                    {
                        'show': show_obj.name,
                        'error': e.message
                    })
                return

    def sync_library(self):
        """Sync Trakt library."""
        if app.TRAKT_SYNC and app.USE_TRAKT:
            log.debug('Syncing Trakt collection')

            if self._get_show_collection():
                self.add_episode_trakt_collection()
                if app.TRAKT_SYNC_REMOVE:
                    self.remove_episode_trakt_collection()
                log.debug('Synced Trakt collection')

    def remove_episode_trakt_collection(self, filter_show=None):
        """Remove episode from trakt collection.

        For episodes that no longer have a media file (location)
        :param filter_show: optional. Only remove episodes from trakt collection for given shows
        """
        if app.TRAKT_SYNC_REMOVE and app.TRAKT_SYNC and app.USE_TRAKT:

            params = []
            main_db_con = db.DBConnection()
            statuses = [DOWNLOADED, ARCHIVED]
            sql_selection = b'SELECT s.indexer, s.startyear, s.indexer_id, s.show_name,' \
                            b'e.season, e.episode, e.status ' \
                            b'FROM tv_episodes AS e, tv_shows AS s WHERE e.indexer = s.indexer AND ' \
                            b's.indexer_id = e.showid and e.location = "" ' \
                            b'AND e.status in ({0})'.format(','.join(['?'] * len(statuses)))
            if filter_show:
                sql_selection += b' AND s.indexer_id = ? AND e.indexer = ?'
                params = [filter_show.series_id, filter_show.indexer]

            sql_result = main_db_con.select(sql_selection, statuses + params)
            episodes = [dict(e) for e in sql_result]

            if episodes:
                trakt_data = []

                for cur_episode in episodes:
                    # Check if TRAKT supports that indexer
                    if not get_trakt_indexer(cur_episode[b'indexer']):
                        continue
                    if self._check_list(indexer=cur_episode[b'indexer'],
                                        indexer_id=cur_episode[b'indexer_id'],
                                        season=cur_episode[b'season'],
                                        episode=cur_episode[b'episode'],
                                        list_type='Collection'):
                        log.info(
                            "Removing episode '{show}' {ep} from Trakt collection",
                            {
                                'show':
                                cur_episode[b'show_name'],
                                'ep':
                                episode_num(cur_episode[b'season'],
                                            cur_episode[b'episode'])
                            })
                        title = get_title_without_year(
                            cur_episode[b'show_name'],
                            cur_episode[b'startyear'])
                        trakt_data.append(
                            (cur_episode[b'indexer_id'],
                             cur_episode[b'indexer'], title,
                             cur_episode[b'startyear'], cur_episode[b'season'],
                             cur_episode[b'episode']))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self._request('sync/collection/remove',
                                      data,
                                      method='POST')
                        self._get_show_collection()
                    except (TraktException, AuthException,
                            TokenExpiredException) as e:
                        log.info(
                            'Unable to remove episodes from Trakt collection. Error: {error}',
                            {'error': e.message})

    def add_episode_trakt_collection(self):
        """Add all existing episodes to Trakt collections.

        For episodes that have a media file (location)
        """
        if app.TRAKT_SYNC and app.USE_TRAKT:

            main_db_con = db.DBConnection()
            statuses = [DOWNLOADED, ARCHIVED]
            sql_selection = b'SELECT s.indexer, s.startyear, s.indexer_id, s.show_name, e.season, e.episode ' \
                            b'FROM tv_episodes AS e, tv_shows AS s ' \
                            b'WHERE e.indexer = s.indexer AND s.indexer_id = e.showid ' \
                            b"AND e.status in ({0}) AND e.location <> ''".format(','.join(['?'] * len(statuses)))

            sql_result = main_db_con.select(sql_selection, statuses)
            episodes = [dict(e) for e in sql_result]

            if episodes:
                trakt_data = []

                for cur_episode in episodes:
                    # Check if TRAKT supports that indexer
                    if not get_trakt_indexer(cur_episode[b'indexer']):
                        continue

                    if not self._check_list(
                            indexer=cur_episode[b'indexer'],
                            indexer_id=cur_episode[b'indexer_id'],
                            season=cur_episode[b'season'],
                            episode=cur_episode[b'episode'],
                            list_type='Collection'):
                        log.info(
                            "Adding episode '{show}' {ep} to Trakt collection",
                            {
                                'show':
                                cur_episode[b'show_name'],
                                'ep':
                                episode_num(cur_episode[b'season'],
                                            cur_episode[b'episode'])
                            })
                        title = get_title_without_year(
                            cur_episode[b'show_name'],
                            cur_episode[b'startyear'])
                        trakt_data.append(
                            (cur_episode[b'indexer_id'],
                             cur_episode[b'indexer'], title,
                             cur_episode[b'startyear'], cur_episode[b'season'],
                             cur_episode[b'episode']))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self._request('sync/collection', data, method='POST')
                        self._get_show_collection()
                    except (TraktException, AuthException,
                            TokenExpiredException) as e:
                        log.info(
                            'Unable to add episodes to Trakt collection. Error: {error}',
                            {'error': e.message})

    def sync_watchlist(self):
        """Sync Trakt watchlist."""
        if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT:
            log.debug('Syncing Trakt Watchlist')

            self.remove_from_library()

            if self._get_show_watchlist():
                log.debug('Syncing shows with Trakt watchlist')
                self.add_show_watchlist()
                self.sync_trakt_shows()

            if self._get_episode_watchlist():
                log.debug('Syncing episodes with Trakt watchlist')
                self.remove_episode_watchlist()
                self.add_episode_watchlist()
                self.sync_trakt_episodes()

            log.debug('Synced Trakt watchlist')

    def remove_episode_watchlist(self):
        """Remove episode from Trakt watchlist."""
        if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT:

            main_db_con = db.DBConnection()
            statuses = [DOWNLOADED, ARCHIVED]
            sql_selection = b'SELECT s.indexer, s.startyear, e.showid, s.show_name, e.season, e.episode ' \
                            b'FROM tv_episodes AS e, tv_shows AS s ' \
                            b'WHERE e.indexer = s.indexer ' \
                            b'AND s.indexer_id = e.showid AND e.status in ({0})'.format(','.join(['?'] * len(statuses)))

            sql_result = main_db_con.select(sql_selection, statuses)
            episodes = [dict(i) for i in sql_result]

            if episodes:
                trakt_data = []

                for cur_episode in episodes:

                    # Check if TRAKT supports that indexer
                    if not get_trakt_indexer(cur_episode[b'indexer']):
                        continue

                    if self._check_list(indexer=cur_episode[b'indexer'],
                                        indexer_id=cur_episode[b'showid'],
                                        season=cur_episode[b'season'],
                                        episode=cur_episode[b'episode']):
                        log.info(
                            "Removing episode '{show}' {ep} from Trakt watchlist",
                            {
                                'show':
                                cur_episode[b'show_name'],
                                'ep':
                                episode_num(cur_episode[b'season'],
                                            cur_episode[b'episode'])
                            })
                        title = get_title_without_year(
                            cur_episode[b'show_name'],
                            cur_episode[b'startyear'])
                        trakt_data.append(
                            (cur_episode[b'showid'], cur_episode[b'indexer'],
                             title, cur_episode[b'startyear'],
                             cur_episode[b'season'], cur_episode[b'episode']))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self._request('sync/watchlist/remove',
                                      data,
                                      method='POST')
                        self._get_episode_watchlist()
                    except (TraktException, AuthException,
                            TokenExpiredException) as e:
                        log.info(
                            'Unable to remove episodes from Trakt watchlist. Error: {error}',
                            {'error': e.message})

    def add_episode_watchlist(self):
        """Add episode to Tratk watchlist."""
        if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT:

            main_db_con = db.DBConnection()
            statuses = [SNATCHED, SNATCHED_BEST, SNATCHED_PROPER, WANTED]
            sql_selection = b'SELECT s.indexer, s.startyear, e.showid, s.show_name, e.season, e.episode ' \
                            b'FROM tv_episodes AS e, tv_shows AS s ' \
                            b'WHERE e.indexer = s.indexer AND s.indexer_id = e.showid AND s.paused = 0 ' \
                            b'AND e.status in ({0})'.format(','.join(['?'] * len(statuses)))

            sql_result = main_db_con.select(sql_selection, statuses)
            episodes = [dict(i) for i in sql_result]

            if episodes:
                trakt_data = []

                for cur_episode in episodes:
                    # Check if TRAKT supports that indexer
                    if not get_trakt_indexer(cur_episode[b'indexer']):
                        continue

                    if not self._check_list(indexer=cur_episode[b'indexer'],
                                            indexer_id=cur_episode[b'showid'],
                                            season=cur_episode[b'season'],
                                            episode=cur_episode[b'episode']):
                        log.info(
                            "Adding episode '{show}' {ep} to Trakt watchlist",
                            {
                                'show':
                                cur_episode[b'show_name'],
                                'ep':
                                episode_num(cur_episode[b'season'],
                                            cur_episode[b'episode'])
                            })
                        title = get_title_without_year(
                            cur_episode[b'show_name'],
                            cur_episode[b'startyear'])
                        trakt_data.append(
                            (cur_episode[b'showid'], cur_episode[b'indexer'],
                             title, cur_episode[b'startyear'],
                             cur_episode[b'season'], cur_episode[b'episode']))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self._request('sync/watchlist', data, method='POST')
                        self._get_episode_watchlist()
                    except (TraktException, AuthException,
                            TokenExpiredException) as e:
                        log.info(
                            'Unable to add episode to Trakt watchlist. Error: {error}',
                            {'error': e.message})

    def add_show_watchlist(self):
        """Add show to Trakt watchlist.

        It will add all shows from Medusa library
        """
        if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT:
            if app.showList:
                trakt_data = []

                for show_obj in app.showList:
                    if not self._check_list(show_obj=show_obj,
                                            list_type='Show'):
                        log.info("Adding show '{show}' to Trakt watchlist",
                                 {'show': show_obj.name})
                        title = get_title_without_year(show_obj.name,
                                                       show_obj.start_year)
                        show_el = {
                            'title': title,
                            'year': show_obj.start_year,
                            'ids': {}
                        }
                        trakt_data.append(show_el)

                if trakt_data:
                    try:
                        data = {'shows': trakt_data}
                        self._request('sync/watchlist', data, method='POST')
                    except (TraktException, AuthException,
                            TokenExpiredException) as e:
                        log.info(
                            'Unable to add shows to Trakt watchlist. Error: {error}',
                            {'error': e.message})
                    self._get_show_watchlist()

    def remove_from_library(self):
        """Remove show from Medusa library is if ended/completed."""
        if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT and app.TRAKT_REMOVE_SHOW_FROM_APPLICATION:
            log.debug('Retrieving ended/completed shows to remove from Medusa')

            if app.showList:
                for show in app.showList:
                    if show.status == 'Ended':
                        trakt_id = show.externals.get('trakt_id', None)
                        if not (trakt_id or show.imdb_id):
                            log.info(
                                "Unable to check Trakt progress for show '{show}' "
                                'because Trakt|IMDB ID is missing. Skipping',
                                {'show': show.name})
                            continue

                        try:
                            progress = self._request(
                                'shows/{0}/progress/watched'.format(
                                    trakt_id or show.imdb_id))
                        except (TraktException, AuthException,
                                TokenExpiredException) as e:
                            log.info(
                                "Unable to check if show '{show}' is ended/completed. Error: {error}",
                                {
                                    'show': show.name,
                                    'error': e.message
                                })
                            continue
                        else:
                            if progress.get('aired', True) == progress.get(
                                    'completed', False):
                                app.show_queue_scheduler.action.removeShow(
                                    show, full=True)
                                log.info(
                                    "Show '{show}' has being queued to be removed from Medusa library",
                                    {'show': show.name})

    def sync_trakt_shows(self):
        """Sync Trakt shows watchlist."""
        if not self.show_watchlist:
            log.info('No shows found in your Trakt watchlist. Nothing to sync')
        else:
            trakt_default_indexer = int(app.TRAKT_DEFAULT_INDEXER)

            for watchlisted_show in self.show_watchlist:
                trakt_show = watchlisted_show['show']

                if trakt_show['year'] and trakt_show['ids']['slug'].endswith(
                        str(trakt_show['year'])):
                    show_name = '{title} ({year})'.format(
                        title=trakt_show['title'], year=trakt_show['year'])
                else:
                    show_name = trakt_show['title']

                show = None
                indexer = None
                for i in indexerConfig:
                    trakt_indexer = get_trakt_indexer(i)
                    indexer_id = trakt_show['ids'].get(trakt_indexer, -1)
                    indexer = indexerConfig[i]['id']
                    show = Show.find_by_id(app.showList, indexer, indexer_id)
                    if show:
                        break
                if not show:
                    # If can't find with available indexers try IMDB
                    trakt_indexer = get_trakt_indexer(EXTERNAL_IMDB)
                    indexer_id = trakt_show['ids'].get(trakt_indexer, -1)
                    show = Show.find_by_id(app.showList, EXTERNAL_IMDB,
                                           indexer_id)
                if not show:
                    # If can't find with available indexers try TRAKT
                    trakt_indexer = get_trakt_indexer(EXTERNAL_TRAKT)
                    indexer_id = trakt_show['ids'].get(trakt_indexer, -1)
                    show = Show.find_by_id(app.showList, EXTERNAL_TRAKT,
                                           indexer_id)

                if show:
                    continue

                indexer_id = trakt_show['ids'].get(
                    get_trakt_indexer(trakt_default_indexer), -1)
                if int(app.TRAKT_METHOD_ADD) != 2:
                    self.add_show(trakt_default_indexer, indexer_id, show_name,
                                  SKIPPED)
                else:
                    self.add_show(trakt_default_indexer, indexer_id, show_name,
                                  WANTED)

                if int(app.TRAKT_METHOD_ADD) == 1 and indexer:
                    new_show = Show.find_by_id(app.showList, indexer,
                                               indexer_id)

                    if new_show:
                        set_episode_to_wanted(new_show, 1, 1)
                    else:
                        log.warning(
                            'Unable to find the new added show.'
                            'Pilot will be set to wanted in the next Trakt run'
                        )
                        self.todoWanted.append(indexer_id)
            log.debug('Synced shows with Trakt watchlist')

    def sync_trakt_episodes(self):
        """Sync Trakt episodes watchlist."""
        if not self.episode_watchlist:
            log.info(
                'No episodes found in your Trakt watchlist. Nothing to sync')
            return

        added_shows = []
        trakt_default_indexer = int(app.TRAKT_DEFAULT_INDEXER)

        for watchlist_item in self.episode_watchlist:
            trakt_show = watchlist_item['show']
            trakt_episode = watchlist_item['episode'].get('number', -1)
            trakt_season = watchlist_item['episode'].get('season', -1)

            show = None
            for i in indexerConfig:
                trakt_indexer = get_trakt_indexer(i)
                indexer_id = trakt_show['ids'].get(trakt_indexer, -1)
                indexer = indexerConfig[i]['id']
                show = Show.find_by_id(app.showList, indexer, indexer_id)
                if show:
                    break

            if not show:
                # If can't find with available indexers try IMDB
                trakt_indexer = get_trakt_indexer(EXTERNAL_IMDB)
                indexer_id = trakt_show['ids'].get(trakt_indexer, -1)
                show = Show.find_by_id(app.showList, EXTERNAL_IMDB, indexer_id)
            if not show:
                # If can't find with available indexers try TRAKT
                trakt_indexer = get_trakt_indexer(EXTERNAL_TRAKT)
                indexer_id = trakt_show['ids'].get(trakt_indexer, -1)
                show = Show.find_by_id(app.showList, EXTERNAL_TRAKT,
                                       indexer_id)

            # If can't find show add with default trakt indexer
            if not show:
                indexer_id = trakt_show['ids'].get(
                    get_trakt_indexer(trakt_default_indexer), -1)
                # Only add show if we didn't added it before
                if indexer_id not in added_shows:
                    self.add_show(trakt_default_indexer, indexer_id,
                                  trakt_show['title'], SKIPPED)
                    added_shows.append(indexer_id)

            elif not trakt_season == 0 and not show.paused:
                set_episode_to_wanted(show, trakt_season, trakt_episode)

        log.debug('Synced episodes with Trakt watchlist')

    @staticmethod
    def add_show(indexer, indexer_id, show_name, status):
        """Add a new show with default settings."""
        if not Show.find_by_id(app.showList, EXTERNAL_IMDB, indexer_id):
            root_dirs = app.ROOT_DIRS

            location = root_dirs[int(root_dirs[0]) + 1] if root_dirs else None

            if location:
                log.info(
                    "Adding show '{show}' using indexer: '{indexer_name}' and ID: {id}",
                    {
                        'show': show_name,
                        'indexer_name': indexerConfig[indexer]['identifier'],
                        'id': indexer_id
                    })

                app.show_queue_scheduler.action.addShow(
                    indexer,
                    indexer_id,
                    None,
                    default_status=status,
                    quality=int(app.QUALITY_DEFAULT),
                    season_folders=int(app.SEASON_FOLDERS_DEFAULT),
                    paused=app.TRAKT_START_PAUSED,
                    default_status_after=status,
                    root_dir=location)
                tries = 0
                while tries < 3:
                    if Show.find_by_id(app.showList, indexer, indexer_id):
                        return
                    # Wait before show get's added and refreshed
                    time.sleep(60)
                    tries += 1
                log.warning("Error creating show '{show}. Please check logs' ",
                            {'show': show_name})
                return
            else:
                log.warning(
                    "Error creating show '{show}' folder. No default root directory",
                    {'show': show_name})
                return

    def manage_new_show(self, show):
        """Set episodes to wanted for the recently added show."""
        log.debug(
            "Checking for wanted episodes for show '{show}' in Trakt watchlist",
            {'show': show.name})
        episodes = [i for i in self.todoWanted if i[0] == show.indexerid]

        for episode in episodes:
            self.todoWanted.remove(episode)
            set_episode_to_wanted(show, episode[1], episode[2])

    def _check_list(self,
                    show_obj=None,
                    indexer=None,
                    indexer_id=None,
                    season=None,
                    episode=None,
                    list_type=None):
        """Check if we can find the show in the Trakt watchlist|collection list."""
        if 'Collection' == list_type:
            trakt_indexer = get_trakt_indexer(indexer)
            for collected_show in self.collection_list:
                if not collected_show['show']['ids'].get(trakt_indexer,
                                                         '') == indexer_id:
                    continue
                if 'seasons' in collected_show:
                    for season_item in collected_show['seasons']:
                        for episode_item in season_item['episodes']:
                            trakt_season = season_item['number']
                            trakt_episode = episode_item['number']
                            if trakt_season == season and trakt_episode == episode:
                                return True
                else:
                    return False
        elif 'Show' == list_type:
            trakt_indexer = get_trakt_indexer(show_obj.indexer)
            for watchlisted_show in self.show_watchlist:
                if watchlisted_show['show']['ids'].get(trakt_indexer) == show_obj.indexerid or \
                        watchlisted_show['show']['ids'].get(get_trakt_indexer(EXTERNAL_IMDB), '') == show_obj.imdb_id:
                    return True
            return False
        else:
            trakt_indexer = get_trakt_indexer(indexer)
            for watchlisted_episode in self.episode_watchlist:
                if watchlisted_episode['episode'].get('season', -1) == season and \
                        watchlisted_episode['episode'].get('number', -1) == episode and \
                        watchlisted_episode['show']['ids'].get(trakt_indexer, '') == indexer_id:
                    return True
            return False

    def _get_show_watchlist(self):
        """Get shows watchlist."""
        try:
            self.show_watchlist = self._request('sync/watchlist/shows')
        except (TraktException, AuthException, TokenExpiredException) as e:
            log.info(
                u'Unable to retrieve shows from Trakt watchlist. Error: {error}',
                {'error': e.message})
            return False
        return True

    def _get_episode_watchlist(self):
        """Get episodes watchlist."""
        try:
            self.episode_watchlist = self._request('sync/watchlist/episodes')
        except (TraktException, AuthException, TokenExpiredException) as e:
            log.info(
                u'Unable to retrieve episodes from Trakt watchlist. Error: {error}',
                {'error': e.message})
            return False
        return True

    def _get_show_collection(self):
        """Get show collection."""
        try:
            self.collection_list = self._request('sync/collection/shows')
        except (TraktException, AuthException, TokenExpiredException) as e:
            log.info(
                'Unable to retrieve shows from Trakt collection. Error: {error}',
                {'error': e.message})
            return False
        return True

    @staticmethod
    def trakt_bulk_data_generate(trakt_data):
        """Build the JSON structure to send back to Trakt."""
        unique_shows = {}
        unique_seasons = {}

        for indexer_id, indexer, show_name, start_year, season, episode in trakt_data:
            if indexer_id not in unique_shows:
                unique_shows[indexer_id] = {
                    'title': show_name,
                    'year': start_year,
                    'ids': {},
                    'seasons': []
                }
                unique_shows[indexer_id]['ids'][get_trakt_indexer(
                    indexer)] = indexer_id
                unique_seasons[indexer_id] = []

        # Get the unique seasons per Show
        for indexer_id, indexer, show_name, start_year, season, episode in trakt_data:
            if season not in unique_seasons[indexer_id]:
                unique_seasons[indexer_id].append(season)

        # build the query
        show_list = []
        seasons_list = {}

        for searched_show in unique_shows:
            show = []
            seasons_list[searched_show] = []

            for searched_season in unique_seasons[searched_show]:
                episodes_list = []

                for indexer_id, indexer, show_name, start_year, season, episode in trakt_data:
                    if season == searched_season and indexer_id == searched_show:
                        episodes_list.append({'number': episode})
                show = unique_shows[searched_show]
                show['seasons'].append({
                    'number': searched_season,
                    'episodes': episodes_list
                })
            if show:
                show_list.append(show)
        post_data = {'shows': show_list}
        return post_data
示例#11
0
    def fetch_popular_shows(self, page_url=None, trakt_list=None):  # pylint: disable=too-many-nested-blocks,too-many-branches
        """Get a list of popular shows from different Trakt lists based on a provided trakt_list.

        :param page_url: the page url opened to the base api url, for retreiving a specific list
        :param trakt_list: a description of the trakt list
        :return: A list of RecommendedShow objects, an empty list of none returned
        :throw: ``Exception`` if an Exception is thrown not handled by the libtrats exceptions
        """
        trending_shows = []
        removed_from_medusa = []

        # Create a trakt settings dict
        trakt_settings = {
            'trakt_api_secret': app.TRAKT_API_SECRET,
            'trakt_api_key': app.TRAKT_API_KEY,
            'trakt_access_token': app.TRAKT_ACCESS_TOKEN
        }

        trakt_api = TraktApi(timeout=app.TRAKT_TIMEOUT,
                             ssl_verify=app.SSL_VERIFY,
                             **trakt_settings)

        try:  # pylint: disable=too-many-nested-blocks
            not_liked_show = ''
            if app.TRAKT_ACCESS_TOKEN != '':
                library_shows = self.fetch_and_refresh_token(trakt_api, 'sync/watched/shows?extended=noseasons') + \
                    self.fetch_and_refresh_token(trakt_api, 'sync/collection/shows?extended=full')

                medusa_shows = [
                    show.indexerid for show in app.showList if show.indexerid
                ]
                removed_from_medusa = [
                    lshow['show']['ids']['tvdb'] for lshow in library_shows
                    if lshow['show']['ids']['tvdb'] not in medusa_shows
                ]

                if app.TRAKT_BLACKLIST_NAME is not None and app.TRAKT_BLACKLIST_NAME:
                    not_liked_show = trakt_api.request(
                        'users/' + app.TRAKT_USERNAME + '/lists/' +
                        app.TRAKT_BLACKLIST_NAME + '/items') or []
                else:
                    logger.log('Trakt blacklist name is empty', logger.DEBUG)

            if trakt_list not in ['recommended', 'newshow', 'newseason']:
                limit_show = '?limit=' + str(100 + len(not_liked_show)) + '&'
            else:
                limit_show = '?'

            shows = self.fetch_and_refresh_token(
                trakt_api,
                page_url + limit_show + 'extended=full,images') or []

            for show in shows:
                try:
                    if 'show' not in show:
                        show['show'] = show

                    if not_liked_show:
                        if show['show']['ids']['tvdb'] not in (
                                show['show']['ids']['tvdb']
                                for show in not_liked_show
                                if show['type'] == 'show'):
                            trending_shows.append(
                                self._create_recommended_show(show))
                    else:
                        trending_shows.append(
                            self._create_recommended_show(show))

                except MultipleShowObjectsException:
                    continue

            blacklist = app.TRAKT_BLACKLIST_NAME not in ''

        except TraktException as e:
            logger.log('Could not connect to Trakt service: %s' % ex(e),
                       logger.WARNING)
            raise

        return blacklist, trending_shows, removed_from_medusa
示例#12
0
    def fetch_popular_shows(self, page_url=None, trakt_list=None):
        """Get a list of popular shows from different Trakt lists based on a provided trakt_list.

        :param page_url: the page url opened to the base api url, for retreiving a specific list
        :param trakt_list: a description of the trakt list
        :return: A list of RecommendedShow objects, an empty list of none returned
        :throw: ``Exception`` if an Exception is thrown not handled by the libtrats exceptions
        """
        trending_shows = []
        removed_from_medusa = []

        # Create a trakt settings dict
        trakt_settings = {'trakt_api_secret': app.TRAKT_API_SECRET,
                          'trakt_api_key': app.TRAKT_API_KEY,
                          'trakt_access_token': app.TRAKT_ACCESS_TOKEN,
                          'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN}

        trakt_api = TraktApi(timeout=app.TRAKT_TIMEOUT, ssl_verify=app.SSL_VERIFY, **trakt_settings)

        try:
            not_liked_show = ''
            if app.TRAKT_ACCESS_TOKEN != '':
                library_shows = self.fetch_and_refresh_token(trakt_api, 'sync/watched/shows?extended=noseasons') + \
                    self.fetch_and_refresh_token(trakt_api, 'sync/collection/shows?extended=full')

                medusa_shows = [show.indexerid for show in app.showList if show.indexerid]
                removed_from_medusa = [lshow['show']['ids']['tvdb'] for lshow in library_shows if lshow['show']['ids']['tvdb'] not in medusa_shows]

                if app.TRAKT_BLACKLIST_NAME is not None and app.TRAKT_BLACKLIST_NAME:
                    not_liked_show = trakt_api.request('users/' + app.TRAKT_USERNAME + '/lists/' +
                                                       app.TRAKT_BLACKLIST_NAME + '/items') or []
                else:
                    log.debug('Trakt blacklist name is empty')

            if trakt_list not in ['recommended', 'newshow', 'newseason']:
                limit_show = '?limit=' + text_type(100 + len(not_liked_show)) + '&'
            else:
                limit_show = '?'

            series = self.fetch_and_refresh_token(trakt_api, page_url + limit_show + 'extended=full,images') or []

            # Let's trigger a cache cleanup.
            missing_posters.clean()

            for show in series:
                try:
                    if 'show' not in show:
                        show['show'] = show

                    if not_liked_show and show['show']['ids']['tvdb'] in (s['show']['ids']['tvdb']
                                                                          for s in not_liked_show if s['type'] == 'show'):
                        continue

                    trending_shows.append(self._create_recommended_show(
                        storage_key=show['show']['ids']['trakt'],
                        series=show
                    ))

                except MultipleShowObjectsException:
                    continue

            # Update the dogpile index. This will allow us to retrieve all stored dogpile shows from the dbm.
            blacklist = app.TRAKT_BLACKLIST_NAME not in ''

        except TraktException as error:
            log.warning('Could not connect to Trakt service: {0}', error)
            raise

        return blacklist, trending_shows, removed_from_medusa
示例#13
0
    def update_watchlist(show_obj=None,
                         s=None,
                         e=None,
                         data_show=None,
                         data_episode=None,
                         update='add'):
        """
        Sends a request to trakt indicating that the given episode is part of our library.

        show_obj: The TVShow object to add to trakt
        s: season number
        e: episode number
        data_show: structured object of shows trakt type
        data_episode: structured object of episodes trakt type
        update: type o action add or remove
        """

        trakt_settings = {
            'trakt_api_secret': app.TRAKT_API_SECRET,
            'trakt_api_key': app.TRAKT_API_KEY,
            'trakt_access_token': app.TRAKT_ACCESS_TOKEN,
            'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN
        }

        trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT,
                             **trakt_settings)

        if app.USE_TRAKT:

            data = {}
            try:
                # URL parameters
                if show_obj is not None:
                    trakt_id = indexerApi(show_obj.indexer).config['trakt_id']
                    data = {
                        'shows': [{
                            'title': show_obj.name,
                            'year': show_obj.startyear,
                            'ids': {},
                        }]
                    }

                    if trakt_id == 'tvdb_id':
                        data['shows'][0]['ids']['tvdb'] = show_obj.indexerid
                    else:
                        data['shows'][0]['ids']['tvrage'] = show_obj.indexerid
                elif data_show is not None:
                    data.update(data_show)
                else:
                    logger.log(
                        "There's a coding problem contact developer. "
                        "It's needed to be provided at least one of the two: data_show or show_obj",
                        logger.WARNING)
                    return False

                if data_episode is not None:
                    data['shows'][0].update(data_episode)

                elif s is not None:
                    # trakt URL parameters
                    season = {
                        'season': [{
                            'number': s,
                        }]
                    }

                    if e is not None:
                        # trakt URL parameters
                        episode = {'episodes': [{'number': e}]}

                        season['season'][0].update(episode)

                    data['shows'][0].update(season)

                trakt_url = 'sync/watchlist'
                if update == 'remove':
                    trakt_url += '/remove'

                trakt_api.request(trakt_url, data, method='POST')

            except (TraktException, AuthException, ServerBusy) as trakt_ex:
                logger.log(
                    'Could not connect to Trakt service: {0}'.format(
                        ex(trakt_ex)), logger.WARNING)
                return False

        return True
示例#14
0
class TraktChecker(object):
    """Trakt checker class."""

    def __init__(self):
        """Initialize the class."""
        trakt_settings = {'trakt_api_key': app.TRAKT_API_KEY,
                          'trakt_api_secret': app.TRAKT_API_SECRET,
                          'trakt_access_token': app.TRAKT_ACCESS_TOKEN,
                          'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN}
        self.trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT, **trakt_settings)
        self.todoWanted = []
        self.show_watchlist = {}
        self.episode_watchlist = {}
        self.collection_list = {}
        self.amActive = False

    def run(self, force=False):
        """Run Trakt Checker."""
        self.amActive = True

        # add shows from Trakt watchlist
        if app.TRAKT_SYNC_WATCHLIST:
            self.todoWanted = []  # its about to all get re-added
            if len(app.ROOT_DIRS) < 2:
                log.warning('No default root directory')
                ui.notifications.error('Unable to add show',
                                       'You do not have any default root directory. '
                                       'Please configure in general settings!')
                return

            self.sync_watchlist()
            self.sync_library()

        self.amActive = False

    def _request(self, path, data=None, method='GET'):
        """Fetch shows from trakt and store the refresh token when needed."""
        try:
            library_shows = self.trakt_api.request(path, data, method=method) or []
            if self.trakt_api.access_token_refreshed:
                app.TRAKT_ACCESS_TOKEN = self.trakt_api.access_token
                app.TRAKT_REFRESH_TOKEN = self.trakt_api.refresh_token
                app.instance.save_config()
        except TokenExpiredException:
            log.warning(u'You need to get a PIN and authorize Medusa app')
            app.TRAKT_ACCESS_TOKEN = ''
            app.TRAKT_REFRESH_TOKEN = ''
            app.instance.save_config()
            raise TokenExpiredException('You need to get a PIN and authorize Medusa app')

        return library_shows

    def find_show(self, indexerid, indexer):
        """Find show in Trakt library."""
        trakt_library = []
        try:
            trakt_library = self._request('sync/collection/shows')
        except (TraktException, AuthException, TokenExpiredException) as error:
            log.info('Unable to retrieve shows from Trakt collection. Error: {error!r}', {'error': error})

        if not trakt_library:
            log.info('No shows found in your Trakt library. Nothing to sync')
            return
        trakt_show = [x for x in trakt_library if
                      get_trakt_indexer(indexer) and
                      int(indexerid) in [int(x['show']['ids'].get(get_trakt_indexer(indexer)))]]

        return trakt_show if trakt_show else None

    def remove_show_trakt_library(self, show_obj):
        """Remove show from trakt library."""
        if self.find_show(show_obj.indexerid, show_obj.indexer):

            # Check if TRAKT supports that indexer
            if not get_trakt_indexer(show_obj.indexer):
                return

            # URL parameters
            title = get_title_without_year(show_obj.name, show_obj.start_year)
            data = {
                'shows': [
                    {
                        'title': title,
                        'year': show_obj.start_year,
                        'ids': {}
                    }
                ]
            }

            data['shows'][0]['ids'][get_trakt_indexer(show_obj.indexer)] = show_obj.indexerid

            log.info("Removing '{show}' from Trakt library", {'show': show_obj.name})

            # Remove all episodes from the Trakt collection for this show
            try:
                self.remove_episode_trakt_collection(filter_show=show_obj)
            except (TraktException, AuthException, TokenExpiredException) as error:
                log.info("Unable to remove all episodes from show '{show}' from Trakt library. Error: {error!r}", {
                    'show': show_obj.name,
                    'error': error
                })

            try:
                self._request('sync/collection/remove', data, method='POST')
            except (TraktException, AuthException, TokenExpiredException) as error:
                log.info("Unable to remove show '{show}' from Trakt library. Error: {error!r}", {
                    'show': show_obj.name,
                    'error': error
                })

    def add_show_trakt_library(self, show_obj):
        """Add show to trakt library."""
        data = {}

        if not self.find_show(show_obj.indexerid, show_obj.indexer):

            # Check if TRAKT supports that indexer
            if not get_trakt_indexer(show_obj.indexer):
                return

            # URL parameters
            title = get_title_without_year(show_obj.name, show_obj.start_year)
            data = {
                'shows': [
                    {
                        'title': title,
                        'year': show_obj.start_year,
                        'ids': {}
                    }
                ]
            }

            data['shows'][0]['ids'][get_trakt_indexer(show_obj.indexer)] = show_obj.indexerid

        if data:
            log.info("Adding show '{show}' to Trakt library", {'show': show_obj.name})

            try:
                self._request('sync/collection', data, method='POST')
            except (TraktException, AuthException, TokenExpiredException) as error:
                log.info("Unable to add show '{show}' to Trakt library. Error: {error!r}", {
                    'show': show_obj.name,
                    'error': error
                })
                return

    def sync_library(self):
        """Sync Trakt library."""
        if app.TRAKT_SYNC and app.USE_TRAKT:
            log.debug('Syncing Trakt collection')

            if self._get_show_collection():
                self.add_episode_trakt_collection()
                if app.TRAKT_SYNC_REMOVE:
                    self.remove_episode_trakt_collection()
                log.debug('Synced Trakt collection')

    def remove_episode_trakt_collection(self, filter_show=None):
        """Remove episode from trakt collection.

        For episodes that no longer have a media file (location)
        :param filter_show: optional. Only remove episodes from trakt collection for given shows
        """
        if app.TRAKT_SYNC_REMOVE and app.TRAKT_SYNC and app.USE_TRAKT:

            params = []
            main_db_con = db.DBConnection()
            statuses = [DOWNLOADED, ARCHIVED]
            sql_selection = 'SELECT s.indexer, s.startyear, s.indexer_id, s.show_name,' \
                            'e.season, e.episode, e.status ' \
                            'FROM tv_episodes AS e, tv_shows AS s WHERE e.indexer = s.indexer AND ' \
                            's.indexer_id = e.showid and e.location = "" ' \
                            'AND e.status in ({0})'.format(','.join(['?'] * len(statuses)))
            if filter_show:
                sql_selection += ' AND s.indexer_id = ? AND e.indexer = ?'
                params = [filter_show.series_id, filter_show.indexer]

            sql_result = main_db_con.select(sql_selection, statuses + params)

            if sql_result:
                trakt_data = []

                for cur_episode in sql_result:
                    # Check if TRAKT supports that indexer
                    if not get_trakt_indexer(cur_episode['indexer']):
                        continue
                    if self._check_list(indexer=cur_episode['indexer'], indexer_id=cur_episode['indexer_id'],
                                        season=cur_episode['season'], episode=cur_episode['episode'],
                                        list_type='Collection'):
                        log.info("Removing episode '{show}' {ep} from Trakt collection", {
                            'show': cur_episode['show_name'],
                            'ep': episode_num(cur_episode['season'],
                                              cur_episode['episode'])
                        })
                        title = get_title_without_year(cur_episode['show_name'], cur_episode['startyear'])
                        trakt_data.append((cur_episode['indexer_id'], cur_episode['indexer'],
                                           title, cur_episode['startyear'],
                                           cur_episode['season'], cur_episode['episode']))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self._request('sync/collection/remove', data, method='POST')
                        self._get_show_collection()
                    except (TraktException, AuthException, TokenExpiredException) as error:
                        log.info('Unable to remove episodes from Trakt collection. Error: {error!r}', {
                            'error': error
                        })

    def add_episode_trakt_collection(self):
        """Add all existing episodes to Trakt collections.

        For episodes that have a media file (location)
        """
        if app.TRAKT_SYNC and app.USE_TRAKT:

            main_db_con = db.DBConnection()
            statuses = [DOWNLOADED, ARCHIVED]
            sql_selection = 'SELECT s.indexer, s.startyear, s.indexer_id, s.show_name, e.season, e.episode ' \
                            'FROM tv_episodes AS e, tv_shows AS s ' \
                            'WHERE e.indexer = s.indexer AND s.indexer_id = e.showid ' \
                            "AND e.status in ({0}) AND e.location <> ''".format(','.join(['?'] * len(statuses)))

            sql_result = main_db_con.select(sql_selection, statuses)

            if sql_result:
                trakt_data = []

                for cur_episode in sql_result:
                    # Check if TRAKT supports that indexer
                    if not get_trakt_indexer(cur_episode['indexer']):
                        continue

                    if not self._check_list(indexer=cur_episode['indexer'], indexer_id=cur_episode['indexer_id'],
                                            season=cur_episode['season'], episode=cur_episode['episode'],
                                            list_type='Collection'):
                        log.info("Adding episode '{show}' {ep} to Trakt collection", {
                            'show': cur_episode['show_name'],
                            'ep': episode_num(cur_episode['season'],
                                              cur_episode['episode'])
                        })
                        title = get_title_without_year(cur_episode['show_name'], cur_episode['startyear'])
                        trakt_data.append((cur_episode['indexer_id'], cur_episode['indexer'],
                                           title, cur_episode['startyear'],
                                           cur_episode['season'], cur_episode['episode']))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self._request('sync/collection', data, method='POST')
                        self._get_show_collection()
                    except (TraktException, AuthException, TokenExpiredException) as error:
                        log.info('Unable to add episodes to Trakt collection. Error: {error!r}', {'error': error})

    def sync_watchlist(self):
        """Sync Trakt watchlist."""
        if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT:
            log.debug('Syncing Trakt Watchlist')

            self.remove_from_library()

            if self._get_show_watchlist():
                log.debug('Syncing shows with Trakt watchlist')
                self.add_show_watchlist()
                self.sync_trakt_shows()

            if self._get_episode_watchlist():
                log.debug('Syncing episodes with Trakt watchlist')
                self.remove_episode_watchlist()
                self.add_episode_watchlist()
                self.sync_trakt_episodes()

            log.debug('Synced Trakt watchlist')

    def remove_episode_watchlist(self):
        """Remove episode from Trakt watchlist."""
        if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT:

            main_db_con = db.DBConnection()
            statuses = [DOWNLOADED, ARCHIVED]
            sql_selection = 'SELECT s.indexer, s.startyear, e.showid, s.show_name, e.season, e.episode ' \
                            'FROM tv_episodes AS e, tv_shows AS s ' \
                            'WHERE e.indexer = s.indexer ' \
                            'AND s.indexer_id = e.showid AND e.status in ({0})'.format(','.join(['?'] * len(statuses)))

            sql_result = main_db_con.select(sql_selection, statuses)

            if sql_result:
                trakt_data = []

                for cur_episode in sql_result:

                    # Check if TRAKT supports that indexer
                    if not get_trakt_indexer(cur_episode['indexer']):
                        continue

                    if self._check_list(indexer=cur_episode['indexer'], indexer_id=cur_episode['showid'],
                                        season=cur_episode['season'], episode=cur_episode['episode']):
                        log.info("Removing episode '{show}' {ep} from Trakt watchlist", {
                            'show': cur_episode['show_name'],
                            'ep': episode_num(cur_episode['season'],
                                              cur_episode['episode'])
                        })
                        title = get_title_without_year(cur_episode['show_name'], cur_episode['startyear'])
                        trakt_data.append((cur_episode['showid'], cur_episode['indexer'],
                                           title, cur_episode['startyear'],
                                           cur_episode['season'], cur_episode['episode']))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self._request('sync/watchlist/remove', data, method='POST')
                        self._get_episode_watchlist()
                    except (TraktException, AuthException, TokenExpiredException) as error:
                        log.info('Unable to remove episodes from Trakt watchlist. Error: {error!r}', {
                            'error': error
                        })

    def add_episode_watchlist(self):
        """Add episode to Tratk watchlist."""
        if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT:

            main_db_con = db.DBConnection()
            statuses = [SNATCHED, SNATCHED_BEST, SNATCHED_PROPER, WANTED]
            sql_selection = 'SELECT s.indexer, s.startyear, e.showid, s.show_name, e.season, e.episode ' \
                            'FROM tv_episodes AS e, tv_shows AS s ' \
                            'WHERE e.indexer = s.indexer AND s.indexer_id = e.showid AND s.paused = 0 ' \
                            'AND e.status in ({0})'.format(','.join(['?'] * len(statuses)))

            sql_result = main_db_con.select(sql_selection, statuses)

            if sql_result:
                trakt_data = []

                for cur_episode in sql_result:
                    # Check if TRAKT supports that indexer
                    if not get_trakt_indexer(cur_episode['indexer']):
                        continue

                    if not self._check_list(indexer=cur_episode['indexer'], indexer_id=cur_episode['showid'],
                                            season=cur_episode['season'], episode=cur_episode['episode']):
                        log.info("Adding episode '{show}' {ep} to Trakt watchlist", {
                            'show': cur_episode['show_name'],
                            'ep': episode_num(cur_episode['season'],
                                              cur_episode['episode'])
                        })
                        title = get_title_without_year(cur_episode['show_name'], cur_episode['startyear'])
                        trakt_data.append((cur_episode['showid'], cur_episode['indexer'], title,
                                           cur_episode['startyear'], cur_episode['season'], cur_episode['episode']))

                if trakt_data:
                    try:
                        data = self.trakt_bulk_data_generate(trakt_data)
                        self._request('sync/watchlist', data, method='POST')
                        self._get_episode_watchlist()
                    except (TraktException, AuthException, TokenExpiredException) as error:
                        log.info('Unable to add episode to Trakt watchlist. Error: {error!r}', {
                            'error': error
                        })

    def add_show_watchlist(self):
        """Add show to Trakt watchlist.

        It will add all shows from Medusa library
        """
        if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT:
            if app.showList:
                trakt_data = []

                for show_obj in app.showList:
                    if not self._check_list(show_obj=show_obj, list_type='Show'):
                        log.info("Adding show '{show}' to Trakt watchlist", {'show': show_obj.name})
                        title = get_title_without_year(show_obj.name, show_obj.start_year)
                        show_el = {'title': title, 'year': show_obj.start_year, 'ids': {}}
                        trakt_data.append(show_el)

                if trakt_data:
                    try:
                        data = {'shows': trakt_data}
                        self._request('sync/watchlist', data, method='POST')
                    except (TraktException, AuthException, TokenExpiredException) as error:
                        log.info('Unable to add shows to Trakt watchlist. Error: {error!r}', {'error': error})
                    self._get_show_watchlist()

    def remove_from_library(self):
        """Remove show from Medusa library is if ended/completed."""
        if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT and app.TRAKT_REMOVE_SHOW_FROM_APPLICATION:
            log.debug('Retrieving ended/completed shows to remove from Medusa')

            if app.showList:
                for show in app.showList:
                    if show.status == 'Ended':
                        trakt_id = show.externals.get('trakt_id', None)
                        if not (trakt_id or show.imdb_id):
                            log.info("Unable to check Trakt progress for show '{show}' "
                                     'because Trakt|IMDB ID is missing. Skipping', {'show': show.name})
                            continue

                        try:
                            progress = self._request('shows/{0}/progress/watched'.format(trakt_id or show.imdb_id))
                        except (TraktException, AuthException, TokenExpiredException) as error:
                            log.info("Unable to check if show '{show}' is ended/completed. Error: {error!r}", {
                                'show': show.name,
                                'error': error
                            })
                            continue
                        else:
                            if progress.get('aired', True) == progress.get('completed', False):
                                app.show_queue_scheduler.action.removeShow(show, full=True)
                                log.info("Show '{show}' has being queued to be removed from Medusa library", {
                                    'show': show.name
                                })

    def sync_trakt_shows(self):
        """Sync Trakt shows watchlist."""
        if not self.show_watchlist:
            log.info('No shows found in your Trakt watchlist. Nothing to sync')
        else:
            trakt_default_indexer = int(app.TRAKT_DEFAULT_INDEXER)

            for watchlisted_show in self.show_watchlist:
                trakt_show = watchlisted_show['show']

                if trakt_show['year'] and trakt_show['ids']['slug'].endswith(str(trakt_show['year'])):
                    show_name = '{title} ({year})'.format(title=trakt_show['title'], year=trakt_show['year'])
                else:
                    show_name = trakt_show['title']

                show = None
                indexer = None
                for i in indexerConfig:
                    trakt_indexer = get_trakt_indexer(i)
                    indexer_id = trakt_show['ids'].get(trakt_indexer, -1)
                    indexer = indexerConfig[i]['id']
                    show = Show.find_by_id(app.showList, indexer, indexer_id)
                    if show:
                        break
                if not show:
                    # If can't find with available indexers try IMDB
                    trakt_indexer = get_trakt_indexer(EXTERNAL_IMDB)
                    indexer_id = trakt_show['ids'].get(trakt_indexer, -1)
                    show = Show.find_by_id(app.showList, EXTERNAL_IMDB, indexer_id)
                if not show:
                    # If can't find with available indexers try TRAKT
                    trakt_indexer = get_trakt_indexer(EXTERNAL_TRAKT)
                    indexer_id = trakt_show['ids'].get(trakt_indexer, -1)
                    show = Show.find_by_id(app.showList, EXTERNAL_TRAKT, indexer_id)

                if show:
                    continue

                indexer_id = trakt_show['ids'].get(get_trakt_indexer(trakt_default_indexer), -1)
                if int(app.TRAKT_METHOD_ADD) != 2:
                    self.add_show(trakt_default_indexer, indexer_id, show_name, SKIPPED)
                else:
                    self.add_show(trakt_default_indexer, indexer_id, show_name, WANTED)

                if int(app.TRAKT_METHOD_ADD) == 1 and indexer:
                    new_show = Show.find_by_id(app.showList, indexer, indexer_id)

                    if new_show:
                        set_episode_to_wanted(new_show, 1, 1)
                    else:
                        log.warning('Unable to find the new added show.'
                                    'Pilot will be set to wanted in the next Trakt run')
                        self.todoWanted.append(indexer_id)
            log.debug('Synced shows with Trakt watchlist')

    def sync_trakt_episodes(self):
        """Sync Trakt episodes watchlist."""
        if not self.episode_watchlist:
            log.info('No episodes found in your Trakt watchlist. Nothing to sync')
            return

        added_shows = []
        trakt_default_indexer = int(app.TRAKT_DEFAULT_INDEXER)

        for watchlist_item in self.episode_watchlist:
            trakt_show = watchlist_item['show']
            trakt_episode = watchlist_item['episode'].get('number', -1)
            trakt_season = watchlist_item['episode'].get('season', -1)

            show = None
            for i in indexerConfig:
                trakt_indexer = get_trakt_indexer(i)
                indexer_id = trakt_show['ids'].get(trakt_indexer, -1)
                indexer = indexerConfig[i]['id']
                show = Show.find_by_id(app.showList, indexer, indexer_id)
                if show:
                    break

            if not show:
                # If can't find with available indexers try IMDB
                trakt_indexer = get_trakt_indexer(EXTERNAL_IMDB)
                indexer_id = trakt_show['ids'].get(trakt_indexer, -1)
                show = Show.find_by_id(app.showList, EXTERNAL_IMDB, indexer_id)
            if not show:
                # If can't find with available indexers try TRAKT
                trakt_indexer = get_trakt_indexer(EXTERNAL_TRAKT)
                indexer_id = trakt_show['ids'].get(trakt_indexer, -1)
                show = Show.find_by_id(app.showList, EXTERNAL_TRAKT, indexer_id)

            # If can't find show add with default trakt indexer
            if not show:
                indexer_id = trakt_show['ids'].get(get_trakt_indexer(trakt_default_indexer), -1)
                # Only add show if we didn't added it before
                if indexer_id not in added_shows:
                    self.add_show(trakt_default_indexer, indexer_id, trakt_show['title'], SKIPPED)
                    added_shows.append(indexer_id)

            elif not trakt_season == 0 and not show.paused:
                set_episode_to_wanted(show, trakt_season, trakt_episode)

        log.debug('Synced episodes with Trakt watchlist')

    @staticmethod
    def add_show(indexer, indexer_id, show_name, status):
        """Add a new show with default settings."""
        if not Show.find_by_id(app.showList, EXTERNAL_IMDB, indexer_id):
            root_dirs = app.ROOT_DIRS

            location = root_dirs[int(root_dirs[0]) + 1] if root_dirs else None

            if location:
                log.info("Adding show '{show}' using indexer: '{indexer_name}' and ID: {id}", {
                    'show': show_name,
                    'indexer_name': indexerConfig[indexer]['identifier'],
                    'id': indexer_id
                })

                app.show_queue_scheduler.action.addShow(indexer, indexer_id, None,
                                                        default_status=status,
                                                        quality=int(app.QUALITY_DEFAULT),
                                                        season_folders=int(app.SEASON_FOLDERS_DEFAULT),
                                                        paused=app.TRAKT_START_PAUSED,
                                                        default_status_after=status,
                                                        root_dir=location)
                tries = 0
                while tries < 3:
                    if Show.find_by_id(app.showList, indexer, indexer_id):
                        return
                    # Wait before show get's added and refreshed
                    time.sleep(60)
                    tries += 1
                log.warning("Error creating show '{show}. Please check logs' ", {
                    'show': show_name
                })
                return
            else:
                log.warning("Error creating show '{show}' folder. No default root directory", {
                    'show': show_name
                })
                return

    def manage_new_show(self, show):
        """Set episodes to wanted for the recently added show."""
        log.debug("Checking for wanted episodes for show '{show}' in Trakt watchlist", {'show': show.name})
        episodes = [i for i in self.todoWanted if i[0] == show.indexerid]

        for episode in episodes:
            self.todoWanted.remove(episode)
            set_episode_to_wanted(show, episode[1], episode[2])

    def _check_list(self, show_obj=None, indexer=None, indexer_id=None, season=None, episode=None, list_type=None):
        """Check if we can find the show in the Trakt watchlist|collection list."""
        if 'Collection' == list_type:
            trakt_indexer = get_trakt_indexer(indexer)
            for collected_show in self.collection_list:
                if not collected_show['show']['ids'].get(trakt_indexer, '') == indexer_id:
                    continue
                if 'seasons' in collected_show:
                    for season_item in collected_show['seasons']:
                        for episode_item in season_item['episodes']:
                            trakt_season = season_item['number']
                            trakt_episode = episode_item['number']
                            if trakt_season == season and trakt_episode == episode:
                                return True
                else:
                    return False
        elif 'Show' == list_type:
            trakt_indexer = get_trakt_indexer(show_obj.indexer)
            for watchlisted_show in self.show_watchlist:
                if watchlisted_show['show']['ids'].get(trakt_indexer) == show_obj.indexerid or \
                        watchlisted_show['show']['ids'].get(get_trakt_indexer(EXTERNAL_IMDB), '') == show_obj.imdb_id:
                    return True
            return False
        else:
            trakt_indexer = get_trakt_indexer(indexer)
            for watchlisted_episode in self.episode_watchlist:
                if watchlisted_episode['episode'].get('season', -1) == season and \
                        watchlisted_episode['episode'].get('number', -1) == episode and \
                        watchlisted_episode['show']['ids'].get(trakt_indexer, '') == indexer_id:
                    return True
            return False

    def _get_show_watchlist(self):
        """Get shows watchlist."""
        try:
            self.show_watchlist = self._request('sync/watchlist/shows')
        except (TraktException, AuthException, TokenExpiredException) as error:
            log.info(u'Unable to retrieve shows from Trakt watchlist. Error: {error!r}', {'error': error})
            return False
        return True

    def _get_episode_watchlist(self):
        """Get episodes watchlist."""
        try:
            self.episode_watchlist = self._request('sync/watchlist/episodes')
        except (TraktException, AuthException, TokenExpiredException) as error:
            log.info(u'Unable to retrieve episodes from Trakt watchlist. Error: {error!r}', {'error': error})
            return False
        return True

    def _get_show_collection(self):
        """Get show collection."""
        try:
            self.collection_list = self._request('sync/collection/shows')
        except (TraktException, AuthException, TokenExpiredException) as error:
            log.info('Unable to retrieve shows from Trakt collection. Error: {error!r}', {'error': error})
            return False
        return True

    @staticmethod
    def trakt_bulk_data_generate(trakt_data):
        """Build the JSON structure to send back to Trakt."""
        unique_shows = {}
        unique_seasons = {}

        for indexer_id, indexer, show_name, start_year, season, episode in trakt_data:
            if indexer_id not in unique_shows:
                unique_shows[indexer_id] = {'title': show_name, 'year': start_year, 'ids': {}, 'seasons': []}
                unique_shows[indexer_id]['ids'][get_trakt_indexer(indexer)] = indexer_id
                unique_seasons[indexer_id] = []

        # Get the unique seasons per Show
        for indexer_id, indexer, show_name, start_year, season, episode in trakt_data:
            if season not in unique_seasons[indexer_id]:
                unique_seasons[indexer_id].append(season)

        # build the query
        show_list = []
        seasons_list = {}

        for searched_show in unique_shows:
            show = []
            seasons_list[searched_show] = []

            for searched_season in unique_seasons[searched_show]:
                episodes_list = []

                for indexer_id, indexer, show_name, start_year, season, episode in trakt_data:
                    if season == searched_season and indexer_id == searched_show:
                        episodes_list.append({'number': episode})
                show = unique_shows[searched_show]
                show['seasons'].append({'number': searched_season, 'episodes': episodes_list})
            if show:
                show_list.append(show)
        post_data = {'shows': show_list}
        return post_data