diff --git a/README.md b/README.md index 9afcc70..913d75d 100644 --- a/README.md +++ b/README.md @@ -1163,28 +1163,32 @@ Usage: traktarr movies [OPTIONS] Add multiple movies to Radarr. Options: - -t, --list-type TEXT Trakt list to process. For example, 'anticipated', 'trending', + -t, --list-type TEXT Trakt list to process. + For example, 'anticipated', 'trending', 'popular', 'person', 'watched', 'played', 'recommended', - 'watchlist', or any URL to a list [required] + 'watchlist', or any URL to a list. [required] -l, --add-limit INTEGER Limit number of movies added to Radarr. -d, --add-delay FLOAT Seconds between each add request to Radarr. [default: 2.5] -s, --sort [rating|release|votes] Sort list to process. [default: votes] -r, --rating INTEGER Set a minimum Rotten Tomatoes score. - -g, --genre TEXT Only add movies from this genre to Radarr. Use 'ignore' to add - movies from any genre, including ones with no genre specified. + -g, --genre TEXT Only add movies from this genre to Radarr. Only one genre can be + specified. + Use 'ignore' to add movies from any genre, including + ones with no genre specified. -f, --folder TEXT Add movies with this root folder to Radarr. -ma, --minimum-availability [announced|in_cinemas|released|predb] Add movies with this minimum availability to Radarr. Default is 'released'. - -a, --actor TEXT Only add movies from this actor to Radarr. Requires the 'person' - list. + -a, --actor TEXT Only add movies from this actor to Radarr.Only one actor can be + specified. + Requires the 'person' list. --include-non-acting-roles Include non-acting roles such as 'As Himself', 'Narrator', etc. Requires the 'person' list option with the 'actor' argument. --no-search Disable search when adding movies to Radarr. --notifications Send notifications. --authenticate-user TEXT Specify which user to authenticate with to retrieve Trakt lists. - Default: first user in the config. + Defaults to first user in the config. --ignore-blacklist Ignores the blacklist when running the command. --remove-rejected-from-recommended Removes rejected/existing movies from recommended. @@ -1297,18 +1301,22 @@ Usage: traktarr shows [OPTIONS] Add multiple shows to Sonarr. Options: - -t, --list-type TEXT Trakt list to process. For example, 'anticipated', 'trending', + -t, --list-type TEXT Trakt list to process. + For example, 'anticipated', 'trending', 'popular', 'person', 'watched', 'played', 'recommended', - 'watchlist', or any URL to a list [required] + 'watchlist', or any URL to a list. [required] -l, --add-limit INTEGER Limit number of shows added to Sonarr. -d, --add-delay FLOAT Seconds between each add request to Sonarr. [default: 2.5] -s, --sort [rating|release|votes] Sort list to process. [default: votes] - -g, --genre TEXT Only add shows from this genre to Sonarr. Use 'ignore' to add - shows from any genre, including ones with no genre specified. + -g, --genre TEXT Only add shows from this genre to Sonarr. Only one genre can be + specified. + Use 'ignore' to add shows from any genre, including + ones with no genre specified. -f, --folder TEXT Add shows with this root folder to Sonarr. - -a, --actor TEXT Only add movies from this actor to Radarr. Requires the 'person' - list option. + -a, --actor TEXT Only add movies from this actor to Radarr. Only one actor can be + specified. + Requires the 'person' list option. --include-non-acting-roles Include non-acting roles such as 'As Himself', 'Narrator', etc. Requires the 'person' list option with the 'actor' argument. --no-search Disable search when adding shows to Sonarr. diff --git a/media/trakt.py b/media/trakt.py index 39a6994..2748625 100644 --- a/media/trakt.py +++ b/media/trakt.py @@ -13,6 +13,7 @@ from misc.config import Config log = logger.get_logger(__name__) cachefile = Config().cachefile + class Trakt: non_user_lists = ['anticipated', 'trending', 'popular', 'boxoffice', 'watched', 'played'] @@ -76,7 +77,14 @@ class Trakt: if not languages: languages = ['en'] - payload = dict_merge(payload, {'extended': 'full', 'limit': limit, 'page': 1, 'languages': ','.join(languages)}) + payload = dict_merge(payload, { + 'extended': 'full', + 'limit': limit, + 'page': 1, + 'languages': ','.join(languages), + }) + + # currently only support for one genre item, despite name if genres: payload['genres'] = genres @@ -153,13 +161,13 @@ class Trakt: # 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") + 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") + 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) + log.info("There are %d page(s) left to retrieve results from.", total_pages - current_page) payload['page'] += 1 time.sleep(sleep_between) @@ -390,88 +398,89 @@ class Trakt: def get_trending_shows(self, limit=1000, languages=None, genres=None): return self._make_items_request( url='https://api.trakt.tv/shows/trending', - limit=limit, - languages=languages, object_name='shows', type_name='trending', - genres=genres + limit=limit, + languages=languages, + genres=genres, ) @cache(cache_file=cachefile, retry_if_blank=True) def get_popular_shows(self, limit=1000, languages=None, genres=None): return self._make_items_request( url='https://api.trakt.tv/shows/popular', - limit=limit, - languages=languages, object_name='shows', type_name='popular', - genres=genres + limit=limit, + languages=languages, + genres=genres, ) @cache(cache_file=cachefile, retry_if_blank=True) def get_anticipated_shows(self, limit=1000, languages=None, genres=None): return self._make_items_request( url='https://api.trakt.tv/shows/anticipated', - limit=limit, - languages=languages, object_name='shows', type_name='anticipated', - genres=genres + limit=limit, + languages=languages, + genres=genres, ) - def get_person_shows(self, person, limit=1000, languages=None, genres=None, include_non_acting_roles=False): + def get_person_shows(self, person, limit=1000, languages=None, genres=None, + include_non_acting_roles=False): return self._make_items_request( url='https://api.trakt.tv/people/%s/shows' % person.replace(' ', '-').lower(), - limit=limit, - languages=languages, object_name='shows', type_name='person', + limit=limit, + languages=languages, genres=genres, - include_non_acting_roles=include_non_acting_roles + include_non_acting_roles=include_non_acting_roles, ) @cache(cache_file=cachefile, retry_if_blank=True) def get_most_played_shows(self, limit=1000, languages=None, genres=None, most_type=None): return self._make_items_request( url='https://api.trakt.tv/shows/played/%s' % ('weekly' if not most_type else most_type), - limit=limit, - languages=languages, object_name='shows', type_name='played', - genres=genres + limit=limit, + languages=languages, + genres=genres, ) @cache(cache_file=cachefile, retry_if_blank=True) def get_most_watched_shows(self, limit=1000, languages=None, genres=None, most_type=None): return self._make_items_request( url='https://api.trakt.tv/shows/watched/%s' % ('weekly' if not most_type else most_type), - limit=limit, - languages=languages, object_name='shows', type_name='watched', - genres=genres + limit=limit, + languages=languages, + genres=genres, ) @cache(cache_file=cachefile, retry_if_blank=True) def get_recommended_shows(self, authenticate_user=None, limit=1000, languages=None, genres=None): return self._make_items_request( url='https://api.trakt.tv/recommendations/shows', + object_name='shows', + type_name='recommended from {authenticate_user}', authenticate_user=authenticate_user, limit=limit, languages=languages, - object_name='shows', - type_name='recommended from {authenticate_user}', - genres=genres + genres=genres, ) def get_watchlist_shows(self, authenticate_user=None, limit=1000, languages=None): return self._make_items_request( url='https://api.trakt.tv/users/{authenticate_user}/watchlist/shows', + object_name='shows', + type_name='watchlist from {authenticate_user}', authenticate_user=authenticate_user, limit=limit, languages=languages, - object_name='shows', - type_name='watchlist from {authenticate_user}', ) def get_user_list_shows(self, list_url, authenticate_user=None, limit=1000, languages=None): @@ -481,11 +490,11 @@ class Trakt: return self._make_items_request( url='https://api.trakt.tv/users/' + list_user + '/lists/' + list_key + '/items/shows', + object_name='shows', + type_name=(list_key + ' from ' + list_user), authenticate_user=authenticate_user, limit=limit, languages=languages, - object_name='shows', - type_name=(list_key + ' from ' + list_user), ) ############################################################ @@ -502,96 +511,98 @@ class Trakt: def get_trending_movies(self, limit=1000, languages=None, genres=None): return self._make_items_request( url='https://api.trakt.tv/movies/trending', - limit=limit, - languages=languages, object_name='movies', type_name='trending', - genres=genres + limit=limit, + languages=languages, + genres=genres, ) @cache(cache_file=cachefile, retry_if_blank=True) def get_popular_movies(self, limit=1000, languages=None, genres=None): return self._make_items_request( url='https://api.trakt.tv/movies/popular', - limit=limit, - languages=languages, object_name='movies', type_name='popular', - genres=genres + limit=limit, + languages=languages, + genres=genres, ) @cache(cache_file=cachefile, retry_if_blank=True) def get_anticipated_movies(self, limit=1000, languages=None, genres=None): return self._make_items_request( url='https://api.trakt.tv/movies/anticipated', - limit=limit, - languages=languages, object_name='movies', type_name='anticipated', - genres=genres + limit=limit, + languages=languages, + genres=genres, ) - def get_person_movies(self, person, limit=1000, languages=None, genres=None, include_non_acting_roles=False): + def get_person_movies(self, person, limit=1000, languages=None, genres=None, + include_non_acting_roles=False): return self._make_items_request( url='https://api.trakt.tv/people/%s/movies' % person.replace(' ', '-').lower(), - limit=limit, - languages=languages, object_name='movies', type_name='person', + limit=limit, + languages=languages, genres=genres, - include_non_acting_roles=include_non_acting_roles + include_non_acting_roles=include_non_acting_roles, ) @cache(cache_file=cachefile, retry_if_blank=True) def get_most_played_movies(self, limit=1000, languages=None, genres=None, most_type=None): return self._make_items_request( url='https://api.trakt.tv/movies/played/%s' % ('weekly' if not most_type else most_type), - limit=limit, - languages=languages, object_name='movies', type_name='played', - genres=genres + limit=limit, + languages=languages, + genres=genres, ) @cache(cache_file=cachefile, retry_if_blank=True) def get_most_watched_movies(self, limit=1000, languages=None, genres=None, most_type=None): return self._make_items_request( url='https://api.trakt.tv/movies/watched/%s' % ('weekly' if not most_type else most_type), - limit=limit, - languages=languages, object_name='movies', type_name='watched', - genres=genres + limit=limit, + languages=languages, + genres=genres, ) - def get_boxoffice_movies(self, limit=1000, languages=None): + def get_boxoffice_movies(self, limit=1000, languages=None, genres=None): return self._make_items_request( url='https://api.trakt.tv/movies/boxoffice', - limit=limit, - languages=languages, object_name='movies', type_name='anticipated', + limit=limit, + languages=languages, + genres=genres, ) def get_recommended_movies(self, authenticate_user=None, limit=1000, languages=None, genres=None): return self._make_items_request( url='https://api.trakt.tv/recommendations/movies', + object_name='movies', + type_name='recommended from {authenticate_user}', authenticate_user=authenticate_user, limit=limit, languages=languages, - object_name='movies', - type_name='recommended from {authenticate_user}', - genres=genres + genres=genres, ) def get_watchlist_movies(self, authenticate_user=None, limit=1000, languages=None): return self._make_items_request( url='https://api.trakt.tv/users/{authenticate_user}/watchlist/movies', + object_name='movies', + type_name='watchlist from {authenticate_user}', authenticate_user=authenticate_user, limit=limit, languages=languages, - object_name='movies', - type_name='watchlist from {authenticate_user}', ) def get_user_list_movies(self, list_url, authenticate_user=None, limit=1000, languages=None): @@ -601,9 +612,9 @@ class Trakt: return self._make_items_request( url='https://api.trakt.tv/users/' + list_user + '/lists/' + list_key + '/items/movies', + object_name='movies', + type_name=(list_key + ' from ' + list_user), authenticate_user=authenticate_user, limit=limit, languages=languages, - object_name='movies', - type_name=(list_key + ' from ' + list_user), ) diff --git a/traktarr.py b/traktarr.py index 93c55c9..e12876e 100755 --- a/traktarr.py +++ b/traktarr.py @@ -209,9 +209,9 @@ def show(show_id, folder=None, no_search=False): @app.command(help='Add multiple shows to Sonarr.', context_settings=dict(max_content_width=100)) @click.option( '--list-type', '-t', - help='Trakt list to process. ' + help='Trakt list to process. \n' 'For example, \'anticipated\', \'trending\', \'popular\', \'person\', \'watched\', \'played\', ' - '\'recommended\', \'watchlist\', or any URL to a list', + '\'recommended\', \'watchlist\', or any URL to a list.', required=True) @click.option( '--add-limit', '-l', @@ -232,6 +232,7 @@ def show(show_id, folder=None, no_search=False): '--genre', '-g', default=None, help='Only add shows from this genre to Sonarr. ' + 'Only one genre can be specified. \n' 'Use \'ignore\' to add shows from any genre, including ones with no genre specified.') @click.option( '--folder', '-f', @@ -241,11 +242,12 @@ def show(show_id, folder=None, no_search=False): '--actor', '-a', default=None, help='Only add movies from this actor to Radarr. ' + 'Only one actor can be specified. \n' 'Requires the \'person\' list option.') @click.option( '--include-non-acting-roles', is_flag=True, - help='Include non-acting roles such as \'As Himself\', \'Narrator\', etc. ' + help='Include non-acting roles such as \'As Himself\', \'Narrator\', etc. \n' 'Requires the \'person\' list option with the \'actor\' argument.') @click.option( '--no-search', @@ -257,7 +259,7 @@ def show(show_id, folder=None, no_search=False): help='Send notifications.') @click.option( '--authenticate-user', - help='Specify which user to authenticate with to retrieve Trakt lists. ' + help='Specify which user to authenticate with to retrieve Trakt lists. \n' 'Defaults to first user in the config') @click.option( '--ignore-blacklist', @@ -279,12 +281,15 @@ def shows(list_type, add_limit=0, add_delay=2.5, sort='votes', genre=None, folde added_shows = 0 - # set special genre keyword 'ignore' if supplied - if genre and genre.lower == 'ignore': - cfg['filters']['shows']['blacklisted_genres'] = ['ignore'] - # remove genre from shows blacklisted_genres if supplied - elif genre: - misc_helper.unblacklist_genres(genre, cfg['filters']['shows']['blacklisted_genres']) + # process genre + if genre: + # set special genre keyword to show's blacklisted_genres list + if genre.lower() == 'ignore': + cfg['filters']['shows']['blacklisted_genres'] = ['ignore'] + genre = None + # remove genre from show's blacklisted_genres list + else: + misc_helper.unblacklist_genres(genre, cfg['filters']['shows']['blacklisted_genres']) # replace sonarr root_folder if folder is supplied if folder: @@ -304,16 +309,13 @@ def shows(list_type, add_limit=0, add_delay=2.5, sort='votes', genre=None, folde # get trakt series list if list_type.lower() == 'anticipated': - trakt_objects_list = trakt.get_anticipated_shows(genres=genre if genre and - 'ignore' not in genre.lower() else None, + trakt_objects_list = trakt.get_anticipated_shows(genres=genre, languages=cfg.filters.shows.allowed_languages) elif list_type.lower() == 'trending': - trakt_objects_list = trakt.get_trending_shows(genres=genre if genre and - 'ignore' not in genre.lower() else None, + trakt_objects_list = trakt.get_trending_shows(genres=genre, languages=cfg.filters.shows.allowed_languages) elif list_type.lower() == 'popular': - trakt_objects_list = trakt.get_popular_shows(genres=genre if genre and - 'ignore' not in genre.lower() else None, + trakt_objects_list = trakt.get_popular_shows(genres=genre, languages=cfg.filters.shows.allowed_languages) elif list_type.lower() == 'person': if not actor: @@ -321,25 +323,21 @@ def shows(list_type, add_limit=0, add_delay=2.5, sort='votes', genre=None, folde " list type!") return None trakt_objects_list = trakt.get_person_shows(person=actor, - genres=genre if genre and - 'ignore' not in genre.lower() else None, + genres=genre, languages=cfg.filters.shows.allowed_languages, include_non_acting_roles=include_non_acting_roles) elif list_type.lower() == 'recommended': trakt_objects_list = trakt.get_recommended_shows(authenticate_user, - genres=genre if genre - and 'ignore' not in genre.lower() else None, + genres=genre, languages=cfg.filters.shows.allowed_languages) elif list_type.lower().startswith('played'): most_type = misc_helper.substring_after(list_type.lower(), "_") - trakt_objects_list = trakt.get_most_played_shows(genres=genre if genre - and 'ignore' not in genre.lower() else None, + trakt_objects_list = trakt.get_most_played_shows(genres=genre, languages=cfg.filters.shows.allowed_languages, most_type=most_type if most_type else None) elif list_type.lower().startswith('watched'): most_type = misc_helper.substring_after(list_type.lower(), "_") - trakt_objects_list = trakt.get_most_watched_shows(genres=genre if genre - and 'ignore' not in genre.lower() else None, + trakt_objects_list = trakt.get_most_watched_shows(genres=genre, languages=cfg.filters.shows.allowed_languages, most_type=most_type if most_type else None) elif list_type.lower() == 'watchlist': @@ -550,9 +548,9 @@ def movie(movie_id, folder=None, minimum_availability=None, no_search=False): @app.command(help='Add multiple movies to Radarr.', context_settings=dict(max_content_width=100)) @click.option( '--list-type', '-t', - help='Trakt list to process. ' + help='Trakt list to process. \n' 'For example, \'anticipated\', \'trending\', \'popular\', \'person\', \'watched\', \'played\', ' - '\'recommended\', \'watchlist\', or any URL to a list', + '\'recommended\', \'watchlist\', or any URL to a list.', required=True) @click.option( '--add-limit', '-l', @@ -577,6 +575,7 @@ def movie(movie_id, folder=None, minimum_availability=None, no_search=False): '--genre', '-g', default=None, help='Only add movies from this genre to Radarr. ' + 'Only one genre can be specified. \n' 'Use \'ignore\' to add movies from any genre, including ones with no genre specified.') @click.option( '--folder', '-f', @@ -589,12 +588,13 @@ def movie(movie_id, folder=None, minimum_availability=None, no_search=False): @click.option( '--actor', '-a', default=None, - help='Only add movies from this actor to Radarr. ' + help='Only add movies from this actor to Radarr.' + 'Only one actor can be specified. \n' 'Requires the \'person\' list.') @click.option( '--include-non-acting-roles', is_flag=True, - help='Include non-acting roles such as \'As Himself\', \'Narrator\', etc. ' + help='Include non-acting roles such as \'As Himself\', \'Narrator\', etc. \n' 'Requires the \'person\' list option with the \'actor\' argument.') @click.option( '--no-search', @@ -606,8 +606,8 @@ def movie(movie_id, folder=None, minimum_availability=None, no_search=False): help='Send notifications.') @click.option( '--authenticate-user', - help='Specify which user to authenticate with to retrieve Trakt lists. ' - 'Default: first user in the config.') + help='Specify which user to authenticate with to retrieve Trakt lists. \n' + 'Defaults to first user in the config.') @click.option( '--ignore-blacklist', is_flag=True, @@ -629,12 +629,15 @@ def movies(list_type, add_limit=0, add_delay=2.5, sort='votes', rating=None, gen added_movies = 0 - # set special genre keyword 'ignore' if supplied - if genre and genre.lower() == 'ignore': - cfg['filters']['movies']['blacklisted_genres'] = ['ignore'] - # remove genre from movies blacklisted_genres if supplied - elif genre: - misc_helper.unblacklist_genres(genre, cfg['filters']['movies']['blacklisted_genres']) + # process genre + if genre: + # set special genre keyword to movies's blacklisted_genres list + if genre.lower() == 'ignore': + cfg['filters']['movies']['blacklisted_genres'] = ['ignore'] + genre = None + # remove genre from movies's blacklisted_genres list + else: + misc_helper.unblacklist_genres(genre, cfg['filters']['movies']['blacklisted_genres']) # replace radarr root_folder if folder is supplied if folder: @@ -664,45 +667,39 @@ def movies(list_type, add_limit=0, add_delay=2.5, sort='votes', rating=None, gen # get trakt movies list if list_type.lower() == 'anticipated': - trakt_objects_list = trakt.get_anticipated_movies(genres=genre if genre - and 'ignore' not in genre.lower() else None, + trakt_objects_list = trakt.get_anticipated_movies(genres=genre, languages=cfg.filters.movies.allowed_languages) elif list_type.lower() == 'trending': - trakt_objects_list = trakt.get_trending_movies(genres=genre if genre - and 'ignore' not in genre.lower() else None, + trakt_objects_list = trakt.get_trending_movies(genres=genre, languages=cfg.filters.movies.allowed_languages) elif list_type.lower() == 'popular': - trakt_objects_list = trakt.get_popular_movies(genres=genre if genre - and 'ignore' not in genre.lower() else None, + trakt_objects_list = trakt.get_popular_movies(genres=genre, languages=cfg.filters.movies.allowed_languages) elif list_type.lower() == 'boxoffice': - trakt_objects_list = trakt.get_boxoffice_movies() + trakt_objects_list = trakt.get_boxoffice_movies(genres=genre, + languages=cfg.filters.movies.allowed_languages) elif list_type.lower() == 'person': if not actor: log.error("You must specify an actor with the \'--actor\' / \'-a\' parameter when using the \'person\'" + " list type!") return None trakt_objects_list = trakt.get_person_movies(person=actor, - genres=genre if genre - and 'ignore' not in genre.lower() else None, + genres=genre, languages=cfg.filters.movies.allowed_languages, include_non_acting_roles=include_non_acting_roles) elif list_type.lower() == 'recommended': trakt_objects_list = trakt.get_recommended_movies(authenticate_user, - genres=genre if genre - and 'ignore' not in genre.lower() else None, + genres=genre, languages=cfg.filters.movies.allowed_languages) elif list_type.lower().startswith('played'): most_type = misc_helper.substring_after(list_type.lower(), "_") - trakt_objects_list = trakt.get_most_played_movies(genres=genre if genre - and 'ignore' not in genre.lower() else None, + trakt_objects_list = trakt.get_most_played_movies(genres=genre, languages=cfg.filters.movies.allowed_languages, most_type=most_type if most_type else None) elif list_type.lower().startswith('watched'): most_type = misc_helper.substring_after(list_type.lower(), "_") - trakt_objects_list = trakt.get_most_watched_movies(genres=genre if genre - and 'ignore' not in genre.lower() else None, + trakt_objects_list = trakt.get_most_watched_movies(genres=genre, languages=cfg.filters.movies.allowed_languages, most_type=most_type if most_type else None) elif list_type.lower() == 'watchlist':