예제 #1
0
    def _retrieve_show_image(self, image_type, show_obj, which=None):
        """
        Gets an image URL from theTVDB.com and TMDB.com, downloads it and returns the data.

        image_type: type of image to retrieve (currently supported: fanart, poster, banner)
        show_obj: a TVShow object to use when searching for the image
        which: optional, a specific numbered poster to look for

        Returns: the binary image data if available, or else None
        """
        image_url = None
        indexer_lang = show_obj.lang

        try:
            # There's gotta be a better way of doing this but we don't wanna
            # change the language value elsewhere
            lINDEXER_API_PARMS = app.indexerApi(show_obj.indexer).api_params.copy()

            lINDEXER_API_PARMS['banners'] = True

            if indexer_lang and not indexer_lang == app.INDEXER_DEFAULT_LANGUAGE:
                lINDEXER_API_PARMS['language'] = indexer_lang

            if show_obj.dvdorder != 0:
                lINDEXER_API_PARMS['dvdorder'] = True

            t = app.indexerApi(show_obj.indexer).indexer(**lINDEXER_API_PARMS)
            indexer_show_obj = t[show_obj.indexerid]
        except (app.indexer_error, IOError) as e:
            logger.log(u"Unable to look up show on " + app.indexerApi(
                show_obj.indexer).name + ", not downloading images: " + ex(e), logger.WARNING)
            logger.log(u"%s may be experiencing some problems. Try again later." % app.indexerApi(show_obj.indexer).name, logger.DEBUG)
            return None

        if image_type not in ('fanart', 'poster', 'banner', 'poster_thumb', 'banner_thumb'):
            logger.log(u"Invalid image type " + str(image_type) + ", couldn't find it in the " + app.indexerApi(
                show_obj.indexer).name + " object", logger.ERROR)
            return None

        if image_type == 'poster_thumb':
            if getattr(indexer_show_obj, 'poster', None):
                image_url = re.sub('posters', '_cache/posters', indexer_show_obj['poster'])
            if not image_url:
                # Try and get images from TMDB
                image_url = self._retrieve_show_images_from_tmdb(show_obj, image_type)
        elif image_type == 'banner_thumb':
            if getattr(indexer_show_obj, 'banner', None):
                image_url = re.sub('graphical', '_cache/graphical', indexer_show_obj['banner'])
        else:
            if getattr(indexer_show_obj, image_type, None):
                image_url = indexer_show_obj[image_type]
            if not image_url:
                # Try and get images from TMDB
                image_url = self._retrieve_show_images_from_tmdb(show_obj, image_type)

        if image_url:
            image_data = metadata_helpers.getShowImage(image_url, which)
            return image_data

        return None
예제 #2
0
    def _season_posters_dict(self, show_obj, season):
        """
        Should return a dict like:

        result = {<season number>:
                    {1: '<url 1>', 2: <url 2>, ...},}
        """

        # This holds our resulting dictionary of season art
        result = {}

        indexer_lang = show_obj.lang

        try:
            # There's gotta be a better way of doing this but we don't wanna
            # change the language value elsewhere
            lINDEXER_API_PARMS = app.indexerApi(show_obj.indexer).api_params.copy()

            lINDEXER_API_PARMS['banners'] = True

            if indexer_lang and not indexer_lang == app.INDEXER_DEFAULT_LANGUAGE:
                lINDEXER_API_PARMS['language'] = indexer_lang

            if show_obj.dvdorder != 0:
                lINDEXER_API_PARMS['dvdorder'] = True

            t = app.indexerApi(show_obj.indexer).indexer(**lINDEXER_API_PARMS)
            indexer_show_obj = t[show_obj.indexerid]
        except (app.indexer_error, IOError) as e:
            logger.log(u"Unable to look up show on " + app.indexerApi(
                show_obj.indexer).name + ", not downloading images: " + ex(e), logger.WARNING)
            logger.log(u"%s may be experiencing some problems. Try again later." % app.indexerApi(show_obj.indexer).name, logger.DEBUG)
            return result

        # if we have no season banners then just finish
        if not getattr(indexer_show_obj, '_banners', None):
            return result

        if 'season' not in indexer_show_obj['_banners'] or 'season' not in indexer_show_obj['_banners']['season']:
            return result

        # Give us just the normal poster-style season graphics
        seasonsArtObj = indexer_show_obj['_banners']['season']['season']

        # Returns a nested dictionary of season art with the season
        # number as primary key. It's really overkill but gives the option
        # to present to user via ui to pick down the road.

        result[season] = {}

        # find the correct season in the TVDB object and just copy the dict into our result dict
        for seasonArtID in seasonsArtObj.keys():
            if int(seasonsArtObj[seasonArtID]['season']) == season and seasonsArtObj[seasonArtID]['language'] == app.INDEXER_DEFAULT_LANGUAGE:
                result[season][seasonArtID] = seasonsArtObj[seasonArtID]['_bannerpath']

        return result
예제 #3
0
    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)
예제 #4
0
    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
예제 #5
0
    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)
예제 #6
0
    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)
예제 #7
0
    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)
예제 #8
0
    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)
예제 #9
0
 def __str__(self):
     return u'{date} {name} {season}x{episode} of {series_id} from {indexer}'.format(
         date=self.date,
         name=self.name,
         season=self.season,
         episode=self.episode,
         series_id=self.indexerid,
         indexer=app.indexerApi(self.indexer).name)
예제 #10
0
def _get_xem_exceptions():
    xem_exceptions = {}

    if should_refresh('xem'):
        for indexer in app.indexerApi().indexers:
            logger.log(
                'Checking for XEM scene exceptions updates for {0}'.format(
                    app.indexerApi(indexer).name))

            xem_url = 'http://thexem.de/map/allNames?origin={0}&seasonNumbers=1'.format(
                app.indexerApi(indexer).config['xem_origin'])

            response = helpers.getURL(xem_url,
                                      session=xem_session,
                                      timeout=60,
                                      returns='response')
            try:
                jdata = response.json()
            except (ValueError, AttributeError) as error:
                logger.log(
                    'Check scene exceptions update failed for {0}. Unable to get URL: {1}'
                    .format(app.indexerApi(indexer).name,
                            xem_url), logger.DEBUG)
                continue

            if not jdata['data'] or jdata['result'] == 'failure':
                logger.log(
                    'No data returned from XEM while checking for scene exceptions. '
                    'Update failed for {0}'.format(
                        app.indexerApi(indexer).name), logger.DEBUG)
                continue

            for indexer_id, exceptions in iteritems(jdata['data']):
                try:
                    xem_exceptions[indexer_id] = exceptions
                except Exception as error:
                    logger.log(
                        'XEM: Rejected entry: Indexer ID: {0}, Exceptions: {1}'
                        .format(indexer_id, exceptions), logger.WARNING)
                    logger.log(
                        'XEM: Rejected entry error message: {0}'.format(error),
                        logger.ERROR)

        set_last_refresh('xem')

    return xem_exceptions
예제 #11
0
def _get_custom_exceptions():
    custom_exceptions = {}

    do_refresh = False
    for indexer in app.indexerApi().indexers:
        if should_refresh(app.indexerApi(indexer).name):
            do_refresh = True
            break

    if do_refresh:
        location = app.indexerApi(INDEXER_TVDB).config['scene_loc']
        logger.log(
            'Checking for scene exception updates from {0}'.format(location))

        response = helpers.getURL(location,
                                  session=app.indexerApi(INDEXER_TVDB).session,
                                  timeout=60,
                                  returns='response')
        try:
            jdata = response.json()
        except (ValueError, AttributeError) as error:
            logger.log(
                'Check scene exceptions update failed. Unable to update from {0}. Error: {1}'
                .format(location, error), logger.DEBUG)
            return custom_exceptions

        for indexer in app.indexerApi().indexers:
            try:
                for indexer_id in jdata[app.indexerApi(
                        indexer).config['xem_origin']]:
                    alias_list = [{
                        scene_exception: int(scene_season)
                    } for scene_season in jdata[app.indexerApi(
                        indexer).config['xem_origin']][indexer_id]
                                  for scene_exception in jdata[app.indexerApi(
                                      indexer).config['xem_origin']]
                                  [indexer_id][scene_season]]
                    custom_exceptions[indexer_id] = alias_list
            except Exception as error:
                logger.log(
                    'Unable to update scene exceptions for {0}. Error: {1}'.
                    format(indexer, error), logger.ERROR)
                continue

            set_last_refresh(app.indexerApi(indexer).name)

    return custom_exceptions
