From 54d528b0c5ca1d31308878c981e99cbd8ba91710 Mon Sep 17 00:00:00 2001 From: Mitchell Klijs Date: Wed, 30 May 2018 18:04:21 +0200 Subject: [PATCH 01/11] Add option to ignore blacklist --- README.md | 3 +++ helpers/trakt.py | 10 ++++++++-- traktarr.py | 39 ++++++++++++++++++++++++--------------- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 1c58e2e..b652b01 100644 --- a/README.md +++ b/README.md @@ -726,6 +726,7 @@ You can customize how the scheduled traktarr is ran by editing the `traktarr.ser --no-search Disable search when adding to Sonarr / Radarr. --run-now Do a first run immediately without waiting. --no-notifications Disable notifications. + --ignore-blacklist Ignores the blacklist when running the command. --help Show this message and exit. ``` @@ -809,6 +810,7 @@ Options: -f, --folder TEXT Add movies with this root folder to Radarr. --no-search Disable search when adding movies to Radarr. --notifications Send notifications. + --ignore-blacklist Ignores the blacklist when running the command. --authenticate-user TEXT Specify which user to authenticate with to retrieve Trakt lists. Default: first user in the config. @@ -861,6 +863,7 @@ Options: -f, --folder TEXT Add shows with this root folder to Sonarr. --no-search Disable search when adding shows to Sonarr. --notifications Send notifications. + --ignore-blacklist Ignores the blacklist when running the command. --authenticate-user TEXT Specify which user to authenticate with to retrieve Trakt lists. Default: first user in the config diff --git a/helpers/trakt.py b/helpers/trakt.py index 6e65ccb..484d28a 100644 --- a/helpers/trakt.py +++ b/helpers/trakt.py @@ -106,7 +106,10 @@ def blacklisted_show_id(show, blacklisted_ids): return blacklisted -def is_show_blacklisted(show, blacklist_settings): +def is_show_blacklisted(show, blacklist_settings, ignore_blacklist): + if ignore_blacklist: + return False + blacklisted = False try: if blacklisted_show_year(show, blacklist_settings.blacklisted_min_year, @@ -228,7 +231,10 @@ def blacklisted_movie_id(movie, blacklisted_ids): return blacklisted -def is_movie_blacklisted(movie, blacklist_settings): +def is_movie_blacklisted(movie, blacklist_settings, ignore_blacklist): + if ignore_blacklist: + return False + blacklisted = False try: if blacklisted_movie_title(movie, blacklist_settings.blacklist_title_keywords): diff --git a/traktarr.py b/traktarr.py index 4718e74..6a5a34c 100755 --- a/traktarr.py +++ b/traktarr.py @@ -181,8 +181,9 @@ def show(show_id, folder=None, no_search=False): @click.option('--notifications', is_flag=True, help='Send notifications.') @click.option('--authenticate-user', help='Specify which user to authenticate with to retrieve Trakt lists. Default: first user in the config') +@click.option('--ignore-blacklist', is_flag=True, help='Ignores the blacklist when running the command.') def shows(list_type, add_limit=0, add_delay=2.5, genre=None, folder=None, no_search=False, notifications=False, - authenticate_user=None): + authenticate_user=None, ignore_blacklist=False): from media.sonarr import Sonarr from media.trakt import Trakt from helpers import misc as misc_helper @@ -260,7 +261,7 @@ def shows(list_type, add_limit=0, add_delay=2.5, genre=None, folder=None, no_sea continue # check if series passes out blacklist criteria inspection - if not trakt_helper.is_show_blacklisted(series, cfg.filters.shows): + if not trakt_helper.is_show_blacklisted(series, cfg.filters.shows, ignore_blacklist): log.info("Adding: %s | Genres: %s | Network: %s | Country: %s", series['show']['title'], ', '.join(series['show']['genres']), series['show']['network'], series['show']['country'].upper()) @@ -358,8 +359,9 @@ def movie(movie_id, folder=None, no_search=False): @click.option('--notifications', is_flag=True, help='Send notifications.') @click.option('--authenticate-user', help='Specify which user to authenticate with to retrieve Trakt lists. Default: first user in the config.') +@click.option('--ignore-blacklist', is_flag=True, help='Ignores the blacklist when running the command.') def movies(list_type, add_limit=0, add_delay=2.5, genre=None, folder=None, no_search=False, notifications=False, - authenticate_user=None): + authenticate_user=None, ignore_blacklist=False): from media.radarr import Radarr from media.trakt import Trakt from helpers import misc as misc_helper @@ -438,7 +440,7 @@ def movies(list_type, add_limit=0, add_delay=2.5, genre=None, folder=None, no_se continue # check if movie passes out blacklist criteria inspection - if not trakt_helper.is_movie_blacklisted(movie, cfg.filters.movies): + if not trakt_helper.is_movie_blacklisted(movie, cfg.filters.movies, ignore_blacklist): log.info("Adding: %s (%d) | Genres: %s | Country: %s", movie['movie']['title'], movie['movie']['year'], ', '.join(movie['movie']['genres']), movie['movie']['country'].upper()) # add movie to radarr @@ -499,7 +501,7 @@ def callback_notify(data): return -def automatic_shows(add_delay=2.5, no_search=False, notifications=False): +def automatic_shows(add_delay=2.5, no_search=False, notifications=False, ignore_blacklist=False): from media.trakt import Trakt total_shows_added = 0 @@ -524,7 +526,7 @@ def automatic_shows(add_delay=2.5, no_search=False, notifications=False): # run shows added_shows = shows.callback(list_type=list_type, add_limit=limit, add_delay=add_delay, no_search=no_search, - notifications=notifications) + notifications=notifications, ignore_blacklist=ignore_blacklist) elif list_type.lower() == 'watchlist': for authenticate_user, limit in value.items(): if limit <= 0: @@ -536,7 +538,8 @@ def automatic_shows(add_delay=2.5, no_search=False, notifications=False): # run shows added_shows = shows.callback(list_type=list_type, add_limit=limit, add_delay=add_delay, no_search=no_search, - notifications=notifications, authenticate_user=authenticate_user) + notifications=notifications, authenticate_user=authenticate_user, + ignore_blacklist=ignore_blacklist) elif list_type.lower() == 'lists': for list, v in value.items(): if isinstance(v, dict): @@ -549,7 +552,8 @@ def automatic_shows(add_delay=2.5, no_search=False, notifications=False): # run shows added_shows = shows.callback(list_type=list, add_limit=limit, add_delay=add_delay, no_search=no_search, - notifications=notifications, authenticate_user=authenticate_user) + notifications=notifications, authenticate_user=authenticate_user, + ignore_blacklist=ignore_blacklist) if added_shows is None: log.error("Failed adding shows from Trakt's %s list", list_type) @@ -570,7 +574,7 @@ def automatic_shows(add_delay=2.5, no_search=False, notifications=False): return -def automatic_movies(add_delay=2.5, no_search=False, notifications=False): +def automatic_movies(add_delay=2.5, no_search=False, notifications=False, ignore_blacklist=False): from media.trakt import Trakt total_movies_added = 0 @@ -595,7 +599,7 @@ def automatic_movies(add_delay=2.5, no_search=False, notifications=False): # run movies added_movies = movies.callback(list_type=list_type, add_limit=limit, add_delay=add_delay, no_search=no_search, - notifications=notifications) + notifications=notifications, ignore_blacklist=ignore_blacklist) elif list_type.lower() == 'watchlist': for authenticate_user, limit in value.items(): if limit <= 0: @@ -607,7 +611,8 @@ def automatic_movies(add_delay=2.5, no_search=False, notifications=False): # run movies added_movies = movies.callback(list_type=list_type, add_limit=limit, add_delay=add_delay, no_search=no_search, - notifications=notifications, authenticate_user=authenticate_user) + notifications=notifications, authenticate_user=authenticate_user, + ignore_blacklist=ignore_blacklist) elif list_type.lower() == 'lists': for list, v in value.items(): if isinstance(v, dict): @@ -620,7 +625,8 @@ def automatic_movies(add_delay=2.5, no_search=False, notifications=False): # run shows added_movies = movies.callback(list_type=list, add_limit=limit, add_delay=add_delay, no_search=no_search, - notifications=notifications, authenticate_user=authenticate_user) + notifications=notifications, authenticate_user=authenticate_user, + ignore_blacklist=ignore_blacklist) if added_movies is None: log.error("Failed adding movies from Trakt's %s list", list_type) @@ -647,7 +653,8 @@ def automatic_movies(add_delay=2.5, no_search=False, notifications=False): @click.option('--no-search', is_flag=True, help='Disable search when adding to Sonarr / Radarr.') @click.option('--run-now', is_flag=True, help="Do a first run immediately without waiting.") @click.option('--no-notifications', is_flag=True, help="Disable notifications.") -def run(add_delay=2.5, no_search=False, run_now=False, no_notifications=False): +@click.option('--ignore-blacklist', is_flag=True, help='Ignores the blacklist when running the command.') +def run(add_delay=2.5, no_search=False, run_now=False, no_notifications=False, ignore_blacklist=False): log.info("Automatic mode is now running...") # Add tasks to schedule and do first run if enabled @@ -656,7 +663,8 @@ def run(add_delay=2.5, no_search=False, run_now=False, no_notifications=False): automatic_movies, add_delay, no_search, - not no_notifications + not no_notifications, + ignore_blacklist ) if run_now: movie_schedule.run() @@ -669,7 +677,8 @@ def run(add_delay=2.5, no_search=False, run_now=False, no_notifications=False): automatic_shows, add_delay, no_search, - not no_notifications + not no_notifications, + ignore_blacklist ) if run_now: shows_schedule.run() From 2061c2e42ce5f2f3244676e0c83801dcc02e0174 Mon Sep 17 00:00:00 2001 From: Mitchell Klijs Date: Wed, 30 May 2018 18:33:39 +0200 Subject: [PATCH 02/11] Add ability to specify blacklist ignore in config --- README.md | 27 +++++++++++++++++++++++++++ misc/config.py | 2 ++ traktarr.py | 42 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b652b01..10e7385 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,7 @@ You can repeat this process for as many users as you like. }, "filters": { "movies": { + "disabled_for": [], "allowed_countries": [ "us", "gb", @@ -215,6 +216,7 @@ You can repeat this process for as many users as you like. "blacklisted_tmdb_ids": [] }, "shows": { + "disabled_for": [], "allowed_countries": [ "us", "gb", @@ -444,6 +446,7 @@ Use filters to specify the movie/shows's country of origin or blacklist (i.e. fi ```json "movies": { + "disabled_for": [], "allowed_countries": [ "us", "gb", @@ -466,6 +469,18 @@ Use filters to specify the movie/shows's country of origin or blacklist (i.e. fi }, ``` +`disabled_for` - specify for which lists the blacklist must be disabled when running in automatic mode + +Example: + +``` + "disabled_for": [ + "anticipated", + "watchlist:user1", + "list:http://url-to-list" + ], +``` + `allowed_countries` - only add movies from these countries. `allowed_languages` - only add movies with these languages (default/blank=English). @@ -530,6 +545,18 @@ Use filters to specify the movie/shows's country of origin or blacklist (i.e. fi } ``` +`disabled_for` - specify for which lists the blacklist must be disabled when running in automatic mode + +Example: + +``` + "disabled_for": [ + "anticipated", + "watchlist:user1", + "list:http://url-to-list" + ], +``` + `allowed_countries` - only add shows from these countries. `allowed_languages` - only add shows with these languages (default/blank=English). diff --git a/misc/config.py b/misc/config.py index f123139..e3fbfba 100644 --- a/misc/config.py +++ b/misc/config.py @@ -57,6 +57,7 @@ class Config(object, metaclass=Singleton): }, 'filters': { 'shows': { + 'disabled_for': [], 'blacklisted_genres': [], 'blacklisted_networks': [], 'allowed_countries': [], @@ -67,6 +68,7 @@ class Config(object, metaclass=Singleton): 'blacklisted_tvdb_ids': [], }, 'movies': { + 'disabled_for': [], 'blacklisted_genres': [], 'blacklisted_min_runtime': 60, 'blacklisted_min_year': 2000, diff --git a/traktarr.py b/traktarr.py index 6a5a34c..3ab9baf 100755 --- a/traktarr.py +++ b/traktarr.py @@ -523,10 +523,15 @@ def automatic_shows(add_delay=2.5, no_search=False, notifications=False, ignore_ else: log.info("Adding %d shows from Trakt's %s list", limit, list_type) + local_ignore_blacklist = ignore_blacklist + + if list_type.lower() in cfg.filters.shows.disabled_for: + local_ignore_blacklist = True + # run shows added_shows = shows.callback(list_type=list_type, add_limit=limit, add_delay=add_delay, no_search=no_search, - notifications=notifications, ignore_blacklist=ignore_blacklist) + notifications=notifications, ignore_blacklist=local_ignore_blacklist) elif list_type.lower() == 'watchlist': for authenticate_user, limit in value.items(): if limit <= 0: @@ -535,11 +540,16 @@ def automatic_shows(add_delay=2.5, no_search=False, notifications=False, ignore_ else: log.info("Adding %d shows from the %s from %s", limit, list_type, authenticate_user) + local_ignore_blacklist = ignore_blacklist + + if "watchlist:%s".format(authenticate_user) in cfg.filters.shows.disabled_for: + local_ignore_blacklist = True + # run shows added_shows = shows.callback(list_type=list_type, add_limit=limit, add_delay=add_delay, no_search=no_search, notifications=notifications, authenticate_user=authenticate_user, - ignore_blacklist=ignore_blacklist) + ignore_blacklist=local_ignore_blacklist) elif list_type.lower() == 'lists': for list, v in value.items(): if isinstance(v, dict): @@ -549,11 +559,16 @@ def automatic_shows(add_delay=2.5, no_search=False, notifications=False, ignore_ authenticate_user = None limit = v + local_ignore_blacklist = ignore_blacklist + + if "list:%s".format(list) in cfg.filters.shows.disabled_for: + local_ignore_blacklist = True + # run shows added_shows = shows.callback(list_type=list, add_limit=limit, add_delay=add_delay, no_search=no_search, notifications=notifications, authenticate_user=authenticate_user, - ignore_blacklist=ignore_blacklist) + ignore_blacklist=local_ignore_blacklist) if added_shows is None: log.error("Failed adding shows from Trakt's %s list", list_type) @@ -596,10 +611,15 @@ def automatic_movies(add_delay=2.5, no_search=False, notifications=False, ignore else: log.info("Adding %d movies from Trakt's %s list", limit, list_type) + local_ignore_blacklist = ignore_blacklist + + if list_type.lower() in cfg.filters.movies.disabled_for: + local_ignore_blacklist = True + # run movies added_movies = movies.callback(list_type=list_type, add_limit=limit, add_delay=add_delay, no_search=no_search, - notifications=notifications, ignore_blacklist=ignore_blacklist) + notifications=notifications, ignore_blacklist=local_ignore_blacklist) elif list_type.lower() == 'watchlist': for authenticate_user, limit in value.items(): if limit <= 0: @@ -608,11 +628,16 @@ def automatic_movies(add_delay=2.5, no_search=False, notifications=False, ignore else: log.info("Adding %d movies from the %s from %s", limit, list_type, authenticate_user) + local_ignore_blacklist = ignore_blacklist + + if "watchlist:%s".format(authenticate_user) in cfg.filters.movies.disabled_for: + local_ignore_blacklist = True + # run movies added_movies = movies.callback(list_type=list_type, add_limit=limit, add_delay=add_delay, no_search=no_search, notifications=notifications, authenticate_user=authenticate_user, - ignore_blacklist=ignore_blacklist) + ignore_blacklist=local_ignore_blacklist) elif list_type.lower() == 'lists': for list, v in value.items(): if isinstance(v, dict): @@ -622,11 +647,16 @@ def automatic_movies(add_delay=2.5, no_search=False, notifications=False, ignore authenticate_user = None limit = v + local_ignore_blacklist = ignore_blacklist + + if "list:%s".format(list) in cfg.filters.movies.disabled_for: + local_ignore_blacklist = True + # run shows added_movies = movies.callback(list_type=list, add_limit=limit, add_delay=add_delay, no_search=no_search, notifications=notifications, authenticate_user=authenticate_user, - ignore_blacklist=ignore_blacklist) + ignore_blacklist=local_ignore_blacklist) if added_movies is None: log.error("Failed adding movies from Trakt's %s list", list_type) From d3da1d02ad83313b08524790ce59a9049a55b92c Mon Sep 17 00:00:00 2001 From: Mitchell Klijs Date: Wed, 30 May 2018 21:44:06 +0200 Subject: [PATCH 03/11] Add priorty to pushover notifications --- README.md | 8 ++++++-- notifications/pushover.py | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1c58e2e..1c6c8d0 100644 --- a/README.md +++ b/README.md @@ -259,7 +259,8 @@ You can repeat this process for as many users as you like. "pushover": { "service": "pushover", "app_token": "", - "user_token": "" + "user_token": "", + "priority": 0 }, "slack": { "service": "slack", @@ -564,7 +565,8 @@ Currently, only Pushover and Slack are supported. More will be added later. "pushover": { "service": "pushover", "app_token": "", - "user_token": "" + "user_token": "", + "priority": 0 }, "slack": { "service": "slack", @@ -582,6 +584,8 @@ Currently, only Pushover and Slack are supported. More will be added later. `app_token` and `user_token` - retrieve from Pushover.net. +You can specify a priority for the messages send via Pushover using the priority key. It can be any Pushover priority value (https://pushover.net/api#priority). + _Note: The key name (i.e the name right under notifications) can be anything, but the `"service":` must be exactly `"pushover"`._ diff --git a/notifications/pushover.py b/notifications/pushover.py index 9374dc1..35f8ddd 100644 --- a/notifications/pushover.py +++ b/notifications/pushover.py @@ -8,9 +8,10 @@ log = logger.get_logger(__name__) class Pushover: NAME = "Pushover" - def __init__(self, app_token, user_token): + def __init__(self, app_token, user_token, priority=0): self.app_token = app_token self.user_token = user_token + self.priority = priority log.debug("Initialized Pushover notification agent") def send(self, **kwargs): @@ -23,7 +24,8 @@ class Pushover: payload = { 'token': self.app_token, 'user': self.user_token, - 'message': kwargs['message'] + 'message': kwargs['message'], + 'priority': self.priority, } resp = requests.post('https://api.pushover.net/1/messages.json', data=payload, timeout=30) return True if resp.status_code == 200 else False From 913154abc376fb699ccfe68a5eb4298db8c83b52 Mon Sep 17 00:00:00 2001 From: desimaniac Date: Wed, 30 May 2018 14:49:15 -0500 Subject: [PATCH 04/11] Readme: Priority tweak. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c6c8d0..269ba27 100644 --- a/README.md +++ b/README.md @@ -584,7 +584,7 @@ Currently, only Pushover and Slack are supported. More will be added later. `app_token` and `user_token` - retrieve from Pushover.net. -You can specify a priority for the messages send via Pushover using the priority key. It can be any Pushover priority value (https://pushover.net/api#priority). +You can specify a priority for the messages send via Pushover using the `priority` key. It can be any Pushover priority value (https://pushover.net/api#priority). _Note: The key name (i.e the name right under notifications) can be anything, but the `"service":` must be exactly `"pushover"`._ From 870ba81fed650b514a0bbf8e3e02f2ec2dcef635 Mon Sep 17 00:00:00 2001 From: James Date: Thu, 31 May 2018 22:10:06 +0100 Subject: [PATCH 05/11] added ability to sort list by votes/rating/release date (first aired for tv) --- helpers/misc.py | 14 ++++++++++++++ traktarr.py | 34 ++++++++++++++++++++++++++-------- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/helpers/misc.py b/helpers/misc.py index 0c6572b..b217584 100644 --- a/helpers/misc.py +++ b/helpers/misc.py @@ -1,3 +1,5 @@ +from copy import copy + from misc.log import logger log = logger.get_logger(__name__) @@ -63,3 +65,15 @@ def allowed_genres(genre, object_type, trakt_object): allowed_object = True break return allowed_object + + +def sorted_list(original_list, list_type, sort_key, reverse=True): + prepared_list = copy(original_list) + for item in prepared_list: + if not item[list_type][sort_key]: + if sort_key == 'released' or sort_key == 'first_aired': + item[list_type][sort_key] = "" + else: + item[list_type][sort_key] = 0 + + return sorted(prepared_list, key=lambda k: k[list_type][sort_key], reverse=reverse) diff --git a/traktarr.py b/traktarr.py index 4718e74..88678c8 100755 --- a/traktarr.py +++ b/traktarr.py @@ -175,13 +175,15 @@ def show(show_id, folder=None, no_search=False): required=True) @click.option('--add-limit', '-l', default=0, help='Limit number of shows added to Sonarr.', show_default=True) @click.option('--add-delay', '-d', default=2.5, help='Seconds between each add request to Sonarr.', show_default=True) +@click.option('--sort', '-s', default='votes', type=click.Choice(['votes', 'rating', 'release']), + help='Sort list to process.') @click.option('--genre', '-g', default=None, help='Only add shows from this genre to Sonarr.') @click.option('--folder', '-f', default=None, help='Add shows with this root folder to Sonarr.') @click.option('--no-search', is_flag=True, help='Disable search when adding shows to Sonarr.') @click.option('--notifications', is_flag=True, help='Send notifications.') @click.option('--authenticate-user', help='Specify which user to authenticate with to retrieve Trakt lists. Default: first user in the config') -def shows(list_type, add_limit=0, add_delay=2.5, genre=None, folder=None, no_search=False, notifications=False, +def shows(list_type, add_limit=0, add_delay=2.5, sort='votes', genre=None, folder=None, no_search=False, notifications=False, authenticate_user=None): from media.sonarr import Sonarr from media.trakt import Trakt @@ -246,9 +248,16 @@ def shows(list_type, add_limit=0, add_delay=2.5, genre=None, folder=None, no_sea log.info("Removed existing Sonarr shows from Trakt shows list, shows left to process: %d", len(processed_series_list)) - # sort filtered series list by highest votes - sorted_series_list = sorted(processed_series_list, key=lambda k: k['show']['votes'], reverse=True) - log.info("Sorted shows list to process by highest votes") + # sort filtered series list + if sort == 'release': + sorted_series_list = misc_helper.sorted_list(processed_series_list, 'show', 'first_aired') + log.info("Sorted shows list to process by release date") + elif sort == 'rating': + sorted_series_list = misc_helper.sorted_list(processed_series_list, 'show', 'rating') + log.info("Sorted shows list to process by highest rating") + else: + sorted_series_list = misc_helper.sorted_list(processed_series_list, 'show', 'votes') + log.info("Sorted shows list to process by highest votes") # loop series_list log.info("Processing list now...") @@ -352,13 +361,15 @@ def movie(movie_id, folder=None, no_search=False): 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) +@click.option('--sort', '-s', default='votes', type=click.Choice(['votes', 'rating', 'release']), + help='Sort list to process.') @click.option('--genre', '-g', default=None, help='Only add movies from this genre to Radarr.') @click.option('--folder', '-f', default=None, help='Add movies with this root folder to Radarr.') @click.option('--no-search', is_flag=True, help='Disable search when adding movies to Radarr.') @click.option('--notifications', is_flag=True, help='Send notifications.') @click.option('--authenticate-user', help='Specify which user to authenticate with to retrieve Trakt lists. Default: first user in the config.') -def movies(list_type, add_limit=0, add_delay=2.5, genre=None, folder=None, no_search=False, notifications=False, +def movies(list_type, add_limit=0, add_delay=2.5, sort='votes', genre=None, folder=None, no_search=False, notifications=False, authenticate_user=None): from media.radarr import Radarr from media.trakt import Trakt @@ -424,9 +435,16 @@ def movies(list_type, add_limit=0, add_delay=2.5, genre=None, folder=None, no_se log.info("Removed existing Radarr movies from Trakt movies list, movies left to process: %d", len(processed_movies_list)) - # sort filtered movie list by highest votes - sorted_movies_list = sorted(processed_movies_list, key=lambda k: k['movie']['votes'], reverse=True) - log.info("Sorted movie list to process by highest votes") + # sort filtered movie list + if sort == 'release': + sorted_movies_list = misc_helper.sorted_list(processed_movies_list, 'movie', 'released') + log.info("Sorted movies list to process by release date") + elif sort == 'rating': + sorted_movies_list = misc_helper.sorted_list(processed_movies_list, 'movie', 'rating') + log.info("Sorted movies list to process by highest rating") + else: + sorted_movies_list = misc_helper.sorted_list(processed_movies_list, 'movie', 'votes') + log.info("Sorted movies list to process by highest votes") # loop movies log.info("Processing list now...") From 961486d48b8fceb4fa98a08164fd67b1770bc27d Mon Sep 17 00:00:00 2001 From: James Date: Fri, 1 Jun 2018 21:25:40 +0100 Subject: [PATCH 06/11] add --sort/-s to run mode. --- traktarr.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/traktarr.py b/traktarr.py index 88678c8..00fc4b1 100755 --- a/traktarr.py +++ b/traktarr.py @@ -183,8 +183,8 @@ def show(show_id, folder=None, no_search=False): @click.option('--notifications', is_flag=True, help='Send notifications.') @click.option('--authenticate-user', help='Specify which user to authenticate with to retrieve Trakt lists. Default: first user in the config') -def shows(list_type, add_limit=0, add_delay=2.5, sort='votes', genre=None, folder=None, no_search=False, notifications=False, - authenticate_user=None): +def shows(list_type, add_limit=0, add_delay=2.5, sort='votes', genre=None, folder=None, no_search=False, + notifications=False, authenticate_user=None): from media.sonarr import Sonarr from media.trakt import Trakt from helpers import misc as misc_helper @@ -369,8 +369,8 @@ def movie(movie_id, folder=None, no_search=False): @click.option('--notifications', is_flag=True, help='Send notifications.') @click.option('--authenticate-user', help='Specify which user to authenticate with to retrieve Trakt lists. Default: first user in the config.') -def movies(list_type, add_limit=0, add_delay=2.5, sort='votes', genre=None, folder=None, no_search=False, notifications=False, - authenticate_user=None): +def movies(list_type, add_limit=0, add_delay=2.5, sort='votes', genre=None, folder=None, no_search=False, + notifications=False, authenticate_user=None): from media.radarr import Radarr from media.trakt import Trakt from helpers import misc as misc_helper @@ -517,7 +517,7 @@ def callback_notify(data): return -def automatic_shows(add_delay=2.5, no_search=False, notifications=False): +def automatic_shows(add_delay=2.5, sort='votes', no_search=False, notifications=False): from media.trakt import Trakt total_shows_added = 0 @@ -541,7 +541,7 @@ def automatic_shows(add_delay=2.5, no_search=False, notifications=False): # run shows added_shows = shows.callback(list_type=list_type, add_limit=limit, - add_delay=add_delay, no_search=no_search, + add_delay=add_delay, sort=sort, no_search=no_search, notifications=notifications) elif list_type.lower() == 'watchlist': for authenticate_user, limit in value.items(): @@ -553,7 +553,7 @@ def automatic_shows(add_delay=2.5, no_search=False, notifications=False): # run shows added_shows = shows.callback(list_type=list_type, add_limit=limit, - add_delay=add_delay, no_search=no_search, + add_delay=add_delay, sort=sort, no_search=no_search, notifications=notifications, authenticate_user=authenticate_user) elif list_type.lower() == 'lists': for list, v in value.items(): @@ -566,7 +566,7 @@ def automatic_shows(add_delay=2.5, no_search=False, notifications=False): # run shows added_shows = shows.callback(list_type=list, add_limit=limit, - add_delay=add_delay, no_search=no_search, + add_delay=add_delay, sort=sort, no_search=no_search, notifications=notifications, authenticate_user=authenticate_user) if added_shows is None: @@ -588,7 +588,7 @@ def automatic_shows(add_delay=2.5, no_search=False, notifications=False): return -def automatic_movies(add_delay=2.5, no_search=False, notifications=False): +def automatic_movies(add_delay=2.5, sort='votes', no_search=False, notifications=False): from media.trakt import Trakt total_movies_added = 0 @@ -612,7 +612,7 @@ def automatic_movies(add_delay=2.5, no_search=False, notifications=False): # run movies added_movies = movies.callback(list_type=list_type, add_limit=limit, - add_delay=add_delay, no_search=no_search, + add_delay=add_delay, sort=sort, no_search=no_search, notifications=notifications) elif list_type.lower() == 'watchlist': for authenticate_user, limit in value.items(): @@ -624,7 +624,7 @@ def automatic_movies(add_delay=2.5, no_search=False, notifications=False): # run movies added_movies = movies.callback(list_type=list_type, add_limit=limit, - add_delay=add_delay, no_search=no_search, + add_delay=add_delay, sort=sort, no_search=no_search, notifications=notifications, authenticate_user=authenticate_user) elif list_type.lower() == 'lists': for list, v in value.items(): @@ -637,7 +637,7 @@ def automatic_movies(add_delay=2.5, no_search=False, notifications=False): # run shows added_movies = movies.callback(list_type=list, add_limit=limit, - add_delay=add_delay, no_search=no_search, + add_delay=add_delay, sort=sort, no_search=no_search, notifications=notifications, authenticate_user=authenticate_user) if added_movies is None: @@ -662,10 +662,12 @@ def automatic_movies(add_delay=2.5, no_search=False, notifications=False): @app.command(help='Run in automatic mode.') @click.option('--add-delay', '-d', default=2.5, help='Seconds between each add request to Sonarr / Radarr.', show_default=True) +@click.option('--sort', '-s', default='votes', type=click.Choice(['votes', 'rating', 'release']), + help='Sort list to process.') @click.option('--no-search', is_flag=True, help='Disable search when adding to Sonarr / Radarr.') @click.option('--run-now', is_flag=True, help="Do a first run immediately without waiting.") @click.option('--no-notifications', is_flag=True, help="Disable notifications.") -def run(add_delay=2.5, no_search=False, run_now=False, no_notifications=False): +def run(add_delay=2.5, sort='votes', no_search=False, run_now=False, no_notifications=False): log.info("Automatic mode is now running...") # Add tasks to schedule and do first run if enabled @@ -673,6 +675,7 @@ def run(add_delay=2.5, no_search=False, run_now=False, no_notifications=False): movie_schedule = schedule.every(cfg.automatic.movies.interval).hours.do( automatic_movies, add_delay, + sort, no_search, not no_notifications ) @@ -686,6 +689,7 @@ def run(add_delay=2.5, no_search=False, run_now=False, no_notifications=False): shows_schedule = schedule.every(cfg.automatic.shows.interval).hours.do( automatic_shows, add_delay, + sort, no_search, not no_notifications ) From 2a0cd29c8eb40d7f0071a46d92271f678f6ca980 Mon Sep 17 00:00:00 2001 From: James Date: Sat, 2 Jun 2018 12:31:31 +0100 Subject: [PATCH 07/11] small code formatting change --- traktarr.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/traktarr.py b/traktarr.py index d8d3220..dd437cb 100755 --- a/traktarr.py +++ b/traktarr.py @@ -242,8 +242,8 @@ def shows(list_type, add_limit=0, add_delay=2.5, sort='votes', genre=None, folde log.error("Aborting due to failure to remove existing Sonarr shows from retrieved Trakt shows list") if notifications: callback_notify({'event': 'abort', 'type': 'shows', 'list_type': list_type, - 'reason': 'Failure to remove existing Sonarr shows from retrieved Trakt %s shows list' % list_type - }) + 'reason': 'Failure to remove existing Sonarr shows from retrieved Trakt %s shows list' + % list_type}) return None else: log.info("Removed existing Sonarr shows from Trakt shows list, shows left to process: %d", From d27ee19f3be67d251d24dbbe3924b33b20c18e34 Mon Sep 17 00:00:00 2001 From: James Date: Sun, 3 Jun 2018 01:26:20 +0100 Subject: [PATCH 08/11] added watched + played list type (can use, watched_weekly/monthly/yearly/all) --- helpers/misc.py | 5 +++++ media/trakt.py | 40 ++++++++++++++++++++++++++++++++++++++++ traktarr.py | 27 ++++++++++++++++++++++----- 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/helpers/misc.py b/helpers/misc.py index b217584..d0ba333 100644 --- a/helpers/misc.py +++ b/helpers/misc.py @@ -77,3 +77,8 @@ def sorted_list(original_list, list_type, sort_key, reverse=True): item[list_type][sort_key] = 0 return sorted(prepared_list, key=lambda k: k[list_type][sort_key], reverse=reverse) + + +# reference: https://stackoverflow.com/a/16712886 +def substring_after(s, delim): + return s.partition(delim)[2] diff --git a/media/trakt.py b/media/trakt.py index 69fd1af..f87232a 100644 --- a/media/trakt.py +++ b/media/trakt.py @@ -343,6 +343,26 @@ class Trakt: genres=genres ) + 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 + ) + + 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 + ) + 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', @@ -407,6 +427,26 @@ class Trakt: genres=genres ) + 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 + ) + + 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 + ) + def get_boxoffice_movies(self, limit=1000, languages=None): return self._make_items_request( url='https://api.trakt.tv/movies/boxoffice', diff --git a/traktarr.py b/traktarr.py index dd437cb..e8f1dc5 100755 --- a/traktarr.py +++ b/traktarr.py @@ -114,7 +114,8 @@ def get_objects(pvr, type, notifications): if notifications: callback_notify({'event': 'error', 'reason': 'Failure to retrieve %s shows list' % type}) exit() - log.info("Retrieved %s shows list, shows found: %d", type, len(objects_list)) + objects_type = 'movies' if type.lower() == 'radarr' else 'shows' + log.info("Retrieved %s %s list, %s found: %d", type, objects_type, objects_type, len(objects_list)) return objects_list @@ -171,8 +172,8 @@ def show(show_id, folder=None, no_search=False): @app.command(help='Add multiple 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', - required=True) + help='Trakt list to process. For example, anticipated, trending, popular, watched, played, watchlist ' + 'or any URL to a list', required=True) @click.option('--add-limit', '-l', default=0, help='Limit number of shows added to Sonarr.', show_default=True) @click.option('--add-delay', '-d', default=2.5, help='Seconds between each add request to Sonarr.', show_default=True) @click.option('--sort', '-s', default='votes', type=click.Choice(['votes', 'rating', 'release']), @@ -221,6 +222,14 @@ def shows(list_type, add_limit=0, add_delay=2.5, sort='votes', genre=None, folde 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, 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, 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, languages=cfg.filters.shows.allowed_languages, + most_type=most_type if most_type else None) elif list_type.lower() == 'watchlist': trakt_objects_list = trakt.get_watchlist_shows(authenticate_user) else: @@ -357,8 +366,8 @@ def movie(movie_id, folder=None, no_search=False): @app.command(help='Add multiple 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, watched, played, ' + '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) @@ -409,6 +418,14 @@ def movies(list_type, add_limit=0, add_delay=2.5, sort='votes', genre=None, fold 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() + 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, 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, languages=cfg.filters.movies.allowed_languages, + most_type=most_type if most_type else None) elif list_type.lower() == 'watchlist': trakt_objects_list = trakt.get_watchlist_movies(authenticate_user) else: From 7e1dd2f2d91860dcf10dcfa61ad698fbf036524a Mon Sep 17 00:00:00 2001 From: Filipe Santos Date: Sun, 3 Jun 2018 12:41:24 +1200 Subject: [PATCH 09/11] Fix sleep on creating tasks --- traktarr.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/traktarr.py b/traktarr.py index e8f1dc5..3f1ecdd 100755 --- a/traktarr.py +++ b/traktarr.py @@ -737,8 +737,8 @@ def run(add_delay=2.5, sort='votes', no_search=False, run_now=False, no_notifica if run_now: movie_schedule.run() - # Sleep between tasks - time.sleep(add_delay) + # Sleep between tasks + time.sleep(add_delay) if cfg.automatic.shows.interval: shows_schedule = schedule.every(cfg.automatic.shows.interval).hours.do( @@ -752,6 +752,9 @@ def run(add_delay=2.5, sort='votes', no_search=False, run_now=False, no_notifica if run_now: shows_schedule.run() + # Sleep between tasks + time.sleep(add_delay) + # Enter running schedule while True: try: From 92a1e2d649814432d83feac711f559b7226c2d29 Mon Sep 17 00:00:00 2001 From: James Date: Sun, 3 Jun 2018 01:49:03 +0100 Subject: [PATCH 10/11] enable auto mode with watched + played list types --- media/trakt.py | 2 +- traktarr.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/media/trakt.py b/media/trakt.py index f87232a..133f117 100644 --- a/media/trakt.py +++ b/media/trakt.py @@ -11,7 +11,7 @@ log = logger.get_logger(__name__) class Trakt: - non_user_lists = ['anticipated', 'trending', 'popular', 'boxoffice'] + non_user_lists = ['anticipated', 'trending', 'popular', 'boxoffice', 'watched', 'played'] def __init__(self, cfg): self.cfg = cfg diff --git a/traktarr.py b/traktarr.py index e8f1dc5..cb71193 100755 --- a/traktarr.py +++ b/traktarr.py @@ -549,7 +549,8 @@ def automatic_shows(add_delay=2.5, sort='votes', no_search=False, notifications= if list_type.lower() == 'interval': continue - if list_type.lower() in Trakt.non_user_lists: + if list_type.lower() in Trakt.non_user_lists or ( + '_' in list_type and list_type.lower().partition("_")[0] in Trakt.non_user_lists): limit = value if limit <= 0: @@ -637,7 +638,8 @@ def automatic_movies(add_delay=2.5, sort='votes', no_search=False, notifications if list_type.lower() == 'interval': continue - if list_type.lower() in Trakt.non_user_lists: + if list_type.lower() in Trakt.non_user_lists or ( + '_' in list_type and list_type.lower().partition("_")[0] in Trakt.non_user_lists): limit = value if limit <= 0: From c7034efb9728e8f581c1622994b8a16af2762ad2 Mon Sep 17 00:00:00 2001 From: James Date: Sun, 3 Jun 2018 13:29:53 +0100 Subject: [PATCH 11/11] increase version --- traktarr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traktarr.py b/traktarr.py index 3298da8..2294bb9 100755 --- a/traktarr.py +++ b/traktarr.py @@ -17,7 +17,7 @@ notify = None # Click @click.group(help='Add new shows & movies to Sonarr/Radarr from Trakt.') -@click.version_option('1.2.1', prog_name='traktarr') +@click.version_option('1.2.2', prog_name='traktarr') @click.option( '--config', envvar='TRAKTARR_CONFIG',