def addShowToBlacklist(self, indexer_id): # URL parameters data = {'shows': [{'ids': {'tvdb': indexer_id}}]} trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.TRAKT_TIMEOUT) trakt_api.traktRequest('users/{user}/lists/{blacklist}/items'.format (user=sickbeard.TRAKT_USERNAME, blacklist=sickbeard.TRAKT_BLACKLIST_NAME), data, method='POST') return self.redirect('/addShows/trendingShows/')
def addShowToBlacklist(self, indexer_id): # URL parameters data = {'shows': [{'ids': {'tvdb': indexer_id}}]} trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.TRAKT_TIMEOUT) trakt_api.traktRequest("users/" + sickbeard.TRAKT_USERNAME + "/lists/" + sickbeard.TRAKT_BLACKLIST_NAME + "/items", data, method='POST') return self.redirect('/addShows/trendingShows/')
def test_notify(self, username, blacklist_name=None): """ Sends a test notification to trakt with the given authentication info and returns a boolean representing success. api: The api string to use username: The username to use blacklist_name: slug of trakt list used to hide not interested show Returns: True if the request succeeded, False otherwise """ try: trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.TRAKT_TIMEOUT) trakt_api.validateAccount() if blacklist_name and blacklist_name is not None: trakt_lists = trakt_api.traktRequest("users/" + username + "/lists") found = False for trakt_list in trakt_lists: if trakt_list['ids']['slug'] == blacklist_name: return "Test notice sent successfully to Trakt" if not found: return "Trakt blacklist doesn't exists" else: return "Test notice sent successfully to Trakt" except (traktException, traktAuthException, traktServerBusy) as e: logger.log(u"Could not connect to Trakt service: %s" % ex(e), logger.WARNING) return "Test notice failed to Trakt: %s" % ex(e)
def update_library(self, 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 = sickbeard.indexerApi(ep_obj.show.indexer).config['trakt_id'] trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.TRAKT_TIMEOUT) if sickbeard.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 sickbeard.TRAKT_SYNC_WATCHLIST: if sickbeard.TRAKT_REMOVE_SERIESLIST: trakt_api.traktRequest("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.relatedEps: data['shows'][0]['seasons'][0]['episodes'].append( {'number': relEp_Obj.episode}) if sickbeard.TRAKT_SYNC_WATCHLIST: if sickbeard.TRAKT_REMOVE_WATCHLIST: trakt_api.traktRequest("sync/watchlist/remove", data, method='POST') # update library trakt_api.traktRequest("sync/collection", data, method='POST') except (traktException, traktAuthException, traktServerBusy) as e: logger.log( "Could not connect to Trakt service: {0}".format(ex(e)), logger.WARNING)
def update_library(self, 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 = sickbeard.indexerApi(ep_obj.show.indexer).config['trakt_id'] trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.TRAKT_TIMEOUT) if sickbeard.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 sickbeard.TRAKT_SYNC_WATCHLIST: if sickbeard.TRAKT_REMOVE_SERIESLIST: trakt_api.traktRequest("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.relatedEps: data['shows'][0]['seasons'][0]['episodes'].append({'number': relEp_Obj.episode}) if sickbeard.TRAKT_SYNC_WATCHLIST: if sickbeard.TRAKT_REMOVE_WATCHLIST: trakt_api.traktRequest("sync/watchlist/remove", data, method='POST') # update library trakt_api.traktRequest("sync/collection", data, method='POST') except (traktException, traktAuthException, traktServerBusy) as e: logger.log(u"Could not connect to Trakt service: %s" % ex(e), logger.WARNING)
def run(self): # pylint: disable=too-many-branches, too-many-statements, too-many-return-statements super(QueueItemAdd, self).run() if self.showDir: try: assert isinstance(self.showDir, six.text_type) except AssertionError: logger.log(traceback.format_exc(), logger.WARNING) self._finish_early() return logger.log('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 = sickbeard.indexerApi(self.indexer).api_params.copy() lINDEXER_API_PARMS['language'] = self.lang or sickbeard.INDEXER_DEFAULT_LANGUAGE logger.log('{0}: {1!r}'.format(sickbeard.indexerApi(self.indexer).name, lINDEXER_API_PARMS)) t = sickbeard.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 self.root_dir and not self.showDir: show_name = get_showname_from_indexer(self.indexer, self.indexer_id, self.lang) if not show_name: logger.log('Unable to get a show {0}, can\'t add the show'.format(self.showDir)) self._finish_early() return self.showDir = ek(os.path.join, self.root_dir, sanitize_filename(show_name)) dir_exists = makeDir(self.showDir) if not dir_exists: logger.log('Unable to create the folder {0}, can\'t add the show'.format(self.showDir)) self._finish_early() return chmodAsParent(self.showDir) # 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: # noinspection PyPep8 error_string = 'Show in {0} has no name on {1}, probably searched with the wrong language. Delete .nfo and add manually in the correct language.'.format( self.showDir, sickbeard.indexerApi(self.indexer).name) logger.log(error_string, logger.WARNING) ui.notifications.error('Unable to add show', error_string) self._finish_early() return # if the show has no episodes/seasons if not s: error_string = 'Show {0} is on {1} but contains no season/episode data.'.format( s[b'seriesname'], sickbeard.indexerApi(self.indexer).name) logger.log(error_string) ui.notifications.error('Unable to add show', error_string) self._finish_early() return except Exception as error: error_string = 'Unable to look up the show in {0} on {1} using ID {2}, not using the NFO. Delete .nfo and try adding manually again.'.format( self.showDir, sickbeard.indexerApi(self.indexer).name, self.indexer_id) logger.log('{0}: {1}'.format(error_string, error), logger.ERROR) ui.notifications.error( 'Unable to add show', error_string) if sickbeard.USE_TRAKT: trakt_id = sickbeard.indexerApi(self.indexer).config[b'trakt_id'] trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.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 trakt_api.traktRequest('sync/watchlist/remove', data, method='POST') self._finish_early() return try: try: newShow = TVShow(self.indexer, self.indexer_id, self.lang) except MultipleShowObjectsException as error: # If we have the show in our list, but the location is wrong, lets fix it and refresh! existing_show = Show.find(sickbeard.showList, self.indexer_id) # noinspection PyProtectedMember if existing_show and not ek(os.path.isdir, existing_show._location): # pylint: disable=protected-access newShow = existing_show else: raise error newShow.loadFromIndexer() self.show = newShow # set up initial values self.show.location = self.showDir self.show.subtitles = self.subtitles if self.subtitles is not None else sickbeard.SUBTITLES_DEFAULT self.show.subtitles_sr_metadata = self.subtitles_sr_metadata self.show.quality = self.quality if self.quality else sickbeard.QUALITY_DEFAULT self.show.season_folders = self.season_folders if self.season_folders is not None else sickbeard.SEASON_FOLDERS_DEFAULT self.show.anime = self.anime if self.anime is not None else sickbeard.ANIME_DEFAULT self.show.scene = self.scene if self.scene is not None else sickbeard.SCENE_DEFAULT self.show.paused = self.paused if self.paused is not None else False # set up default new/missing episode status logger.log('Setting all episodes to the specified default status: {0}' .format(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 smart-ish 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 sickbeard.indexer_exception as error: error_string = 'Unable to add {0} due to an error with {1}'.format( self.show.name if self.show else 'show', sickbeard.indexerApi(self.indexer).name) logger.log('{0}: {1}'.format(error_string, error), logger.ERROR) ui.notifications.error('Unable to add show', error_string) self._finish_early() return except MultipleShowObjectsException: error_string = 'The show in {0} is already in your show list, skipping'.format(self.showDir) logger.log(error_string, logger.WARNING) ui.notifications.error('Show skipped', error_string) self._finish_early() return except Exception as error: logger.log('Error trying to add show: {0}'.format(error), logger.ERROR) logger.log(traceback.format_exc(), logger.DEBUG) self._finish_early() raise logger.log('Retrieving show info from IMDb', logger.DEBUG) try: self.show.loadIMDbInfo() except imdb_exceptions.IMDbError as error: logger.log(' Something wrong on IMDb api: {0}'.format(error), logger.WARNING) except Exception as error: logger.log('Error loading IMDb info: {0}'.format(error), logger.ERROR) try: self.show.saveToDB() except Exception as error: logger.log('Error saving the show to the database: {0}'.format(error), logger.ERROR) logger.log(traceback.format_exc(), logger.DEBUG) self._finish_early() raise # add it to the show list if not Show.find(sickbeard.showList, self.indexer_id): sickbeard.showList.append(self.show) try: self.show.loadEpisodesFromIndexer() except Exception as error: logger.log( 'Error with {0}, not creating episode list: {1}'.format (sickbeard.indexerApi(self.show.indexer).name, error), logger.ERROR) logger.log(traceback.format_exc(), logger.DEBUG) # update internal name cache name_cache.buildNameCache(self.show) try: self.show.loadEpisodesFromDir() except Exception as error: logger.log('Error searching dir for episodes: {0}'.format(error), 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('Launching backlog for this show since its episodes are WANTED') sickbeard.backlogSearchScheduler.action.searchBacklog([self.show]) self.show.writeMetadata() self.show.updateMetadata() self.show.populateCache() self.show.flushEpisodes() if sickbeard.USE_TRAKT: # if there are specific episodes that need to be added by trakt sickbeard.traktCheckerScheduler.action.manageNewShow(self.show) # add show to trakt.tv library if sickbeard.TRAKT_SYNC: sickbeard.traktCheckerScheduler.action.addShowToTraktLibrary(self.show) if sickbeard.TRAKT_SYNC_WATCHLIST: logger.log('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 determine 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 super(QueueItemAdd, self).finish() self.finish()
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 = sickbeard.indexerApi(self.indexer).api_params.copy() if self.lang: lINDEXER_API_PARMS['language'] = self.lang logger.log(u"" + str(sickbeard.indexerApi(self.indexer).name) + ": " + repr(lINDEXER_API_PARMS)) t = sickbeard.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, sickbeard.indexerApi(self.indexer).name), logger.ERROR) ui.notifications.error("Unable to add show", "Show in " + self.showDir + " has no name on " + str(sickbeard.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( sickbeard.indexerApi(self.indexer).name) + " but contains no season/episode data.") ui.notifications.error("Unable to add show", "Show " + str(s['seriesname']) + " is on " + str(sickbeard.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, sickbeard.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, sickbeard.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, sickbeard.indexerApi(self.indexer).name, self.indexer_id) ) if sickbeard.USE_TRAKT: trakt_id = sickbeard.indexerApi(self.indexer).config['trakt_id'] trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.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 trakt_api.traktRequest("sync/watchlist/remove", data, method='POST') 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 sickbeard.SUBTITLES_DEFAULT self.show.quality = self.quality if self.quality else sickbeard.QUALITY_DEFAULT self.show.flatten_folders = self.flatten_folders if self.flatten_folders is not None else sickbeard.FLATTEN_FOLDERS_DEFAULT self.show.anime = self.anime if self.anime is not None else sickbeard.ANIME_DEFAULT self.show.scene = self.scene if self.scene is not None else sickbeard.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 sickbeard.indexer_exception as e: logger.log( u"Unable to add show due to an error with " + sickbeard.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 " + sickbeard.indexerApi( self.indexer).name + "") else: ui.notifications.error( "Unable to add show due to an error with " + sickbeard.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 sickbeard.showList.append(self.show) try: self.show.load_episodes_from_indexer() except Exception as e: logger.log( u"Error with " + sickbeard.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") sickbeard.backlogSearchScheduler.action.searchBacklog([self.show]) self.show.write_metadata() self.show.update_metadata() self.show.populate_cache() self.show.flush_episodes() if sickbeard.USE_TRAKT: # if there are specific episodes that need to be added by trakt sickbeard.traktCheckerScheduler.action.manage_new_show(self.show) # add show to trakt.tv library if sickbeard.TRAKT_SYNC: sickbeard.traktCheckerScheduler.action.add_show_trakt_library(self.show) if sickbeard.TRAKT_SYNC_WATCHLIST: logger.log(u"update watchlist") notifiers.trakt_notifier.update_watchlist(show_obj=self.show) # Load XEM data to DB for show sickbeard.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 sickbeard.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()
class TraktChecker(object): def __init__(self): self.trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.TRAKT_TIMEOUT) self.todoBacklog = [] self.todoWanted = [] self.ShowWatchlist = {} self.EpisodeWatchlist = {} self.Collectionlist = {} self.amActive = False def run(self, force=False): self.amActive = True # add shows from trakt.tv watchlist if sickbeard.TRAKT_SYNC_WATCHLIST: self.todoWanted = [] # its about to all get re-added if len(sickbeard.ROOT_DIRS.split('|')) < 2: logger.log(u"No default root directory", logger.WARNING) return try: self.syncWatchlist() except Exception: logger.log(traceback.format_exc(), logger.DEBUG) try: # sync trakt.tv library with sickrage library self.syncLibrary() except Exception: logger.log(traceback.format_exc(), logger.DEBUG) self.amActive = False def findShow(self, indexer, indexerid): traktShow = None try: library = self.trakt_api.traktRequest("sync/collection/shows") or [] if not library: logger.log(u"Could not connect to trakt service, aborting library check", logger.WARNING) return if not len(library): logger.log(u"No shows found in your library, aborting library update", logger.DEBUG) return traktShow = [x for x in library if int(indexerid) in [int(x['show']['ids']['tvdb'] or 0), int(x['show']['ids']['tvrage'] or 0)]] except traktException as e: logger.log(u"Could not connect to Trakt service. Aborting library check. Error: %s" % repr(e), logger.WARNING) return traktShow def removeShowFromTraktLibrary(self, show_obj): if self.findShow(show_obj.indexer, show_obj.indexerid): trakt_id = sickbeard.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(u"Removing %s from trakt.tv library" % show_obj.name, logger.DEBUG) try: self.trakt_api.traktRequest("sync/collection/remove", data, method='POST') except traktException as e: logger.log(u"Could not connect to Trakt service. Aborting removing show %s from Trakt library. Error: %s" % (show_obj.name, repr(e)), logger.WARNING) def addShowToTraktLibrary(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.findShow(show_obj.indexer, show_obj.indexerid): trakt_id = sickbeard.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 len(data): logger.log(u"Adding %s to trakt.tv library" % show_obj.name, logger.DEBUG) try: self.trakt_api.traktRequest("sync/collection", data, method='POST') except traktException as e: logger.log(u"Could not connect to Trakt service. Aborting adding show %s to Trakt library. Error: %s" % (show_obj.name, repr(e)), logger.WARNING) return def syncLibrary(self): if sickbeard.TRAKT_SYNC and sickbeard.USE_TRAKT: logger.log(u"Sync SickRage with Trakt Collection", logger.DEBUG) if self._getShowCollection(): self.addEpisodeToTraktCollection() if sickbeard.TRAKT_SYNC_REMOVE: self.removeEpisodeFromTraktCollection() def removeEpisodeFromTraktCollection(self): if sickbeard.TRAKT_SYNC_REMOVE and sickbeard.TRAKT_SYNC and sickbeard.USE_TRAKT: logger.log(u"COLLECTION::REMOVE::START - Look for Episodes to Remove From Trakt Collection", logger.DEBUG) myDB = db.DBConnection() sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode, tv_episodes.status, tv_episodes.location from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid' episodes = myDB.select(sql_selection) if episodes is not None: trakt_data = [] for cur_episode in episodes: trakt_id = sickbeard.indexerApi(cur_episode["indexer"]).config['trakt_id'] if self._checkInList(trakt_id, str(cur_episode["showid"]), str(cur_episode["season"]), str(cur_episode["episode"]), List='Collection'): if cur_episode["location"] == '': logger.log(u"Removing Episode %s S%02dE%02d from collection" % (cur_episode["show_name"], cur_episode["season"], cur_episode["episode"]), logger.DEBUG) trakt_data.append((cur_episode["showid"], cur_episode["indexer"], cur_episode["show_name"], cur_episode["startyear"], cur_episode["season"], cur_episode["episode"])) if len(trakt_data): try: data = self.trakt_bulk_data_generate(trakt_data) self.trakt_api.traktRequest("sync/collection/remove", data, method='POST') self._getShowCollection() except traktException as e: logger.log(u"Could not connect to Trakt service. Error: %s" % ex(e), logger.WARNING) logger.log(u"COLLECTION::REMOVE::FINISH - Look for Episodes to Remove From Trakt Collection", logger.DEBUG) def addEpisodeToTraktCollection(self): if sickbeard.TRAKT_SYNC and sickbeard.USE_TRAKT: logger.log(u"COLLECTION::ADD::START - Look for Episodes to Add to Trakt Collection", logger.DEBUG) myDB = db.DBConnection() sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid and tv_episodes.status in (' + ','.join([str(x) for x in Quality.DOWNLOADED + Quality.ARCHIVED]) + ')' episodes = myDB.select(sql_selection) if episodes is not None: trakt_data = [] for cur_episode in episodes: trakt_id = sickbeard.indexerApi(cur_episode["indexer"]).config['trakt_id'] if not self._checkInList(trakt_id, str(cur_episode["showid"]), str(cur_episode["season"]), str(cur_episode["episode"]), List='Collection'): logger.log(u"Adding Episode %s S%02dE%02d to collection" % (cur_episode["show_name"], cur_episode["season"], cur_episode["episode"]), logger.DEBUG) trakt_data.append((cur_episode["showid"], cur_episode["indexer"], cur_episode["show_name"], cur_episode["startyear"], cur_episode["season"], cur_episode["episode"])) if len(trakt_data): try: data = self.trakt_bulk_data_generate(trakt_data) self.trakt_api.traktRequest("sync/collection", data, method='POST') self._getShowCollection() except traktException as e: logger.log(u"Could not connect to Trakt service. Error: %s" % ex(e), logger.WARNING) logger.log(u"COLLECTION::ADD::FINISH - Look for Episodes to Add to Trakt Collection", logger.DEBUG) def syncWatchlist(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: logger.log(u"Sync SickRage with Trakt Watchlist", logger.DEBUG) self.removeShowFromSickRage() if self._getShowWatchlist(): self.addShowToTraktWatchList() self.updateShows() if self._getEpisodeWatchlist(): self.removeEpisodeFromTraktWatchList() self.addEpisodeToTraktWatchList() self.updateEpisodes() def removeEpisodeFromTraktWatchList(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: logger.log(u"WATCHLIST::REMOVE::START - Look for Episodes to Remove from Trakt Watchlist", logger.DEBUG) myDB = db.DBConnection() sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode, tv_episodes.status from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid' episodes = myDB.select(sql_selection) if episodes is not None: trakt_data = [] for cur_episode in episodes: trakt_id = sickbeard.indexerApi(cur_episode["indexer"]).config['trakt_id'] if self._checkInList(trakt_id, str(cur_episode["showid"]), str(cur_episode["season"]), str(cur_episode["episode"])): if cur_episode["status"] not in Quality.SNATCHED + Quality.SNATCHED_PROPER + [UNKNOWN] + [WANTED]: logger.log(u"Removing Episode %s S%02dE%02d from watchlist" % (cur_episode["show_name"], cur_episode["season"], cur_episode["episode"]), logger.DEBUG) trakt_data.append((cur_episode["showid"], cur_episode["indexer"], cur_episode["show_name"], cur_episode["startyear"], cur_episode["season"], cur_episode["episode"])) if len(trakt_data): try: data = self.trakt_bulk_data_generate(trakt_data) self.trakt_api.traktRequest("sync/watchlist/remove", data, method='POST') self._getEpisodeWatchlist() except traktException as e: logger.log(u"Could not connect to Trakt service. Error: %s" % ex(e), logger.WARNING) logger.log(u"WATCHLIST::REMOVE::FINISH - Look for Episodes to Remove from Trakt Watchlist", logger.DEBUG) def addEpisodeToTraktWatchList(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: logger.log(u"WATCHLIST::ADD::START - Look for Episodes to Add to Trakt Watchlist", logger.DEBUG) myDB = db.DBConnection() sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid and tv_episodes.status in (' + ','.join([str(x) for x in Quality.SNATCHED + Quality.SNATCHED_PROPER + [WANTED]]) + ')' episodes = myDB.select(sql_selection) if episodes is not None: trakt_data = [] for cur_episode in episodes: trakt_id = sickbeard.indexerApi(cur_episode["indexer"]).config['trakt_id'] if not self._checkInList(trakt_id, str(cur_episode["showid"]), str(cur_episode["season"]), str(cur_episode["episode"])): logger.log(u"Adding Episode %s S%02dE%02d to watchlist" % (cur_episode["show_name"], cur_episode["season"], cur_episode["episode"]), logger.DEBUG) trakt_data.append((cur_episode["showid"], cur_episode["indexer"], cur_episode["show_name"], cur_episode["startyear"], cur_episode["season"], cur_episode["episode"])) if len(trakt_data): try: data = self.trakt_bulk_data_generate(trakt_data) self.trakt_api.traktRequest("sync/watchlist", data, method='POST') self._getEpisodeWatchlist() except traktException as e: logger.log(u"Could not connect to Trakt service. Error %s" % ex(e), logger.WARNING) logger.log(u"WATCHLIST::ADD::FINISH - Look for Episodes to Add to Trakt Watchlist", logger.DEBUG) def addShowToTraktWatchList(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: logger.log(u"SHOW_WATCHLIST::ADD::START - Look for Shows to Add to Trakt Watchlist", logger.DEBUG) if sickbeard.showList is not None: trakt_data = [] for show in sickbeard.showList: trakt_id = sickbeard.indexerApi(show.indexer).config['trakt_id'] if not self._checkInList(trakt_id, str(show.indexerid), '0', '0', List='Show'): logger.log(u"Adding Show: Indexer %s %s - %s to Watchlist" % (trakt_id, str(show.indexerid), show.name), logger.DEBUG) show_el = {'title': show.name, 'year': show.startyear, 'ids': {}} if trakt_id == 'tvdb_id': show_el['ids']['tvdb'] = show.indexerid else: show_el['ids']['tvrage'] = show.indexerid trakt_data.append(show_el) if len(trakt_data): try: data = {'shows': trakt_data} self.trakt_api.traktRequest("sync/watchlist", data, method='POST') self._getShowWatchlist() except traktException as e: logger.log(u"Could not connect to Trakt service. Error: %s" % ex(e), logger.WARNING) logger.log(u"SHOW_WATCHLIST::ADD::FINISH - Look for Shows to Add to Trakt Watchlist", logger.DEBUG) def removeShowFromSickRage(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT and sickbeard.TRAKT_REMOVE_SHOW_FROM_SICKRAGE: logger.log(u"SHOW_SICKRAGE::REMOVE::START - Look for Shows to remove from SickRage", logger.DEBUG) if sickbeard.showList: for show in sickbeard.showList: if show.status == "Ended": try: progress = self.trakt_api.traktRequest("shows/" + show.imdbid + "/progress/watched") or [] except traktException as e: logger.log(u"Could not connect to Trakt service. Aborting removing show %s from SickRage. Error: %s" % (show.name, repr(e)), logger.WARNING) return if 'aired' in progress and 'completed' in progress and progress['aired'] == progress['completed']: sickbeard.showQueueScheduler.action.removeShow(show, full=True) logger.log(u"Show: %s has been removed from SickRage" % show.name, logger.DEBUG) logger.log(u"SHOW_SICKRAGE::REMOVE::FINISH - Trakt Show Watchlist", logger.DEBUG) def updateShows(self): logger.log(u"SHOW_WATCHLIST::CHECK::START - Trakt Show Watchlist", logger.DEBUG) if not len(self.ShowWatchlist): logger.log(u"No shows found in your watchlist, aborting watchlist update", logger.DEBUG) return indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) trakt_id = sickbeard.indexerApi(indexer).config['trakt_id'] for show_el in self.ShowWatchlist[trakt_id]: indexer_id = int(str(show_el)) show = self.ShowWatchlist[trakt_id][show_el] # logger.log(u"Checking Show: %s %s %s" % (trakt_id, indexer_id, show['title']),logger.DEBUG) if int(sickbeard.TRAKT_METHOD_ADD) != 2: self.addDefaultShow(indexer, indexer_id, show['title'], SKIPPED) else: self.addDefaultShow(indexer, indexer_id, show['title'], WANTED) if int(sickbeard.TRAKT_METHOD_ADD) == 1: newShow = Show.find(sickbeard.showList, indexer_id) if newShow is not None: setEpisodeToWanted(newShow, 1, 1) else: self.todoWanted.append((indexer_id, 1, 1)) logger.log(u"SHOW_WATCHLIST::CHECK::FINISH - Trakt Show Watchlist", logger.DEBUG) def updateEpisodes(self): """ Sets episodes to wanted that are in trakt watchlist """ logger.log(u"SHOW_WATCHLIST::CHECK::START - Trakt Episode Watchlist", logger.DEBUG) if not len(self.EpisodeWatchlist): logger.log(u"No episode found in your watchlist, aborting episode update", logger.DEBUG) return managed_show = [] indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) trakt_id = sickbeard.indexerApi(indexer).config['trakt_id'] for show_el in self.EpisodeWatchlist[trakt_id]: indexer_id = int(show_el) show = self.EpisodeWatchlist[trakt_id][show_el] newShow = Show.find(sickbeard.showList, indexer_id) try: if newShow is None: if indexer_id not in managed_show: self.addDefaultShow(indexer, indexer_id, show['title'], SKIPPED) managed_show.append(indexer_id) for season_el in show['seasons']: season = int(season_el) for episode_el in show['seasons'][season_el]['episodes']: self.todoWanted.append((indexer_id, season, int(episode_el))) else: if newShow.indexer == indexer: for season_el in show['seasons']: season = int(season_el) for episode_el in show['seasons'][season_el]['episodes']: setEpisodeToWanted(newShow, season, int(episode_el)) except TypeError: logger.log(u"Could not parse the output from trakt for %s " % show["title"], logger.DEBUG) logger.log(u"SHOW_WATCHLIST::CHECK::FINISH - Trakt Episode Watchlist", logger.DEBUG) @staticmethod def addDefaultShow(indexer, indexer_id, name, status): """ Adds a new show with the default settings """ if not Show.find(sickbeard.showList, int(indexer_id)): logger.log(u"Adding show " + str(indexer_id)) root_dirs = sickbeard.ROOT_DIRS.split('|') try: location = root_dirs[int(root_dirs[0]) + 1] except Exception: location = None if location: showPath = ek(os.path.join, location, sanitize_filename(name)) dir_exists = helpers.makeDir(showPath) if not dir_exists: logger.log(u"Unable to create the folder %s , can't add the show" % showPath, logger.WARNING) return else: helpers.chmodAsParent(showPath) sickbeard.showQueueScheduler.action.addShow(int(indexer), int(indexer_id), showPath, default_status=status, quality=int(sickbeard.QUALITY_DEFAULT), flatten_folders=int(sickbeard.FLATTEN_FOLDERS_DEFAULT), paused=sickbeard.TRAKT_START_PAUSED, default_status_after=status) else: logger.log(u"There was an error creating the show, no root directory setting found", logger.WARNING) return def manageNewShow(self, show): logger.log(u"Checking if trakt watch list wants to search for episodes from new show " + show.name, logger.DEBUG) episodes = [i for i in self.todoWanted if i[0] == show.indexerid] for episode in episodes: self.todoWanted.remove(episode) setEpisodeToWanted(show, episode[1], episode[2]) def _checkInList(self, trakt_id, showid, season, episode, List=None): """ Check in the Watchlist or CollectionList for Show Is the Show, Season and Episode in the trakt_id list (tvdb / tvrage) """ # logger.log(u"Checking Show: %s %s %s " % (trakt_id, showid, List),logger.DEBUG) if "Collection" == List: try: if self.Collectionlist[trakt_id][showid]['seasons'][season]['episodes'][episode] == episode: return True except Exception: return False elif "Show" == List: try: if self.ShowWatchlist[trakt_id][showid]['id'] == showid: return True except Exception: return False else: try: if self.EpisodeWatchlist[trakt_id][showid]['seasons'][season]['episodes'][episode] == episode: return True except Exception: return False def _getShowWatchlist(self): """ Get Watchlist and parse once into addressable structure """ try: self.ShowWatchlist = {'tvdb_id': {}, 'tvrage_id': {}} TraktShowWatchlist = self.trakt_api.traktRequest("sync/watchlist/shows") tvdb_id = 'tvdb' tvrage_id = 'tvrage' for watchlist_el in TraktShowWatchlist: tvdb = False tvrage = False if not watchlist_el['show']['ids']["tvdb"] is None: tvdb = True if not watchlist_el['show']['ids']["tvrage"] is None: tvrage = True title = watchlist_el['show']['title'] year = str(watchlist_el['show']['year']) if tvdb: showid = str(watchlist_el['show']['ids'][tvdb_id]) self.ShowWatchlist[tvdb_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year} if tvrage: showid = str(watchlist_el['show']['ids'][tvrage_id]) self.ShowWatchlist[tvrage_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year} except traktException as e: logger.log(u"Could not connect to trakt service, cannot download Show Watchlist: %s" % repr(e), logger.WARNING) return False return True def _getEpisodeWatchlist(self): """ Get Watchlist and parse once into addressable structure """ try: self.EpisodeWatchlist = {'tvdb_id': {}, 'tvrage_id': {}} TraktEpisodeWatchlist = self.trakt_api.traktRequest("sync/watchlist/episodes") tvdb_id = 'tvdb' tvrage_id = 'tvrage' for watchlist_el in TraktEpisodeWatchlist: tvdb = False tvrage = False if not watchlist_el['show']['ids']["tvdb"] is None: tvdb = True if not watchlist_el['show']['ids']["tvrage"] is None: tvrage = True title = watchlist_el['show']['title'] year = str(watchlist_el['show']['year']) season = str(watchlist_el['episode']['season']) episode = str(watchlist_el['episode']['number']) if tvdb: showid = str(watchlist_el['show']['ids'][tvdb_id]) if showid not in self.EpisodeWatchlist[tvdb_id + '_id'].keys(): self.EpisodeWatchlist[tvdb_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year, 'seasons': {}} if season not in self.EpisodeWatchlist[tvdb_id + '_id'][showid]['seasons'].keys(): self.EpisodeWatchlist[tvdb_id + '_id'][showid]['seasons'][season] = {'s': season, 'episodes': {}} if episode not in self.EpisodeWatchlist[tvdb_id + '_id'][showid]['seasons'][season]['episodes'].keys(): self.EpisodeWatchlist[tvdb_id + '_id'][showid]['seasons'][season]['episodes'][episode] = episode if tvrage: showid = str(watchlist_el['show']['ids'][tvrage_id]) if showid not in self.EpisodeWatchlist[tvrage_id + '_id'].keys(): self.EpisodeWatchlist[tvrage_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year, 'seasons': {}} if season not in self.EpisodeWatchlist[tvrage_id + '_id'][showid]['seasons'].keys(): self.EpisodeWatchlist[tvrage_id + '_id'][showid]['seasons'][season] = {'s': season, 'episodes': {}} if episode not in self.EpisodeWatchlist[tvrage_id + '_id'][showid]['seasons'][season]['episodes'].keys(): self.EpisodeWatchlist[tvrage_id + '_id'][showid]['seasons'][season]['episodes'][episode] = episode except traktException as e: logger.log(u"Could not connect to trakt service, cannot download Episode Watchlist: %s" % repr(e), logger.WARNING) return False return True def _getShowCollection(self): """ Get Collection and parse once into addressable structure """ try: self.Collectionlist = {'tvdb_id': {}, 'tvrage_id': {}} logger.log(u"Getting Show Collection", logger.DEBUG) TraktCollectionList = self.trakt_api.traktRequest("sync/collection/shows") tvdb_id = 'tvdb' tvrage_id = 'tvrage' for watchlist_el in TraktCollectionList: tvdb = False tvrage = False if not watchlist_el['show']['ids']["tvdb"] is None: tvdb = True if not watchlist_el['show']['ids']["tvrage"] is None: tvrage = True title = watchlist_el['show']['title'] year = str(watchlist_el['show']['year']) if 'seasons' in watchlist_el: for season_el in watchlist_el['seasons']: for episode_el in season_el['episodes']: season = str(season_el['number']) episode = str(episode_el['number']) if tvdb: showid = str(watchlist_el['show']['ids'][tvdb_id]) if showid not in self.Collectionlist[tvdb_id + '_id'].keys(): self.Collectionlist[tvdb_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year, 'seasons': {}} if season not in self.Collectionlist[tvdb_id + '_id'][showid]['seasons'].keys(): self.Collectionlist[tvdb_id + '_id'][showid]['seasons'][season] = {'s': season, 'episodes': {}} if episode not in self.Collectionlist[tvdb_id + '_id'][showid]['seasons'][season]['episodes'].keys(): self.Collectionlist[tvdb_id + '_id'][showid]['seasons'][season]['episodes'][episode] = episode if tvrage: showid = str(watchlist_el['show']['ids'][tvrage_id]) if showid not in self.Collectionlist[tvrage_id + '_id'].keys(): self.Collectionlist[tvrage_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year, 'seasons': {}} if season not in self.Collectionlist[tvrage_id + '_id'][showid]['seasons'].keys(): self.Collectionlist[tvrage_id + '_id'][showid]['seasons'][season] = {'s': season, 'episodes': {}} if episode not in self.Collectionlist[tvrage_id + '_id'][showid]['seasons'][season]['episodes'].keys(): self.Collectionlist[tvrage_id + '_id'][showid]['seasons'][season]['episodes'][episode] = episode except traktException as e: logger.log(u"Could not connect to trakt service, cannot download Show Collection: %s" % repr(e), logger.WARNING) return False return True @staticmethod def trakt_bulk_data_generate(data): """ 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 = sickbeard.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
def run(self): ShowQueueItem.run(self) logger.log(u"Starting to add show " + self.showDir) # make sure the Indexer IDs are valid try: lINDEXER_API_PARMS = sickbeard.indexerApi(self.indexer).api_params.copy() if self.lang: lINDEXER_API_PARMS['language'] = self.lang logger.log(u"" + str(sickbeard.indexerApi(self.indexer).name) + ": " + repr(lINDEXER_API_PARMS)) t = sickbeard.indexerApi(self.indexer).indexer(**lINDEXER_API_PARMS) s = t[self.indexer_id] # 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 " + self.showDir + " has no name on " + str( sickbeard.indexerApi(self.indexer).name) + ", probably the wrong language used to search with.", logger.ERROR) ui.notifications.error("Unable to add show", "Show in " + self.showDir + " has no name on " + str(sickbeard.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( sickbeard.indexerApi(self.indexer).name) + " but contains no season/episode data.", logger.ERROR) ui.notifications.error("Unable to add show", "Show " + str(s['seriesname']) + " is on " + str(sickbeard.indexerApi( self.indexer).name) + " but contains no season/episode data.") self._finishEarly() return except Exception, e: logger.log(u"Error while loading information from indexer %s. Error: %r" % (self.indexer_id,sickbeard.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,sickbeard.indexerApi(self.indexer).name) , logger.WARNING) ui.notifications.error("Unable to add show", "Unable to look up the show in " + self.showDir + " on " + str(sickbeard.indexerApi( self.indexer).name) + " using ID " + str( self.indexer_id) + ", not using the NFO. Delete .nfo and try adding manually again.") if sickbeard.USE_TRAKT: trakt_id = sickbeard.indexerApi(self.indexer).config['trakt_id'] trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.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 trakt_api.traktRequest("sync/watchlist/remove", data, method='POST') self._finishEarly() return
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 = sickbeard.indexerApi(self.indexer).api_params.copy() if self.lang: lINDEXER_API_PARMS['language'] = self.lang logger.log(u"" + str(sickbeard.indexerApi(self.indexer).name) + ": " + repr(lINDEXER_API_PARMS)) t = sickbeard.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, sickbeard.indexerApi(self.indexer).name), logger.ERROR) ui.notifications.error("Unable to add show", "Show in " + self.showDir + " has no name on " + str(sickbeard.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( sickbeard.indexerApi(self.indexer).name) + " but contains no season/episode data.") ui.notifications.error("Unable to add show", "Show " + str(s['seriesname']) + " is on " + str(sickbeard.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, sickbeard.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, sickbeard.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, sickbeard.indexerApi(self.indexer).name, self.indexer_id) ) if sickbeard.USE_TRAKT: trakt_id = sickbeard.indexerApi(self.indexer).config['trakt_id'] trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.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 trakt_api.traktRequest("sync/watchlist/remove", data, method='POST') self._finishEarly() return try: newShow = TVShow(self.indexer, self.indexer_id, self.lang) newShow.loadFromIndexer() self.show = newShow # set up initial values self.show.location = self.showDir self.show.subtitles = self.subtitles if self.subtitles is not None else sickbeard.SUBTITLES_DEFAULT self.show.quality = self.quality if self.quality else sickbeard.QUALITY_DEFAULT self.show.flatten_folders = self.flatten_folders if self.flatten_folders is not None else sickbeard.FLATTEN_FOLDERS_DEFAULT self.show.anime = self.anime if self.anime is not None else sickbeard.ANIME_DEFAULT self.show.scene = self.scene if self.scene is not None else sickbeard.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 sickbeard.indexer_exception as e: logger.log( u"Unable to add show due to an error with " + sickbeard.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 " + sickbeard.indexerApi( self.indexer).name + "") else: ui.notifications.error( "Unable to add show due to an error with " + sickbeard.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.loadIMDbInfo() 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.saveToDB() 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 sickbeard.showList.append(self.show) try: self.show.loadEpisodesFromIndexer() except Exception as e: logger.log( u"Error with " + sickbeard.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.loadEpisodesFromDir() 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") sickbeard.backlogSearchScheduler.action.searchBacklog([self.show]) self.show.writeMetadata() self.show.updateMetadata() self.show.populateCache() self.show.flushEpisodes() if sickbeard.USE_TRAKT: # if there are specific episodes that need to be added by trakt sickbeard.traktCheckerScheduler.action.manageNewShow(self.show) # add show to trakt.tv library if sickbeard.TRAKT_SYNC: sickbeard.traktCheckerScheduler.action.addShowToTraktLibrary(self.show) if sickbeard.TRAKT_SYNC_WATCHLIST: logger.log(u"update watchlist") notifiers.trakt_notifier.update_watchlist(show_obj=self.show) # Load XEM data to DB for show sickbeard.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 sickbeard.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()
def run(self): # pylint: disable=too-many-branches, too-many-statements, too-many-return-statements super(QueueItemAdd, self).run() if self.showDir: try: assert isinstance(self.showDir, six.text_type) except AssertionError: logger.log(traceback.format_exc(), logger.WARNING) self._finish_early() return logger.log('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 = sickbeard.indexerApi( self.indexer).api_params.copy() lINDEXER_API_PARMS[ 'language'] = self.lang or sickbeard.INDEXER_DEFAULT_LANGUAGE logger.log('{0}: {1!r}'.format( sickbeard.indexerApi(self.indexer).name, lINDEXER_API_PARMS)) t = sickbeard.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 self.root_dir and not self.showDir: show_name = get_showname_from_indexer(self.indexer, self.indexer_id, self.lang) if not show_name: logger.log( 'Unable to get a show {0}, can\'t add the show'.format( self.showDir)) self._finish_early() return self.showDir = ek(os.path.join, self.root_dir, sanitize_filename(show_name)) dir_exists = makeDir(self.showDir) if not dir_exists: logger.log( 'Unable to create the folder {0}, can\'t add the show'. format(self.showDir)) self._finish_early() return chmodAsParent(self.showDir) # 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: error_string = 'Show in {0} has no name on {1}, probably searched with the wrong language. Delete .nfo and add manually in the correct language.'.format( self.showDir, sickbeard.indexerApi(self.indexer).name) logger.log(error_string, logger.WARNING) ui.notifications.error('Unable to add show', error_string) self._finish_early() return # if the show has no episodes/seasons if not s: error_string = 'Show {0} is on {1} but contains no season/episode data.'.format( s[b'seriesname'], sickbeard.indexerApi(self.indexer).name) logger.log(error_string) ui.notifications.error('Unable to add show', error_string) self._finish_early() return except Exception as error: error_string = 'Unable to look up the show in {0} on {1} using ID {2}, not using the NFO. Delete .nfo and try adding manually again.'.format( self.showDir, sickbeard.indexerApi(self.indexer).name, self.indexer_id) logger.log('{0}: {1}'.format(error_string, error), logger.ERROR) ui.notifications.error('Unable to add show', error_string) if sickbeard.USE_TRAKT: trakt_id = sickbeard.indexerApi( self.indexer).config[b'trakt_id'] trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.TRAKT_TIMEOUT) title = self.showDir.split('/')[-1] data = {'shows': [{'title': title, 'ids': {}}]} if trakt_id == 'tvdb_id': data[b'shows'][0][b'ids'][b'tvdb'] = self.indexer_id else: data[b'shows'][0][b'ids'][b'tvrage'] = self.indexer_id trakt_api.traktRequest('sync/watchlist/remove', data, method='POST') self._finish_early() return try: try: newShow = TVShow(self.indexer, self.indexer_id, self.lang) except MultipleShowObjectsException as error: # If we have the show in our list, but the location is wrong, lets fix it and refresh! existing_show = Show.find(sickbeard.showList, self.indexer_id) if existing_show and not ek(os.path.isdir, existing_show._location): # pylint: disable=protected-access newShow = existing_show else: raise error newShow.loadFromIndexer() self.show = newShow # set up initial values self.show.location = self.showDir self.show.subtitles = self.subtitles if self.subtitles is not None else sickbeard.SUBTITLES_DEFAULT self.show.subtitles_sr_metadata = self.subtitles_sr_metadata self.show.quality = self.quality if self.quality else sickbeard.QUALITY_DEFAULT self.show.season_folders = self.season_folders if self.season_folders is not None else sickbeard.SEASON_FOLDERS_DEFAULT self.show.anime = self.anime if self.anime is not None else sickbeard.ANIME_DEFAULT self.show.scene = self.scene if self.scene is not None else sickbeard.SCENE_DEFAULT self.show.paused = self.paused if self.paused is not None else False # set up default new/missing episode status logger.log( 'Setting all episodes to the specified default status: {0}'. format(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 sickbeard.indexer_exception as error: error_string = 'Unable to add {0} due to an error with {1}'.format( self.show.name if self.show else 'show', sickbeard.indexerApi(self.indexer).name) logger.log('{0}: {1}'.format(error_string, error), logger.ERROR) ui.notifications.error('Unable to add show', error_string) self._finish_early() return except MultipleShowObjectsException: error_string = 'The show in {0} is already in your show list, skipping'.format( self.showDir) logger.log(error_string, logger.WARNING) ui.notifications.error('Show skipped', error_string) self._finish_early() return except Exception as error: logger.log('Error trying to add show: {0}'.format(error), logger.ERROR) logger.log(traceback.format_exc(), logger.DEBUG) self._finish_early() raise logger.log('Retrieving show info from IMDb', logger.DEBUG) try: self.show.loadIMDbInfo() except imdb_exceptions.IMDbError as error: logger.log(' Something wrong on IMDb api: {0}'.format(error), logger.WARNING) except Exception as error: logger.log('Error loading IMDb info: {0}'.format(error), logger.ERROR) try: self.show.saveToDB() except Exception as error: logger.log( 'Error saving the show to the database: {0}'.format(error), logger.ERROR) logger.log(traceback.format_exc(), logger.DEBUG) self._finish_early() raise # add it to the show list if not Show.find(sickbeard.showList, self.indexer_id): sickbeard.showList.append(self.show) try: self.show.loadEpisodesFromIndexer() except Exception as error: logger.log( 'Error with {0}, not creating episode list: {1}'.format( sickbeard.indexerApi(self.show.indexer).name, error), logger.ERROR) logger.log(traceback.format_exc(), logger.DEBUG) # update internal name cache name_cache.buildNameCache(self.show) try: self.show.loadEpisodesFromDir() except Exception as error: logger.log('Error searching dir for episodes: {0}'.format(error), 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( 'Launching backlog for this show since its episodes are WANTED' ) sickbeard.backlogSearchScheduler.action.searchBacklog([self.show]) self.show.writeMetadata() self.show.updateMetadata() self.show.populateCache() self.show.flushEpisodes() if sickbeard.USE_TRAKT: # if there are specific episodes that need to be added by trakt sickbeard.traktCheckerScheduler.action.manageNewShow(self.show) # add show to trakt.tv library if sickbeard.TRAKT_SYNC: sickbeard.traktCheckerScheduler.action.addShowToTraktLibrary( self.show) if sickbeard.TRAKT_SYNC_WATCHLIST: logger.log('update watchlist') notifiers.trakt_notifier.update_watchlist(show_obj=self.show) # Load XEM data to DB for show sickbeard.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 sickbeard.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 super(QueueItemAdd, self).finish() self.finish()
class TraktChecker(object): def __init__(self): self.trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.TRAKT_TIMEOUT) self.todoBacklog = [] self.todoWanted = [] self.ShowWatchlist = {} self.EpisodeWatchlist = {} self.Collectionlist = {} self.amActive = False def run(self, force=False): self.amActive = True # add shows from trakt.tv watchlist if sickbeard.TRAKT_SYNC_WATCHLIST: self.todoWanted = [] # its about to all get re-added if len(sickbeard.ROOT_DIRS.split('|')) < 2: logger.log("No default root directory", logger.WARNING) return try: self.syncWatchlist() except Exception: logger.log(traceback.format_exc(), logger.DEBUG) try: # sync trakt.tv library with sickrage library self.syncLibrary() except Exception: logger.log(traceback.format_exc(), logger.DEBUG) self.amActive = False def findShow(self, indexer, indexerid): traktShow = None try: library = self.trakt_api.traktRequest( "sync/collection/shows") or [] if not library: logger.log( "No shows found in your library, aborting library update", logger.DEBUG) return traktShow = [ x for x in library if int(indexerid) in [ int(x['show']['ids']['tvdb'] or 0), int(x['show']['ids']['tvrage'] or 0) ] ] except traktException as e: logger.log( "Could not connect to Trakt service. Aborting library check. Error: {0}" .format(repr(e)), logger.WARNING) return traktShow def removeShowFromTraktLibrary(self, show_obj): if self.findShow(show_obj.indexer, show_obj.indexerid): trakt_id = sickbeard.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.tv library".format(show_obj.name), logger.DEBUG) try: self.trakt_api.traktRequest("sync/collection/remove", data, method='POST') except traktException as e: logger.log( "Could not connect to Trakt service. Aborting removing show {0} from Trakt library. Error: {1}" .format(show_obj.name, repr(e)), logger.WARNING) def addShowToTraktLibrary(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.findShow(show_obj.indexer, show_obj.indexerid): trakt_id = sickbeard.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.tv library".format(show_obj.name), logger.DEBUG) try: self.trakt_api.traktRequest("sync/collection", data, method='POST') except traktException as e: logger.log( "Could not connect to Trakt service. Aborting adding show {0} to Trakt library. Error: {1}" .format(show_obj.name, repr(e)), logger.WARNING) return def syncLibrary(self): if sickbeard.TRAKT_SYNC and sickbeard.USE_TRAKT: logger.log("Sync SickRage with Trakt Collection", logger.DEBUG) if self._getShowCollection(): self.addEpisodeToTraktCollection() if sickbeard.TRAKT_SYNC_REMOVE: self.removeEpisodeFromTraktCollection() def removeEpisodeFromTraktCollection(self): if sickbeard.TRAKT_SYNC_REMOVE and sickbeard.TRAKT_SYNC and sickbeard.USE_TRAKT: logger.log( "COLLECTION::REMOVE::START - Look for Episodes to Remove From Trakt Collection", logger.DEBUG) main_db_con = db.DBConnection() sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode, tv_episodes.status, tv_episodes.location from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid' episodes = main_db_con.select(sql_selection) if episodes is not None: trakt_data = [] for cur_episode in episodes: trakt_id = sickbeard.indexerApi( cur_episode[b"indexer"]).config[b'trakt_id'] if self._checkInList(trakt_id, str(cur_episode[b"showid"]), str(cur_episode[b"season"]), str(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.traktRequest("sync/collection/remove", data, method='POST') self._getShowCollection() except traktException as e: logger.log( "Could not connect to Trakt service. Error: {0}". format(ex(e)), logger.WARNING) logger.log( "COLLECTION::REMOVE::FINISH - Look for Episodes to Remove From Trakt Collection", logger.DEBUG) def addEpisodeToTraktCollection(self): if sickbeard.TRAKT_SYNC and sickbeard.USE_TRAKT: logger.log( "COLLECTION::ADD::START - Look for Episodes to Add to Trakt Collection", logger.DEBUG) main_db_con = db.DBConnection() sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid and tv_episodes.status in (' + ','.join( [str(x) for x in Quality.DOWNLOADED + Quality.ARCHIVED]) + ')' episodes = main_db_con.select(sql_selection) if episodes is not None: trakt_data = [] for cur_episode in episodes: trakt_id = sickbeard.indexerApi( cur_episode[b"indexer"]).config['trakt_id'] if not self._checkInList(trakt_id, str(cur_episode[b"showid"]), str(cur_episode[b"season"]), str(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.traktRequest("sync/collection", data, method='POST') self._getShowCollection() except traktException as e: logger.log( "Could not connect to Trakt service. Error: {0}". format(ex(e)), logger.WARNING) logger.log( "COLLECTION::ADD::FINISH - Look for Episodes to Add to Trakt Collection", logger.DEBUG) def syncWatchlist(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: logger.log("Sync SickRage with Trakt Watchlist", logger.DEBUG) self.removeShowFromSickRage() if self._getShowWatchlist(): self.addShowToTraktWatchList() self.updateShows() if self._getEpisodeWatchlist(): self.removeEpisodeFromTraktWatchList() self.addEpisodeToTraktWatchList() self.updateEpisodes() def removeEpisodeFromTraktWatchList(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: logger.log( "WATCHLIST::REMOVE::START - Look for Episodes to Remove from Trakt Watchlist", logger.DEBUG) main_db_con = db.DBConnection() sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode, tv_episodes.status from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid' episodes = main_db_con.select(sql_selection) if episodes is not None: trakt_data = [] for cur_episode in episodes: trakt_id = sickbeard.indexerApi( cur_episode[b"indexer"]).config['trakt_id'] if self._checkInList(trakt_id, str(cur_episode[b"showid"]), str(cur_episode[b"season"]), str(cur_episode[b"episode"])): if cur_episode[ b"status"] not in Quality.SNATCHED + Quality.SNATCHED_PROPER + [ UNKNOWN ] + [WANTED]: logger.log( "Removing Episode {show} {ep} from watchlist". format( show=cur_episode[b"show_name"], ep=episode_num(cur_episode[b"season"], cur_episode[b"episode"])), logger.DEBUG) trakt_data.append((cur_episode[b"showid"], cur_episode[b"indexer"], cur_episode[b"show_name"], cur_episode[b"startyear"], cur_episode[b"season"], cur_episode[b"episode"])) if trakt_data: try: data = self.trakt_bulk_data_generate(trakt_data) self.trakt_api.traktRequest("sync/watchlist/remove", data, method='POST') self._getEpisodeWatchlist() except traktException as e: logger.log( "Could not connect to Trakt service. Error: {0}". format(ex(e)), logger.WARNING) logger.log( "WATCHLIST::REMOVE::FINISH - Look for Episodes to Remove from Trakt Watchlist", logger.DEBUG) def addEpisodeToTraktWatchList(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: logger.log( "WATCHLIST::ADD::START - Look for Episodes to Add to Trakt Watchlist", logger.DEBUG) main_db_con = db.DBConnection() sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid and tv_episodes.status in (' + ','.join( [ str(x) for x in Quality.SNATCHED + Quality.SNATCHED_PROPER + [WANTED] ]) + ')' episodes = main_db_con.select(sql_selection) if episodes is not None: trakt_data = [] for cur_episode in episodes: trakt_id = sickbeard.indexerApi( cur_episode[b"indexer"]).config['trakt_id'] if not self._checkInList(trakt_id, str(cur_episode[b"showid"]), str(cur_episode[b"season"]), str(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.traktRequest("sync/watchlist", data, method='POST') self._getEpisodeWatchlist() except traktException as e: logger.log( "Could not connect to Trakt service. Error {0}". format(ex(e)), logger.WARNING) logger.log( "WATCHLIST::ADD::FINISH - Look for Episodes to Add to Trakt Watchlist", logger.DEBUG) def addShowToTraktWatchList(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: logger.log( "SHOW_WATCHLIST::ADD::START - Look for Shows to Add to Trakt Watchlist", logger.DEBUG) if sickbeard.showList is not None: trakt_data = [] for show in sickbeard.showList: trakt_id = sickbeard.indexerApi( show.indexer).config['trakt_id'] if not self._checkInList( trakt_id, str( show.indexerid), '0', '0', List='Show'): logger.log( "Adding Show: Indexer {0} {1} - {2} to Watchlist". format(trakt_id, str(show.indexerid), show.name), logger.DEBUG) show_el = { 'title': show.name, 'year': show.startyear, 'ids': {} } if trakt_id == 'tvdb_id': show_el['ids']['tvdb'] = show.indexerid else: show_el['ids']['tvrage'] = show.indexerid trakt_data.append(show_el) if trakt_data: try: data = {'shows': trakt_data} self.trakt_api.traktRequest("sync/watchlist", data, method='POST') self._getShowWatchlist() except traktException as e: logger.log( "Could not connect to Trakt service. Error: {0}". format(ex(e)), logger.WARNING) logger.log( "SHOW_WATCHLIST::ADD::FINISH - Look for Shows to Add to Trakt Watchlist", logger.DEBUG) def removeShowFromSickRage(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT and sickbeard.TRAKT_REMOVE_SHOW_FROM_SICKRAGE: logger.log( "SHOW_SICKRAGE::REMOVE::START - Look for Shows to remove from SickRage", logger.DEBUG) if sickbeard.showList: for show in sickbeard.showList: if show.status in ("Ended", "Canceled"): if not show.imdbid: logger.log( 'Could not check trakt progress for {0} because the imdb id is missing from tvdb data, skipping' .format(show.name), logger.WARNING) continue try: progress = self.trakt_api.traktRequest( "shows/" + show.imdbid + "/progress/watched") or [] except traktException as e: logger.log( "Could not connect to Trakt service. Aborting removing show {0} from SickRage. Error: {1}" .format(show.name, repr(e)), logger.WARNING) continue if not progress: continue if progress.get('aired', True) == progress.get( 'completed', False): sickbeard.showQueueScheduler.action.remove_show( show, full=True) logger.log( "Show: {0} has been removed from SickRage". format(show.name), logger.DEBUG) logger.log("SHOW_SICKRAGE::REMOVE::FINISH - Trakt Show Watchlist", logger.DEBUG) def updateShows(self): logger.log("SHOW_WATCHLIST::CHECK::START - Trakt Show Watchlist", logger.DEBUG) self._getShowWatchlist() if not self.ShowWatchlist: logger.log( "No shows found in your watchlist, aborting watchlist update", logger.DEBUG) return indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) trakt_id = sickbeard.indexerApi(indexer).config['trakt_id'] for show_el in self.ShowWatchlist[trakt_id]: indexer_id = int(str(show_el)) show = self.ShowWatchlist[trakt_id][show_el] # logger.log(u"Checking Show: %s %s %s" % (trakt_id, indexer_id, show['title']),logger.DEBUG) if int(sickbeard.TRAKT_METHOD_ADD) != 2: self.addDefaultShow(indexer, indexer_id, show['title'], SKIPPED) else: self.addDefaultShow(indexer, indexer_id, show['title'], WANTED) if int(sickbeard.TRAKT_METHOD_ADD) == 1: newShow = Show.find(sickbeard.showList, indexer_id) if newShow is not None: setEpisodeToWanted(newShow, 1, 1) else: self.todoWanted.append((indexer_id, 1, 1)) logger.log("SHOW_WATCHLIST::CHECK::FINISH - Trakt Show Watchlist", logger.DEBUG) def updateEpisodes(self): """ Sets episodes to wanted that are in trakt watchlist """ logger.log("SHOW_WATCHLIST::CHECK::START - Trakt Episode Watchlist", logger.DEBUG) self._getEpisodeWatchlist() if not self.EpisodeWatchlist: logger.log( "No episode found in your watchlist, aborting episode update", logger.DEBUG) return managed_show = [] indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) trakt_id = sickbeard.indexerApi(indexer).config['trakt_id'] for show_el in self.EpisodeWatchlist[trakt_id]: indexer_id = int(show_el) show = self.EpisodeWatchlist[trakt_id][show_el] newShow = Show.find(sickbeard.showList, indexer_id) try: if newShow is None: if indexer_id not in managed_show: self.addDefaultShow(indexer, indexer_id, show['title'], SKIPPED) managed_show.append(indexer_id) for season_el in show['seasons']: season = int(season_el) for episode_el in show['seasons'][season_el][ 'episodes']: self.todoWanted.append( (indexer_id, season, int(episode_el))) else: if newShow.indexer == indexer: for season_el in show['seasons']: season = int(season_el) for episode_el in show['seasons'][season_el][ 'episodes']: setEpisodeToWanted(newShow, season, int(episode_el)) except TypeError: logger.log( "Could not parse the output from trakt for {0} ".format( show["title"]), logger.DEBUG) logger.log("SHOW_WATCHLIST::CHECK::FINISH - Trakt Episode Watchlist", logger.DEBUG) @staticmethod def addDefaultShow(indexer, indexer_id, name, status): """ Adds a new show with the default settings """ if not Show.find(sickbeard.showList, int(indexer_id)): logger.log("Adding show " + str(indexer_id)) root_dirs = sickbeard.ROOT_DIRS.split('|') try: location = root_dirs[int(root_dirs[0]) + 1] except Exception: location = None if location: showPath = ek(os.path.join, location, sanitize_filename(name)) dir_exists = helpers.makeDir(showPath) if not dir_exists: logger.log( "Unable to create the folder {0} , can't add the show". format(showPath), logger.WARNING) return else: helpers.chmodAsParent(showPath) sickbeard.showQueueScheduler.action.add_show( int(indexer), int(indexer_id), showPath, default_status=status, quality=int(sickbeard.QUALITY_DEFAULT), season_folders=int(sickbeard.SEASON_FOLDERS_DEFAULT), paused=sickbeard.TRAKT_START_PAUSED, default_status_after=status) else: logger.log( "There was an error creating the show, no root directory setting found", logger.WARNING) return def manageNewShow(self, show): logger.log( "Checking if trakt watch list wants to search for episodes from new show " + show.name, logger.DEBUG) episodes = [i for i in self.todoWanted if i[0] == show.indexerid] for episode in episodes: self.todoWanted.remove(episode) setEpisodeToWanted(show, episode[1], episode[2]) def _checkInList(self, trakt_id, showid, season, episode, List=None): """ Check in the Watchlist or CollectionList for Show Is the Show, Season and Episode in the trakt_id list (tvdb / tvrage) """ # logger.log(u"Checking Show: %s %s %s " % (trakt_id, showid, List),logger.DEBUG) if "Collection" == List: try: if self.Collectionlist[trakt_id][showid]['seasons'][season][ 'episodes'][episode] == episode: return True except Exception: return False elif "Show" == List: try: if self.ShowWatchlist[trakt_id][showid]['id'] == showid: return True except Exception: return False else: try: if self.EpisodeWatchlist[trakt_id][showid]['seasons'][season][ 'episodes'][episode] == episode: return True except Exception: return False def _getShowWatchlist(self): """ Get Watchlist and parse once into addressable structure """ try: self.ShowWatchlist = {'tvdb_id': {}, 'tvrage_id': {}} TraktShowWatchlist = self.trakt_api.traktRequest( "sync/watchlist/shows") tvdb_id = 'tvdb' tvrage_id = 'tvrage' for watchlist_el in TraktShowWatchlist: tvdb = False tvrage = False if watchlist_el['show']['ids']["tvdb"] is not None: tvdb = True if watchlist_el['show']['ids']["tvrage"] is not None: tvrage = True title = watchlist_el['show']['title'] year = str(watchlist_el['show']['year']) if tvdb: showid = str(watchlist_el['show']['ids'][tvdb_id]) self.ShowWatchlist[tvdb_id + '_id'][showid] = { 'id': showid, 'title': title, 'year': year } if tvrage: showid = str(watchlist_el['show']['ids'][tvrage_id]) self.ShowWatchlist[tvrage_id + '_id'][showid] = { 'id': showid, 'title': title, 'year': year } except traktException as e: logger.log( "Could not connect to trakt service, cannot download Show Watchlist: {0}" .format(repr(e)), logger.WARNING) return False return True def _getEpisodeWatchlist(self): """ Get Watchlist and parse once into addressable structure """ try: self.EpisodeWatchlist = {'tvdb_id': {}, 'tvrage_id': {}} TraktEpisodeWatchlist = self.trakt_api.traktRequest( "sync/watchlist/episodes") tvdb_id = 'tvdb' tvrage_id = 'tvrage' for watchlist_el in TraktEpisodeWatchlist: tvdb = False tvrage = False if watchlist_el['show']['ids']["tvdb"] is not None: tvdb = True if watchlist_el['show']['ids']["tvrage"] is not None: tvrage = True title = watchlist_el['show']['title'] year = str(watchlist_el['show']['year']) season = str(watchlist_el['episode']['season']) episode = str(watchlist_el['episode']['number']) if tvdb: showid = str(watchlist_el['show']['ids'][tvdb_id]) if showid not in self.EpisodeWatchlist[tvdb_id + '_id'].keys(): self.EpisodeWatchlist[tvdb_id + '_id'][showid] = { 'id': showid, 'title': title, 'year': year, 'seasons': {} } if season not in self.EpisodeWatchlist[ tvdb_id + '_id'][showid]['seasons'].keys(): self.EpisodeWatchlist[ tvdb_id + '_id'][showid]['seasons'][season] = { 's': season, 'episodes': {} } if episode not in self.EpisodeWatchlist[tvdb_id + '_id'][ showid]['seasons'][season]['episodes'].keys(): self.EpisodeWatchlist[tvdb_id + '_id'][showid][ 'seasons'][season]['episodes'][episode] = episode if tvrage: showid = str(watchlist_el['show']['ids'][tvrage_id]) if showid not in self.EpisodeWatchlist[tvrage_id + '_id'].keys(): self.EpisodeWatchlist[tvrage_id + '_id'][showid] = { 'id': showid, 'title': title, 'year': year, 'seasons': {} } if season not in self.EpisodeWatchlist[ tvrage_id + '_id'][showid]['seasons'].keys(): self.EpisodeWatchlist[ tvrage_id + '_id'][showid]['seasons'][season] = { 's': season, 'episodes': {} } if episode not in self.EpisodeWatchlist[tvrage_id + '_id'][ showid]['seasons'][season]['episodes'].keys(): self.EpisodeWatchlist[tvrage_id + '_id'][showid][ 'seasons'][season]['episodes'][episode] = episode except traktException as e: logger.log( "Could not connect to trakt service, cannot download Episode Watchlist: {0}" .format(repr(e)), logger.WARNING) return False return True def _getShowCollection(self): """ Get Collection and parse once into addressable structure """ try: self.Collectionlist = {'tvdb_id': {}, 'tvrage_id': {}} logger.log("Getting Show Collection", logger.DEBUG) TraktCollectionList = self.trakt_api.traktRequest( "sync/collection/shows") tvdb_id = 'tvdb' tvrage_id = 'tvrage' for watchlist_el in TraktCollectionList: tvdb = False tvrage = False if watchlist_el['show']['ids']["tvdb"] is not None: tvdb = True if watchlist_el['show']['ids']["tvrage"] is not None: tvrage = True title = watchlist_el['show']['title'] year = str(watchlist_el['show']['year']) if 'seasons' in watchlist_el: for season_el in watchlist_el['seasons']: for episode_el in season_el['episodes']: season = str(season_el['number']) episode = str(episode_el['number']) if tvdb: showid = str( watchlist_el['show']['ids'][tvdb_id]) if showid not in self.Collectionlist[ tvdb_id + '_id'].keys(): self.Collectionlist[tvdb_id + '_id'][showid] = { 'id': showid, 'title': title, 'year': year, 'seasons': {} } if season not in self.Collectionlist[ tvdb_id + '_id'][showid]['seasons'].keys(): self.Collectionlist[ tvdb_id + '_id'][showid]['seasons'][season] = { 's': season, 'episodes': {} } if episode not in self.Collectionlist[ tvdb_id + '_id'][showid]['seasons'][ season]['episodes'].keys(): self.Collectionlist[ tvdb_id + '_id'][showid]['seasons'][season][ 'episodes'][episode] = episode if tvrage: showid = str( watchlist_el['show']['ids'][tvrage_id]) if showid not in self.Collectionlist[ tvrage_id + '_id'].keys(): self.Collectionlist[tvrage_id + '_id'][showid] = { 'id': showid, 'title': title, 'year': year, 'seasons': {} } if season not in self.Collectionlist[ tvrage_id + '_id'][showid]['seasons'].keys(): self.Collectionlist[ tvrage_id + '_id'][showid]['seasons'][season] = { 's': season, 'episodes': {} } if episode not in self.Collectionlist[ tvrage_id + '_id'][showid]['seasons'][ season]['episodes'].keys(): self.Collectionlist[ tvrage_id + '_id'][showid]['seasons'][season][ 'episodes'][episode] = episode except traktException as e: logger.log( "Could not connect to trakt service, cannot download Show Collection: {0}" .format(repr(e)), logger.WARNING) return False return True @staticmethod def trakt_bulk_data_generate(data): """ 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 = sickbeard.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
def update_watchlist(self, show_obj=None, s=None, e=None, data_show=None, data_episode=None, update="add"): """ Sends a request to trakt indicating that the given episode is part of our library. show_obj: The TVShow object to add to trakt s: season number e: episode number data_show: structured object of shows trakt type data_episode: structured object of episodes trakt type update: type o action add or remove """ trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.TRAKT_TIMEOUT) if sickbeard.USE_TRAKT: data = {} try: # URL parameters if show_obj is not None: trakt_id = sickbeard.indexerApi(show_obj.indexer).config['trakt_id'] data = { 'shows': [ { 'title': show_obj.name, 'year': show_obj.startyear, 'ids': {}, } ] } if trakt_id == 'tvdb_id': data['shows'][0]['ids']['tvdb'] = show_obj.indexerid else: data['shows'][0]['ids']['tvrage'] = show_obj.indexerid elif data_show is not None: data.update(data_show) else: logger.log(u"there's a coding problem contact developer. It's needed to be provided at lest one of the two: data_show or show_obj", logger.WARNING) return False if data_episode is not None: data['shows'][0].update(data_episode) elif s is not None: # trakt URL parameters season = { 'season': [ { 'number': s, } ] } if e is not None: # trakt URL parameters episode = { 'episodes': [ { 'number': e } ] } season['season'][0].update(episode) data['shows'][0].update(season) trakt_url = "sync/watchlist" if update == "remove": trakt_url += "/remove" trakt_api.traktRequest(trakt_url, data, method='POST') except (traktException, traktAuthException, traktServerBusy) as e: logger.log(u"Could not connect to Trakt service: %s" % ex(e), logger.WARNING) return False return True
def run(self): ShowQueueItem.run(self) logging.info("Starting to add show " + self.showDir) # make sure the Indexer IDs are valid try: lINDEXER_API_PARMS = sickbeard.indexerApi(self.indexer).api_params.copy() if self.lang: lINDEXER_API_PARMS[b'language'] = self.lang logging.info("" + str(sickbeard.indexerApi(self.indexer).name) + ": " + repr(lINDEXER_API_PARMS)) t = sickbeard.indexerApi(self.indexer).indexer(**lINDEXER_API_PARMS) s = t[self.indexer_id] # 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: logging.error("Show in " + self.showDir + " has no name on " + str( sickbeard.indexerApi(self.indexer).name) + ", probably the wrong language used to search with.") ui.notifications.error("Unable to add show", "Show in " + self.showDir + " has no name on " + str(sickbeard.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: logging.error("Show " + str(s[b'seriesname']) + " is on " + str( sickbeard.indexerApi(self.indexer).name) + " but contains no season/episode data.") ui.notifications.error("Unable to add show", "Show " + str(s[b'seriesname']) + " is on " + str(sickbeard.indexerApi( self.indexer).name) + " but contains no season/episode data.") self._finishEarly() return except Exception as e: logging.error("%s Error while loading information from indexer %s. Error: %r" % ( self.indexer_id, sickbeard.indexerApi(self.indexer).name, ex(e))) 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, sickbeard.indexerApi(self.indexer).name, self.indexer_id) ) if sickbeard.USE_TRAKT: trakt_id = sickbeard.indexerApi(self.indexer).config[b'trakt_id'] trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.TRAKT_TIMEOUT) title = self.showDir.split("/")[-1] data = { 'shows': [ { 'title': title, 'ids': {} } ] } if trakt_id == 'tvdb_id': data[b'shows'][0][b'ids'][b'tvdb'] = self.indexer_id else: data[b'shows'][0][b'ids'][b'tvrage'] = self.indexer_id trakt_api.traktRequest("sync/watchlist/remove", data, method='POST') self._finishEarly() return try: newShow = TVShow(self.indexer, self.indexer_id, self.lang) newShow.loadFromIndexer() self.show = newShow # set up initial values self.show.location = self.showDir self.show.subtitles = self.subtitles if self.subtitles != None else sickbeard.SUBTITLES_DEFAULT self.show.quality = self.quality if self.quality else sickbeard.QUALITY_DEFAULT self.show.flatten_folders = self.flatten_folders if self.flatten_folders != None else sickbeard.FLATTEN_FOLDERS_DEFAULT self.show.anime = self.anime if self.anime != None else sickbeard.ANIME_DEFAULT self.show.scene = self.scene if self.scene != None else sickbeard.SCENE_DEFAULT self.show.archive_firstmatch = self.archive if self.archive != None else sickbeard.ARCHIVE_DEFAULT self.show.paused = self.paused if self.paused != None else False # set up default new/missing episode status logging.info("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 sickbeard.indexer_exception as e: logging.error( "Unable to add show due to an error with " + sickbeard.indexerApi( self.indexer).name + ": {}".format(ex(e))) if self.show: ui.notifications.error( "Unable to add " + str(self.show.name) + " due to an error with " + sickbeard.indexerApi( self.indexer).name + "") else: ui.notifications.error( "Unable to add show due to an error with " + sickbeard.indexerApi(self.indexer).name + "") self._finishEarly() return except MultipleShowObjectsException: logging.warning("The show in " + self.showDir + " is already in your show list, skipping") ui.notifications.error('Show skipped', "The show in " + self.showDir + " is already in your show list") self._finishEarly() return except Exception as e: logging.error("Error trying to add show: {}".format(ex(e))) logging.debug(traceback.format_exc()) self._finishEarly() raise logging.debug("Retrieving show info from IMDb") try: self.show.loadIMDbInfo() except imdb_exceptions.IMDbError as e: logging.warning(" Something wrong on IMDb api: {}".format(ex(e))) except Exception as e: logging.error("Error loading IMDb info: {}".format(ex(e))) try: self.show.saveToDB() except Exception as e: logging.error("Error saving the show to the database: {}".format(ex(e))) logging.debug(traceback.format_exc()) self._finishEarly() raise # add it to the show list sickbeard.showList.append(self.show) try: self.show.loadEpisodesFromIndexer() except Exception as e: logging.error( "Error with " + sickbeard.indexerApi( self.show.indexer).name + ", not creating episode list: {}".format(ex(e))) logging.debug(traceback.format_exc()) # update internal name cache name_cache.buildNameCache() try: self.show.loadEpisodesFromDir() except Exception as e: logging.error("Error searching dir for episodes: {}".format(ex(e))) logging.debug(traceback.format_exc()) # 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: logging.info("Launching backlog for this show since its episodes are WANTED") sickbeard.backlogSearchScheduler.action.searchBacklog([self.show]) self.show.writeMetadata() self.show.updateMetadata() self.show.populateCache() self.show.flushEpisodes() if sickbeard.USE_TRAKT: # if there are specific episodes that need to be added by trakt sickbeard.traktCheckerScheduler.action.manageNewShow(self.show) # add show to trakt.tv library if sickbeard.TRAKT_SYNC: sickbeard.traktCheckerScheduler.action.addShowToTraktLibrary(self.show) if sickbeard.TRAKT_SYNC_WATCHLIST: logging.info("update watchlist") notifiers.trakt_notifier.update_watchlist(show_obj=self.show) # Load XEM data to DB for show sickbeard.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 sickbeard.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()
def getTrendingShows(self, traktList=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='trendingShows.mako') trakt_list = traktList if traktList else '' trakt_list = trakt_list.lower() if trakt_list == 'trending': page_url = 'shows/trending' elif trakt_list == 'popular': page_url = 'shows/popular' elif trakt_list == 'anticipated': page_url = 'shows/anticipated' elif trakt_list == 'collected': page_url = 'shows/collected' elif trakt_list == 'watched': page_url = 'shows/watched' elif trakt_list == 'played': page_url = 'shows/played' elif trakt_list == 'recommended': page_url = 'recommendations/shows' elif trakt_list == 'newshow': page_url = 'calendars/all/shows/new/%s/30' % datetime.date.today().strftime('%Y-%m-%d') elif trakt_list == 'newseason': page_url = 'calendars/all/shows/premieres/%s/30' % datetime.date.today().strftime('%Y-%m-%d') else: page_url = 'shows/anticipated' trending_shows = [] trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.TRAKT_TIMEOUT) try: not_liked_show = '' if sickbeard.TRAKT_ACCESS_TOKEN != '': library_shows = trakt_api.traktRequest('sync/collection/shows?extended=full') or [] if sickbeard.TRAKT_BLACKLIST_NAME is not None and sickbeard.TRAKT_BLACKLIST_NAME: not_liked_show = trakt_api.traktRequest('users/{user}/lists/{blacklist}/items'.format( user=sickbeard.TRAKT_USERNAME, blacklist=sickbeard.TRAKT_BLACKLIST_NAME)) or [] else: logger.log(u'Trakt blacklist name is empty', logger.DEBUG) limit_show = '' if trakt_list not in ['recommended', 'newshow', 'newseason']: limit_show = 'limit={number}&'.format(number=100 + len(not_liked_show)) shows = trakt_api.traktRequest('{url}?{limit}extended=full,images'.format(url=page_url, limit=limit_show)) or [] if sickbeard.TRAKT_ACCESS_TOKEN != '': library_shows = trakt_api.traktRequest('sync/collection/shows?extended=full') or [] for show in shows: try: if 'show' not in show: show['show'] = show if not Show.find(sickbeard.showList, [int(show['show']['ids']['tvdb'])]): if sickbeard.TRAKT_ACCESS_TOKEN != '': if show['show']['ids']['tvdb'] not in (lshow['show']['ids']['tvdb'] for lshow in library_shows): if not_liked_show: if show['show']['ids']['tvdb'] not in (show['show']['ids']['tvdb'] for show in not_liked_show if show['type'] == 'show'): trending_shows += [show] else: trending_shows += [show] else: if not_liked_show: if show['show']['ids']['tvdb'] not in (show['show']['ids']['tvdb'] for show in not_liked_show if show['type'] == 'show'): trending_shows += [show] else: trending_shows += [show] except MultipleShowObjectsException: continue if sickbeard.TRAKT_BLACKLIST_NAME != '': blacklist = True else: blacklist = False except traktException as e: logger.log(u'Could not connect to Trakt service: %s' % ex(e), logger.WARNING) return t.render(blacklist=blacklist, trending_shows=trending_shows)
class TraktChecker(object): def __init__(self): self.trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.TRAKT_TIMEOUT) self.todoWanted = [] self.show_watchlist = {} self.episode_watchlist = {} self.collection_list = {} self.amActive = False def run(self, force=False): # pylint: disable=unused-argument self.amActive = True # add shows from Trakt watchlist if sickbeard.TRAKT_SYNC_WATCHLIST: self.todoWanted = [] # its about to all get re-added if len(sickbeard.ROOT_DIRS.split('|')) < 2: logger.log(u"No default root directory", logger.WARNING) return try: self.sync_watchlist() except Exception: logger.log(traceback.format_exc(), logger.DEBUG) try: # sync Trakt library with medusa library self.sync_library() except Exception: logger.log(traceback.format_exc(), logger.DEBUG) self.amActive = False def find_show(self, indexerid): try: trakt_library = self.trakt_api.traktRequest("sync/collection/shows") or [] if not trakt_library: logger.log(u"No shows found in your library, aborting library update", logger.DEBUG) return trakt_show = [x for x in trakt_library if int(indexerid) in [int(x['show']['ids']['tvdb'] or 0), int(x['show']['ids']['tvrage'] or 0)]] except traktException as e: logger.log(u"Could not connect to Trakt. Aborting library check. Error: {}".format(repr(e)), logger.WARNING) return trakt_show if trakt_show else None def remove_show_trakt_library(self, show_obj): if self.find_show(show_obj.indexerid): trakt_id = sickbeard.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(u"Removing '{}' from Trakt library".format(show_obj.name), logger.DEBUG) try: self.trakt_api.traktRequest("sync/collection/remove", data, method='POST') except traktException as e: logger.log(u"Could not connect to Trakt. Aborting removing show '{}' from Trakt library. Error: {}".format(show_obj.name, repr(e)), logger.WARNING) def add_show_trakt_library(self, show_obj): """ Sends a request to trakt indicating that the given show and all its episodes is part of our library. show_obj: The TVShow object to add to trakt """ data = {} if not self.find_show(show_obj.indexerid): trakt_id = sickbeard.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(u"Adding '{}' to Trakt library".format(show_obj.name), logger.DEBUG) try: self.trakt_api.traktRequest("sync/collection", data, method='POST') except traktException as e: logger.log(u"Could not connect to Trakt. Aborting adding show '{}' to Trakt library. Error: {}".format(show_obj.name, repr(e)), logger.WARNING) return def sync_library(self): if sickbeard.TRAKT_SYNC and sickbeard.USE_TRAKT: logger.log(u"Starting to sync Medusa with Trakt collection", logger.DEBUG) if self._get_show_collection(): self.add_episode_trakt_collection() if sickbeard.TRAKT_SYNC_REMOVE: self.remove_episode_trakt_collection() def remove_episode_trakt_collection(self): if sickbeard.TRAKT_SYNC_REMOVE and sickbeard.TRAKT_SYNC and sickbeard.USE_TRAKT: main_db_con = db.DBConnection() sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode, tv_episodes.status, tv_episodes.location from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid' episodes = main_db_con.select(sql_selection) if episodes: trakt_data = [] for cur_episode in episodes: trakt_id = sickbeard.indexerApi(cur_episode["indexer"]).config['trakt_id'] if self._check_list(trakt_id, cur_episode["showid"], cur_episode["season"], cur_episode["episode"], List='Collection'): if cur_episode["location"] == '': logger.log(u"Removing Episode {show} {ep} from collection".format (show=cur_episode["show_name"], ep=episode_num(cur_episode["season"], cur_episode["episode"])), logger.DEBUG) trakt_data.append((cur_episode["showid"], cur_episode["indexer"], cur_episode["show_name"], cur_episode["startyear"], cur_episode["season"], cur_episode["episode"])) if trakt_data: try: data = self.trakt_bulk_data_generate(trakt_data) self.trakt_api.traktRequest("sync/collection/remove", data, method='POST') self._get_show_collection() except traktException as e: logger.log(u"Could not connect to Trakt. Error: {}".format(ex(e)), logger.WARNING) def add_episode_trakt_collection(self): if sickbeard.TRAKT_SYNC and sickbeard.USE_TRAKT: main_db_con = db.DBConnection() sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid and tv_episodes.status in (' + ','.join([str(x) for x in Quality.DOWNLOADED + Quality.ARCHIVED]) + ')' episodes = main_db_con.select(sql_selection) if episodes: trakt_data = [] for cur_episode in episodes: trakt_id = sickbeard.indexerApi(cur_episode["indexer"]).config['trakt_id'] if not self._check_list(trakt_id, cur_episode["showid"], cur_episode["season"], cur_episode["episode"], List='Collection'): logger.log(u"Adding Episode {show} {ep} to collection".format (show=cur_episode["show_name"], ep=episode_num(cur_episode["season"], cur_episode["episode"])), logger.DEBUG) trakt_data.append((cur_episode["showid"], cur_episode["indexer"], cur_episode["show_name"], cur_episode["startyear"], cur_episode["season"], cur_episode["episode"])) if trakt_data: try: data = self.trakt_bulk_data_generate(trakt_data) self.trakt_api.traktRequest("sync/collection", data, method='POST') self._get_show_collection() except traktException as e: logger.log(u"Could not connect to Trakt. Error: {}".format(ex(e)), logger.WARNING) def sync_watchlist(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: logger.log(u"Starting to sync Medusa with Trakt Watchlist", logger.DEBUG) self.remove_from_library() if self._get_show_watchlist(): logger.log(u"Syncing shows with Trakt watchlist", logger.DEBUG) self.add_show_watchlist() self.fetch_trakt_shows() if self._get_episode_watchlist(): logger.log(u"Syncing episodes with Trakt watchlist", logger.DEBUG) self.remove_episode_watchlist() self.add_episode_watchlist() self.fetch_trakt_episodes() logger.log(u"Medusa is synced with Trakt watchlist", logger.DEBUG) def remove_episode_watchlist(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: main_db_con = db.DBConnection() sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode, tv_episodes.status from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid' episodes = main_db_con.select(sql_selection) if episodes: trakt_data = [] for cur_episode in episodes: trakt_id = sickbeard.indexerApi(cur_episode["indexer"]).config['trakt_id'] if self._check_list(trakt_id, cur_episode["showid"], cur_episode["season"], cur_episode["episode"]): if cur_episode["status"] not in Quality.SNATCHED + Quality.SNATCHED_PROPER + [UNKNOWN] + [WANTED]: logger.log(u"Removing Episode {show} {ep} from watchlist".format (show=cur_episode["show_name"], ep=episode_num(cur_episode["season"], cur_episode["episode"])), logger.DEBUG) trakt_data.append((cur_episode["showid"], cur_episode["indexer"], cur_episode["show_name"], cur_episode["startyear"], cur_episode["season"], cur_episode["episode"])) if trakt_data: try: data = self.trakt_bulk_data_generate(trakt_data) self.trakt_api.traktRequest("sync/watchlist/remove", data, method='POST') self._get_episode_watchlist() except traktException as e: logger.log(u"Could not connect to Trakt. Error: {}".format(ex(e)), logger.WARNING) def add_episode_watchlist(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: main_db_con = db.DBConnection() sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid and tv_episodes.status in (' + ','.join([str(x) for x in Quality.SNATCHED + Quality.SNATCHED_PROPER + [WANTED]]) + ')' episodes = main_db_con.select(sql_selection) if episodes: trakt_data = [] for cur_episode in episodes: trakt_id = sickbeard.indexerApi(cur_episode["indexer"]).config['trakt_id'] if not self._check_list(trakt_id, cur_episode["showid"], cur_episode["season"], cur_episode["episode"]): logger.log(u"Adding Episode {show} {ep} to watchlist".format (show=cur_episode["show_name"], ep=episode_num(cur_episode["season"], cur_episode["episode"])), logger.DEBUG) trakt_data.append((cur_episode["showid"], cur_episode["indexer"], cur_episode["show_name"], cur_episode["startyear"], cur_episode["season"], cur_episode["episode"])) if trakt_data: try: data = self.trakt_bulk_data_generate(trakt_data) self.trakt_api.traktRequest("sync/watchlist", data, method='POST') self._get_episode_watchlist() except traktException as e: logger.log(u"Could not connect to Trakt. Error: {}".format(ex(e)), logger.WARNING) def add_show_watchlist(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: logger.log(u"Syncing shows to Trakt watchlist", logger.DEBUG) if sickbeard.showList: trakt_data = [] for show_obj in sickbeard.showList: trakt_id = sickbeard.indexerApi(show_obj.indexer).config['trakt_id'] if not self._check_list(trakt_id, show_obj.indexerid, 0, 0, List='Show'): logger.log(u"Adding Show '{}' with ID: '{}' 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.traktRequest("sync/watchlist", data, method='POST') self._get_show_watchlist() except traktException as e: logger.log(u"Could not connect to Trakt. Error: {}".format(ex(e)), logger.WARNING) def remove_from_library(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT and sickbeard.TRAKT_REMOVE_SHOW_FROM_SICKRAGE: logger.log(u"Retrieving ended/completed shows to remove from Medusa", logger.DEBUG) if sickbeard.showList: for show in sickbeard.showList: if show.status == "Ended": if not show.imdbid: logger.log(u'Could not check trakt progress for {0} because the imdb id is missing from tvdb data, skipping'.format (show.name), logger.WARNING) continue try: progress = self.trakt_api.traktRequest("shows/" + show.imdbid + "/progress/watched") or [] except traktException as e: logger.log(u"Could not connect to Trakt. Aborting removing show '{}' from Medusa. Error: {}".format(show.name, repr(e)), logger.WARNING) continue if not progress: continue if progress.get('aired', True) == progress.get('completed', False): sickbeard.showQueueScheduler.action.removeShow(show, full=True) logger.log(u"Show '{}' has been removed from Medusa".format(show.name), logger.DEBUG) def fetch_trakt_shows(self): if not self.show_watchlist: logger.log(u"No shows found in your watchlist, aborting watchlist update", logger.DEBUG) else: indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) trakt_id = sickbeard.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 = '{} ({})'.format(show_obj['title'], show_obj['year']) else: show_name = show_obj['title'] if int(sickbeard.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(sickbeard.TRAKT_METHOD_ADD) == 1: new_show = Show.find(sickbeard.showList, indexer_id) if new_show: setEpisodeToWanted(new_show, 1, 1) else: self.todoWanted.append(indexer_id, 1, 1) def fetch_trakt_episodes(self): """ Sets episodes to wanted that are in trakt watchlist """ logger.log(u"Retrieving episodes to sync with Trakt episode's watchlist", logger.DEBUG) if not self.episode_watchlist: logger.log(u"No episode found in your watchlist, aborting episode update", logger.DEBUG) return managed_show = [] indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) trakt_id = sickbeard.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(sickbeard.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(u"Could not parse the output from trakt for '{}' ".format(show["title"]), logger.DEBUG) @staticmethod def add_show(indexer, indexer_id, show_name, status): """ Adds a new show with the default settings """ if not Show.find(sickbeard.showList, int(indexer_id)): root_dirs = sickbeard.ROOT_DIRS.split('|') location = root_dirs[int(root_dirs[0]) + 1] if root_dirs else None if location: show_path = ek(os.path.join, location, show_name) logger.log(u"Adding show '{}' with ID: '{}' in location: '{}'".format(show_name, indexer_id, show_path)) dir_exists = helpers.makeDir(show_path) if not dir_exists: logger.log(u"Unable to create the folder {}. Unable to add the show {}".format(show_path, show_name), logger.WARNING) return else: logger.log(u"Creating the folder '{}'".format(show_path), logger.DEBUG) helpers.chmodAsParent(show_path) sickbeard.showQueueScheduler.action.addShow(indexer, indexer_id, show_path, default_status=status, quality=int(sickbeard.QUALITY_DEFAULT), flatten_folders=int(sickbeard.FLATTEN_FOLDERS_DEFAULT), paused=sickbeard.TRAKT_START_PAUSED, default_status_after=status) else: logger.log(u"There was an error creating the show, no root directory setting found", logger.WARNING) return def manage_new_show(self, show): logger.log(u"Checking if trakt watchlist wants to search for episodes from new show " + show.name, logger.DEBUG) episodes = [i for i in self.todoWanted if i[0] == show.indexerid] for episode in episodes: self.todoWanted.remove(episode) setEpisodeToWanted(show, episode[1], episode[2]) def _check_list(self, trakt_id, showid, season, episode, List=None): # pylint: disable=too-many-arguments """ Check in the Watchlist or collection list for Show Is the Show, Season and Episode in the trakt_id list (tvdb / tvrage) """ if "Collection" == List: try: if self.collection_list[trakt_id][showid]['seasons'][season]['episodes'][episode] == episode: return True except Exception: return False elif "Show" == List: try: if self.show_watchlist[trakt_id][showid]['id'] == showid: return True except Exception: return False else: try: if self.episode_watchlist[trakt_id][showid]['seasons'][season]['episodes'][episode] == episode: return True except Exception: return False def _get_show_watchlist(self): """ Get Watchlist and parse once into addressable structure """ try: self.show_watchlist = {'tvdb_id': {}, 'tvrage_id': {}} trakt_show_watchlist = self.trakt_api.traktRequest("sync/watchlist/shows") tvdb_id = 'tvdb' tvrage_id = 'tvrage' for watchlist_item in trakt_show_watchlist: tvdb = True if watchlist_item['show']['ids']["tvdb"] else False tvrage = True if watchlist_item['show']['ids']["tvrage"] else False title = watchlist_item['show']['title'] year = watchlist_item['show']['year'] slug = watchlist_item['show']['ids']['slug'] if tvdb: showid = watchlist_item['show']['ids'][tvdb_id] self.show_watchlist[tvdb_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year, 'slug': slug} if tvrage: showid = watchlist_item['show']['ids'][tvrage_id] self.show_watchlist[tvrage_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year, 'slug': slug} except traktException as e: logger.log(u"Could not connect to Trakt. Unable to retrieve show's watchlist: {}".format(repr(e)), logger.WARNING) return False return True def _get_episode_watchlist(self): """ Get Watchlist and parse once into addressable structure """ try: self.episode_watchlist = {'tvdb_id': {}, 'tvrage_id': {}} trakt_episode_watchlist = self.trakt_api.traktRequest("sync/watchlist/episodes") tvdb_id = 'tvdb' tvrage_id = 'tvrage' for watchlist_item in trakt_episode_watchlist: tvdb = True if watchlist_item['show']['ids']["tvdb"] else False tvrage = True if watchlist_item['show']['ids']["tvrage"] else False title = watchlist_item['show']['title'] year = watchlist_item['show']['year'] season = watchlist_item['episode']['season'] episode = watchlist_item['episode']['number'] if tvdb: showid = watchlist_item['show']['ids'][tvdb_id] if showid not in self.episode_watchlist[tvdb_id + '_id'].keys(): self.episode_watchlist[tvdb_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year, 'seasons': {}} if season not in self.episode_watchlist[tvdb_id + '_id'][showid]['seasons'].keys(): self.episode_watchlist[tvdb_id + '_id'][showid]['seasons'][season] = {'s': season, 'episodes': {}} if episode not in self.episode_watchlist[tvdb_id + '_id'][showid]['seasons'][season]['episodes'].keys(): self.episode_watchlist[tvdb_id + '_id'][showid]['seasons'][season]['episodes'][episode] = episode if tvrage: showid = watchlist_item['show']['ids'][tvrage_id] if showid not in self.episode_watchlist[tvrage_id + '_id'].keys(): self.episode_watchlist[tvrage_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year, 'seasons': {}} if season not in self.episode_watchlist[tvrage_id + '_id'][showid]['seasons'].keys(): self.episode_watchlist[tvrage_id + '_id'][showid]['seasons'][season] = {'s': season, 'episodes': {}} if episode not in self.episode_watchlist[tvrage_id + '_id'][showid]['seasons'][season]['episodes'].keys(): self.episode_watchlist[tvrage_id + '_id'][showid]['seasons'][season]['episodes'][episode] = episode except traktException as e: logger.log(u"Could not connect to Trakt. Unable to retrieve episode's watchlist: {}".format(repr(e)), logger.WARNING) return False return True def _get_show_collection(self): # pylint: disable=too-many-branches """ Get Collection and parse once into addressable structure """ try: self.collection_list = {'tvdb_id': {}, 'tvrage_id': {}} logger.log(u"Getting Show Collection", logger.DEBUG) trakt_collection = self.trakt_api.traktRequest("sync/collection/shows") tvdb_id = 'tvdb' tvrage_id = 'tvrage' for watchlist_item in trakt_collection: tvdb = True if watchlist_item['show']['ids']["tvdb"] else False tvrage = True if watchlist_item['show']['ids']["tvrage"] else False title = watchlist_item['show']['title'] year = watchlist_item['show']['year'] if 'seasons' in watchlist_item: for season_item in watchlist_item['seasons']: for episode_item in season_item['episodes']: season = season_item['number'] episode = episode_item['number'] if tvdb: showid = watchlist_item['show']['ids'][tvdb_id] if showid not in self.collection_list[tvdb_id + '_id'].keys(): self.collection_list[tvdb_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year, 'seasons': {}} if season not in self.collection_list[tvdb_id + '_id'][showid]['seasons'].keys(): self.collection_list[tvdb_id + '_id'][showid]['seasons'][season] = {'s': season, 'episodes': {}} if episode not in self.collection_list[tvdb_id + '_id'][showid]['seasons'][season]['episodes'].keys(): self.collection_list[tvdb_id + '_id'][showid]['seasons'][season]['episodes'][episode] = episode if tvrage: showid = watchlist_item['show']['ids'][tvrage_id] if showid not in self.collection_list[tvrage_id + '_id'].keys(): self.collection_list[tvrage_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year, 'seasons': {}} if season not in self.collection_list[tvrage_id + '_id'][showid]['seasons'].keys(): self.collection_list[tvrage_id + '_id'][showid]['seasons'][season] = {'s': season, 'episodes': {}} if episode not in self.collection_list[tvrage_id + '_id'][showid]['seasons'][season]['episodes'].keys(): self.collection_list[tvrage_id + '_id'][showid]['seasons'][season]['episodes'][episode] = episode except traktException as e: logger.log(u"Could not connect to Trakt. Unable to retrieve show's collection: {}".format(repr(e)), logger.WARNING) return False return True @staticmethod def trakt_bulk_data_generate(data): # pylint: disable=too-many-locals """ Build the JSON structure to send back to Trakt """ uniqueShows = {} uniqueSeasons = {} for showid, indexerid, show_name, startyear, season, episode in data: if showid not in uniqueShows: uniqueShows[showid] = {'title': show_name, 'year': startyear, 'ids': {}, 'seasons': []} trakt_id = sickbeard.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
class TraktChecker(object): def __init__(self): self.trakt_api = TraktAPI(sickbeard.SSL_VERIFY, sickbeard.TRAKT_TIMEOUT) self.todoBacklog = [] self.todoWanted = [] self.ShowWatchlist = {} self.EpisodeWatchlist = {} self.Collectionlist = {} self.amActive = False def run(self, force=False): self.amActive = True # add shows from trakt.tv watchlist if sickbeard.TRAKT_SYNC_WATCHLIST: self.todoWanted = [] # its about to all get re-added if len(sickbeard.ROOT_DIRS.split('|')) < 2: logger.log("No default root directory", logger.WARNING) return try: self.syncWatchlist() except Exception: logger.log(traceback.format_exc(), logger.DEBUG) try: # sync trakt.tv library with sickrage library self.syncLibrary() except Exception: logger.log(traceback.format_exc(), logger.DEBUG) # check if the user has watched any episode if sickbeard.TRAKT_SYNC_WATCHED: self.updateWatchedData() self.amActive = False def findShow(self, indexer, indexerid): traktShow = None try: library = self.trakt_api.traktRequest("sync/collection/shows") or [] if not library: logger.log("No shows found in your library, aborting library update", logger.DEBUG) return traktShow = [x for x in library if int(indexerid) in [int(x['show']['ids']['tvdb'] or 0), int(x['show']['ids']['tvrage'] or 0)]] except traktException as e: logger.log("Could not connect to Trakt service. Aborting library check. Error: {0}".format(repr(e)), logger.WARNING) return traktShow def removeShowFromTraktLibrary(self, show_obj): if self.findShow(show_obj.indexer, show_obj.indexerid): trakt_id = sickbeard.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.tv library".format(show_obj.name), logger.DEBUG) try: self.trakt_api.traktRequest("sync/collection/remove", data, method='POST') except traktException as e: logger.log("Could not connect to Trakt service. Aborting removing show {0} from Trakt library. Error: {1}".format(show_obj.name, repr(e)), logger.WARNING) def addShowToTraktLibrary(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.findShow(show_obj.indexer, show_obj.indexerid): trakt_id = sickbeard.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.tv library".format(show_obj.name), logger.DEBUG) try: self.trakt_api.traktRequest("sync/collection", data, method='POST') except traktException as e: logger.log("Could not connect to Trakt service. Aborting adding show {0} to Trakt library. Error: {1}".format(show_obj.name, repr(e)), logger.WARNING) return def syncLibrary(self): if sickbeard.TRAKT_SYNC and sickbeard.USE_TRAKT: logger.log("Sync SickRage with Trakt Collection", logger.DEBUG) if self._getShowCollection(): self.addEpisodeToTraktCollection() if sickbeard.TRAKT_SYNC_REMOVE: self.removeEpisodeFromTraktCollection() def removeEpisodeFromTraktCollection(self): if sickbeard.TRAKT_SYNC_REMOVE and sickbeard.TRAKT_SYNC and sickbeard.USE_TRAKT: logger.log("COLLECTION::REMOVE::START - Look for Episodes to Remove From Trakt Collection", logger.DEBUG) main_db_con = db.DBConnection() sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode, tv_episodes.status, tv_episodes.location from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid' episodes = main_db_con.select(sql_selection) if episodes is not None: trakt_data = [] for cur_episode in episodes: trakt_id = sickbeard.indexerApi(cur_episode[b"indexer"]).config[b'trakt_id'] if self._checkInList(trakt_id, str(cur_episode[b"showid"]), str(cur_episode[b"season"]), str(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.traktRequest("sync/collection/remove", data, method='POST') self._getShowCollection() except traktException as e: logger.log("Could not connect to Trakt service. Error: {0}".format(ex(e)), logger.WARNING) logger.log("COLLECTION::REMOVE::FINISH - Look for Episodes to Remove From Trakt Collection", logger.DEBUG) def addEpisodeToTraktCollection(self): if sickbeard.TRAKT_SYNC and sickbeard.USE_TRAKT: logger.log("COLLECTION::ADD::START - Look for Episodes to Add to Trakt Collection", logger.DEBUG) main_db_con = db.DBConnection() sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid and tv_episodes.status in (' + ','.join([str(x) for x in Quality.DOWNLOADED + Quality.ARCHIVED]) + ')' episodes = main_db_con.select(sql_selection) if episodes is not None: trakt_data = [] for cur_episode in episodes: trakt_id = sickbeard.indexerApi(cur_episode[b"indexer"]).config['trakt_id'] if not self._checkInList(trakt_id, str(cur_episode[b"showid"]), str(cur_episode[b"season"]), str(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.traktRequest("sync/collection", data, method='POST') self._getShowCollection() except traktException as e: logger.log("Could not connect to Trakt service. Error: {0}".format(ex(e)), logger.WARNING) logger.log("COLLECTION::ADD::FINISH - Look for Episodes to Add to Trakt Collection", logger.DEBUG) def syncWatchlist(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: logger.log("Sync SickRage with Trakt Watchlist", logger.DEBUG) self.removeShowFromSickRage() if self._getShowWatchlist(): self.addShowToTraktWatchList() self.updateShows() if self._getEpisodeWatchlist(): self.removeEpisodeFromTraktWatchList() self.addEpisodeToTraktWatchList() self.updateEpisodes() def removeEpisodeFromTraktWatchList(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: logger.log("WATCHLIST::REMOVE::START - Look for Episodes to Remove from Trakt Watchlist", logger.DEBUG) main_db_con = db.DBConnection() sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode, tv_episodes.status from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid' episodes = main_db_con.select(sql_selection) if episodes is not None: trakt_data = [] for cur_episode in episodes: trakt_id = sickbeard.indexerApi(cur_episode[b"indexer"]).config['trakt_id'] if self._checkInList(trakt_id, str(cur_episode[b"showid"]), str(cur_episode[b"season"]), str(cur_episode[b"episode"])): if cur_episode[b"status"] not in Quality.SNATCHED + Quality.SNATCHED_PROPER + [UNKNOWN] + [WANTED]: logger.log("Removing Episode {show} {ep} from watchlist".format (show=cur_episode[b"show_name"], ep=episode_num(cur_episode[b"season"], cur_episode[b"episode"])), logger.DEBUG) trakt_data.append((cur_episode[b"showid"], cur_episode[b"indexer"], cur_episode[b"show_name"], cur_episode[b"startyear"], cur_episode[b"season"], cur_episode[b"episode"])) if trakt_data: try: data = self.trakt_bulk_data_generate(trakt_data) self.trakt_api.traktRequest("sync/watchlist/remove", data, method='POST') self._getEpisodeWatchlist() except traktException as e: logger.log("Could not connect to Trakt service. Error: {0}".format(ex(e)), logger.WARNING) logger.log("WATCHLIST::REMOVE::FINISH - Look for Episodes to Remove from Trakt Watchlist", logger.DEBUG) def addEpisodeToTraktWatchList(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: logger.log("WATCHLIST::ADD::START - Look for Episodes to Add to Trakt Watchlist", logger.DEBUG) main_db_con = db.DBConnection() sql_selection = 'select tv_shows.indexer, tv_shows.startyear, showid, show_name, season, episode from tv_episodes,tv_shows where tv_shows.indexer_id = tv_episodes.showid and tv_episodes.status in (' + ','.join([str(x) for x in Quality.SNATCHED + Quality.SNATCHED_PROPER + [WANTED]]) + ')' episodes = main_db_con.select(sql_selection) if episodes is not None: trakt_data = [] for cur_episode in episodes: trakt_id = sickbeard.indexerApi(cur_episode[b"indexer"]).config['trakt_id'] if not self._checkInList(trakt_id, str(cur_episode[b"showid"]), str(cur_episode[b"season"]), str(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.traktRequest("sync/watchlist", data, method='POST') self._getEpisodeWatchlist() except traktException as e: logger.log("Could not connect to Trakt service. Error {0}".format(ex(e)), logger.WARNING) logger.log("WATCHLIST::ADD::FINISH - Look for Episodes to Add to Trakt Watchlist", logger.DEBUG) def addShowToTraktWatchList(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT: logger.log("SHOW_WATCHLIST::ADD::START - Look for Shows to Add to Trakt Watchlist", logger.DEBUG) if sickbeard.showList is not None: trakt_data = [] for show in sickbeard.showList: trakt_id = sickbeard.indexerApi(show.indexer).config['trakt_id'] if not self._checkInList(trakt_id, str(show.indexerid), '0', '0', List='Show'): logger.log("Adding Show: Indexer {0} {1} - {2} to Watchlist".format(trakt_id, str(show.indexerid), show.name), logger.DEBUG) show_el = {'title': show.name, 'year': show.startyear, 'ids': {}} if trakt_id == 'tvdb_id': show_el['ids']['tvdb'] = show.indexerid else: show_el['ids']['tvrage'] = show.indexerid trakt_data.append(show_el) if trakt_data: try: data = {'shows': trakt_data} self.trakt_api.traktRequest("sync/watchlist", data, method='POST') self._getShowWatchlist() except traktException as e: logger.log("Could not connect to Trakt service. Error: {0}".format(ex(e)), logger.WARNING) logger.log("SHOW_WATCHLIST::ADD::FINISH - Look for Shows to Add to Trakt Watchlist", logger.DEBUG) def removeShowFromSickRage(self): if sickbeard.TRAKT_SYNC_WATCHLIST and sickbeard.USE_TRAKT and sickbeard.TRAKT_REMOVE_SHOW_FROM_SICKRAGE: logger.log("SHOW_SICKRAGE::REMOVE::START - Look for Shows to remove from SickRage", logger.DEBUG) if sickbeard.showList: for show in sickbeard.showList: if show.status in ("Ended", "Canceled"): if not show.imdbid: logger.log('Could not check trakt progress for {0} because the imdb id is missing from tvdb data, skipping'.format (show.name), logger.WARNING) continue try: progress = self.trakt_api.traktRequest("shows/" + show.imdbid + "/progress/watched") or [] except traktException as e: logger.log("Could not connect to Trakt service. Aborting removing show {0} from SickRage. Error: {1}".format(show.name, repr(e)), logger.WARNING) continue if not progress: continue if progress.get('aired', True) == progress.get('completed', False): sickbeard.showQueueScheduler.action.remove_show(show, full=True) logger.log("Show: {0} has been removed from SickRage".format(show.name), logger.DEBUG) logger.log("SHOW_SICKRAGE::REMOVE::FINISH - Trakt Show Watchlist", logger.DEBUG) def updateShows(self): logger.log("SHOW_WATCHLIST::CHECK::START - Trakt Show Watchlist", logger.DEBUG) self._getShowWatchlist() if not self.ShowWatchlist: logger.log("No shows found in your watchlist, aborting watchlist update", logger.DEBUG) return indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) trakt_id = sickbeard.indexerApi(indexer).config['trakt_id'] for show_el in self.ShowWatchlist[trakt_id]: indexer_id = int(str(show_el)) show = self.ShowWatchlist[trakt_id][show_el] # logger.log(u"Checking Show: %s %s %s" % (trakt_id, indexer_id, show['title']),logger.DEBUG) if int(sickbeard.TRAKT_METHOD_ADD) != 2: self.addDefaultShow(indexer, indexer_id, show['title'], SKIPPED) else: self.addDefaultShow(indexer, indexer_id, show['title'], WANTED) if int(sickbeard.TRAKT_METHOD_ADD) == 1: newShow = Show.find(sickbeard.showList, indexer_id) if newShow is not None: setEpisodeToWanted(newShow, 1, 1) else: self.todoWanted.append((indexer_id, 1, 1)) logger.log("SHOW_WATCHLIST::CHECK::FINISH - Trakt Show Watchlist", logger.DEBUG) def updateEpisodes(self): """ Sets episodes to wanted that are in trakt watchlist """ logger.log("SHOW_WATCHLIST::CHECK::START - Trakt Episode Watchlist", logger.DEBUG) self._getEpisodeWatchlist() if not self.EpisodeWatchlist: logger.log("No episode found in your watchlist, aborting episode update", logger.DEBUG) return managed_show = [] indexer = int(sickbeard.TRAKT_DEFAULT_INDEXER) trakt_id = sickbeard.indexerApi(indexer).config['trakt_id'] for show_el in self.EpisodeWatchlist[trakt_id]: indexer_id = int(show_el) show = self.EpisodeWatchlist[trakt_id][show_el] newShow = Show.find(sickbeard.showList, indexer_id) try: if newShow is None: if indexer_id not in managed_show: self.addDefaultShow(indexer, indexer_id, show['title'], SKIPPED) managed_show.append(indexer_id) for season_el in show['seasons']: season = int(season_el) for episode_el in show['seasons'][season_el]['episodes']: self.todoWanted.append((indexer_id, season, int(episode_el))) else: if newShow.indexer == indexer: for season_el in show['seasons']: season = int(season_el) for episode_el in show['seasons'][season_el]['episodes']: setEpisodeToWanted(newShow, season, int(episode_el)) except TypeError: logger.log("Could not parse the output from trakt for {0} ".format(show["title"]), logger.DEBUG) logger.log("SHOW_WATCHLIST::CHECK::FINISH - Trakt Episode Watchlist", logger.DEBUG) @staticmethod def addDefaultShow(indexer, indexer_id, name, status): """ Adds a new show with the default settings """ if not Show.find(sickbeard.showList, int(indexer_id)): logger.log("Adding show " + str(indexer_id)) root_dirs = sickbeard.ROOT_DIRS.split('|') try: location = root_dirs[int(root_dirs[0]) + 1] except Exception: location = None if location: showPath = ek(os.path.join, location, sanitize_filename(name)) dir_exists = helpers.makeDir(showPath) if not dir_exists: logger.log("Unable to create the folder {0} , can't add the show".format(showPath), logger.WARNING) return else: helpers.chmodAsParent(showPath) sickbeard.showQueueScheduler.action.add_show(int(indexer), int(indexer_id), showPath, default_status=status, quality=int(sickbeard.QUALITY_DEFAULT), season_folders=int(sickbeard.SEASON_FOLDERS_DEFAULT), paused=sickbeard.TRAKT_START_PAUSED, default_status_after=status) else: logger.log("There was an error creating the show, no root directory setting found", logger.WARNING) return def manageNewShow(self, show): logger.log("Checking if trakt watch list wants to search for episodes from new show " + show.name, logger.DEBUG) episodes = [i for i in self.todoWanted if i[0] == show.indexerid] for episode in episodes: self.todoWanted.remove(episode) setEpisodeToWanted(show, episode[1], episode[2]) self._updateShowNextEpisodeData(show) def _checkInList(self, trakt_id, showid, season, episode, List=None): """ Check in the Watchlist or CollectionList for Show Is the Show, Season and Episode in the trakt_id list (tvdb / tvrage) """ # logger.log(u"Checking Show: %s %s %s " % (trakt_id, showid, List),logger.DEBUG) if "Collection" == List: try: if self.Collectionlist[trakt_id][showid]['seasons'][season]['episodes'][episode] == episode: return True except Exception: return False elif "Show" == List: try: if self.ShowWatchlist[trakt_id][showid]['id'] == showid: return True except Exception: return False else: try: if self.EpisodeWatchlist[trakt_id][showid]['seasons'][season]['episodes'][episode] == episode: return True except Exception: return False def _getShowWatchlist(self): """ Get Watchlist and parse once into addressable structure """ try: self.ShowWatchlist = {'tvdb_id': {}, 'tvrage_id': {}} TraktShowWatchlist = self.trakt_api.traktRequest("sync/watchlist/shows") tvdb_id = 'tvdb' tvrage_id = 'tvrage' for watchlist_el in TraktShowWatchlist: tvdb = False tvrage = False if watchlist_el['show']['ids']["tvdb"] is not None: tvdb = True if watchlist_el['show']['ids']["tvrage"] is not None: tvrage = True title = watchlist_el['show']['title'] year = str(watchlist_el['show']['year']) if tvdb: showid = str(watchlist_el['show']['ids'][tvdb_id]) self.ShowWatchlist[tvdb_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year} if tvrage: showid = str(watchlist_el['show']['ids'][tvrage_id]) self.ShowWatchlist[tvrage_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year} except traktException as e: logger.log("Could not connect to trakt service, cannot download Show Watchlist: {0}".format(repr(e)), logger.WARNING) return False return True def _getEpisodeWatchlist(self): """ Get Watchlist and parse once into addressable structure """ try: self.EpisodeWatchlist = {'tvdb_id': {}, 'tvrage_id': {}} TraktEpisodeWatchlist = self.trakt_api.traktRequest("sync/watchlist/episodes") tvdb_id = 'tvdb' tvrage_id = 'tvrage' for watchlist_el in TraktEpisodeWatchlist: tvdb = False tvrage = False if watchlist_el['show']['ids']["tvdb"] is not None: tvdb = True if watchlist_el['show']['ids']["tvrage"] is not None: tvrage = True title = watchlist_el['show']['title'] year = str(watchlist_el['show']['year']) season = str(watchlist_el['episode']['season']) episode = str(watchlist_el['episode']['number']) if tvdb: showid = str(watchlist_el['show']['ids'][tvdb_id]) if showid not in self.EpisodeWatchlist[tvdb_id + '_id'].keys(): self.EpisodeWatchlist[tvdb_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year, 'seasons': {}} if season not in self.EpisodeWatchlist[tvdb_id + '_id'][showid]['seasons'].keys(): self.EpisodeWatchlist[tvdb_id + '_id'][showid]['seasons'][season] = {'s': season, 'episodes': {}} if episode not in self.EpisodeWatchlist[tvdb_id + '_id'][showid]['seasons'][season]['episodes'].keys(): self.EpisodeWatchlist[tvdb_id + '_id'][showid]['seasons'][season]['episodes'][episode] = episode if tvrage: showid = str(watchlist_el['show']['ids'][tvrage_id]) if showid not in self.EpisodeWatchlist[tvrage_id + '_id'].keys(): self.EpisodeWatchlist[tvrage_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year, 'seasons': {}} if season not in self.EpisodeWatchlist[tvrage_id + '_id'][showid]['seasons'].keys(): self.EpisodeWatchlist[tvrage_id + '_id'][showid]['seasons'][season] = {'s': season, 'episodes': {}} if episode not in self.EpisodeWatchlist[tvrage_id + '_id'][showid]['seasons'][season]['episodes'].keys(): self.EpisodeWatchlist[tvrage_id + '_id'][showid]['seasons'][season]['episodes'][episode] = episode except traktException as e: logger.log("Could not connect to trakt service, cannot download Episode Watchlist: {0}".format(repr(e)), logger.WARNING) return False return True def _getShowCollection(self): """ Get Collection and parse once into addressable structure """ try: self.Collectionlist = {'tvdb_id': {}, 'tvrage_id': {}} logger.log("Getting Show Collection", logger.DEBUG) TraktCollectionList = self.trakt_api.traktRequest("sync/collection/shows") tvdb_id = 'tvdb' tvrage_id = 'tvrage' for watchlist_el in TraktCollectionList: tvdb = False tvrage = False if watchlist_el['show']['ids']["tvdb"] is not None: tvdb = True if watchlist_el['show']['ids']["tvrage"] is not None: tvrage = True title = watchlist_el['show']['title'] year = str(watchlist_el['show']['year']) if 'seasons' in watchlist_el: for season_el in watchlist_el['seasons']: for episode_el in season_el['episodes']: season = str(season_el['number']) episode = str(episode_el['number']) if tvdb: showid = str(watchlist_el['show']['ids'][tvdb_id]) if showid not in self.Collectionlist[tvdb_id + '_id'].keys(): self.Collectionlist[tvdb_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year, 'seasons': {}} if season not in self.Collectionlist[tvdb_id + '_id'][showid]['seasons'].keys(): self.Collectionlist[tvdb_id + '_id'][showid]['seasons'][season] = {'s': season, 'episodes': {}} if episode not in self.Collectionlist[tvdb_id + '_id'][showid]['seasons'][season]['episodes'].keys(): self.Collectionlist[tvdb_id + '_id'][showid]['seasons'][season]['episodes'][episode] = episode if tvrage: showid = str(watchlist_el['show']['ids'][tvrage_id]) if showid not in self.Collectionlist[tvrage_id + '_id'].keys(): self.Collectionlist[tvrage_id + '_id'][showid] = {'id': showid, 'title': title, 'year': year, 'seasons': {}} if season not in self.Collectionlist[tvrage_id + '_id'][showid]['seasons'].keys(): self.Collectionlist[tvrage_id + '_id'][showid]['seasons'][season] = {'s': season, 'episodes': {}} if episode not in self.Collectionlist[tvrage_id + '_id'][showid]['seasons'][season]['episodes'].keys(): self.Collectionlist[tvrage_id + '_id'][showid]['seasons'][season]['episodes'][episode] = episode except traktException as e: logger.log("Could not connect to trakt service, cannot download Show Collection: {0}".format(repr(e)), logger.WARNING) return False return True @staticmethod def trakt_bulk_data_generate(data): """ 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 = sickbeard.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 def updateWatchedData(self): try: response = self.trakt_api.traktRequest("users/me/history/episodes") changes = dict() myDB = db.DBConnection() for data in response: show_id = None if not data['show']['ids']["tvdb"] is None: show_id = data['show']['ids']["tvdb"] elif not data['show']['ids']["tvrage"] is None: show_id = data['show']['ids']["tvrage"] else: logger.log(u"Could not retrieve show_id from trakt history", logger.WARNING) continue show_name = data["show"]["title"] season = data["episode"]["season"] episode = data["episode"]["number"] watched = time.mktime(parser.parse(data["watched_at"]).timetuple()) cursor = myDB.action("UPDATE tv_episodes SET last_watched=? WHERE showid=? AND season=? AND episode=? AND (last_watched IS NULL OR last_watched < ?)", [watched, show_id, season, episode, watched]) if cursor.rowcount > 0: changes[show_name] = changes.get(show_name, 0) + 1 logger.log("Updated " + show_name + ", episode " + str(season) + "x" + str(episode) + ": Episode was watched at " + str(watched)) show = Show.find(sickbeard.showList, int(show_id)) show.last_seen = max(show.last_seen, watched) message = "Watched episodes synchronization complete: "; if (len(changes) == 0): message += "No changes detected." else: message += "Marked as watched " first = True; for show_name in changes: if (not first): message += ", " message += str(changes[show_name]) + " episodes of " + show_name first = False; logger.log(message) self._updateAllShowsNextEpisodeData() except traktException as e: logger.log(u"Could not connect to trakt service, cannot synch Watched Data: %s" % ex(e), logger.ERROR) def _updateAllShowsNextEpisodeData(self): showList = list(sickbeard.showList) for show in showList: self._updateShowNextEpisodeData(show) logger.log("Next episodes synchronization complete.") def _updateShowNextEpisodeData(self, show): logger.log(u"Updating show next episode data: {show}".format(show=show.name)) update_datetime = int(time.time()) myDB = db.DBConnection() sqlResults = myDB.select("SELECT season, episode FROM v_episodes_to_watch where indexer = ? and indexer_id = ? order by season asc, episode asc limit 1", [show.indexer, show.indexerid]); if len(sqlResults) == 1: nextSeason = sqlResults[0][b'season']; nextEpisode = sqlResults[0][b'episode']; else: nextSeason = -1; nextEpisode = -1; myDB.action("DELETE FROM trakt_data WHERE indexer=? AND indexer_id=?", [show.indexer, show.indexerid]) myDB.action("INSERT INTO trakt_data(indexer, indexer_id, next_season, next_episode, last_updated) VALUES(?, ?, ?, ?, ?)", [show.indexer, show.indexerid, nextSeason, nextEpisode, update_datetime]); if show.stay_ahead > 0: sqlResults = myDB.select("SELECT season, episode FROM tv_episodes WHERE status = ? and episode_id IN (select ep.episode_id from tv_episodes ep left join trakt_data trakt on (trakt.indexer = ep.indexer and trakt.indexer_id = ep.showid) where ep.indexer = ? and ep.showid = ? AND ep.season > 0 AND ((trakt.next_season IS NULL) OR (trakt.next_season > -1 AND ((ep.season > trakt.next_season) OR (ep.season = trakt.next_season AND ep.episode >= trakt.next_episode)))) order by ep.season ASC, ep.episode ASC limit ?)", [SKIPPED, show.indexer, show.indexerid, show.stay_ahead]); for row in sqlResults: setEpisodeToWanted(show, row[b'season'], row[b'episode'])