Fixes for JSON data and markdown (#95)

Co-authored-by: aljohn92 <16975578+aljohn92@users.noreply.github.com>
Co-authored-by: Junkbite <clobts@protonmail.com>
develop
Carl Jamilkowski 1 year ago committed by GitHub
parent 2c38787852
commit cfc3ff790a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -9,17 +9,18 @@ Syncs two Radarr/Sonarr/Lidarr servers through the web API. Useful for syncing a
* Can set interval for syncing * Can set interval for syncing
* Support two way sync (one way by default) * Support two way sync (one way by default)
* Skip content with missing files * Skip content with missing files
* Set language profiles (Sonarr) * Set language profiles
* Filter syncing by content file quality (Radarr only) * Filter syncing by content file quality (Radarr only)
* Filter syncing by tags (Sonarr/Radarr) * Filter syncing by tags (Sonarr/Radarr)
* Allow for a test run using `test_run` flag (does everything but actually sync) * Allow for a test run using `test_run` flag (does everything but actually sync)
## Configuration ## Configuration
1. Edit the config.conf file and enter your servers URLs and API keys for each server. 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: 2. Add the profile name (case insensitive) and movie path for the Radarr instance the movies will be synced to:
```ini ```ini
[radarrA] [radarrA]
url = https://4k.example.com:443 url = https://4k.example.com:443
key = XXXXX key = XXXXX
@ -29,11 +30,11 @@ Syncs two Radarr/Sonarr/Lidarr servers through the web API. Useful for syncing a
key = XXXXX key = XXXXX
profile = 1080p profile = 1080p
path = /data/Movies # if not given will use RadarrA path for each movie - may not be what you want! 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: 3. Or if you want to sync two Sonarr instances:
```ini ```ini
[sonarrA] [sonarrA]
url = https://4k.example.com:443 url = https://4k.example.com:443
key = XXXXX key = XXXXX
@ -43,10 +44,11 @@ Syncs two Radarr/Sonarr/Lidarr servers through the web API. Useful for syncing a
key = XXXXX key = XXXXX
profile = 1080p profile = 1080p
path = /data/Shows path = /data/Shows
```
4. Or if you want to sync two Lidarr instances: 4. Or if you want to sync two Lidarr instances:
5.
```ini ```ini
[lidarrA] [lidarrA]
url = https://lossless.example.com:443 url = https://lossless.example.com:443
key = XXXXX key = XXXXX
@ -56,13 +58,13 @@ Syncs two Radarr/Sonarr/Lidarr servers through the web API. Useful for syncing a
key = XXXXX key = XXXXX
profile = Standard profile = Standard
path = /data/Music path = /data/Music
``` ```
**Note** you cannot have a mix of Radarr, Lidarr, or Sonarr config setups at the same time. **Note** you cannot have a mix of Radarr, Lidarr, or Sonarr config setups at the same time.
6. Optional Configuration 5. Optional Configuration
```ini ```ini
[*arrA] [*arrA]
url = http://127.0.0.1:8080 url = http://127.0.0.1:8080
key = XXXXX key = XXXXX
@ -81,36 +83,43 @@ Syncs two Radarr/Sonarr/Lidarr servers through the web API. Useful for syncing a
path = /data/Movies path = /data/Movies
[general] [general]
sync_bidirectionally = 1 # sync from instance A to B **AND** instance B to A (default 0) bidirectional = 1 # sync from instance A to B **AND** instance B to A (default 0)
auto_search = 0 # search is automatically started on new content - disable by setting to 0 (default 1) 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) skip_missing = 1 # content with missing files are skipped on sync - disable by setting to 0 (default 1) (Radarr only)
monitor_new_content = 0 # set to 0 to never monitor new content synced or to 1 to always monitor new content synced (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 (default 0) test_run = 1 # enable test mode - will run through sync program but will not actually sync content (default 0)
sync_monitor = 1 # if set to 1 will sync if the content is monitored or not to instance B (default 0) sync_monitor = 1 # if set to 1 will sync if the content is monitored or not to instance B (default 0)
``` ```
**Note** If `sync_bidirectionally` is set to `1`, then instance A will require either `profile_id` or `profile` AND `path` as well **Note** If `bidirectional` is set to `1`, then instance A will require either `profile_id` or `profile` AND `path` as well
--- ---
## Requirements ## Requirements
* Python 3.6 or greater
* 2 Radarr, Sonarr, or Lidarr servers * Python 3.6 or greater
* 2 Radarr, Sonarr, or Lidarr servers
--- ---
## How to Run ## How to Run
1. install the needed python modules (you'll need pip or you can install the modules manually inside the `requirements.txt` file): 1. install the needed python modules (you'll need pip or you can install the modules manually inside the `requirements.txt` file):
```bash
```bash
pip install -r requirements.txt pip install -r requirements.txt
``` ```
2. run this script directly or through a Cron: 2. run this script directly or through a Cron:
```bash
```bash
python index.py python index.py
``` ```
--- ---
## Docker Compose ## Docker Compose
This script can run through a docker container with a set interval (default every 5 minutes) This script can run through a docker container with a set interval (default every 5 minutes)
```bash ```bash

@ -1,12 +1,21 @@
# [radarrA] # [radarrA]
# url = https://example.com:443 # url = https://example.com:443
# key = FCKGW-RHQQ2-YXRKT-8TG6W-2B7Q8 # key = FCKGW-RHQQ2-YXRKT-8TG6W-2B7Q8
# profile = HD-1080p
# profile_id = 4
# path = /data/Movies
# [radarrB] # [radarrB]
# url = http://127.0.0.1:8080 # url = http://127.0.0.1:8080
# key = FCKGW-RHQQ2-YXRKT-8TG6W-2B7Q8 # key = FCKGW-RHQQ2-YXRKT-8TG6W-2B7Q8
# profile_id = 1 # profile_id = 1
# profile = Ultra-HD
# path = /data/4k_Movies # path = /data/4k_Movies
# [general] # [general]
# sync_bidirectionally = 0 # bidirectional = 0
# log_level = 20
# skip_missing = 0
# auto_search = 1
# monitor_new_content = 1
# test_run = 0

@ -79,6 +79,8 @@ radarrA_profile = get_config_value('RADARR_A_PROFILE', 'profile', 'radarrA')
radarrA_profile_id = get_config_value('RADARR_A_PROFILE_ID', 'profile_id', 'radarrA') radarrA_profile_id = get_config_value('RADARR_A_PROFILE_ID', 'profile_id', 'radarrA')
radarrA_profile_filter = get_config_value('RADARR_A_PROFILE_FILTER', 'profile_filter', 'radarrA') radarrA_profile_filter = get_config_value('RADARR_A_PROFILE_FILTER', 'profile_filter', 'radarrA')
radarrA_profile_filter_id = get_config_value('RADARR_A_PROFILE_FILTER_ID', 'profile_filter_id', 'radarrA') radarrA_profile_filter_id = get_config_value('RADARR_A_PROFILE_FILTER_ID', 'profile_filter_id', 'radarrA')
radarrA_tag_filter = get_config_value('RADARR_A_TAG_FILTER', 'tag_filter', 'radarrA')
radarrA_tag_filter_id = get_config_value('RADARR_A_TAG_FILTER_ID', 'tag_filter_id', 'radarrA')
radarrA_language = get_config_value('RADARR_A_LANGUAGE', 'language', 'radarrA') radarrA_language = get_config_value('RADARR_A_LANGUAGE', 'language', 'radarrA')
radarrA_language_id = get_config_value('RADARR_A_LANGUAGE_ID', 'language_id', 'radarrA') radarrA_language_id = get_config_value('RADARR_A_LANGUAGE_ID', 'language_id', 'radarrA')
radarrA_quality_match = get_config_value('RADARR_A_QUALITY_MATCH', 'quality_match', 'radarrA') radarrA_quality_match = get_config_value('RADARR_A_QUALITY_MATCH', 'quality_match', 'radarrA')
@ -91,6 +93,9 @@ radarrB_profile = get_config_value('RADARR_B_PROFILE', 'profile', 'radarrB')
radarrB_profile_id = get_config_value('RADARR_B_PROFILE_ID', 'profile_id', 'radarrB') radarrB_profile_id = get_config_value('RADARR_B_PROFILE_ID', 'profile_id', 'radarrB')
radarrB_profile_filter = get_config_value('RADARR_B_PROFILE_FILTER', 'profile_filter', 'radarrB') radarrB_profile_filter = get_config_value('RADARR_B_PROFILE_FILTER', 'profile_filter', 'radarrB')
radarrB_profile_filter_id = get_config_value('RADARR_B_PROFILE_FILTER_ID', 'profile_filter_id', 'radarrB') radarrB_profile_filter_id = get_config_value('RADARR_B_PROFILE_FILTER_ID', 'profile_filter_id', 'radarrB')
radarrB_tag_filter = get_config_value('RADARR_B_TAG_FILTER', 'tag_filter', 'radarrB')
radarrB_tag_filter_id = get_config_value('RADARR_B_TAG_FILTER_ID', 'tag_filter_id', 'radarrB')
radarrB_language = get_config_value('RADARR_B_LANGUAGE', 'language', 'radarrB') radarrB_language = get_config_value('RADARR_B_LANGUAGE', 'language', 'radarrB')
radarrB_language_id = get_config_value('RADARR_B_LANGUAGE_ID', 'language_id', 'radarrB') radarrB_language_id = get_config_value('RADARR_B_LANGUAGE_ID', 'language_id', 'radarrB')
radarrB_quality_match = get_config_value('RADARR_B_QUALITY_MATCH', 'quality_match', 'radarrB') radarrB_quality_match = get_config_value('RADARR_B_QUALITY_MATCH', 'quality_match', 'radarrB')
@ -273,6 +278,8 @@ if radarrA_url and radarrB_url:
instanceA_profile_filter_id = radarrA_profile_filter_id instanceA_profile_filter_id = radarrA_profile_filter_id
instanceA_language = radarrA_language instanceA_language = radarrA_language
instanceA_language_id = radarrA_language_id instanceA_language_id = radarrA_language_id
instanceA_tag_filter = radarrA_tag_filter and radarrA_tag_filter.split(',')
instanceA_tag_filter_id = radarrA_tag_filter_id and radarrA_tag_filter_id.split(',')
instanceA_quality_match = radarrA_quality_match instanceA_quality_match = radarrA_quality_match
instanceA_blacklist = radarrA_blacklist instanceA_blacklist = radarrA_blacklist
@ -285,6 +292,8 @@ if radarrA_url and radarrB_url:
instanceB_profile_filter_id = radarrB_profile_filter_id instanceB_profile_filter_id = radarrB_profile_filter_id
instanceB_language = radarrB_language instanceB_language = radarrB_language
instanceB_language_id = radarrB_language_id instanceB_language_id = radarrB_language_id
instanceB_tag_filter = radarrB_tag_filter and radarrB_tag_filter.split(',')
instanceB_tag_filter_id = radarrB_tag_filter_id and radarrB_tag_filter_id.split(',')
instanceB_quality_match = radarrB_quality_match instanceB_quality_match = radarrB_quality_match
instanceB_blacklist = radarrB_blacklist instanceB_blacklist = radarrB_blacklist

@ -211,7 +211,7 @@ def sync_servers(instanceA_contents, instanceB_language_id, instanceB_contentIds
instance_path = instanceB_path or dirname(content.get('path')) instance_path = instanceB_path or dirname(content.get('path'))
# if skipping missing files, we want to skip any that don't have files # if skipping missing files, we want to skip any that don't have files
if skip_missing: if is_radarr and skip_missing:
content_has_file = content.get('hasFile') content_has_file = content.get('hasFile')
if not content_has_file: if not content_has_file:
logging.debug(f'Skipping content {title} - file missing') logging.debug(f'Skipping content {title} - file missing')
@ -253,7 +253,7 @@ def sync_servers(instanceA_contents, instanceB_language_id, instanceB_contentIds
# generate content from instance A to sync into instance B # generate content from instance A to sync into instance B
formatted_content = get_content_details( formatted_content = get_content_details(
content=dict(content), content,
instance_path=instance_path, instance_path=instance_path,
instance_profile_id=instanceB_profile_id, instance_profile_id=instanceB_profile_id,
instance_url=instanceB_url, instance_url=instanceB_url,
@ -266,7 +266,7 @@ def sync_servers(instanceA_contents, instanceB_language_id, instanceB_contentIds
elif content_not_synced: elif content_not_synced:
# sync content if not synced # sync content if not synced
logging.info(f'syncing content title "{title}"') logging.info(f'syncing content title "{title}"')
sync_response = instanceB_session.post(instanceB_content_url, data=json.dumps(formatted_content)) sync_response = instanceB_session.post(instanceB_content_url, json=formatted_content)
# check response and save content id for searching later on if success # check response and save content id for searching later on if success
if sync_response.status_code != 201 and sync_response.status_code != 200: if sync_response.status_code != 201 and sync_response.status_code != 200:
logger.error(f'server sync error for {title} - response: {sync_response.text}') logger.error(f'server sync error for {title} - response: {sync_response.text}')
@ -288,7 +288,7 @@ def sync_servers(instanceA_contents, instanceB_language_id, instanceB_contentIds
if matching_content_instanceB['monitored'] != content['monitored']: if matching_content_instanceB['monitored'] != content['monitored']:
matching_content_instanceB['monitored'] = content['monitored'] matching_content_instanceB['monitored'] = content['monitored']
instanceB_content_url = get_content_put_path(instanceB_url, instanceB_key, matching_content_instanceB.get('id')) instanceB_content_url = get_content_put_path(instanceB_url, instanceB_key, matching_content_instanceB.get('id'))
sync_response = instanceB_session.put(instanceB_content_url, data=json.dumps(matching_content_instanceB)) sync_response = instanceB_session.put(instanceB_content_url, json=matching_content_instanceB)
# check response and save content id for searching later on if success # check response and save content id for searching later on if success
if sync_response.status_code != 202: if sync_response.status_code != 202:
logger.error(f'server monitoring sync error for {title} - response: {sync_response.text}') logger.error(f'server monitoring sync error for {title} - response: {sync_response.text}')

Loading…
Cancel
Save