def sync_trakt_shows(self): """Sync Trakt shows watchlist.""" if not self.show_watchlist: log.info('No shows found in your Trakt watchlist. Nothing to sync') else: trakt_default_indexer = int(app.TRAKT_DEFAULT_INDEXER) for watchlisted_show in self.show_watchlist: trakt_show = watchlisted_show['show'] if trakt_show['year'] and trakt_show['ids']['slug'].endswith( str(trakt_show['year'])): show_name = '{title} ({year})'.format( title=trakt_show['title'], year=trakt_show['year']) else: show_name = trakt_show['title'] show = None for i in indexerConfig: trakt_indexer = get_trakt_indexer(i) indexer_id = trakt_show['ids'].get(trakt_indexer, -1) indexer = indexerConfig[i]['id'] show = Show.find(app.showList, indexer_id, indexer) if show: break if not show: # If can't find with available indexers try IMDB trakt_indexer = get_trakt_indexer(EXTERNAL_IMDB) indexer_id = trakt_show['ids'].get(trakt_indexer, -1) show = Show.find(app.showList, indexer_id, EXTERNAL_IMDB) if not show: # If can't find with available indexers try TRAKT trakt_indexer = get_trakt_indexer(EXTERNAL_TRAKT) indexer_id = trakt_show['ids'].get(trakt_indexer, -1) show = Show.find(app.showList, indexer_id, EXTERNAL_TRAKT) if show: continue indexer_id = trakt_show['ids'].get( get_trakt_indexer(trakt_default_indexer), -1) if int(app.TRAKT_METHOD_ADD) != 2: self.add_show(trakt_default_indexer, indexer_id, show_name, SKIPPED) else: self.add_show(trakt_default_indexer, indexer_id, show_name, WANTED) if int(app.TRAKT_METHOD_ADD) == 1: new_show = Show.find(app.showList, indexer_id, indexer) if new_show: set_episode_to_wanted(new_show, 1, 1) else: log.warning( 'Unable to find the new added show.' 'Pilot will be set to wanted in the next Trakt run' ) self.todoWanted.append(indexer_id) log.debug('Synced shows with Trakt watchlist')
def sync_trakt_episodes(self): """Sync Trakt episodes watchlist.""" if not self.episode_watchlist: log.info( 'No episodes found in your Trakt watchlist. Nothing to sync') return added_shows = [] trakt_default_indexer = int(app.TRAKT_DEFAULT_INDEXER) for watchlist_item in self.episode_watchlist: trakt_show = watchlist_item['show'] trakt_episode = watchlist_item['episode'].get('number', -1) trakt_season = watchlist_item['episode'].get('season', -1) show = None for i in indexerConfig: trakt_indexer = get_trakt_indexer(i) indexer_id = trakt_show['ids'].get(trakt_indexer, -1) indexer = indexerConfig[i]['id'] show = Show.find(app.showList, indexer_id, indexer) if show: break if not show: # If can't find with available indexers try IMDB trakt_indexer = get_trakt_indexer(EXTERNAL_IMDB) indexer_id = trakt_show['ids'].get(trakt_indexer, -1) show = Show.find(app.showList, indexer_id, EXTERNAL_IMDB) if not show: # If can't find with available indexers try TRAKT trakt_indexer = get_trakt_indexer(EXTERNAL_TRAKT) indexer_id = trakt_show['ids'].get(trakt_indexer, -1) show = Show.find(app.showList, indexer_id, EXTERNAL_TRAKT) # If can't find show add with default trakt indexer if not show: indexer_id = trakt_show['ids'].get( get_trakt_indexer(trakt_default_indexer), -1) # Only add show if we didn't added it before if indexer_id not in added_shows: self.add_show(trakt_default_indexer, indexer_id, trakt_show['title'], SKIPPED) added_shows.append(indexer_id) elif not trakt_season == 0 and not show.paused: set_episode_to_wanted(show, trakt_season, trakt_episode) log.debug('Synced episodes with Trakt watchlist')
def remove_show_trakt_library(self, show_obj): """Remove show from trakt library.""" if self.find_show(show_obj.indexerid, show_obj.indexer): # Check if TRAKT supports that indexer if not get_trakt_indexer(show_obj.indexer): return # URL parameters title = get_title_without_year(show_obj.name, show_obj.start_year) data = { 'shows': [{ 'title': title, 'year': show_obj.start_year, 'ids': {} }] } data['shows'][0]['ids'][get_trakt_indexer( show_obj.indexer)] = show_obj.indexerid log.info("Removing '{show}' from Trakt library", {'show': show_obj.name}) # Remove all episodes from the Trakt collection for this show try: self.remove_episode_trakt_collection(filter_show=show_obj) except (TraktException, AuthException, TokenExpiredException) as e: log.info( "Unable to remove all episodes from show '{show}' from Trakt library. Error: {error}", { 'show': show_obj.name, 'error': e.message }) try: self._request('sync/collection/remove', data, method='POST') except (TraktException, AuthException, TokenExpiredException) as e: log.info( "Unable to remove show '{show}' from Trakt library. Error: {error}", { 'show': show_obj.name, 'error': e.message })
def add_episode_watchlist(self): """Add episode to Tratk watchlist.""" if app.TRAKT_SYNC_WATCHLIST and app.USE_TRAKT: main_db_con = db.DBConnection() status = Quality.SNATCHED + Quality.SNATCHED_BEST + Quality.SNATCHED_PROPER + [ WANTED ] selection_status = [b'?' for _ in status] sql_selection = b'SELECT s.indexer, s.startyear, e.showid, s.show_name, e.season, e.episode ' \ b'FROM tv_episodes AS e, tv_shows AS s ' \ b'WHERE s.indexer_id = e.showid AND s.paused = 0 ' \ b'AND e.status in ({0})'.format(b','.join(selection_status)) sql_result = main_db_con.select(sql_selection, status) episodes = [dict(i) for i in sql_result] if episodes: trakt_data = [] for cur_episode in episodes: # Check if TRAKT supports that indexer if not get_trakt_indexer(cur_episode[b'indexer']): continue if not self._check_list(indexer=cur_episode[b'indexer'], indexer_id=cur_episode[b'showid'], season=cur_episode[b'season'], episode=cur_episode[b'episode']): log.info( "Adding episode '{show}' {ep} to Trakt watchlist", { 'show': cur_episode[b'show_name'], 'ep': episode_num(cur_episode[b'season'], cur_episode[b'episode']) }) title = get_title_without_year( cur_episode[b'show_name'], cur_episode[b'startyear']) trakt_data.append( (cur_episode[b'showid'], cur_episode[b'indexer'], title, cur_episode[b'startyear'], cur_episode[b'season'], cur_episode[b'episode'])) if trakt_data: try: data = self.trakt_bulk_data_generate(trakt_data) self._request('sync/watchlist', data, method='POST') self._get_episode_watchlist() except (TraktException, AuthException, TokenExpiredException) as e: log.info( 'Unable to add episode to Trakt watchlist. Error: {error}', {'error': e.message})
def trakt_show_data_generate(data): """Build the JSON structure to send back to Trakt.""" show_list = [] for indexer, indexerid, title, year in data: show = {'title': title, 'year': year, 'ids': {}} show['ids'][get_trakt_indexer(indexer)] = indexerid show_list.append(show) post_data = {'shows': show_list} return post_data
def _check_list(self, show_obj=None, indexer=None, indexer_id=None, season=None, episode=None, list_type=None): """Check if we can find the show in the Trakt watchlist|collection list.""" if 'Collection' == list_type: trakt_indexer = get_trakt_indexer(indexer) for collected_show in self.collection_list: if not collected_show['show']['ids'].get(trakt_indexer, '') == indexer_id: continue if 'seasons' in collected_show: for season_item in collected_show['seasons']: for episode_item in season_item['episodes']: trakt_season = season_item['number'] trakt_episode = episode_item['number'] if trakt_season == season and trakt_episode == episode: return True else: return False elif 'Show' == list_type: trakt_indexer = get_trakt_indexer(show_obj.indexer) for watchlisted_show in self.show_watchlist: if watchlisted_show['show']['ids'].get(trakt_indexer) == show_obj.indexerid or \ watchlisted_show['show']['ids'].get(get_trakt_indexer(EXTERNAL_IMDB), '') == show_obj.imdb_id: return True return False else: trakt_indexer = get_trakt_indexer(indexer) for watchlisted_episode in self.episode_watchlist: if watchlisted_episode['episode'].get('season', -1) == season and \ watchlisted_episode['episode'].get('number', -1) == episode and \ watchlisted_episode['show']['ids'].get(trakt_indexer, '') == indexer_id: return True return False
def add_show_trakt_library(self, show_obj): """Add show to trakt library.""" data = {} if not self.find_show(show_obj.indexerid, show_obj.indexer): # Check if TRAKT supports that indexer if not get_trakt_indexer(show_obj.indexer): return # URL parameters title = get_title_without_year(show_obj.name, show_obj.start_year) data = { 'shows': [{ 'title': title, 'year': show_obj.start_year, 'ids': {} }] } data['shows'][0]['ids'][get_trakt_indexer( show_obj.indexer)] = show_obj.indexerid if data: log.info("Adding show '{show}' to Trakt library", {'show': show_obj.name}) try: self._request('sync/collection', data, method='POST') except (TraktException, AuthException, TokenExpiredException) as e: log.info( "Unable to add show '{show}' to Trakt library. Error: {error}", { 'show': show_obj.name, 'error': e.message }) return
def trakt_bulk_data_generate(trakt_data): """Build the JSON structure to send back to Trakt.""" unique_shows = {} unique_seasons = {} for indexer_id, indexer, show_name, start_year, season, episode in trakt_data: if indexer_id not in unique_shows: unique_shows[indexer_id] = { 'title': show_name, 'year': start_year, 'ids': {}, 'seasons': [] } unique_shows[indexer_id]['ids'][get_trakt_indexer( indexer)] = indexer_id unique_seasons[indexer_id] = [] # Get the unique seasons per Show for indexer_id, indexer, show_name, start_year, season, episode in trakt_data: if season not in unique_seasons[indexer_id]: unique_seasons[indexer_id].append(season) # build the query show_list = [] seasons_list = {} for searched_show in unique_shows: show = [] seasons_list[searched_show] = [] for searched_season in unique_seasons[searched_show]: episodes_list = [] for indexer_id, indexer, show_name, start_year, season, episode in trakt_data: if season == searched_season and indexer_id == searched_show: episodes_list.append({'number': episode}) show = unique_shows[searched_show] show['seasons'].append({ 'number': searched_season, 'episodes': episodes_list }) if show: show_list.append(show) post_data = {'shows': show_list} return post_data
def find_show(self, indexerid, indexer): """Find show in Trakt library.""" trakt_library = [] try: trakt_library = self._request('sync/collection/shows') except (TraktException, AuthException, TokenExpiredException) as e: log.info( 'Unable to retrieve shows from Trakt collection. Error: {error}', {'error': e.message}) if not trakt_library: log.info('No shows found in your Trakt library. Nothing to sync') return trakt_show = [ x for x in trakt_library if int(indexerid) in [int(x['show']['ids'].get(get_trakt_indexer(indexer)))] ] return trakt_show if trakt_show else None
def update_library(ep_obj): """Send a request to trakt indicating that the given episode is part of our library. ep_obj: The Episode object to add to trakt """ # Check if TRAKT supports that indexer if not get_trakt_indexer(ep_obj.series.indexer): return # Create a trakt settings dict trakt_settings = { 'trakt_api_secret': app.TRAKT_API_SECRET, 'trakt_api_key': app.TRAKT_API_KEY, 'trakt_access_token': app.TRAKT_ACCESS_TOKEN, 'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN } trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT, **trakt_settings) if app.USE_TRAKT: try: # URL parameters title = get_title_without_year(ep_obj.series.name, ep_obj.series.start_year) data = { 'shows': [{ 'title': title, 'year': ep_obj.series.start_year, 'ids': {}, }] } data['shows'][0]['ids'][get_trakt_indexer( ep_obj.series.indexer)] = ep_obj.series.indexerid if app.TRAKT_SYNC_WATCHLIST: if app.TRAKT_REMOVE_SERIESLIST: trakt_api.request('sync/watchlist/remove', data, method='POST') # Add Season and Episode + Related Episodes data['shows'][0]['seasons'] = [{ 'number': ep_obj.season, 'episodes': [] }] for relEp_Obj in [ep_obj] + ep_obj.related_episodes: data['shows'][0]['seasons'][0]['episodes'].append( {'number': relEp_Obj.episode}) if app.TRAKT_SYNC_WATCHLIST: if app.TRAKT_REMOVE_WATCHLIST: trakt_api.request('sync/watchlist/remove', data, method='POST') # update library trakt_api.request('sync/collection', data, method='POST') except (TokenExpiredException, TraktException, AuthException) as error: log.debug('Unable to update Trakt: {0}', error.message)
def update_watchlist(show_obj=None, s=None, e=None, data_show=None, data_episode=None, update='add'): """Send a request to trakt indicating that the given episode is part of our library. show_obj: The Series object to add to trakt s: season number e: episode number data_show: structured object of shows trakt type data_episode: structured object of episodes trakt type update: type o action add or remove """ # Check if TRAKT supports that indexer if not get_trakt_indexer(show_obj.indexer): return trakt_settings = { 'trakt_api_secret': app.TRAKT_API_SECRET, 'trakt_api_key': app.TRAKT_API_KEY, 'trakt_access_token': app.TRAKT_ACCESS_TOKEN, 'trakt_refresh_token': app.TRAKT_REFRESH_TOKEN } trakt_api = TraktApi(app.SSL_VERIFY, app.TRAKT_TIMEOUT, **trakt_settings) if app.USE_TRAKT: data = {} try: # URL parameters if show_obj is not None: title = get_title_without_year(show_obj.name, show_obj.start_year) data = { 'shows': [{ 'title': title, 'year': show_obj.start_year, 'ids': {}, }] } data['shows'][0]['ids'][get_trakt_indexer( show_obj.indexer)] = show_obj.indexerid elif data_show is not None: data.update(data_show) else: log.warning( "There's a coding problem contact developer. It's needed to be provided at" " least one of the two: data_show or show_obj", ) return False if data_episode is not None: data['shows'][0].update(data_episode) elif s is not None: # trakt URL parameters season = { 'season': [{ 'number': s, }] } if e is not None: # trakt URL parameters episode = {'episodes': [{'number': e}]} season['season'][0].update(episode) data['shows'][0].update(season) trakt_url = 'sync/watchlist' if update == 'remove': trakt_url += '/remove' trakt_api.request(trakt_url, data, method='POST') except (TokenExpiredException, TraktException, AuthException) as error: log.debug('Unable to update Trakt watchlist: {0}', error.message) return False return True
def add_episode_trakt_collection(self): """Add all existing episodes to Trakt collections. For episodes that have a media file (location) """ if app.TRAKT_SYNC and app.USE_TRAKT: main_db_con = db.DBConnection() selection_status = [ '?' for _ in Quality.DOWNLOADED + Quality.ARCHIVED ] sql_selection = b'SELECT s.indexer, s.startyear, s.indexer_id, s.show_name, e.season, e.episode ' \ b'FROM tv_episodes AS e, tv_shows AS s WHERE s.indexer_id = e.showid ' \ b"AND e.status in ({0}) AND e.location <> ''".format(','.join(selection_status)) sql_result = main_db_con.select( sql_selection, Quality.DOWNLOADED + Quality.ARCHIVED) episodes = [dict(e) for e in sql_result] if episodes: trakt_data = [] for cur_episode in episodes: # Check if TRAKT supports that indexer if not get_trakt_indexer(cur_episode[b'indexer']): continue if not self._check_list( indexer=cur_episode[b'indexer'], indexer_id=cur_episode[b'indexer_id'], season=cur_episode[b'season'], episode=cur_episode[b'episode'], list_type='Collection'): log.info( "Adding episode '{show}' {ep} to Trakt collection", { 'show': cur_episode[b'show_name'], 'ep': episode_num(cur_episode[b'season'], cur_episode[b'episode']) }) title = get_title_without_year( cur_episode[b'show_name'], cur_episode[b'startyear']) trakt_data.append( (cur_episode[b'indexer_id'], cur_episode[b'indexer'], title, cur_episode[b'startyear'], cur_episode[b'season'], cur_episode[b'episode'])) if trakt_data: try: data = self.trakt_bulk_data_generate(trakt_data) self._request('sync/collection', data, method='POST') self._get_show_collection() except (TraktException, AuthException, TokenExpiredException) as e: log.info( 'Unable to add episodes to Trakt collection. Error: {error}', {'error': e.message})
def remove_episode_trakt_collection(self, filter_show=None): """Remove episode from trakt collection. For episodes that no longer have a media file (location) :param filter_show: optional. Only remove episodes from trakt collection for given shows """ if app.TRAKT_SYNC_REMOVE and app.TRAKT_SYNC and app.USE_TRAKT: params = [] main_db_con = db.DBConnection() selection_status = [ '?' for _ in Quality.DOWNLOADED + Quality.ARCHIVED ] sql_selection = b'SELECT s.indexer, s.startyear, s.indexer_id, s.show_name,' \ b'e.season, e.episode, e.status ' \ b'FROM tv_episodes AS e, tv_shows AS s WHERE s.indexer_id = e.showid and e.location = "" ' \ b'AND e.status in ({0})'.format(','.join(selection_status)) if filter_show: sql_selection += b' AND s.indexer_id = ? AND e.indexer = ?' params = [filter_show.indexerid, filter_show.indexer] sql_result = main_db_con.select( sql_selection, Quality.DOWNLOADED + Quality.ARCHIVED + params) episodes = [dict(e) for e in sql_result] if episodes: trakt_data = [] for cur_episode in episodes: # Check if TRAKT supports that indexer if not get_trakt_indexer(cur_episode[b'indexer']): continue if self._check_list(indexer=cur_episode[b'indexer'], indexer_id=cur_episode[b'indexer_id'], season=cur_episode[b'season'], episode=cur_episode[b'episode'], list_type='Collection'): log.info( "Removing episode '{show}' {ep} from Trakt collection", { 'show': cur_episode[b'show_name'], 'ep': episode_num(cur_episode[b'season'], cur_episode[b'episode']) }) title = get_title_without_year( cur_episode[b'show_name'], cur_episode[b'startyear']) trakt_data.append( (cur_episode[b'indexer_id'], cur_episode[b'indexer'], title, cur_episode[b'startyear'], cur_episode[b'season'], cur_episode[b'episode'])) if trakt_data: try: data = self.trakt_bulk_data_generate(trakt_data) self._request('sync/collection/remove', data, method='POST') self._get_show_collection() except (TraktException, AuthException, TokenExpiredException) as e: log.info( 'Unable to remove episodes from Trakt collection. Error: {error}', {'error': e.message})