From 4b27d8b432f10faa4ec4c285feaee955b4c7fc09 Mon Sep 17 00:00:00 2001 From: Junkbite <62021344+Junkbite@users.noreply.github.com> Date: Thu, 16 Jul 2020 16:13:15 -0400 Subject: [PATCH 1/2] dont exit on error if in docker --- config.py | 2 ++ index.py | 49 ++++++++++++++++++++++++++++++------------------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/config.py b/config.py index 18743d3..a415f32 100644 --- a/config.py +++ b/config.py @@ -64,6 +64,8 @@ if DEV: settingsFilename = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'dev-{}'.format(BASE_CONFIG)) else: settingsFilename = os.path.join(os.path.abspath(os.path.dirname(__file__)), BASE_CONFIG) + sys.tracebacklimit = 0 # dont show stack traces in prod mode + config = configparser.ConfigParser() config.read(settingsFilename) diff --git a/index.py b/index.py index 8617268..6950d7c 100644 --- a/index.py +++ b/index.py @@ -100,7 +100,7 @@ def get_quality_profiles(instance_session, instance_url, instance_key): profiles_response = instance_session.get(instance_profile_url) if profiles_response.status_code != 200: logger.error(f'Could not get profile id from {instance_profile_url}') - sys.exit(0) + exit_system() instance_profiles = None try: @@ -108,7 +108,7 @@ def get_quality_profiles(instance_session, instance_url, instance_key): return instance_profiles except: logger.error(f'Could not decode profile id from {instance_profile_url}') - sys.exit(0) + exit_system() def get_profile_from_id(instance_session, instance_url, instance_key, instance_profile, instance_name=''): @@ -117,7 +117,7 @@ def get_profile_from_id(instance_session, instance_url, instance_key, instance_p profile = next((item for item in instance_profiles if item["name"].lower() == instance_profile.lower()), False) if not profile: logger.error('Could not find profile_id for instance {} profile {}'.format(instance_name, instance_profile)) - sys.exit(0) + exit_system() instance_profile_id = profile.get('id') logger.debug(f'found profile_id (instance{instance_name}) "{instance_profile_id}" from profile "{instance_profile}"') @@ -130,14 +130,14 @@ def get_tag_from_id(instance_session, instance_url, instance_key, instance_tag, tag_response = instance_session.get(instance_tag_url) if tag_response.status_code != 200: logger.error(f'Could not get tag id from (instance{instance_name}) {instance_tag_url} - only works on Sonarr') - sys.exit(0) + exit_system() instance_tags = None try: instance_tags = tag_response.json() except: logger.error(f'Could not decode tag id from {instance_tag_url}') - sys.exit(0) + exit_system() tag_ids = [] for item in instance_tags: @@ -147,14 +147,14 @@ def get_tag_from_id(instance_session, instance_url, instance_key, instance_tag, if not tag_ids: logger.error(f'Could not find tag_id for instance {instance_name} and tag {instance_tags}') - sys.exit(0) + exit_system() instance_tag_ids = [tag.get('id') for tag in tag_ids] logger.debug(f'found id "{instance_tag_ids}" from tag "{instance_tag}" for instance {instance_name}') if instance_tag_ids is None: logger.error(f'tag_id is None for instance {instance_name} and tag {instance_tag}') - sys.exit(0) + exit_system() return instance_tag_ids @@ -164,28 +164,28 @@ def get_language_from_id(instance_session, instance_url, instance_key, instance_ language_response = instance_session.get(instance_language_url) if language_response.status_code != 200: logger.error(f'Could not get language id from (instance{instance_name}) {instance_language_url} - only works on sonarr v3') - sys.exit(0) + exit_system() instance_languages = None try: instance_languages = language_response.json() except: logger.error(f'Could not decode language id from {instance_language_url}') - sys.exit(0) + exit_system() instance_languages = instance_languages[0]['languages'] language = next((item for item in instance_languages if item.get('language', {}).get('name').lower() == instance_language.lower()), False) if not language: logger.error(f'Could not find language_id for instance {instance_name} and language {instance_language}') - sys.exit(0) + exit_system() instance_language_id = language.get('language', {}).get('id') logger.debug(f'found id "{instance_language_id}" from language "{instance_language}" for instance {instance_name}') if instance_language_id is None: logger.error(f'language_id is None for instance {instance_name} and language {instance_language}') - sys.exit(0) + exit_system() return instance_language_id @@ -278,13 +278,13 @@ def get_instance_contents(instance_url, instance_key, instance_session, instance if instance_contents.status_code != 200: logger.error('instance{} server error - response {}'.format(instance_name, instance_contents.status_code)) - sys.exit(0) + exit_system() else: try: instance_contents = instance_contents.json() except: logger.error(f'Could not decode contents from {instance_content_url}') - sys.exit(0) + exit_system() for content_to_sync in instance_contents: instance_contentIds.append(content_to_sync[content_id_key]) @@ -310,7 +310,7 @@ def check_status(instance_session, instance_url, instance_key, instance_name='', status_response = check_status(instance_session, instance_url, instance_key, instance_name, True) elif status_response.status_code != 200: logger.error(error_message) - sys.exit(0) + exit_system() except: if not changed_api_version and not is_lidarr: @@ -320,7 +320,7 @@ def check_status(instance_session, instance_url, instance_key, instance_name='', if status_response is None: logger.error(error_message) - sys.exit(0) + exit_system() else: try: status_response = status_response.json() @@ -328,11 +328,11 @@ def check_status(instance_session, instance_url, instance_key, instance_name='', if not isinstance(status_response, dict): logger.error( f"Could not retrieve status for {instance_status_url}: {status_response} - {error}") - sys.exit(0) + exit_system() if(status_response.get('error')): logger.error(f"{instance_status_url} error {status_response.get('error')}") - sys.exit(0) + exit_system() logger.debug(f"{instance_status_url} version {status_response.get('version')}") @@ -461,6 +461,14 @@ def sync_content(): ######################################################################################################################## +def exit_system(): + """we dont want to exit if in docker""" + if is_in_docker: + raise Exception + else: + sys.exit(0) + + if is_in_docker: logger.info('syncing every {} seconds'.format(instance_sync_interval_seconds)) @@ -468,5 +476,8 @@ sync_content() if is_in_docker: while True: - time.sleep(instance_sync_interval_seconds) - sync_content() + try: + time.sleep(instance_sync_interval_seconds) + sync_content() + except Exception as inst: + d = inst From ad6856cfb48c42de077b810665453331d3c797a9 Mon Sep 17 00:00:00 2001 From: aljohn92 <16975578+aljohn92@users.noreply.github.com> Date: Wed, 21 Oct 2020 19:13:10 +0000 Subject: [PATCH 2/2] Added skip_missing config (#57) --- README.md | 2 ++ config.py | 11 +++++++++++ index.py | 9 ++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6854568..db60fa6 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Syncs two Radarr/Sonarr/Lidarr servers through the web API. Useful for syncing a * Supports Docker for multiple instances * Can set interval for syncing * Support two way sync (one way by default) +* Skip content with missing files * Set language profiles (Sonarr v3 only) * Filter syncing by content file quality (Radarr only) * Filter syncing by tags (Sonarr/Radarr v3 only) @@ -76,6 +77,7 @@ Syncs two Radarr/Sonarr/Lidarr servers through the web API. Useful for syncing a [general] sync_bidirectionally = 1 # sync from instance A to B **AND** instance B to A auto_search = 0 # search is automatically started on new content - disable by setting to 0 (default 1) + skip_missing = 1 # content with missing files are skipped on sync - disable by setting to 0 (default 1) monitor_new_content = 0 # set to 0 to never monitor new content synced or to 1 to always monitor new content synced (default 1) test_run = 1 # enable test mode - will run through sync program but will not actually sync content ``` diff --git a/config.py b/config.py index a415f32..711451e 100644 --- a/config.py +++ b/config.py @@ -170,6 +170,16 @@ if auto_search is not None: else: auto_search = 1 +# set to skip missing if config not set +skip_missing = get_config_value('SYNCARR_SKIP_MISSING', 'skip_missing', 'general') +if skip_missing is not None: + try: + skip_missing = int(skip_missing) + except ValueError: + skip_missing = 0 +else: + skip_missing = 1 + # set to monitor if config not set monitor_new_content = get_config_value('SYNCARR_MONITOR_NEW_CONTENT', 'monitor_new_content', 'general') if monitor_new_content is not None: @@ -497,6 +507,7 @@ logger.debug({ 'monitor_new_content': monitor_new_content, 'sync_bidirectionally': sync_bidirectionally, 'auto_search': auto_search, + 'skip_missing': skip_missing, 'api_version': api_version, }) diff --git a/index.py b/index.py index 6950d7c..49fd935 100644 --- a/index.py +++ b/index.py @@ -25,7 +25,7 @@ from config import ( get_status_path, get_content_path, get_profile_path, get_language_path, get_tag_path, is_in_docker, instance_sync_interval_seconds, - sync_bidirectionally, auto_search, monitor_new_content, + sync_bidirectionally, auto_search, skip_missing, monitor_new_content, tested_api_version, api_version, V3_API_PATH, is_test_run, ) @@ -207,6 +207,13 @@ def sync_servers(instanceA_contents, instanceB_language_id, instanceB_contentIds title = content.get('title') or content.get('artistName') instance_path = instanceB_path or dirname(content.get('path')) + # if skipping missing files, we want to skip any that don't have files + if skip_missing: + content_has_file = content.get('hasFile') + if not content_has_file: + logging.debug(f'Skipping content {title} - file missing') + continue + # if given this, we want to filter from instance by profile id if instanceA_profile_filter_id: quality_profile_id = content.get('qualityProfileId')