def test_notify(username, blacklist_name=None): """ Sends a test notification to trakt with the given authentication info and returns a boolean representing success. api: The api string to use username: The username to use blacklist_name: slug of trakt list used to hide not interested show Returns: True if the request succeeded, False otherwise """ try: trakt_api = TraktAPI(settings.SSL_VERIFY, settings.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.warning("Could not connect to Trakt service: {0}".format( str(e))) return "Test notice failed to Trakt: {0}".format(str(e))
def __init__(self): self.trakt_api = TraktAPI(settings.SSL_VERIFY, settings.TRAKT_TIMEOUT) self.todoBacklog = [] self.todoWanted = [] self.ShowWatchlist = {} self.EpisodeWatchlist = {} self.Collectionlist = {} self.amActive = False
def addShowToBlacklist(self): # URL parameters indexer_id = self.get_query_argument('indexer_id') if not indexer_id: raise HTTPError(404) data = {'shows': [{'ids': {'tvdb': indexer_id}}]} trakt_api = TraktAPI(settings.SSL_VERIFY, settings.TRAKT_TIMEOUT) trakt_api.traktRequest("users/" + settings.TRAKT_USERNAME + "/lists/" + settings.TRAKT_BLACKLIST_NAME + "/items", data, method='POST') return self.redirect('/addShows/trendingShows/')
def update_library(ep_obj): """ Sends a request to trakt indicating that the given episode is part of our library. ep_obj: The TVEpisode object to add to trakt """ trakt_api = TraktAPI(settings.SSL_VERIFY, settings.TRAKT_TIMEOUT) if settings.USE_TRAKT: try: # URL parameters data = { 'shows': [{ 'title': ep_obj.show.name, 'year': ep_obj.show.startyear, 'ids': { ep_obj.idxr.slug: ep_obj.show.indexerid }, }] } if settings.TRAKT_SYNC_WATCHLIST and settings.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 settings.TRAKT_SYNC_WATCHLIST and settings.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.warning( "Could not connect to Trakt service: {0}".format(str(e)))
def fetch_trending_shows(self, trakt_list, page_url): """Get trending show information from Trakt""" trending_shows = [] trakt_api = TraktAPI(settings.SSL_VERIFY, settings.TRAKT_TIMEOUT) try: not_liked_show = "" if settings.TRAKT_ACCESS_TOKEN != '': library_shows = trakt_api.traktRequest( "sync/collection/shows?extended=full") or [] if settings.TRAKT_BLACKLIST_NAME: not_liked_show = trakt_api.traktRequest( "users/" + settings.TRAKT_USERNAME + "/lists/" + settings.TRAKT_BLACKLIST_NAME + "/items") or [] else: logger.debug("Trakt blacklist name is empty") if trakt_list not in ["recommended", "newshow", "newseason"]: limit_show = "?limit=" + str(100 + len(not_liked_show)) + "&" else: limit_show = "?" shows = trakt_api.traktRequest(page_url + limit_show + "extended=full") or [] if settings.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 settings.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 settings.TRAKT_BLACKLIST_NAME != '': black_list = True else: black_list = False except traktException as e: logger.warning("Could not connect to Trakt service: {0}".format( str(e))) for trending_show in trending_shows: # get indexer id indexer_id = trending_show['show']['ids']['tvdb'] trending_show['indexer_id'] = indexer_id # set image path to show (needed to show it on the screen from the cache) image_name = self.get_image_name(indexer_id) image_path_relative = posixpath.join('images', 'trakt_trending', image_name) trending_show['image_path'] = image_path_relative # clear indexer_id if we already have the image in the cache so we don't retrieve it again image_path = self.get_image_path(image_name) if os.path.isfile(image_path): trending_show['indexer_id'] = '' return trending_shows, black_list
class TraktChecker(object): def __init__(self): self.trakt_api = TraktAPI(settings.SSL_VERIFY, settings.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 settings.TRAKT_SYNC_WATCHLIST: self.todoWanted = [] # its about to all get re-added if len(settings.ROOT_DIRS.split("|")) < 2: logger.warning("No default root directory") return try: self.syncWatchlist() except Exception: logger.debug(traceback.format_exc()) try: # sync trakt.tv library with sickchill library self.syncLibrary() except Exception: logger.debug(traceback.format_exc()) self.amActive = False def findShow(self, indexer, indexerid): traktShow = None try: library = self.trakt_api.traktRequest( "sync/collection/shows") or [] if not library: logger.debug( "No shows found in your library, aborting library update") return traktShow = [ x for x in library if int(indexerid) == int( x["show"]["ids"][sickchill.indexer.slug(indexer)] or -1) ] except traktException as e: logger.warning( "Could not connect to Trakt service. Aborting library check. Error: {0}" .format(repr(e))) return traktShow def removeShowFromTraktLibrary(self, show_obj): if self.findShow(show_obj.indexer, show_obj.indexerid): # URL parameters data = { "shows": [{ "title": show_obj.name, "year": show_obj.startyear, "ids": { show_obj.idxr.slug: show_obj.indexerid } }] } logger.debug("Removing {0} from trakt.tv library".format( show_obj.name)) try: self.trakt_api.traktRequest("sync/collection/remove", data, method="POST") except traktException as e: logger.warning( "Could not connect to Trakt service. Aborting removing show {0} from Trakt library. Error: {1}" .format(show_obj.name, repr(e))) 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 """ if not self.findShow(show_obj.indexer, show_obj.indexerid): # URL parameters data = { "shows": [{ "title": show_obj.name, "year": show_obj.startyear, "ids": { show_obj.idxr.slug: show_obj.indexerid } }] } logger.debug("Adding {0} to trakt.tv library".format( show_obj.name)) try: self.trakt_api.traktRequest("sync/collection", data, method="POST") except traktException as e: logger.warning( "Could not connect to Trakt service. Aborting adding show {0} to Trakt library. Error: {1}" .format(show_obj.name, repr(e))) return def syncLibrary(self): if settings.TRAKT_SYNC and settings.USE_TRAKT: logger.debug("Sync SickChill with Trakt Collection") if self._getShowCollection(): self.addEpisodeToTraktCollection() if settings.TRAKT_SYNC_REMOVE: self.removeEpisodeFromTraktCollection() def removeEpisodeFromTraktCollection(self): if settings.TRAKT_SYNC_REMOVE and settings.TRAKT_SYNC and settings.USE_TRAKT: logger.debug( "COLLECTION::REMOVE::START - Look for Episodes to Remove From Trakt Collection" ) 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: if self._checkInList( sickchill.indexer.slug(cur_episode["indexer"]), str(cur_episode["showid"]), str(cur_episode["season"]), str(cur_episode["episode"]), List="Collection", ): if cur_episode["location"] == "": logger.debug( "Removing Episode {show} {ep} from collection". format(show=cur_episode["show_name"], ep=episode_num(cur_episode["season"], cur_episode["episode"]))) 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._getShowCollection() except traktException as e: logger.warning( "Could not connect to Trakt service. Error: {0}". format(str(e))) logger.debug( "COLLECTION::REMOVE::FINISH - Look for Episodes to Remove From Trakt Collection" ) def addEpisodeToTraktCollection(self): if settings.TRAKT_SYNC and settings.USE_TRAKT: logger.debug( "COLLECTION::ADD::START - Look for Episodes to Add to Trakt Collection" ) 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: if not self._checkInList( sickchill.indexer.slug(cur_episode["indexer"]), str(cur_episode["showid"]), str(cur_episode["season"]), str(cur_episode["episode"]), List="Collection", ): logger.debug( "Adding Episode {show} {ep} to collection".format( show=cur_episode["show_name"], ep=episode_num(cur_episode["season"], cur_episode["episode"]))) 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._getShowCollection() except traktException as e: logger.warning( "Could not connect to Trakt service. Error: {0}". format(str(e))) logger.debug( "COLLECTION::ADD::FINISH - Look for Episodes to Add to Trakt Collection" ) def syncWatchlist(self): if settings.TRAKT_SYNC_WATCHLIST and settings.USE_TRAKT: logger.debug("Sync SickChill with Trakt Watchlist") self.removeShowFromSickChill() if self._getShowWatchlist(): self.addShowToTraktWatchList() self.updateShows() if self._getEpisodeWatchlist(): self.removeEpisodeFromTraktWatchList() self.addEpisodeToTraktWatchList() self.updateEpisodes() def removeEpisodeFromTraktWatchList(self): if settings.TRAKT_SYNC_WATCHLIST and settings.USE_TRAKT: logger.debug( "WATCHLIST::REMOVE::START - Look for Episodes to Remove from Trakt Watchlist" ) 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: if self._checkInList( sickchill.indexer.slug(cur_episode["indexer"]), 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.debug( "Removing Episode {show} {ep} from watchlist". format(show=cur_episode["show_name"], ep=episode_num(cur_episode["season"], cur_episode["episode"]))) 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._getEpisodeWatchlist() except traktException as e: logger.warning( "Could not connect to Trakt service. Error: {0}". format(str(e))) logger.debug( "WATCHLIST::REMOVE::FINISH - Look for Episodes to Remove from Trakt Watchlist" ) def addEpisodeToTraktWatchList(self): if settings.TRAKT_SYNC_WATCHLIST and settings.USE_TRAKT: logger.debug( "WATCHLIST::ADD::START - Look for Episodes to Add to Trakt Watchlist" ) 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: if not self._checkInList( sickchill.indexer.slug(cur_episode["indexer"]), str(cur_episode["showid"]), str(cur_episode["season"]), str(cur_episode["episode"])): logger.debug( "Adding Episode {show} {ep} to watchlist".format( show=cur_episode["show_name"], ep=episode_num(cur_episode["season"], cur_episode["episode"]))) 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._getEpisodeWatchlist() except traktException as e: logger.warning( "Could not connect to Trakt service. Error {0}". format(str(e))) logger.debug( "WATCHLIST::ADD::FINISH - Look for Episodes to Add to Trakt Watchlist" ) def addShowToTraktWatchList(self): if settings.TRAKT_SYNC_WATCHLIST and settings.USE_TRAKT: logger.debug( "SHOW_WATCHLIST::ADD::START - Look for Shows to Add to Trakt Watchlist" ) if settings.showList is not None: trakt_data = [] for show in settings.showList: if not self._checkInList(show.idxr.slug, str(show.indexerid), "0", "0", List="Show"): logger.debug( "Adding Show: Indexer {0} {1} - {2} to Watchlist". format(show.idxr.name, str(show.indexerid), show.name)) show_el = { "title": show.name, "year": show.startyear, "ids": { show.idxr.slug: 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.warning( "Could not connect to Trakt service. Error: {0}". format(str(e))) logger.debug( "SHOW_WATCHLIST::ADD::FINISH - Look for Shows to Add to Trakt Watchlist" ) def removeShowFromSickChill(self): if settings.TRAKT_SYNC_WATCHLIST and settings.USE_TRAKT and settings.TRAKT_REMOVE_SHOW_FROM_SICKCHILL: logger.debug( "SHOW_SICKCHILL::REMOVE::START - Look for Shows to remove from SickChill" ) if settings.showList: for show in settings.showList: if show.status in ("Ended", "Canceled"): if not show.imdb_id: logger.warning( "Could not check trakt progress for {0} because the imdb id is missing from {} data, skipping" .format(show.name, show.idxr.name)) continue try: progress = self.trakt_api.traktRequest( "shows/" + show.imdb_id + "/progress/watched") or {} except traktException as e: logger.warning( "Could not connect to Trakt service. Aborting removing show {0} from SickChill. Error: {1}" .format(show.name, repr(e))) continue if not progress: continue if progress.get("aired", True) == progress.get( "completed", False): settings.showQueueScheduler.action.remove_show( show, full=True) logger.debug( "Show: {0} has been removed from SickChill". format(show.name)) logger.debug( "SHOW_SICKCHILL::REMOVE::FINISH - Trakt Show Watchlist") def updateShows(self): logger.debug("SHOW_WATCHLIST::CHECK::START - Trakt Show Watchlist") self._getShowWatchlist() if not self.ShowWatchlist: logger.debug( "No shows found in your watchlist, aborting watchlist update") return for index, indexer in sickchill.indexer: if indexer.slug in self.ShowWatchlist: for show_el in self.ShowWatchlist[indexer.slug]: indexer_id = int(str(show_el)) show = self.ShowWatchlist[indexer.slug][show_el] # logger.debug("Checking Show: %s %s %s" % (slug, indexer_id, show['title'])) if int(settings.TRAKT_METHOD_ADD) != 2: self.addDefaultShow(index, indexer_id, show["title"], SKIPPED) else: self.addDefaultShow(index, indexer_id, show["title"], WANTED) if int(settings.TRAKT_METHOD_ADD) == 1: newShow = Show.find(settings.showList, indexer_id) if newShow is not None: setEpisodeToWanted(newShow, 1, 1) else: self.todoWanted.append((indexer_id, 1, 1)) logger.debug("SHOW_WATCHLIST::CHECK::FINISH - Trakt Show Watchlist") def updateEpisodes(self): """ Sets episodes to wanted that are in trakt watchlist """ logger.debug("SHOW_WATCHLIST::CHECK::START - Trakt Episode Watchlist") self._getEpisodeWatchlist() if not self.EpisodeWatchlist: logger.debug( "No episode found in your watchlist, aborting episode update") return managed_show = [] for index, indexer in sickchill.indexer: if indexer.slug in self.EpisodeWatchlist: for show_el in self.EpisodeWatchlist[indexer.slug]: indexer_id = int(show_el) show = self.EpisodeWatchlist[indexer.slug][show_el] newShow = Show.find(settings.showList, indexer_id) try: if newShow is None: if indexer_id not in managed_show: self.addDefaultShow(index, 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.debug( "Could not parse the output from trakt for {0} ". format(show["title"])) logger.debug("SHOW_WATCHLIST::CHECK::FINISH - Trakt Episode Watchlist") @staticmethod def addDefaultShow(indexer, indexer_id, name, status): """ Adds a new show with the default settings """ if not Show.find(settings.showList, int(indexer_id)): logger.info("Adding show " + str(indexer_id)) root_dirs = settings.ROOT_DIRS.split("|") try: location = root_dirs[int(root_dirs[0]) + 1] except Exception: location = None if location: showPath = os.path.join(location, sanitize_filename(name)) dir_exists = helpers.makeDir(showPath) if not dir_exists: logger.warning( "Unable to create the folder {0} , can't add the show". format(showPath)) return else: helpers.chmodAsParent(showPath) settings.showQueueScheduler.action.add_show( int(indexer), int(indexer_id), showPath, default_status=status, quality=int(settings.QUALITY_DEFAULT), season_folders=int(settings.SEASON_FOLDERS_DEFAULT), paused=settings.TRAKT_START_PAUSED, default_status_after=status, ) else: logger.warning( "There was an error creating the show, no root directory setting found" ) return def manageNewShow(self, show): logger.debug( "Checking if trakt watch list wants to search for episodes from new show " + show.name) 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, slug, showid, season, episode, List=None): """ Check in the Watchlist or CollectionList for Show Is the Show, Season and Episode in the slug list """ # logger.debug("Checking Show: %s %s %s " % (slug, showid, List)) if "Collection" == List: try: if self.Collectionlist[slug][showid]["seasons"][season][ "episodes"][episode] == episode: return True except Exception: return False elif "Show" == List: try: if self.ShowWatchlist[slug][showid]["id"] == showid: return True except Exception: return False else: try: if self.EpisodeWatchlist[slug][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 = { indexer.slug: {} for index, indexer in sickchill.indexer } TraktShowWatchlist = self.trakt_api.traktRequest( "sync/watchlist/shows") for slug in self.ShowWatchlist: for watchlist_el in TraktShowWatchlist: if watchlist_el["show"]["ids"][slug]: title = watchlist_el["show"]["title"] year = str(watchlist_el["show"]["year"]) showid = str(watchlist_el["show"]["ids"][slug]) self.ShowWatchlist[slug][showid] = { "id": showid, "title": title, "year": year } except traktException as e: logger.warning( "Could not connect to trakt service, cannot download Show Watchlist: {0}" .format(repr(e))) return False return True def _getEpisodeWatchlist(self): """ Get Watchlist and parse once into addressable structure """ try: self.EpisodeWatchlist = { indexer.slug: {} for index, indexer in sickchill.indexer } TraktEpisodeWatchlist = self.trakt_api.traktRequest( "sync/watchlist/episodes") for slug in self.EpisodeWatchlist: for watchlist_el in TraktEpisodeWatchlist: if watchlist_el["show"]["ids"][slug]: title = watchlist_el["show"]["title"] year = str(watchlist_el["show"]["year"]) season = str(watchlist_el["episode"]["season"]) episode = str(watchlist_el["episode"]["number"]) showid = str(watchlist_el["show"]["ids"][slug]) if showid not in self.EpisodeWatchlist[slug]: self.EpisodeWatchlist[slug][showid] = { "id": showid, "title": title, "year": year, "seasons": {} } if season not in self.EpisodeWatchlist[slug][showid][ "seasons"]: self.EpisodeWatchlist[slug][showid]["seasons"][ season] = { "s": season, "episodes": {} } if episode not in self.EpisodeWatchlist[slug][showid][ "seasons"][season]["episodes"]: self.EpisodeWatchlist[slug][showid]["seasons"][ season]["episodes"][episode] = episode except traktException as e: logger.warning( "Could not connect to trakt service, cannot download Episode Watchlist: {0}" .format(repr(e))) return False return True def _getShowCollection(self): """ Get Collection and parse once into addressable structure """ try: self.Collectionlist = { indexer.slug: {} for index, indexer in sickchill.indexer } logger.debug("Getting Show Collection") TraktCollectionList = self.trakt_api.traktRequest( "sync/collection/shows") for slug in self.Collectionlist: for watchlist_el in TraktCollectionList: 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 watchlist_el["show"]["ids"][ slug] is not None: title = watchlist_el["show"]["title"] year = str(watchlist_el["show"]["year"]) showid = str( watchlist_el["show"]["ids"][slug]) if showid not in self.Collectionlist[slug]: self.Collectionlist[slug][showid] = { "id": showid, "title": title, "year": year, "seasons": {} } if season not in self.Collectionlist[slug][ showid]["seasons"]: self.Collectionlist[slug][showid][ "seasons"][season] = { "s": season, "episodes": {} } if episode not in self.Collectionlist[ slug][showid]["seasons"][season][ "episodes"]: self.Collectionlist[slug][showid][ "seasons"][season]["episodes"][ episode] = episode except traktException as e: logger.warning( "Could not connect to trakt service, cannot download Show Collection: {0}" .format(repr(e))) return False return True @staticmethod def trakt_bulk_data_generate(data): """ Build the JSON structure to send back to Trakt """ uniqueShows = {} uniqueSeasons = {} for showid, indexer, show_name, startyear, season, episode in data: slug = sickchill.indexer.slug(indexer) if showid not in uniqueShows: uniqueShows[showid] = { "title": show_name, "year": startyear, "ids": { slug: showid }, "seasons": [] } uniqueSeasons[showid] = [] 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}) uniqueShows[searchedShow]["seasons"].append({ "number": searchedSeason, "episodes": episodesList }) showList.append(uniqueShows[searchedShow]) post_data = {"shows": showList} return post_data
def run(self): super(QueueItemAdd, self).run() logger.info(_('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: s = sickchill.indexer.series_by_id(indexerid=self.indexer_id, indexer=self.indexer, language=self.lang) if not s: error_string = _('Could not find show with id:{0} on {1}, skipping').format( self.indexer_id, sickchill.indexer.name(self.indexer)) logger.info(error_string) ui.notifications.error(_('Unable to add show'), error_string) self._finish_early() return # 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: if not s.seriesName: logger.info(_('Unable to get a show {0}, can\'t add the show').format(self.showDir)) self._finish_early() return show_dir = s.seriesName if settings.ADD_SHOWS_WITH_YEAR and s.firstAired: try: year = '({0})'.format(dateutil.parser.parse(s.firstAired).year) if year not in show_dir: show_dir = '{0} {1}'.format(s.seriesName, year) except (TypeError, ValueError): logger.info(_('Could not append the show year folder for the show: {0}').format(show_dir)) self.showDir = os.path.join(self.root_dir, sanitize_filename(show_dir)) if settings.ADD_SHOWS_WO_DIR: logger.info(_("Skipping initial creation of {0} due to config.ini setting").format(self.showDir)) else: dir_exists = makeDir(self.showDir) if not dir_exists: logger.info(_('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, sickchill.indexer.name(self.indexer)) logger.warning(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, sickchill.indexer.name(self.indexer), self.indexer_id) logger.exception('{0}: {1}'.format(error_string, error)) ui.notifications.error(_('Unable to add show'), error_string) if settings.USE_TRAKT: trakt_api = TraktAPI(settings.SSL_VERIFY, settings.TRAKT_TIMEOUT) title = self.showDir.split('/')[-1] data = { 'shows': [ { 'title': title, 'ids': {sickchill.indexer.slug(self.indexer): 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(settings.showList, self.indexer_id) # noinspection PyProtectedMember if existing_show and not os.path.isdir(existing_show._location): 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 settings.SUBTITLES_DEFAULT self.show.subtitles_sr_metadata = self.subtitles_sr_metadata self.show.quality = self.quality if self.quality else settings.QUALITY_DEFAULT self.show.season_folders = self.season_folders if self.season_folders is not None else settings.SEASON_FOLDERS_DEFAULT self.show.anime = self.anime if self.anime is not None else settings.ANIME_DEFAULT self.show.scene = self.scene if self.scene is not None else settings.SCENE_DEFAULT self.show.paused = self.paused if self.paused is not None else False # set up default new/missing episode status logger.info(_('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 Exception as error: error_string = 'Unable to add {0} due to an error with {1}'.format( self.show.name if self.show else 'show', sickchill.indexer.name(self.indexer)) logger.exception('{0}: {1}'.format(error_string, error)) logger.exception('Error trying to add show: {0}'.format(error)) logger.debug(traceback.format_exc()) 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.warning(error_string) ui.notifications.error(_('Show skipped'), error_string) self._finish_early() return self.show.load_imdb_imfo() try: self.show.saveToDB() except Exception as error: logger.exception('Error saving the show to the database: {0}'.format(error)) logger.debug(traceback.format_exc()) self._finish_early() raise # add it to the show list if not Show.find(settings.showList, self.indexer_id): settings.showList.append(self.show) try: self.show.loadEpisodesFromIndexer() except Exception as error: logger.exception('Error with {0}, not creating episode list: {1}'.format(self.show.idxr.name, error)) logger.debug(traceback.format_exc()) # update internal name cache name_cache.build_name_cache(self.show) try: self.show.loadEpisodesFromDir() except Exception as error: logger.exception('Error searching dir for episodes: {0}'.format(error)) logger.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: logger.info('Launching backlog for this show since its episodes are WANTED') settings.backlogSearchScheduler.action.searchBacklog([self.show]) self.show.writeMetadata() self.show.updateMetadata() self.show.populateCache() self.show.flushEpisodes() if settings.USE_TRAKT: # if there are specific episodes that need to be added by trakt settings.traktCheckerScheduler.action.manageNewShow(self.show) # add show to trakt.tv library if settings.TRAKT_SYNC: settings.traktCheckerScheduler.action.addShowToTraktLibrary(self.show) if settings.TRAKT_SYNC_WATCHLIST: logger.info('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 update_watchlist(show_obj=None, s=None, e=None, data_show=None, data_episode=None, update="add"): """ Sends a request to trakt indicating that the given episode is part of our library. show_obj: The TVShow object to add to trakt s: season number e: episode number data_show: structured object of shows trakt type data_episode: structured object of episodes trakt type update: type o action add or remove """ trakt_api = TraktAPI(settings.SSL_VERIFY, settings.TRAKT_TIMEOUT) if settings.USE_TRAKT: data = {} try: # URL parameters if show_obj is not None: data = { 'shows': [{ 'title': show_obj.name, 'year': show_obj.startyear, 'ids': { show_obj.idxr.slug: show_obj.indexerid }, }] } elif data_show is not None: data.update(data_show) else: logger.warning( "there's a coding problem contact developer. It's needed to be provided at lest one of the two: data_show or show_obj" ) return False if data_episode is not None: data['shows'][0].update(data_episode) elif s is not None: # trakt URL parameters season = { 'season': [{ 'number': s, }] } if e is not None: # trakt URL parameters episode = {'episodes': [{'number': e}]} season['season'][0].update(episode) data['shows'][0].update(season) trakt_url = "sync/watchlist" if update == "remove": trakt_url += "/remove" trakt_api.traktRequest(trakt_url, data, method='POST') except (traktException, traktAuthException, traktServerBusy) as e: logger.warning( "Could not connect to Trakt service: {0}".format(str(e))) return False return True