예제 #12
0
    def newShow(self, show_to_add=None, other_shows=None, search_string=None):
        """
        Display the new show page which collects a tvdb id, folder, and extra options and
        posts them to addNewShow
        """
        t = PageTemplate(rh=self, filename='addShows_newShow.mako')

        indexer, show_dir, indexer_id, show_name = self.split_extra_show(
            show_to_add)
        use_provided_info = bool(indexer_id and indexer and show_name)

        # use the given show_dir for the indexer search if available
        if not show_dir:
            if search_string:
                default_show_name = search_string
            else:
                default_show_name = ''

        elif not show_name:
            default_show_name = re.sub(
                r' \(\d{4}\)', '',
                os.path.basename(os.path.normpath(show_dir)).replace('.', ' '))
        else:
            default_show_name = show_name

        # carry a list of other dirs if given
        if not other_shows:
            other_shows = []
        elif not isinstance(other_shows, list):
            other_shows = [other_shows]

        provided_indexer_id = int(indexer_id or 0)
        provided_indexer_name = show_name

        provided_indexer = int(indexer or app.INDEXER_DEFAULT)

        return t.render(enable_anime_options=True,
                        use_provided_info=use_provided_info,
                        default_show_name=default_show_name,
                        other_shows=other_shows,
                        provided_show_dir=show_dir,
                        provided_indexer_id=provided_indexer_id,
                        provided_indexer_name=provided_indexer_name,
                        provided_indexer=provided_indexer,
                        indexers=app.indexerApi().indexers,
                        whitelist=[],
                        blacklist=[],
                        groups=[],
                        title='New Show',
                        header='New Show',
                        topmenu='home',
                        controller='addShows',
                        action='newShow')
예제 #13
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)
예제 #14
0
    def searchIndexersForShowName(search_term, lang=None, indexer=None):
        if not lang or lang == 'null':
            lang = app.INDEXER_DEFAULT_LANGUAGE

        search_term = search_term.encode('utf-8')

        search_terms = [search_term]

        # If search term ends with what looks like a year, enclose it in ()
        matches = re.match(r'^(.+ |)([12][0-9]{3})$', search_term)
        if matches:
            search_terms.append('%s(%s)' %
                                (matches.group(1), matches.group(2)))

        for searchTerm in search_terms:
            # If search term begins with an article, let's also search for it without
            matches = re.match(r'^(?:a|an|the) (.+)$', searchTerm, re.I)
            if matches:
                search_terms.append(matches.group(1))

        results = {}
        final_results = []

        # Query Indexers for each search term and build the list of results
        for indexer in app.indexerApi().indexers if not int(indexer) else [
                int(indexer)
        ]:
            l_indexer_api_parms = app.indexerApi(indexer).api_params.copy()
            l_indexer_api_parms['language'] = lang
            l_indexer_api_parms['custom_ui'] = classes.AllShowsListUI
            t = app.indexerApi(indexer).indexer(**l_indexer_api_parms)

            logger.log(
                u'Searching for Show with searchterm(s): %s on Indexer: %s' %
                (search_terms, app.indexerApi(indexer).name), logger.DEBUG)
            for searchTerm in search_terms:
                try:
                    indexer_results = t[searchTerm]
                    # add search results
                    results.setdefault(indexer, []).extend(indexer_results)
                except indexer_exception as msg:
                    logger.log(
                        u'Error searching for show: {error}'.format(error=msg))

        for i, shows in iteritems(results):
            final_results.extend({(app.indexerApi(i).name, i,
                                   app.indexerApi(i).config['show_url'],
                                   int(show['id']), show['seriesname'],
                                   show['firstaired'])
                                  for show in shows})

        lang_id = app.indexerApi().config['langabbv_to_id'][lang]
        return json.dumps({'results': final_results, 'langid': lang_id})
예제 #15
0
    def trakt_show_data_generate(data):

        showList = []
        for indexer, indexerid, title, year in data:
            trakt_id = app.indexerApi(indexer).config['trakt_id']
            show = {'title': title, 'year': year, 'ids': {}}
            if trakt_id == 'tvdb_id':
                show['ids']['tvdb'] = indexerid
            else:
                show['ids']['tvrage'] = indexerid
            showList.append(show)

        post_data = {'shows': showList}

        return post_data
예제 #16
0
    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
예제 #17
0
    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)
예제 #18
0
    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)
예제 #19
0
    def run(self):

        ShowQueueItem.run(self)

        logger.log(
            u'{id}: Beginning update of {show}'.format(id=self.show.indexerid,
                                                       show=self.show.name),
            logger.DEBUG)

        logger.log(
            u'{id}: Retrieving show info from {indexer}'.format(
                id=self.show.indexerid,
                indexer=app.indexerApi(self.show.indexer).name), logger.DEBUG)
        try:
            self.show.load_from_indexer()
        except app.indexer_error as e:
            logger.log(
                u'{id}: Unable to contact {indexer}. Aborting: {error_msg}'.
                format(id=self.show.indexerid,
                       indexer=app.indexerApi(self.show.indexer).name,
                       error_msg=ex(e)), logger.WARNING)
            return
        except app.indexer_attributenotfound as e:
            logger.log(
                u'{id}: Data retrieved from {indexer} was incomplete. Aborting: {error_msg}'
                .format(id=self.show.indexerid,
                        indexer=app.indexerApi(self.show.indexer).name,
                        error_msg=ex(e)), logger.WARNING)
            return

        logger.log(
            u'{id}: Retrieving show info from IMDb'.format(
                id=self.show.indexerid), logger.DEBUG)
        try:
            self.show.load_imdb_info()
        except imdb_exceptions.IMDbError as e:
            logger.log(
                u'{id}: Something wrong on IMDb api: {error_msg}'.format(
                    id=self.show.indexerid, error_msg=ex(e)), logger.WARNING)
        except Exception as e:
            logger.log(
                u'{id}: Error loading IMDb info: {error_msg}'.format(
                    id=self.show.indexerid, error_msg=ex(e)), logger.WARNING)

        # have to save show before reading episodes from db
        try:
            logger.log(
                u'{id}: Saving new IMDb show info to database'.format(
                    id=self.show.indexerid), logger.DEBUG)
            self.show.save_to_db()
        except Exception as e:
            logger.log(
                u"{id}: Error saving new IMDb show info to database: {error_msg}"
                .format(id=self.show.indexerid,
                        error_msg=ex(e)), logger.WARNING)
            logger.log(traceback.format_exc(), logger.ERROR)

        # get episode list from DB
        DBEpList = self.show.load_episodes_from_db()

        # get episode list from TVDB
        try:
            IndexerEpList = self.show.load_episodes_from_indexer()
        except app.indexer_exception as e:
            logger.log(
                u'{id}: Unable to get info from {indexer}. The show info will not be refreshed. '
                u'Error: {error_msg}'.format(id=self.show.indexerid,
                                             indexer=app.indexerApi(
                                                 self.show.indexer).name,
                                             error_msg=ex(e)), logger.WARNING)
            IndexerEpList = None

        if IndexerEpList is None:
            logger.log(
                u'{id}: No data returned from {indexer}. Unable to update this show'
                .format(id=self.show.indexerid,
                        indexer=app.indexerApi(self.show.indexer).name),
                logger.WARNING)
        else:
            # for each ep we found on the Indexer delete it from the DB list
            for cur_season in IndexerEpList:
                for cur_episode in IndexerEpList[cur_season]:
                    if cur_season in DBEpList and cur_episode in DBEpList[
                            cur_season]:
                        del DBEpList[cur_season][cur_episode]
                    else:
                        # Create the episode objectes for episodes that are not going to be deleted
                        curEp = self.show.get_episode(cur_season, cur_episode)

            # remaining episodes in the DB list are not on the indexer, just delete them from the DB
            for cur_season in DBEpList:
                for cur_episode in DBEpList[cur_season]:
                    logger.log(
                        u'{id}: Permanently deleting episode {show} {ep} from the database'
                        .format(id=self.show.indexerid,
                                show=self.show.name,
                                ep=episode_num(cur_season,
                                               cur_episode)), logger.DEBUG)
                    # Create the ep object only because Im going to delete it
                    curEp = self.show.get_episode(cur_season, cur_episode)
                    try:
                        curEp.delete_episode()
                    except EpisodeDeletedException:
                        pass

        # Save only after all changes were applied
        try:
            logger.log(
                u'{id}: Saving all updated show info to database'.format(
                    id=self.show.indexerid), logger.DEBUG)
            self.show.save_to_db()
        except Exception as e:
            logger.log(
                u'{id}: Error saving all updated show info to database: {error_msg}'
                .format(id=self.show.indexerid,
                        error_msg=ex(e)), logger.WARNING)
            logger.log(traceback.format_exc(), logger.ERROR)

        logger.log(
            u'{id}: Finished update of {show}'.format(id=self.show.indexerid,
                                                      show=self.show.name),
            logger.DEBUG)
        # Refresh show needs to be forced since current execution locks the queue
        app.showQueueScheduler.action.refreshShow(self.show, True)
        self.finish()
