diff --git a/README.md b/README.md index db60fa6..c5da110 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # Syncarr + Syncs two Radarr/Sonarr/Lidarr servers through the web API. Useful for syncing a 4k Radarr/Sonarr instance to a 1080p Radarr/Sonarr instance. -* Supports Radarr/Sonarr version 2 and 3. +* Supports Radarr/Sonarr v3. * Can sync by `profile` name or `profile_id` * Filter what media gets synced by `profile` name or `profile_id` * Supports Docker for multiple instances @@ -13,11 +14,12 @@ Syncs two Radarr/Sonarr/Lidarr servers through the web API. Useful for syncing a * Filter syncing by tags (Sonarr/Radarr v3 only) * Allow for a test run using `test_run` flag (does everything but actually sync) - ## Configuration + 1. Edit the config.conf file and enter your servers URLs and API keys for each server. 2. Add the profile name (case insensitive) and movie path for the Radarr instance the movies will be synced to: - ```ini + + ```ini [radarrA] url = https://4k.example.com:443 key = XXXXX @@ -28,7 +30,9 @@ Syncs two Radarr/Sonarr/Lidarr servers through the web API. Useful for syncing a profile = 1080p path = /data/Movies # if not given will use RadarrA path for each movie - may not be what you want! ``` + 3. Or if you want to sync two Sonarr instances: + ```ini [sonarrA] url = https://4k.example.com:443 @@ -39,8 +43,9 @@ Syncs two Radarr/Sonarr/Lidarr servers through the web API. Useful for syncing a key = XXXXX profile = 1080p path = /data/Shows - + 4. Or if you want to sync two Lidarr instances: + 5. ```ini [lidarrA] url = https://lossless.example.com:443 @@ -55,7 +60,8 @@ Syncs two Radarr/Sonarr/Lidarr servers through the web API. Useful for syncing a **Note** you cannot have a mix of Radarr, Lidarr, or Sonarr config setups at the same time. - 5. Optional Configuration + 6. Optional Configuration + ```ini [*arrA] url = http://127.0.0.1:8080 @@ -106,7 +112,7 @@ Syncs two Radarr/Sonarr/Lidarr servers through the web API. Useful for syncing a ## Docker Compose This script can run through a docker container with a set interval (default every 5 minutes) -``` +```bash syncarr: image: syncarr/syncarr:latest container_name: syncarr @@ -123,7 +129,7 @@ syncarr: or -``` +```bash syncarr: image: syncarr/syncarr:latest container_name: syncarr @@ -140,7 +146,7 @@ syncarr: or -``` +```bash syncarr: image: syncarr/syncarr:latest container_name: syncarr @@ -156,14 +162,17 @@ syncarr: ``` --- + ## Docker + For just plain docker (radarr example): -``` +```bash docker run -it --rm --name syncarr -e RADARR_A_URL=https://4k.example.com:443 -e RADARR_A_KEY=XXXXX -e RADARR_B_URL=http://127.0.0.1:8080 -e RADARR_B_KEY=XXXXX -e RADARR_B_PROFILE=1080p -e RADARR_B_PATH=/data/Movies -e SYNC_INTERVAL_SECONDS=300 syncarr/syncarr ``` -**Notes** +## Notes + * You can also specify the `PROFILE_ID` directly through the `*ARR_A_PROFILE_ID` and `*ARR_B_PROFILE_ID` ENV variables. To filter by profile in docker use `*ARR_A_PROFILE_FILTER` or `*ARR_A_PROFILE_FILTER_ID` ENV variables. (same for `*arr_B` in bidirectional sync) * Language for new content (Sonarr v3 only) can be set by `SONARR_B_LANGUAGE` or `SONARR_B_LANGUAGE_ID` (and `SONARR_B` if bidirectional sync) @@ -176,16 +185,20 @@ To filter by profile in docker use `*ARR_A_PROFILE_FILTER` or `*ARR_A_PROFILE_FI * add blacklist with `*ARR_A_BLACKLIST` and `**ARR_B_BLACKLIST` --- + ## Troubleshooting + If you need to troubleshoot syncarr, then you can either set the log level through the config file: ```ini [general] log_level = 10 ``` - + Or in docker, set the `LOG_LEVEL` ENV variable. Default is set to `20` (info only) but you can set to `10` to get debug info as well. When pasting debug logs online, **make sure to remove any apikeys and any other data you don't want others to see.** --- + ## Disclaimer + Back up your instances before trying this out. I am not responsible for any lost data. diff --git a/config.py b/config.py index 711451e..fe615e1 100644 --- a/config.py +++ b/config.py @@ -277,8 +277,8 @@ instanceB_tag_filter = '' instanceB_tag_filter_id = '' instanceB_blacklist = '' -api_version = '' # we are going to detect what API version we are on -tested_api_version = False # only get api version once +api_version = '' + api_content_path = '' # url path to add content api_profile_path = '' # url path to get quality profiles @@ -317,9 +317,9 @@ if radarrA_url and radarrB_url: instanceB_quality_match = radarrB_quality_match instanceB_blacklist = radarrB_blacklist - api_version = V2_API_PATH # radarr v2 doesnt have version in api url + api_version = V3_API_PATH api_content_path = 'movie' - api_profile_path = 'profile' + api_profile_path = 'qualityprofile' api_status_path = 'system/status' content_id_key = 'tmdbId' @@ -354,7 +354,7 @@ elif sonarrA_url and sonarrB_url: instanceB_quality_match = sonarrB_quality_match instanceB_blacklist = sonarrB_blacklist - api_version = V3_API_PATH # for sonarr try v3 first + api_version = V3_API_PATH api_content_path = 'series' api_profile_path = 'qualityprofile' api_status_path = 'system/status' @@ -412,14 +412,6 @@ if instanceB_blacklist: def get_path(instance_url, api_path, key, changed_api_version=False): global api_version, api_profile_path - if changed_api_version: - api_version = V3_API_PATH - - # for sonarr - we check v3 first then v2 - if is_sonarr and changed_api_version: - api_version = V2_API_PATH - api_profile_path = 'profile' - logger.debug(DEBUG_LINE) logger.debug({ 'instance_url': instance_url, diff --git a/index.py b/index.py index 49fd935..b31950e 100644 --- a/index.py +++ b/index.py @@ -26,7 +26,7 @@ from config import ( is_in_docker, instance_sync_interval_seconds, sync_bidirectionally, auto_search, skip_missing, monitor_new_content, - tested_api_version, api_version, V3_API_PATH, is_test_run, + api_version, is_test_run, ) @@ -279,7 +279,6 @@ def sync_servers(instanceA_contents, instanceB_language_id, instanceB_contentIds def get_instance_contents(instance_url, instance_key, instance_session, instance_name=''): instance_contentIds = [] - instance_content_url = get_content_path(instance_url, instance_key) instance_contents = instance_session.get(instance_content_url) @@ -296,34 +295,25 @@ def get_instance_contents(instance_url, instance_key, instance_session, instance for content_to_sync in instance_contents: instance_contentIds.append(content_to_sync[content_id_key]) - logger.debug('{} contents in instance{}'.format(len(instance_contentIds), instance_name)) + logger.debug('{} contents in instance {}'.format(len(instance_contentIds), instance_name)) return instance_contents, instance_contentIds -def check_status(instance_session, instance_url, instance_key, instance_name='', changed_api_version=False): +def check_status(instance_session, instance_url, instance_key, instance_name=''): global api_version - instance_status_url = get_status_path( - instance_url, instance_key, changed_api_version) + instance_status_url = get_status_path(instance_url, instance_key) error_message = f'Could not connect to instance{instance_name}: {instance_status_url}' status_response = None try: status_response = instance_session.get(instance_status_url) - - # only test again if not lidarr and we haven't tested v3 already - if status_response.status_code != 200 and not changed_api_version and not is_lidarr: - logger.debug(f'check api_version again') - status_response = check_status(instance_session, instance_url, instance_key, instance_name, True) - elif status_response.status_code != 200: + if status_response.status_code != 200: logger.error(error_message) exit_system() - except: - if not changed_api_version and not is_lidarr: - logger.debug(f'check api_version again exception') - status_response = check_status( - instance_session, instance_url, instance_key, instance_name, True) + logger.error(error_message) + exit_system() if status_response is None: logger.error(error_message) @@ -355,12 +345,6 @@ def sync_content(): instanceB_session = requests.Session() instanceB_session.trust_env = False - # check if we tested if we are using v2 or v3 - if not tested_api_version: - check_status(instanceA_session, instanceA_url, instanceA_key, instance_name='A') - check_status(instanceB_session, instanceB_url, instanceB_key, instance_name='B') - tested_api_version = True - # if given a profile instead of a profile id then try to find the profile id if not instanceA_profile_id and instanceA_profile: instanceA_profile_id = get_profile_from_id(instanceA_session, instanceA_url, instanceA_key, instanceA_profile, 'A')