def add_movie(self, movie_tmdbid, movie_title, movie_year, movie_title_slug, profile_id, root_folder, search_missing=False): payload = self._prepare_add_object_payload(movie_title, movie_title_slug, profile_id, root_folder) payload = dict_merge( payload, { 'tmdbId': movie_tmdbid, 'year': movie_year, 'minimumAvailability': 'released', 'addOptions': { 'searchForMovie': search_missing } }) return self._add_object('api/movie', payload, identifier_field='tmdbId', identifier=movie_tmdbid)
def add_series(self, series_tvdbid, series_title, series_title_slug, profile_id, root_folder, tag_ids=None, search_missing=False): payload = self._prepare_add_object_payload(series_title, series_title_slug, profile_id, root_folder) payload = dict_merge( payload, { 'tvdbId': series_tvdbid, 'tags': [] if not tag_ids or not isinstance(tag_ids, list) else tag_ids, 'seasons': [], 'seasonFolder': True, 'addOptions': { 'searchForMissingEpisodes': search_missing } }) return self._add_object('api/series', payload, identifier_field='tvdbId', identifier=series_tvdbid)
def _make_item_request(self, url, object_name, payload=None): if payload is None: payload = {} payload = dict_merge(payload, {'extended': 'full'}) try: req, resp_data = self._make_request(url, payload) if req.status_code == 200 and len(resp_data): resp_json = json.loads(resp_data) return resp_json elif req.status_code == 401: log.error( "The authentication to Trakt is revoked. Please re-authenticate." ) exit() else: log.error("Failed to retrieve %s, request response: %d", object_name, req.status_code) return None except Exception: log.exception("Exception retrieving %s: ", object_name) return None
def add_series(self, series_tvdb_id, series_title, series_title_slug, quality_profile_id, language_profile_id, root_folder, tag_ids=None, search_missing=False, series_type='standard'): payload = self._prepare_add_object_payload(series_title, series_title_slug, quality_profile_id, root_folder) payload = dict_merge(payload, { 'tvdbId': series_tvdb_id, 'tags': [] if not tag_ids or not isinstance(tag_ids, list) else tag_ids, 'seasons': [], 'seasonFolder': True, 'seriesType': series_type, 'addOptions': { 'searchForMissingEpisodes': search_missing } }) if language_profile_id: payload['languageProfileId'] = language_profile_id endpoint = 'api/v3/series' else: endpoint = 'api/series' return self._add_object(endpoint, payload, identifier_field='tvdbId', identifier=series_tvdb_id)
def add_movie(self, movie_tmdb_id, movie_title, movie_year, movie_title_slug, quality_profile_id, root_folder, min_availability_temp, search_missing=False): payload = self._prepare_add_object_payload(movie_title, movie_title_slug, quality_profile_id, root_folder) # replace radarr minimum_availability if supplied if min_availability_temp == 'announced': minimum_availability = 'announced' elif min_availability_temp == 'in_cinemas': minimum_availability = 'inCinemas' elif min_availability_temp == 'predb': minimum_availability = 'preDB' else: minimum_availability = 'released' payload = dict_merge( payload, { 'tmdbId': movie_tmdb_id, 'year': int(movie_year), 'minimumAvailability': minimum_availability, 'addOptions': { 'searchForMovie': search_missing } }) return self._add_object('api/v3/movie', payload, identifier_field='tmdbId', identifier=movie_tmdb_id)
def _make_items_request( self, url, limit, type_name, object_name, authenticate_user=None, payload=None, sleep_between=5, years=None, countries=None, languages=None, genres=None, runtimes=None, include_non_acting_roles=False, ): # default payload if payload is None: payload = {} payload = dict_merge(payload, { 'extended': 'full', 'limit': limit, 'page': 1, }) # languages list if languages: payload['languages'] = ','.join(languages).lower() # years range if years: payload['years'] = years # countries list if countries: payload['countries'] = ','.join(countries).lower() # genres list if genres: payload['genres'] = ','.join(genres).lower() # runtimes range if runtimes: payload['runtimes'] = runtimes processed = [] if authenticate_user: type_name = type_name.replace( '{authenticate_user}', self._user_used_for_authentication(authenticate_user)) try: resp_data = '' while True: attempts = 0 max_attempts = 6 retrieve_error = False while attempts <= max_attempts: try: req, resp_data = self._make_request( url, payload, authenticate_user) if resp_data is not None: retrieve_error = False break else: log.warning( "Failed to retrieve valid response for Trakt %s %s from _make_item_request", type_name, object_name) except Exception: log.exception( "Exception retrieving %s %s in _make_item_request: ", type_name, object_name) retrieve_error = True attempts += 1 log.info( "Sleeping for %d seconds before making attempt %d/%d", 3 * attempts, attempts + 1, max_attempts) time.sleep(3 * attempts) if retrieve_error or not resp_data or not len(resp_data): log.error( "Failed retrieving %s %s from _make_item_request %d times, aborting...", type_name, object_name, attempts) return None current_page = payload['page'] total_pages = 0 if 'X-Pagination-Page-Count' not in req.headers else int( req.headers['X-Pagination-Page-Count']) log.debug("Response Page: %d of %d", current_page, total_pages) if req.status_code == 200 and len(resp_data): if (resp_data.startswith("[{") and resp_data.endswith("}]")) or \ (resp_data.startswith("{") and resp_data.endswith("}")): resp_json = json.loads(resp_data) if type_name == 'person' and 'cast' in resp_json: for item in resp_json['cast']: # filter out non-acting roles if not include_non_acting_roles and \ ((item['character'].strip() == '') or 'narrat' in item['character'].lower() or 'himself' in item['character'].lower()): continue if item not in processed: if object_name.rstrip( 's' ) not in item and 'title' in item: processed.append( {object_name.rstrip('s'): item}) else: processed.append(item) else: for item in resp_json: if item not in processed: if object_name.rstrip( 's' ) not in item and 'title' in item: processed.append( {object_name.rstrip('s'): item}) else: processed.append(item) elif resp_data == '[]': log.warning( "Received empty JSON response for page: %d of %d", current_page, total_pages) else: log.warning( "Received malformed JSON response for page: %d of %d", current_page, total_pages) # check if we have fetched the last page, break if so if total_pages == 0: log.debug("There were no more pages left to retrieve.") break elif current_page >= total_pages: log.debug( "There are no more pages left to retrieve results from." ) break else: log.info( "There are %d page(s) left to retrieve results from.", total_pages - current_page) payload['page'] += 1 time.sleep(sleep_between) elif req.status_code == 401: log.error( "The authentication to Trakt is revoked. Please re-authenticate." ) exit() else: log.error("Failed to retrieve %s %s, request response: %d", type_name, object_name, req.status_code) break if len(processed): log.debug("Found %d %s %s", len(processed), type_name, object_name) return processed return None except Exception: log.exception("Exception retrieving %s %s: ", type_name, object_name) return None
def _make_items_request(self, url, page, limit, languages, type_name, object_name, authenticate_user=None, payload={}, sleep_between=5, genres=None): if not languages: languages = ['en'] #Limit pages and results per page if a results_limit was sent. if limit == 0: limit_results = False limit = 1000 else: limit_results = True total_pages, limit = self.getPageAndResultsPerPage(limit) payload = dict_merge(payload, {'extended': 'full', 'limit': limit, 'page': 1, 'languages': ','.join(languages)}) if genres: payload['genres'] = genres processed = [] if authenticate_user: type_name = type_name.replace('{authenticate_user}', self._user_used_for_authentication(authenticate_user)) try: resp_data = '' while True: attempts = 0 max_attempts = 6 retrieve_error = False while attempts <= max_attempts: try: req, resp_data = self._make_request(url, payload, authenticate_user) if resp_data is not None: retrieve_error = False break else: log.warning("Failed to retrieve valid response for Trakt %s %s from _make_item_request", type_name, object_name) except Exception: log.exception("Exception retrieving %s %s in _make_item_request: ", type_name, object_name) retrieve_error = True attempts += 1 log.info("Sleeping for %d seconds before making attempt %d/%d", 3 * attempts, attempts + 1, max_attempts) time.sleep(3 * attempts) if retrieve_error or not resp_data or not len(resp_data): log.error("Failed retrieving %s %s from _make_item_request %d times, aborting...", type_name, object_name, attempts) return None current_page = payload['page'] #Limit pages if results are limited. if limit_results == True and not type_name == 'boxoffice': log.debug("Limiting Trakt list results to %d.",limit) else: if type_name == 'boxoffice': log.debug("Cannot limit Trakt's Box Office results. It always has 10 results.") total_pages = 1 else: log.debug("Not limiting Trakt list results.") total_pages = 0 if 'X-Pagination-Page-Count' not in req.headers else int(req.headers['X-Pagination-Page-Count']) log.debug("Response Page: %d of %d", current_page, total_pages) if req.status_code == 200 and len(resp_data): if resp_data.startswith("[{") and resp_data.endswith("}]"): resp_json = json.loads(resp_data) if type_name == 'person' and 'cast' in resp_json: # handle person results for item in resp_json['cast']: if item not in processed: if object_name.rstrip('s') not in item and 'title' in item: processed.append({object_name.rstrip('s'): item}) else: processed.append(item) else: for item in resp_json: if item not in processed: if object_name.rstrip('s') not in item and 'title' in item: processed.append({object_name.rstrip('s'): item}) else: processed.append(item) else: log.warning("Received malformed JSON response for page: %d of %d", current_page, total_pages) # check if we have fetched the last page, break if so if total_pages == 0: log.debug("There were no more pages to retrieve") break elif current_page >= total_pages: log.debug("There are no more pages to retrieve results from") break else: log.info("There are %d pages left to retrieve results from", total_pages - current_page) payload['page'] += 1 time.sleep(sleep_between) elif req.status_code == 401: log.error("The authentication to Trakt is revoked. Please re-authenticate.") exit() else: log.error("Failed to retrieve %s %s, request response: %d", type_name, object_name, req.status_code) break if len(processed): log.debug("Found %d %s %s", len(processed), type_name, object_name) return processed return None except Exception: log.exception("Exception retrieving %s %s: ", type_name, object_name) return None
def _make_items_request(self, url, limit, languages, type_name, object_name, authenticate_user=None, payload={}, sleep_between=5, genres=None): if not languages: languages = ['en'] payload = dict_merge( payload, { 'extended': 'full', 'limit': limit, 'page': 1, 'languages': ','.join(languages) }) if genres: payload['genres'] = genres processed = [] if authenticate_user: type_name = type_name.replace( '{authenticate_user}', self._user_used_for_authentication(authenticate_user)) try: while True: req = self._make_request(url, payload, authenticate_user) current_page = payload['page'] total_pages = 0 if 'X-Pagination-Page-Count' not in req.headers else int( req.headers['X-Pagination-Page-Count']) log.debug("Response Page: %d of %d", current_page, total_pages) if req.status_code == 200: resp_json = req.json() if type_name == 'person' and 'cast' in resp_json: # handle person results for item in resp_json['cast']: if item not in processed: if object_name.rstrip( 's') not in item and 'title' in item: processed.append( {object_name.rstrip('s'): item}) else: processed.append(item) else: for item in resp_json: if item not in processed: if object_name.rstrip( 's') not in item and 'title' in item: processed.append( {object_name.rstrip('s'): item}) else: processed.append(item) # check if we have fetched the last page, break if so if total_pages == 0: log.debug("There were no more pages to retrieve") break elif current_page >= total_pages: log.debug( "There are no more pages to retrieve results from") break else: log.info( "There are %d pages left to retrieve results from", total_pages - current_page) payload['page'] += 1 time.sleep(sleep_between) elif req.status_code == 401: log.error( "The authentication to Trakt is revoked. Please re-authenticate." ) exit() else: log.error("Failed to retrieve %s %s, request response: %d", type_name, object_name, req.status_code) break if len(processed): log.debug("Found %d %s %s", len(processed), type_name, object_name) return processed return None except Exception: log.exception("Exception retrieving %s %s: ", type_name, object_name) return None