예제 #20
0
    def _show_data(self, show_obj):
        """
        Creates an elementTree XML structure for a MediaBrowser-style series.xml
        returns the resulting data object.

        show_obj: a TVShow instance to create the NFO for
        """

        show_id = show_obj.indexerid

        indexer_lang = show_obj.lang
        # There's gotta be a better way of doing this but we don't wanna
        # change the language value elsewhere
        l_indexer_api_params = app.indexerApi(
            show_obj.indexer).api_params.copy()

        l_indexer_api_params['actors'] = True

        if indexer_lang and not indexer_lang == app.INDEXER_DEFAULT_LANGUAGE:
            l_indexer_api_params['language'] = indexer_lang

        if show_obj.dvdorder != 0:
            l_indexer_api_params['dvdorder'] = True

        t = app.indexerApi(show_obj.indexer).indexer(**l_indexer_api_params)

        tv_node = etree.Element('Series')

        try:
            my_show = t[int(show_id)]
        except app.indexer_shownotfound:
            logger.log(
                u'Unable to find {indexer} show {id}, skipping it'.format(
                    indexer=app.indexerApi(show_obj.indexer).name, id=show_id),
                logger.ERROR)
            raise

        except app.indexer_error:
            logger.log(
                u'{indexer} is down, can\'t use its data to add this show'.
                format(indexer=app.indexerApi(show_obj.indexer).name),
                logger.ERROR)
            raise

        # check for title and id
        if not (getattr(my_show, 'seriesname', None)
                and getattr(my_show, 'id', None)):
            logger.log(
                u'Incomplete info for {indexer} show {id}, skipping it'.format(
                    indexer=app.indexerApi(show_obj.indexer).name, id=show_id),
                logger.ERROR)
            return False

        if getattr(my_show, 'id', None):
            indexerid = etree.SubElement(tv_node, 'id')
            indexerid.text = str(my_show['id'])

        if getattr(my_show, 'seriesname', None):
            series_name = etree.SubElement(tv_node, 'SeriesName')
            series_name.text = my_show['seriesname']

        if getattr(my_show, 'status', None):
            status = etree.SubElement(tv_node, 'Status')
            status.text = my_show['status']

        if getattr(my_show, 'network', None):
            network = etree.SubElement(tv_node, 'Network')
            network.text = my_show['network']

        if getattr(my_show, 'airs_time', None):
            airs_time = etree.SubElement(tv_node, 'Airs_Time')
            airs_time.text = my_show['airs_time']

        if getattr(my_show, 'airs_dayofweek', None):
            airs_day_of_week = etree.SubElement(tv_node, 'Airs_DayOfWeek')
            airs_day_of_week.text = my_show['airs_dayofweek']

        first_aired = etree.SubElement(tv_node, 'FirstAired')
        if getattr(my_show, 'firstaired', None):
            first_aired.text = my_show['firstaired']

        if getattr(my_show, 'contentrating', None):
            content_rating = etree.SubElement(tv_node, 'ContentRating')
            content_rating.text = my_show['contentrating']

            mpaa = etree.SubElement(tv_node, 'MPAARating')
            mpaa.text = my_show['contentrating']

            certification = etree.SubElement(tv_node, 'certification')
            certification.text = my_show['contentrating']

        metadata_type = etree.SubElement(tv_node, 'Type')
        metadata_type.text = 'Series'

        if getattr(my_show, 'overview', None):
            overview = etree.SubElement(tv_node, 'Overview')
            overview.text = my_show['overview']

        if getattr(my_show, 'firstaired', None):
            premiere_date = etree.SubElement(tv_node, 'PremiereDate')
            premiere_date.text = my_show['firstaired']

        if getattr(my_show, 'rating', None):
            rating = etree.SubElement(tv_node, 'Rating')
            rating.text = my_show['rating']

        if getattr(my_show, 'firstaired', None):
            try:
                year_text = str(
                    datetime.datetime.strptime(my_show['firstaired'],
                                               dateFormat).year)
                if year_text:
                    production_year = etree.SubElement(tv_node,
                                                       'ProductionYear')
                    production_year.text = year_text
            except Exception:
                pass

        if getattr(my_show, 'runtime', None):
            running_time = etree.SubElement(tv_node, 'RunningTime')
            running_time.text = my_show['runtime']

            runtime = etree.SubElement(tv_node, 'Runtime')
            runtime.text = my_show['runtime']

        if getattr(my_show, 'imdb_id', None):
            imdb_id = etree.SubElement(tv_node, 'IMDB_ID')
            imdb_id.text = my_show['imdb_id']

            imdb_id = etree.SubElement(tv_node, 'IMDB')
            imdb_id.text = my_show['imdb_id']

            imdb_id = etree.SubElement(tv_node, 'IMDbId')
            imdb_id.text = my_show['imdb_id']

        if getattr(my_show, 'zap2it_id', None):
            zap2it_id = etree.SubElement(tv_node, 'Zap2ItId')
            zap2it_id.text = my_show['zap2it_id']

        if getattr(my_show, 'genre', None) and isinstance(
                my_show['genre'], string_types):
            genres = etree.SubElement(tv_node, 'Genres')
            for genre in my_show['genre'].split('|'):
                if genre.strip():
                    cur_genre = etree.SubElement(genres, 'Genre')
                    cur_genre.text = genre.strip()

            genre = etree.SubElement(tv_node, 'Genre')
            genre.text = '|'.join(
                [x.strip() for x in my_show['genre'].split('|') if x.strip()])

        if getattr(my_show, 'network', None):
            studios = etree.SubElement(tv_node, 'Studios')
            studio = etree.SubElement(studios, 'Studio')
            studio.text = my_show['network']

        if getattr(my_show, '_actors', None):
            persons = etree.SubElement(tv_node, 'Persons')
            for actor in my_show['_actors']:
                if not ('name' in actor and actor['name'].strip()):
                    continue

                cur_actor = etree.SubElement(persons, 'Person')

                cur_actor_name = etree.SubElement(cur_actor, 'Name')
                cur_actor_name.text = actor['name'].strip()

                cur_actor_type = etree.SubElement(cur_actor, 'Type')
                cur_actor_type.text = 'Actor'

                if 'role' in actor and actor['role'].strip():
                    cur_actor_role = etree.SubElement(cur_actor, 'Role')
                    cur_actor_role.text = actor['role'].strip()

        helpers.indentXML(tv_node)

        data = etree.ElementTree(tv_node)

        return data
예제 #21
0
    def _ep_data(self, ep_obj):
        """
        Creates an elementTree XML structure for a MediaBrowser style episode.xml
        and returns the resulting data object.

        show_obj: a TVShow instance to create the NFO for
        """

        eps_to_write = [ep_obj] + ep_obj.related_episodes

        persons_dict = {'Director': [], 'GuestStar': [], 'Writer': []}

        indexer_lang = ep_obj.show.lang

        l_indexer_api_params = app.indexerApi(
            ep_obj.show.indexer).api_params.copy()

        l_indexer_api_params[b'actors'] = True

        if indexer_lang and not indexer_lang == app.INDEXER_DEFAULT_LANGUAGE:
            l_indexer_api_params[b'language'] = indexer_lang

        if ep_obj.show.dvdorder != 0:
            l_indexer_api_params[b'dvdorder'] = True

        try:
            t = app.indexerApi(
                ep_obj.show.indexer).indexer(**l_indexer_api_params)
            my_show = t[ep_obj.show.indexerid]
        except app.indexer_shownotfound as e:
            raise ShowNotFoundException(e.message)
        except app.indexer_error:
            logger.log(
                u'Unable to connect to {indexer} while creating meta files - skipping it.'
                .format(indexer=app.indexerApi(ep_obj.show.indexer).name),
                logger.WARNING)
            return

        root_node = etree.Element('Item')

        # write an MediaBrowser XML containing info for all matching episodes
        for ep_to_write in eps_to_write:

            try:
                my_ep = my_show[ep_to_write.season][ep_to_write.episode]
            except (app.indexer_episodenotfound, app.indexer_seasonnotfound):
                logger.log(
                    u'Unable to find episode {ep_num} on {indexer}... '
                    u'has it been removed? Should I delete from db?'.format(
                        ep_num=episode_num(ep_to_write.season,
                                           ep_to_write.episode),
                        indexer=app.indexerApi(ep_obj.show.indexer).name))
                return None

            if ep_to_write == ep_obj:
                # root (or single) episode

                # default to today's date for specials if firstaired is not set
                if ep_to_write.season == 0 and not getattr(
                        my_ep, 'firstaired', None):
                    my_ep['firstaired'] = str(datetime.date.fromordinal(1))

                if not (getattr(my_ep, 'episodename', None)
                        and getattr(my_ep, 'firstaired', None)):
                    return None

                episode = root_node

                if ep_to_write.name:
                    episode_name = etree.SubElement(episode, 'EpisodeName')
                    episode_name.text = ep_to_write.name

                episode_number = etree.SubElement(episode, 'EpisodeNumber')
                episode_number.text = str(ep_obj.episode)

                if ep_obj.related_episodes:
                    episode_number_end = etree.SubElement(
                        episode, 'EpisodeNumberEnd')
                    episode_number_end.text = str(ep_to_write.episode)

                season_number = etree.SubElement(episode, 'SeasonNumber')
                season_number.text = str(ep_to_write.season)

                if not ep_obj.related_episodes and getattr(
                        my_ep, 'absolute_number', None):
                    absolute_number = etree.SubElement(episode,
                                                       'absolute_number')
                    absolute_number.text = str(my_ep['absolute_number'])

                if ep_to_write.airdate != datetime.date.fromordinal(1):
                    first_aired = etree.SubElement(episode, 'FirstAired')
                    first_aired.text = str(ep_to_write.airdate)

                metadata_type = etree.SubElement(episode, 'Type')
                metadata_type.text = 'Episode'

                if ep_to_write.description:
                    overview = etree.SubElement(episode, 'Overview')
                    overview.text = ep_to_write.description

                if not ep_obj.related_episodes:
                    if getattr(my_ep, 'rating', None):
                        rating = etree.SubElement(episode, 'Rating')
                        rating.text = my_ep['rating']

                    if getattr(my_show, 'imdb_id', None):
                        IMDB_ID = etree.SubElement(episode, 'IMDB_ID')
                        IMDB_ID.text = my_show['imdb_id']

                        IMDB = etree.SubElement(episode, 'IMDB')
                        IMDB.text = my_show['imdb_id']

                        IMDbId = etree.SubElement(episode, 'IMDbId')
                        IMDbId.text = my_show['imdb_id']

                indexer_id = etree.SubElement(episode, 'id')
                indexer_id.text = str(ep_to_write.indexerid)

                persons = etree.SubElement(episode, 'Persons')

                if getattr(my_show, '_actors', None):
                    for actor in my_show['_actors']:
                        if not ('name' in actor and actor['name'].strip()):
                            continue

                        cur_actor = etree.SubElement(persons, 'Person')

                        cur_actor_name = etree.SubElement(cur_actor, 'Name')
                        cur_actor_name.text = actor['name'].strip()

                        cur_actor_type = etree.SubElement(cur_actor, 'Type')
                        cur_actor_type.text = 'Actor'

                        if 'role' in actor and actor['role'].strip():
                            cur_actor_role = etree.SubElement(
                                cur_actor, 'Role')
                            cur_actor_role.text = actor['role'].strip()

                language = etree.SubElement(episode, 'Language')
                try:
                    language.text = my_ep['language']
                except Exception:
                    language.text = app.INDEXER_DEFAULT_LANGUAGE  # tvrage api doesn't provide language so we must assume a value here

                thumb = etree.SubElement(episode, 'filename')
                # TODO: See what this is needed for.. if its still needed
                # just write this to the NFO regardless of whether it actually exists or not
                # note: renaming files after nfo generation will break this, tough luck
                thumb_text = self.get_episode_thumb_path(ep_obj)
                if thumb_text:
                    thumb.text = thumb_text

            else:
                # append data from (if any) related episodes
                episode_number_end.text = str(ep_to_write.episode)

                if ep_to_write.name:
                    if not episode_name.text:
                        episode_name.text = ep_to_write.name
                    else:
                        episode_name.text = u', '.join(
                            [episode_name.text, ep_to_write.name])

                if ep_to_write.description:
                    if not overview.text:
                        overview.text = ep_to_write.description
                    else:
                        overview.text = u'\r'.join(
                            [overview.text, ep_to_write.description])

            # collect all directors, guest stars and writers
            if getattr(my_ep, 'director', None):
                persons_dict['Director'] += [
                    x.strip() for x in my_ep['director'].split('|')
                    if x.strip()
                ]
            if getattr(my_ep, 'gueststars', None):
                persons_dict['GuestStar'] += [
                    x.strip() for x in my_ep['gueststars'].split('|')
                    if x.strip()
                ]
            if getattr(my_ep, 'writer', None):
                persons_dict['Writer'] += [
                    x.strip() for x in my_ep['writer'].split('|') if x.strip()
                ]

        # fill in Persons section with collected directors, guest starts and writers
        for person_type, names in iteritems(persons_dict):
            # remove doubles
            names = list(set(names))
            for cur_name in names:
                person = etree.SubElement(persons, 'Person')
                cur_person_name = etree.SubElement(person, 'Name')
                cur_person_name.text = cur_name
                cur_person_type = etree.SubElement(person, 'Type')
                cur_person_type.text = person_type

        # Make it purdy
        helpers.indentXML(root_node)
        data = etree.ElementTree(root_node)

        return data
