From 6644a40234082a1edfbedf305f389f912b8687a6 Mon Sep 17 00:00:00 2001 From: l3uddz Date: Sun, 6 May 2018 02:46:58 +0100 Subject: [PATCH] add show and movie command to add single show/movie to sonarr or radarr. --- media/trakt.py | 61 ++++++++++++++++++++++- traktarr.py | 128 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 186 insertions(+), 3 deletions(-) diff --git a/media/trakt.py b/media/trakt.py index 9989eb1..cb46a0e 100644 --- a/media/trakt.py +++ b/media/trakt.py @@ -161,7 +161,7 @@ class Trakt: if user is None: users = self.cfg['trakt'] - + if 'client_id' in users.keys(): users.pop('client_id') @@ -174,7 +174,8 @@ class Trakt: log.debug('No user provided, so default to the first user in the config (%s)', user) elif user not in self.cfg['trakt'].keys(): log.error( - 'The user %s you specified to use for authentication is not authenticated yet. Authenticate the user first, before you use it to retrieve lists.', + 'The user %s you specified to use for authentication is not authenticated yet. ' + 'Authenticate the user first, before you use it to retrieve lists.', user) exit() @@ -205,6 +206,34 @@ class Trakt: # Shows ############################################################ + @backoff.on_predicate(backoff.expo, lambda x: x is None, max_tries=4, on_backoff=backoff_handler) + def get_show(self, show_id): + try: + # generate payload + payload = {'extended': 'full'} + + # make request + req = requests.get( + 'https://api.trakt.tv/shows/%s' % str(show_id), + headers=self.headers, + params=payload, + timeout=30 + ) + log.debug("Request URL: %s", req.url) + log.debug("Request Payload: %s", payload) + log.debug("Response Code: %d", req.status_code) + + if req.status_code == 200: + resp_json = req.json() + return resp_json + else: + log.error("Failed to retrieve show, request response: %d", req.status_code) + return None + + except Exception: + log.exception("Exception retrieving show: ") + return None + @backoff.on_predicate(backoff.expo, lambda x: x is None, max_tries=4, on_backoff=backoff_handler) def get_anticipated_shows(self, limit=1000, languages=None): try: @@ -533,6 +562,34 @@ class Trakt: # Movies ############################################################ + @backoff.on_predicate(backoff.expo, lambda x: x is None, max_tries=4, on_backoff=backoff_handler) + def get_movie(self, movie_id): + try: + # generate payload + payload = {'extended': 'full'} + + # make request + req = requests.get( + 'https://api.trakt.tv/movies/%s' % str(movie_id), + headers=self.headers, + params=payload, + timeout=30 + ) + log.debug("Request URL: %s", req.url) + log.debug("Request Payload: %s", payload) + log.debug("Response Code: %d", req.status_code) + + if req.status_code == 200: + resp_json = req.json() + return resp_json + else: + log.error("Failed to retrieve movie, request response: %d", req.status_code) + return None + + except Exception: + log.exception("Exception retrieving movie: ") + return None + @backoff.on_predicate(backoff.expo, lambda x: x is None, max_tries=4, on_backoff=backoff_handler) def get_anticipated_movies(self, limit=1000, languages=None): try: diff --git a/traktarr.py b/traktarr.py index 818e508..42501d3 100755 --- a/traktarr.py +++ b/traktarr.py @@ -73,6 +73,76 @@ def trakt_authentication(): # SHOWS ############################################################ +@app.command(help='Add single show to Sonarr.') +@click.option('--show_id', '-s', help='Trakt show_id.', required=True) +@click.option('--folder', '-f', default=None, help='Add show with this root folder to Sonarr.') +@click.option('--no-search', is_flag=True, help='Disable search when adding show to Sonarr.') +def show(show_id, folder=None, no_search=False): + from media.sonarr import Sonarr + from media.trakt import Trakt + from misc import helpers + + # replace sonarr root_folder if folder is supplied + if folder: + cfg['sonarr']['root_folder'] = folder + + # validate trakt api_key + trakt = Trakt(cfg) + if not trakt.validate_client_id(): + log.error("Aborting due to failure to validate Trakt API Key") + return None + else: + log.info("Validated Trakt API Key") + + # validate sonarr url & api_key + sonarr = Sonarr(cfg.sonarr.url, cfg.sonarr.api_key) + if not sonarr.validate_api_key(): + log.error("Aborting due to failure to validate Sonarr URL / API Key") + return None + else: + log.info("Validated Sonarr URL & API Key") + + # retrieve profile id for requested profile + profile_id = sonarr.get_profile_id(cfg.sonarr.profile) + if not profile_id or not profile_id > 0: + log.error("Aborting due to failure to retrieve Profile ID for: %s", cfg.sonarr.profile) + return None + else: + log.info("Retrieved Profile ID for %s: %d", cfg.sonarr.profile, profile_id) + + # retrieve profile tags + profile_tags = sonarr.get_tags() + if profile_tags is None: + log.error("Aborting due to failure to retrieve Tag ID's") + else: + log.info("Retrieved %d Tag ID's", len(profile_tags)) + + # get trakt show + trakt_show = trakt.get_show(show_id) + + if not trakt_show: + log.error("Aborting due to failure to retrieve Trakt show") + return None + else: + log.info("Retrieved Trakt show information for %s: %s (%d)", show_id, trakt_show['title'], + trakt_show['year']) + + # determine which tags to use when adding this series + use_tags = helpers.sonarr_series_tag_id_from_network(profile_tags, cfg.sonarr.tags, + trakt_show['network']) + + # add show to sonarr + if sonarr.add_series(trakt_show['ids']['tvdb'], trakt_show['title'], trakt_show['ids']['slug'], profile_id, + cfg.sonarr.root_folder, use_tags, not no_search): + log.info("ADDED %s (%d) with tags: %s", trakt_show['title'], trakt_show['year'], + helpers.sonarr_readable_tag_from_ids(profile_tags, use_tags)) + else: + log.error("FAILED adding %s (%d) with tags: %s", trakt_show['title'], trakt_show['year'], + helpers.sonarr_readable_tag_from_ids(profile_tags, use_tags)) + + return + + @app.command(help='Add new shows to Sonarr.') @click.option('--list-type', '-t', help='Trakt list to process. For example, anticipated, trending, popular, watchlist or any URL to a list', @@ -250,9 +320,65 @@ def shows(list_type, add_limit=0, add_delay=2.5, genre=None, folder=None, no_sea # MOVIES ############################################################ +@app.command(help='Add single movie to Radarr.') +@click.option('--movie_id', '-m', help='Trakt movie_id.', required=True) +@click.option('--folder', '-f', default=None, help='Add movie with this root folder to Radarr.') +@click.option('--no-search', is_flag=True, help='Disable search when adding movie to Radarr.') +def movie(movie_id, folder=None, no_search=False): + from media.radarr import Radarr + from media.trakt import Trakt + + # replace radarr root_folder if folder is supplied + if folder: + cfg['radarr']['root_folder'] = folder + + # validate trakt api_key + trakt = Trakt(cfg) + if not trakt.validate_client_id(): + log.error("Aborting due to failure to validate Trakt API Key") + return None + else: + log.info("Validated Trakt API Key") + + # validate radarr url & api_key + radarr = Radarr(cfg.radarr.url, cfg.radarr.api_key) + if not radarr.validate_api_key(): + log.error("Aborting due to failure to validate Radarr URL / API Key") + return None + else: + log.info("Validated Radarr URL & API Key") + + # retrieve profile id for requested profile + profile_id = radarr.get_profile_id(cfg.radarr.profile) + if not profile_id or not profile_id > 0: + log.error("Aborting due to failure to retrieve Profile ID for: %s", cfg.radarr.profile) + else: + log.info("Retrieved Profile ID for %s: %d", cfg.radarr.profile, profile_id) + + # get trakt movie + trakt_movie = trakt.get_movie(movie_id) + + if not trakt_movie: + log.error("Aborting due to failure to retrieve Trakt movie") + return None + else: + log.info("Retrieved Trakt movie information for %s: %s (%d)", movie_id, trakt_movie['title'], + trakt_movie['year']) + + # add movie to radarr + if radarr.add_movie(trakt_movie['ids']['tmdb'], trakt_movie['title'], trakt_movie['year'], + trakt_movie['ids']['slug'], profile_id, cfg.radarr.root_folder, not no_search): + log.info("ADDED %s (%d)", trakt_movie['title'], trakt_movie['year']) + else: + log.error("FAILED adding %s (%d)", trakt_movie['title'], trakt_movie['year']) + + return + + @app.command(help='Add new movies to Radarr.') @click.option('--list-type', '-t', - help='Trakt list to process. For example, anticipated, trending, popular, boxoffice, watchlist or any URL to a list', + help='Trakt list to process. For example, anticipated, trending, popular, boxoffice, watchlist ' + 'or any URL to a list', required=True) @click.option('--add-limit', '-l', default=0, help='Limit number of movies added to Radarr.', show_default=True) @click.option('--add-delay', '-d', default=2.5, help='Seconds between each add request to Radarr.', show_default=True)