예제 #22
0
    def getIndexerLanguages():
        result = app.indexerApi().config['valid_languages']

        return json.dumps({'results': result})
예제 #23
0
파일: wdtv.py 프로젝트: DazzFX/SickRage-1
    def _ep_data(self, ep_obj):
        """
        Creates an elementTree XML structure for a WDTV style episode.xml
        and returns the resulting data object.

        ep_obj: a TVShow instance to create the NFO for
        """

        eps_to_write = [ep_obj] + ep_obj.related_episodes

        indexer_lang = ep_obj.show.lang

        l_indexer_api_params = app.indexerApi(
            ep_obj.show.indexer).api_params.copy()

        l_indexer_api_params[b'actors'] = True

        if indexer_lang and not indexer_lang == app.INDEXER_DEFAULT_LANGUAGE:
            l_indexer_api_params[b'language'] = indexer_lang

        if ep_obj.show.dvdorder != 0:
            l_indexer_api_params[b'dvdorder'] = True

        try:
            t = app.indexerApi(
                ep_obj.show.indexer).indexer(**l_indexer_api_params)
            my_show = t[ep_obj.show.indexerid]
        except app.indexer_shownotfound as e:
            raise ShowNotFoundException(e.message)
        except app.indexer_error:
            logger.log(
                u'Unable to connect to {indexer} while creating meta files - skipping it.'
                .format(indexer=app.indexerApi(ep_obj.show.indexer).name),
                logger.WARNING)
            return False

        root_node = etree.Element('details')

        # write an WDTV XML containing info for all matching episodes
        for ep_to_write in eps_to_write:

            try:
                my_ep = my_show[ep_to_write.season][ep_to_write.episode]
            except (app.indexer_episodenotfound, app.indexer_seasonnotfound):
                logger.log(
                    u'Unable to find episode {ep_num} on {indexer}... '
                    u'has it been removed? Should I delete from db?'.format(
                        ep_num=ep_num(ep_to_write.season, ep_to_write.episode),
                        indexer=app.indexerApi(ep_obj.show.indexer).name))
                return None

            if ep_obj.season == 0 and not getattr(my_ep, 'firstaired', None):
                my_ep['firstaired'] = str(datetime.date.fromordinal(1))

            if not (getattr(my_ep, 'episodename', None)
                    and getattr(my_ep, 'firstaired', None)):
                return None

            if len(eps_to_write) > 1:
                episode = etree.SubElement(root_node, 'details')
            else:
                episode = root_node

            # TODO: get right EpisodeID
            episode_id = etree.SubElement(episode, 'id')
            episode_id.text = str(ep_to_write.indexerid)

            title = etree.SubElement(episode, 'title')
            title.text = ep_obj.pretty_name()

            if getattr(my_show, 'seriesname', None):
                series_name = etree.SubElement(episode, 'series_name')
                series_name.text = my_show['seriesname']

            if ep_to_write.name:
                episode_name = etree.SubElement(episode, 'episode_name')
                episode_name.text = ep_to_write.name

            season_number = etree.SubElement(episode, 'season_number')
            season_number.text = str(ep_to_write.season)

            episode_num = etree.SubElement(episode, 'episode_number')
            episode_num.text = str(ep_to_write.episode)

            first_aired = etree.SubElement(episode, 'firstaired')

            if ep_to_write.airdate != datetime.date.fromordinal(1):
                first_aired.text = str(ep_to_write.airdate)

            if getattr(my_show, 'firstaired', None):
                try:
                    year_text = str(
                        datetime.datetime.strptime(my_show['firstaired'],
                                                   dateFormat).year)
                    if year_text:
                        year = etree.SubElement(episode, 'year')
                        year.text = year_text
                except Exception:
                    pass

            if ep_to_write.season != 0 and getattr(my_show, 'runtime', None):
                runtime = etree.SubElement(episode, 'runtime')
                runtime.text = my_show['runtime']

            if getattr(my_show, 'genre', None):
                genre = etree.SubElement(episode, 'genre')
                genre.text = ' / '.join([
                    x.strip() for x in my_show['genre'].split('|')
                    if x.strip()
                ])

            if getattr(my_ep, 'director', None):
                director = etree.SubElement(episode, 'director')
                director.text = my_ep['director']

            if getattr(my_show, '_actors', None):
                for actor in my_show['_actors']:
                    if not ('name' in actor and actor['name'].strip()):
                        continue

                    cur_actor = etree.SubElement(episode, 'actor')

                    cur_actor_name = etree.SubElement(cur_actor, 'name')
                    cur_actor_name.text = actor['name']

                    if 'role' in actor and actor['role'].strip():
                        cur_actor_role = etree.SubElement(cur_actor, 'role')
                        cur_actor_role.text = actor['role'].strip()

            if ep_to_write.description:
                overview = etree.SubElement(episode, 'overview')
                overview.text = ep_to_write.description

            # Make it purdy
            helpers.indentXML(root_node)
            data = etree.ElementTree(root_node)

        return data
예제 #24
0
    def run(self):

        ShowQueueItem.run(self)

        logger.log(u"Starting to add show {0}".format(
            "by ShowDir: {0}".format(self.showDir) if self.
            showDir else "by Indexer Id: {0}".format(self.indexer_id)))
        # make sure the Indexer IDs are valid
        try:

            lINDEXER_API_PARMS = app.indexerApi(self.indexer).api_params.copy()
            if self.lang:
                lINDEXER_API_PARMS['language'] = self.lang

            logger.log(u"" + str(app.indexerApi(self.indexer).name) + ": " +
                       repr(lINDEXER_API_PARMS))

            t = app.indexerApi(self.indexer).indexer(**lINDEXER_API_PARMS)
            s = t[self.indexer_id]

            # Let's try to create the show Dir if it's not provided. This way we force the show dir to build build using the
            # Indexers provided series name
            if not self.showDir and self.root_dir:
                show_name = get_showname_from_indexer(self.indexer,
                                                      self.indexer_id,
                                                      self.lang)
                if show_name:
                    self.showDir = ek(os.path.join, self.root_dir,
                                      sanitize_filename(show_name))
                    dir_exists = makeDir(self.showDir)
                    if not dir_exists:
                        logger.log(
                            u"Unable to create the folder {0}, can't add the show"
                            .format(self.showDir))
                        return

                    chmodAsParent(self.showDir)
                else:
                    logger.log(
                        u"Unable to get a show {0}, can't add the show".format(
                            self.showDir))
                    return

            # this usually only happens if they have an NFO in their show dir which gave us a Indexer ID that has no proper english version of the show
            if getattr(s, 'seriesname', None) is None:
                logger.log(
                    u"Show in {} has no name on {}, probably searched with the wrong language."
                    .format(self.showDir,
                            app.indexerApi(self.indexer).name), logger.ERROR)

                ui.notifications.error(
                    "Unable to add show",
                    "Show in " + self.showDir + " has no name on " +
                    str(app.indexerApi(self.indexer).name) +
                    ", probably the wrong language. Delete .nfo and add manually in the correct language."
                )
                self._finishEarly()
                return
            # if the show has no episodes/seasons
            if not s:
                logger.log(u"Show " + str(s['seriesname']) + " is on " +
                           str(app.indexerApi(self.indexer).name) +
                           " but contains no season/episode data.")
                ui.notifications.error(
                    "Unable to add show", "Show " + str(s['seriesname']) +
                    " is on " + str(app.indexerApi(self.indexer).name) +
                    " but contains no season/episode data.")
                self._finishEarly()
                return
        except Exception as e:
            logger.log(
                u"%s Error while loading information from indexer %s. Error: %r"
                % (self.indexer_id, app.indexerApi(self.indexer).name, ex(e)),
                logger.ERROR)
            # logger.log(u"Show name with ID %s doesn't exist on %s anymore. If you are using trakt, it will be removed from your TRAKT watchlist. If you are adding manually, try removing the nfo and adding again" %
            #            (self.indexer_id, api.indexerApi(self.indexer).name), logger.WARNING)

            ui.notifications.error(
                "Unable to add show",
                "Unable to look up the show in %s on %s using ID %s, not using the NFO. Delete .nfo and try adding manually again."
                % (self.showDir, app.indexerApi(
                    self.indexer).name, self.indexer_id))

            if app.USE_TRAKT:

                trakt_id = app.indexerApi(self.indexer).config['trakt_id']
                trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT)

                title = self.showDir.split("/")[-1]
                data = {'shows': [{'title': title, 'ids': {}}]}
                if trakt_id == 'tvdb_id':
                    data['shows'][0]['ids']['tvdb'] = self.indexer_id
                else:
                    data['shows'][0]['ids']['tvrage'] = self.indexer_id

                try:
                    trakt_api.traktRequest("sync/watchlist/remove",
                                           data,
                                           method='POST')
                except TraktException as e:
                    logger.log(
                        "Could not remove show '{0}' from watchlist. Error: {1}"
                        .format(title, e), logger.WARNING)

            self._finishEarly()
            return

        try:
            newShow = TVShow(self.indexer, self.indexer_id, self.lang)
            newShow.load_from_indexer()

            self.show = newShow

            # set up initial values
            self.show.location = self.showDir
            self.show.subtitles = self.subtitles if self.subtitles is not None else app.SUBTITLES_DEFAULT
            self.show.quality = self.quality if self.quality else app.QUALITY_DEFAULT
            self.show.flatten_folders = self.flatten_folders if self.flatten_folders is not None else app.FLATTEN_FOLDERS_DEFAULT
            self.show.anime = self.anime if self.anime is not None else app.ANIME_DEFAULT
            self.show.scene = self.scene if self.scene is not None else app.SCENE_DEFAULT
            self.show.paused = self.paused if self.paused is not None else False

            # set up default new/missing episode status
            logger.log(
                u"Setting all episodes to the specified default status: " +
                str(self.show.default_ep_status))
            self.show.default_ep_status = self.default_status

            if self.show.anime:
                self.show.release_groups = BlackAndWhiteList(
                    self.show.indexerid)
                if self.blacklist:
                    self.show.release_groups.set_black_keywords(self.blacklist)
                if self.whitelist:
                    self.show.release_groups.set_white_keywords(self.whitelist)

            # # be smartish about this
            # if self.show.genre and "talk show" in self.show.genre.lower():
            #     self.show.air_by_date = 1
            # if self.show.genre and "documentary" in self.show.genre.lower():
            #     self.show.air_by_date = 0
            # if self.show.classification and "sports" in self.show.classification.lower():
            #     self.show.sports = 1

        except app.indexer_exception as e:
            logger.log(
                u"Unable to add show due to an error with " +
                app.indexerApi(self.indexer).name + ": " + ex(e), logger.ERROR)
            if self.show:
                ui.notifications.error("Unable to add " + str(self.show.name) +
                                       " due to an error with " +
                                       app.indexerApi(self.indexer).name + "")
            else:
                ui.notifications.error(
                    "Unable to add show due to an error with " +
                    app.indexerApi(self.indexer).name + "")
            self._finishEarly()
            return

        except MultipleShowObjectsException:
            logger.log(
                u"The show in " + self.showDir +
                " is already in your show list, skipping", logger.WARNING)
            ui.notifications.error(
                'Show skipped', "The show in " + self.showDir +
                " is already in your show list")
            self._finishEarly()
            return

        except Exception as e:
            logger.log(u"Error trying to add show: " + ex(e), logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            self._finishEarly()
            raise

        logger.log(u"Retrieving show info from IMDb", logger.DEBUG)
        try:
            self.show.load_imdb_info()
        except imdb_exceptions.IMDbError as e:
            logger.log(u"Something wrong on IMDb api: " + ex(e),
                       logger.WARNING)
        except Exception as e:
            logger.log(u"Error loading IMDb info: " + ex(e), logger.ERROR)

        try:
            self.show.save_to_db()
        except Exception as e:
            logger.log(u"Error saving the show to the database: " + ex(e),
                       logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)
            self._finishEarly()
            raise

        # add it to the show list
        app.showList.append(self.show)

        try:
            self.show.load_episodes_from_indexer()
        except Exception as e:
            logger.log(
                u"Error with " + app.indexerApi(self.show.indexer).name +
                ", not creating episode list: " + ex(e), logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)

        # update internal name cache
        name_cache.buildNameCache(self.show)

        try:
            self.show.load_episodes_from_dir()
        except Exception as e:
            logger.log(u"Error searching dir for episodes: " + ex(e),
                       logger.ERROR)
            logger.log(traceback.format_exc(), logger.DEBUG)

        # if they set default ep status to WANTED then run the backlog to search for episodes
        # FIXME: This needs to be a backlog queue item!!!
        if self.show.default_ep_status == WANTED:
            logger.log(
                u"Launching backlog for this show since its episodes are WANTED"
            )
            app.backlogSearchScheduler.action.searchBacklog([self.show])

        self.show.write_metadata()
        self.show.update_metadata()
        self.show.populate_cache()

        self.show.flush_episodes()

        if app.USE_TRAKT:
            # if there are specific episodes that need to be added by trakt
            app.traktCheckerScheduler.action.manage_new_show(self.show)

            # add show to trakt.tv library
            if app.TRAKT_SYNC:
                app.traktCheckerScheduler.action.add_show_trakt_library(
                    self.show)

            if app.TRAKT_SYNC_WATCHLIST:
                logger.log(u"update watchlist")
                notifiers.trakt_notifier.update_watchlist(show_obj=self.show)

        # Load XEM data to DB for show
        scene_numbering.xem_refresh(self.show.indexerid,
                                    self.show.indexer,
                                    force=True)

        # check if show has XEM mapping so we can determin if searches should go by scene numbering or indexer numbering.
        if not self.scene and scene_numbering.get_xem_numbering_for_show(
                self.show.indexerid, self.show.indexer):
            self.show.scene = 1

        # After initial add, set to default_status_after.
        self.show.default_ep_status = self.default_status_after

        self.finish()
예제 #25
0
    def _ep_data(self, ep_obj):
        """
        Creates an elementTree XML structure for an KODI-style episode.nfo and
        returns the resulting data object.

        show_obj: a TVEpisode instance to create the NFO for
        """

        eps_to_write = [ep_obj] + ep_obj.related_episodes

        indexer_lang = ep_obj.show.lang

        # There's gotta be a better way of doing this but we don't wanna
        # change the language value elsewhere
        l_indexer_api_params = app.indexerApi(
            ep_obj.show.indexer).api_params.copy()

        l_indexer_api_params[b'actors'] = True

        if indexer_lang and not indexer_lang == app.INDEXER_DEFAULT_LANGUAGE:
            l_indexer_api_params[b'language'] = indexer_lang

        if ep_obj.show.dvdorder != 0:
            l_indexer_api_params[b'dvdorder'] = True

        try:
            t = app.indexerApi(
                ep_obj.show.indexer).indexer(**l_indexer_api_params)
            my_show = t[ep_obj.show.indexerid]
        except app.indexer_shownotfound as e:
            raise ShowNotFoundException(e.message)
        except app.indexer_error:
            logger.log(
                u'Unable to connect to {indexer} while creating meta files - skipping it.'
                .format(indexer=app.indexerApi(ep_obj.show.indexer).name),
                logger.WARNING)
            return

        if len(eps_to_write) > 1:
            root_node = etree.Element('kodimultiepisode')
        else:
            root_node = etree.Element('episodedetails')

        # write an NFO containing info for all matching episodes
        for ep_to_write in eps_to_write:

            try:
                my_ep = my_show[ep_to_write.season][ep_to_write.episode]
            except (app.indexer_episodenotfound, app.indexer_seasonnotfound):
                logger.log(
                    u'Unable to find episode {ep_num} on {indexer}... '
                    u'has it been removed? Should I delete from db?'.format(
                        ep_num=episode_num(ep_to_write.season,
                                           ep_to_write.episode),
                        indexer=app.indexerApi(ep_obj.show.indexer).name))
                return None

            if not getattr(my_ep, 'firstaired', None):
                my_ep['firstaired'] = str(datetime.date.fromordinal(1))

            if not getattr(my_ep, 'episodename', None):
                logger.log(u'Not generating nfo because the ep has no title',
                           logger.DEBUG)
                return None

            logger.log(
                u'Creating metadata for episode {ep_num}'.format(
                    ep_num=episode_num(ep_obj.season, ep_obj.episode)),
                logger.DEBUG)

            if len(eps_to_write) > 1:
                episode = etree.SubElement(root_node, 'episodedetails')
            else:
                episode = root_node

            if getattr(my_ep, 'episodename', None):
                title = etree.SubElement(episode, 'title')
                title.text = my_ep['episodename']

            if getattr(my_show, 'seriesname', None):
                showtitle = etree.SubElement(episode, 'showtitle')
                showtitle.text = my_show['seriesname']

            season = etree.SubElement(episode, 'season')
            season.text = str(ep_to_write.season)

            episodenum = etree.SubElement(episode, 'episode')
            episodenum.text = str(ep_to_write.episode)

            uniqueid = etree.SubElement(episode, 'uniqueid')
            uniqueid.text = str(ep_to_write.indexerid)

            if ep_to_write.airdate != datetime.date.fromordinal(1):
                aired = etree.SubElement(episode, 'aired')
                aired.text = str(ep_to_write.airdate)

            if getattr(my_ep, 'overview', None):
                plot = etree.SubElement(episode, 'plot')
                plot.text = my_ep['overview']

            if ep_to_write.season and getattr(my_show, 'runtime', None):
                runtime = etree.SubElement(episode, 'runtime')
                runtime.text = my_show['runtime']

            if getattr(my_ep, 'airsbefore_season', None):
                displayseason = etree.SubElement(episode, 'displayseason')
                displayseason.text = my_ep['airsbefore_season']

            if getattr(my_ep, 'airsbefore_episode', None):
                displayepisode = etree.SubElement(episode, 'displayepisode')
                displayepisode.text = my_ep['airsbefore_episode']

            if getattr(my_ep, 'filename', None):
                thumb = etree.SubElement(episode, 'thumb')
                thumb.text = my_ep['filename'].strip()

            # watched = etree.SubElement(episode, 'watched')
            # watched.text = 'false'

            if getattr(my_ep, 'rating', None):
                rating = etree.SubElement(episode, 'rating')
                rating.text = my_ep['rating']

            if getattr(my_ep, 'writer', None) and isinstance(
                    my_ep['writer'], string_types):
                for writer in self._split_info(my_ep['writer']):
                    cur_writer = etree.SubElement(episode, 'credits')
                    cur_writer.text = writer

            if getattr(my_ep, 'director', None) and isinstance(
                    my_ep['director'], string_types):
                for director in self._split_info(my_ep['director']):
                    cur_director = etree.SubElement(episode, 'director')
                    cur_director.text = director

            if getattr(my_ep, 'gueststars', None) and isinstance(
                    my_ep['gueststars'], string_types):
                for actor in self._split_info(my_ep['gueststars']):
                    cur_actor = etree.SubElement(episode, 'actor')
                    cur_actor_name = etree.SubElement(cur_actor, 'name')
                    cur_actor_name.text = actor

            if getattr(my_show, '_actors', None):
                for actor in my_show['_actors']:
                    cur_actor = etree.SubElement(episode, 'actor')

                    if 'name' in actor and actor['name'].strip():
                        cur_actor_name = etree.SubElement(cur_actor, 'name')
                        cur_actor_name.text = actor['name'].strip()
                    else:
                        continue

                    if 'role' in actor and actor['role'].strip():
                        cur_actor_role = etree.SubElement(cur_actor, 'role')
                        cur_actor_role.text = actor['role'].strip()

                    if 'image' in actor and actor['image'].strip():
                        cur_actor_thumb = etree.SubElement(cur_actor, 'thumb')
                        cur_actor_thumb.text = actor['image'].strip()

        # Make it purdy
        helpers.indentXML(root_node)

        data = etree.ElementTree(root_node)

        return data
예제 #26
0
def fix_xem_numbering(indexer_id, indexer):  # pylint:disable=too-many-locals, too-many-branches, too-many-statements
    """
    Returns a dict of (season, episode) : (sceneSeason, sceneEpisode) mappings
    for an entire show.  Both the keys and values of the dict are tuples.
    Will be empty if there are no scene numbers set in xem
    """
    if indexer_id is None:
        return {}

    indexer_id = int(indexer_id)
    indexer = int(indexer)

    main_db_con = db.DBConnection()
    rows = main_db_con.select(
        'SELECT season, episode, absolute_number, scene_season, scene_episode, scene_absolute_number FROM tv_episodes WHERE indexer = ? and showid = ?',
        [indexer, indexer_id])

    last_absolute_number = None
    last_scene_season = None
    last_scene_episode = None
    last_scene_absolute_number = None

    update_absolute_number = False
    update_scene_season = False
    update_scene_episode = False
    update_scene_absolute_number = False

    logger.log(
        u'Fixing any XEM scene mapping issues for show %s on %s' % (indexer_id, app.indexerApi(indexer).name,),
        logger.DEBUG)

    cl = []
    for row in rows:
        season = int(row['season'])
        episode = int(row['episode'])

        if not int(row['scene_season']) and last_scene_season:
            scene_season = last_scene_season + 1
            update_scene_season = True
        else:
            scene_season = int(row['scene_season'])
            if last_scene_season and scene_season < last_scene_season:
                scene_season = last_scene_season + 1
                update_scene_season = True

        if not int(row['scene_episode']) and last_scene_episode:
            scene_episode = last_scene_episode + 1
            update_scene_episode = True
        else:
            scene_episode = int(row['scene_episode'])
            if last_scene_episode and scene_episode < last_scene_episode:
                scene_episode = last_scene_episode + 1
                update_scene_episode = True

        # check for unset values and correct them
        if not int(row['absolute_number']) and last_absolute_number:
            absolute_number = last_absolute_number + 1
            update_absolute_number = True
        else:
            absolute_number = int(row['absolute_number'])
            if last_absolute_number and absolute_number < last_absolute_number:
                absolute_number = last_absolute_number + 1
                update_absolute_number = True

        if not int(row['scene_absolute_number']) and last_scene_absolute_number:
            scene_absolute_number = last_scene_absolute_number + 1
            update_scene_absolute_number = True
        else:
            scene_absolute_number = int(row['scene_absolute_number'])
            if last_scene_absolute_number and scene_absolute_number < last_scene_absolute_number:
                scene_absolute_number = last_scene_absolute_number + 1
                update_scene_absolute_number = True

        # store values for lookup on next iteration
        last_absolute_number = absolute_number
        last_scene_season = scene_season
        last_scene_episode = scene_episode
        last_scene_absolute_number = scene_absolute_number

        if update_absolute_number:
            cl.append([
                "UPDATE tv_episodes SET absolute_number = ? WHERE showid = ? AND season = ? AND episode = ?",
                [absolute_number, indexer_id, season, episode]
            ])
            update_absolute_number = False

        if update_scene_season:
            cl.append([
                "UPDATE tv_episodes SET scene_season = ? WHERE showid = ? AND season = ? AND episode = ?",
                [scene_season, indexer_id, season, episode]
            ])
            update_scene_season = False

        if update_scene_episode:
            cl.append([
                "UPDATE tv_episodes SET scene_episode = ? WHERE showid = ? AND season = ? AND episode = ?",
                [scene_episode, indexer_id, season, episode]
            ])
            update_scene_episode = False

        if update_scene_absolute_number:
            cl.append([
                "UPDATE tv_episodes SET scene_absolute_number = ? WHERE showid = ? AND season = ? AND episode = ?",
                [scene_absolute_number, indexer_id, season, episode]
            ])
            update_scene_absolute_number = False

    if cl:
        main_db_con = db.DBConnection()
        main_db_con.mass_action(cl)
예제 #27
0
def xem_refresh(indexer_id, indexer, force=False):
    """
    Refresh data from xem for a tv show

    :param indexer_id: int
    """
    if not indexer_id or indexer_id < 1:
        return

    indexer_id = int(indexer_id)
    indexer = int(indexer)

    MAX_REFRESH_AGE_SECS = 86400  # 1 day

    main_db_con = db.DBConnection()
    rows = main_db_con.select("SELECT last_refreshed FROM xem_refresh WHERE indexer = ? and indexer_id = ?",
                              [indexer, indexer_id])
    if rows:
        lastRefresh = int(rows[0]['last_refreshed'])
        refresh = int(time.mktime(datetime.datetime.today().timetuple())) > lastRefresh + MAX_REFRESH_AGE_SECS
    else:
        refresh = True

    if refresh or force:
        logger.log(
            u'Looking up XEM scene mapping for show %s on %s' % (indexer_id, app.indexerApi(indexer).name,),
            logger.DEBUG)

        # mark refreshed
        main_db_con.upsert(
            "xem_refresh",
            {'indexer': indexer,
             'last_refreshed': int(time.mktime(datetime.datetime.today().timetuple()))},
            {'indexer_id': indexer_id}
        )

        try:
            # XEM MAP URL
            url = "http://thexem.de/map/havemap?origin=%s" % app.indexerApi(indexer).config['xem_origin']
            parsedJSON = app.helpers.getURL(url, session=xem_session, returns='json')
            if not parsedJSON or 'result' not in parsedJSON or 'success' not in parsedJSON['result'] or 'data' not in parsedJSON or str(indexer_id) not in parsedJSON['data']:
                return

            # XEM API URL
            url = "http://thexem.de/map/all?id=%s&origin=%s&destination=scene" % (indexer_id, app.indexerApi(indexer).config['xem_origin'])

            parsedJSON = app.helpers.getURL(url, session=xem_session, returns='json')
            if not parsedJSON or 'result' not in parsedJSON or 'success' not in parsedJSON['result']:
                logger.log(u'No XEM data for show "%s on %s"' % (indexer_id, app.indexerApi(indexer).name,), logger.INFO)
                return

            cl = []
            for entry in parsedJSON['data']:
                if 'scene' in entry:
                    cl.append([
                        "UPDATE tv_episodes SET scene_season = ?, scene_episode = ?, scene_absolute_number = ? WHERE showid = ? AND season = ? AND episode = ?",
                        [entry['scene']['season'], entry['scene']['episode'],
                         entry['scene']['absolute'], indexer_id,
                         entry[app.indexerApi(indexer).config['xem_origin']]['season'],
                         entry[app.indexerApi(indexer).config['xem_origin']]['episode']]
                    ])
                    cl.append([
                        "UPDATE tv_episodes SET absolute_number = ? WHERE showid = ? AND season = ? AND episode = ? AND absolute_number = 0",
                        [entry[app.indexerApi(indexer).config['xem_origin']]['absolute'], indexer_id,
                         entry[app.indexerApi(indexer).config['xem_origin']]['season'],
                         entry[app.indexerApi(indexer).config['xem_origin']]['episode']]
                    ])
                if 'scene_2' in entry:  # for doubles
                    cl.append([
                        "UPDATE tv_episodes SET scene_season = ?, scene_episode = ?, scene_absolute_number = ? WHERE showid = ? AND season = ? AND episode = ?",
                        [entry['scene_2']['season'], entry['scene_2']['episode'],
                         entry['scene_2']['absolute'], indexer_id,
                         entry[app.indexerApi(indexer).config['xem_origin']]['season'],
                         entry[app.indexerApi(indexer).config['xem_origin']]['episode']]
                    ])

            if cl:
                main_db_con = db.DBConnection()
                main_db_con.mass_action(cl)

        except Exception as e:
            logger.log(
                u"Exception while refreshing XEM data for show " + str(indexer_id) + " on " + app.indexerApi(
                    indexer).name + ": " + ex(e), logger.WARNING)
            logger.log(traceback.format_exc(), logger.DEBUG)
예제 #28
0
    def _ep_data(self, ep_obj):
        """
        Creates a key value structure for a Tivo episode metadata file and
        returns the resulting data object.

        ep_obj: a TVEpisode instance to create the metadata file for.

        Lookup the show in http://thetvdb.com/ using the python library:

        https://github.com/dbr/indexer_api/

        The results are saved in the object myShow.

        The key values for the tivo metadata file are from:

        http://pytivo.sourceforge.net/wiki/index.php/Metadata
        """

        data = ''

        eps_to_write = [ep_obj] + ep_obj.related_episodes

        indexer_lang = ep_obj.show.lang

        try:
            l_indexer_api_params = app.indexerApi(
                ep_obj.show.indexer).api_params.copy()

            l_indexer_api_params['actors'] = True

            if indexer_lang and not indexer_lang == app.INDEXER_DEFAULT_LANGUAGE:
                l_indexer_api_params['language'] = indexer_lang

            if ep_obj.show.dvdorder != 0:
                l_indexer_api_params['dvdorder'] = True

            t = app.indexerApi(
                ep_obj.show.indexer).indexer(**l_indexer_api_params)
            my_show = t[ep_obj.show.indexerid]
        except app.indexer_shownotfound as e:
            raise ShowNotFoundException(e.message)
        except app.indexer_error:
            logger.log(
                u'Unable to connect to {indexer} while creating meta files - skipping it.'
                .format(indexer=app.indexerApi(ep_obj.show.indexer).name),
                logger.WARNING)
            return False

        for ep_to_write in eps_to_write:

            try:
                my_ep = my_show[ep_to_write.season][ep_to_write.episode]
            except (app.indexer_episodenotfound, app.indexer_seasonnotfound):
                logger.log(
                    u'Unable to find episode {ep_num} on {indexer}... '
                    u'has it been removed? Should I delete from db?'.format(
                        ep_num=episode_num(ep_to_write.season,
                                           ep_to_write.episode),
                        indexer=app.indexerApi(ep_obj.show.indexer).name))
                return None

            if ep_obj.season == 0 and not getattr(my_ep, 'firstaired', None):
                my_ep['firstaired'] = str(datetime.date.fromordinal(1))

            if not (getattr(my_ep, 'episodename', None)
                    and getattr(my_ep, 'firstaired', None)):
                return None

            if getattr(my_show, 'seriesname', None):
                data += ('title : {title}\n'.format(
                    title=my_show['seriesname']))
                data += ('seriesTitle : {title}\n'.format(
                    title=my_show['seriesname']))

            data += ('episodeTitle : {title}\n'.format(
                title=ep_to_write._format_pattern('%Sx%0E %EN')))

            # This should be entered for episodic shows and omitted for movies. The standard tivo format is to enter
            # the season number followed by the episode number for that season. For example, enter 201 for season 2
            # episode 01.

            # This only shows up if you go into the Details from the Program screen.

            # This seems to disappear once the video is transferred to TiVo.

            # NOTE: May not be correct format, missing season, but based on description from wiki leaving as is.
            data += ('episodeNumber : {ep_num}\n'.format(
                ep_num=ep_to_write.episode))

            # Must be entered as true or false. If true, the year from originalAirDate will be shown in parentheses
            # after the episode's title and before the description on the Program screen.

            # FIXME: Hardcode isEpisode to true for now, not sure how to handle movies
            data += 'isEpisode : true\n'

            # Write the synopsis of the video here
            # Micrsoft Word's smartquotes can die in a fire.
            sanitized_description = ep_to_write.description
            # Replace double curly quotes
            sanitized_description = sanitized_description.replace(
                u'\u201c', '\'').replace(u'\u201d', '\'')
            # Replace single curly quotes
            sanitized_description = sanitized_description.replace(
                u'\u2018', '\'').replace(u'\u2019',
                                         '\'').replace(u'\u02BC', '\'')

            data += ('description : {desc}\n'.format(
                desc=sanitized_description))

            # Usually starts with 'SH' and followed by 6-8 digits.
            # TiVo uses zap2it for their data, so the series id is the zap2it_id.
            if getattr(my_show, 'zap2it_id', None):
                data += ('seriesId : {zap2it}\n'.format(
                    zap2it=my_show['zap2it_id']))

            # This is the call sign of the channel the episode was recorded from.
            if getattr(my_show, 'network', None):
                data += ('callsign : {network}\n'.format(
                    network=my_show['network']))

            # This must be entered as yyyy-mm-ddThh:mm:ssZ (the t is capitalized and never changes, the Z is also
            # capitalized and never changes). This is the original air date of the episode.
            # NOTE: Hard coded the time to T00:00:00Z as we really don't know when during the day the first run happened.
            if ep_to_write.airdate != datetime.date.fromordinal(1):
                data += ('originalAirDate : {airdate}T00:00:00Z\n'.format(
                    airdate=ep_to_write.airdate))

            # This shows up at the beginning of the description on the Program screen and on the Details screen.
            if getattr(my_show, '_actors', None):
                for actor in my_show['_actors']:
                    if 'name' in actor and actor['name'].strip():
                        data += ('vActor : {actor}\n'.format(
                            actor=actor['name'].strip()))

            # This is shown on both the Program screen and the Details screen.
            if getattr(my_ep, 'rating', None):
                try:
                    rating = float(my_ep['rating'])
                except ValueError:
                    rating = 0.0
                # convert 10 to 4 star rating. 4 * rating / 10
                # only whole numbers or half numbers work. multiply by 2, round, divide by 2.0
                rating = round(8 * rating / 10) / 2.0
                data += ('starRating : {rating}\n'.format(rating=rating))

            # This is shown on both the Program screen and the Details screen.
            # It uses the standard TV rating system of: TV-Y7, TV-Y, TV-G, TV-PG, TV-14, TV-MA and TV-NR.
            if getattr(my_show, 'contentrating', None):
                data += ('tvRating : {rating}\n'.format(
                    rating=my_show['contentrating']))

            # This field can be repeated as many times as necessary or omitted completely.
            if ep_obj.show.genre:
                for genre in ep_obj.show.genre.split('|'):
                    if genre:
                        data += ('vProgramGenre : {genre}\n'.format(
                            genre=genre))

                        # NOTE: The following are metadata keywords are not used
                        # displayMajorNumber
                        # showingBits
                        # displayMinorNumber
                        # colorCode
                        # vSeriesGenre
                        # vGuestStar, vDirector, vExecProducer, vProducer, vWriter, vHost, vChoreographer
                        # partCount
                        # partIndex

        return data
예제 #29
0
    def _show_data(self, show_obj):
        """
        Creates an elementTree XML structure for an KODI-style tvshow.nfo and
        returns the resulting data object.

        show_obj: a TVShow instance to create the NFO for
        """

        show_id = show_obj.indexerid

        indexer_lang = show_obj.lang
        l_indexer_api_params = app.indexerApi(
            show_obj.indexer).api_params.copy()

        l_indexer_api_params['actors'] = True

        if indexer_lang and not indexer_lang == app.INDEXER_DEFAULT_LANGUAGE:
            l_indexer_api_params['language'] = indexer_lang

        if show_obj.dvdorder != 0:
            l_indexer_api_params['dvdorder'] = True

        t = app.indexerApi(show_obj.indexer).indexer(**l_indexer_api_params)

        tv_node = etree.Element('tvshow')

        try:
            my_show = t[int(show_id)]
        except app.indexer_shownotfound:
            logger.log(
                u'Unable to find {indexer} show {id}, skipping it'.format(
                    indexer=app.indexerApi(show_obj.indexer).name, id=show_id),
                logger.ERROR)
            raise

        except app.indexer_error:
            logger.log(
                u'{indexer} is down, can\'t use its data to add this show'.
                format(indexer=app.indexerApi(show_obj.indexer).name),
                logger.ERROR)
            raise

        # check for title and id
        if not (getattr(my_show, 'seriesname', None)
                and getattr(my_show, 'id', None)):
            logger.log(
                u'Incomplete info for {indexer} show {id}, skipping it'.format(
                    indexer=app.indexerApi(show_obj.indexer).name, id=show_id),
                logger.ERROR)
            return False

        title = etree.SubElement(tv_node, 'title')
        title.text = my_show['seriesname']

        if getattr(my_show, 'rating', None):
            rating = etree.SubElement(tv_node, 'rating')
            rating.text = my_show['rating']

        if getattr(my_show, 'firstaired', None):
            try:
                year_text = str(
                    datetime.datetime.strptime(my_show['firstaired'],
                                               dateFormat).year)
                if year_text:
                    year = etree.SubElement(tv_node, 'year')
                    year.text = year_text
            except Exception:
                pass

        if getattr(my_show, 'overview', None):
            plot = etree.SubElement(tv_node, 'plot')
            plot.text = my_show['overview']

        if getattr(my_show, 'id', None):
            episode_guide = etree.SubElement(tv_node, 'episodeguide')
            episode_guide_url = etree.SubElement(episode_guide, 'url')
            episode_guide_url.text = '{url}{id}/all/en.zip'.format(
                url=app.indexerApi(show_obj.indexer).config['base_url'],
                id=my_show['id'])

        if getattr(my_show, 'contentrating', None):
            mpaa = etree.SubElement(tv_node, 'mpaa')
            mpaa.text = my_show['contentrating']

        if getattr(my_show, 'id', None):
            indexer_id = etree.SubElement(tv_node, 'id')
            indexer_id.text = str(my_show['id'])

        if getattr(my_show, 'genre', None) and isinstance(
                my_show['genre'], string_types):
            for genre in self._split_info(my_show['genre']):
                cur_genre = etree.SubElement(tv_node, 'genre')
                cur_genre.text = genre

        if 'country_codes' in show_obj.imdb_info:
            for country in self._split_info(
                    show_obj.imdb_info['country_codes']):
                try:
                    cur_country_name = Country(country.upper()).name.title()
                except Exception:
                    continue

                cur_country = etree.SubElement(tv_node, 'country')
                cur_country.text = cur_country_name

        if getattr(my_show, 'firstaired', None):
            premiered = etree.SubElement(tv_node, 'premiered')
            premiered.text = my_show['firstaired']

        if getattr(my_show, 'network', None):
            studio = etree.SubElement(tv_node, 'studio')
            studio.text = my_show['network'].strip()

        if getattr(my_show, 'writer', None) and isinstance(
                my_show['writer'], string_types):
            for writer in self._split_info(my_show['writer']):
                cur_writer = etree.SubElement(tv_node, 'credits')
                cur_writer.text = writer

        if getattr(my_show, 'director', None) and isinstance(
                my_show['director'], string_types):
            for director in self._split_info(my_show['director']):
                cur_director = etree.SubElement(tv_node, 'director')
                cur_director.text = director

        if getattr(my_show, '_actors', None):
            for actor in my_show['_actors']:
                cur_actor = etree.SubElement(tv_node, 'actor')

                if 'name' in actor and actor['name'].strip():
                    cur_actor_name = etree.SubElement(cur_actor, 'name')
                    cur_actor_name.text = actor['name'].strip()
                else:
                    continue

                if 'role' in actor and actor['role'].strip():
                    cur_actor_role = etree.SubElement(cur_actor, 'role')
                    cur_actor_role.text = actor['role'].strip()

                if 'image' in actor and actor['image'].strip():
                    cur_actor_thumb = etree.SubElement(cur_actor, 'thumb')
                    cur_actor_thumb.text = actor['image'].strip()

        # Make it purdy
        helpers.indentXML(tv_node)

        data = etree.ElementTree(tv_node)

        return data
예제 #30
0
    def run(self, force=False):

        self.amActive = True

        bad_indexer = [INDEXER_TVRAGE]
        update_datetime = datetime.datetime.now()
        update_date = update_datetime.date()

        # update_timestamp = calendar.timegm(update_datetime.timetuple())
        update_timestamp = time.mktime(update_datetime.timetuple())
        cache_db_con = db.DBConnection('cache.db')
        result = cache_db_con.select(
            "SELECT `time` FROM lastUpdate WHERE provider = 'theTVDB'")
        if result:
            last_update = int(result[0]['time'])
        else:
            last_update = update_timestamp - 86400
            cache_db_con.action(
                "INSERT INTO lastUpdate (provider,`time`) VALUES (?, ?)",
                ['theTVDB', last_update])

        # refresh network timezones
        network_timezones.update_network_dict()

        # sure, why not?
        if app.USE_FAILED_DOWNLOADS:
            failed_history.trimHistory()

        update_delta = update_timestamp - last_update

        if update_delta >= 691200:  # 8 days ( 7 days + 1 day of buffer time)
            update_file = 'updates_month.xml'
        elif update_delta >= 90000:  # 25 hours ( 1 day + 1 hour of buffer time)
            update_file = 'updates_week.xml'
        else:
            update_file = 'updates_day.xml'

        # url = 'http://thetvdb.com/api/Updates.php?type=series&time=%s' % last_update
        url = 'http://thetvdb.com/api/{0}/updates/{1}'.format(
            app.indexerApi(INDEXER_TVDB).api_params['apikey'], update_file)
        data = helpers.getURL(url, session=self.session, returns='text')
        if not data:
            logger.info(
                u'Could not get the recently updated show data from {indexer}. Retrying later. Url was: {logurl}',
                indexer=app.indexerApi(INDEXER_TVDB).name,
                logurl=url)
            self.amActive = False
            return

        updated_shows = []
        try:
            tree = ET.fromstring(data)
            for show in tree.findall("Series"):
                updated_shows.append(int(show.find('id').text))
        except SyntaxError:
            pass

        logger.info(u'Doing full update on all shows')

        pi_list = []
        for cur_show in app.showList:

            if cur_show.indexer in bad_indexer:
                logger.warning(
                    u'Indexer is no longer available for show [ {show} ] ',
                    show=cur_show.name)
            else:
                indexer_name = app.indexerApi(cur_show.indexer).name

            try:
                if indexer_name == 'theTVDB':
                    if cur_show.indexerid in updated_shows:
                        # If the cur_show is not 'paused' then add to the showQueueSchedular
                        if not cur_show.paused:
                            pi_list.append(
                                app.showQueueScheduler.action.updateShow(
                                    cur_show))
                        else:
                            logger.info(
                                u'Show update skipped, show: {show} is paused.',
                                show=cur_show.name)
                else:
                    cur_show.next_episode()

                    if cur_show.should_update(update_date=update_date):
                        try:
                            pi_list.append(
                                app.showQueueScheduler.action.updateShow(
                                    cur_show))
                        except CantUpdateShowException as e:
                            logger.debug(u'Unable to update show: {error}',
                                         error=e)
                    else:
                        logger.debug(
                            u'Not updating episodes for show {show} because the last or next episode is not within the grace period.',
                            show=cur_show.name)
            except (CantUpdateShowException, CantRefreshShowException) as e:
                logger.warning(u'Automatic update failed. Error: {error}',
                               error=e)
            except Exception as e:
                logger.error(u'Automatic update failed: Error: {error}',
                             error=e)

        ui.ProgressIndicators.setIndicator(
            'dailyUpdate', ui.QueueProgressIndicator("Daily Update", pi_list))

        cache_db_con.action(
            "UPDATE lastUpdate SET `time` = ? WHERE provider=?",
            [update_timestamp, 'theTVDB'])

        logger.info(u'Completed full update on all shows')

        self.amActive = False