Upgraded calls to Sonarr API in order to use the new v3 API when available.

This commit is contained in:
morpheus65535 2021-06-16 13:45:54 -04:00
parent 26e978b14b
commit ee41b78f4e
7 changed files with 137 additions and 33 deletions

View File

@ -290,6 +290,7 @@ def get_settings():
return result
def save_settings(settings_items):
from database import database
@ -479,6 +480,7 @@ def url_sonarr():
return f"{protocol_sonarr}://{settings.sonarr.ip}{port}{settings.sonarr.base_url}"
def url_sonarr_short():
if settings.sonarr.getboolean('ssl'):
protocol_sonarr = "https"
@ -492,6 +494,7 @@ def url_sonarr_short():
return f"{protocol_sonarr}://{settings.sonarr.ip}{port}"
def url_radarr():
if settings.radarr.getboolean('ssl'):
protocol_radarr = "https"
@ -512,6 +515,7 @@ def url_radarr():
return f"{protocol_radarr}://{settings.radarr.ip}{port}{settings.radarr.base_url}"
def url_radarr_short():
if settings.radarr.getboolean('ssl'):
protocol_radarr = "https"
@ -525,6 +529,7 @@ def url_radarr_short():
return f"{protocol_radarr}://{settings.radarr.ip}{port}"
def get_array_from(property):
if property:
if '[' in property:
@ -536,6 +541,7 @@ def get_array_from(property):
else:
return []
def configure_captcha_func():
# set anti-captcha provider and key
if settings.general.anti_captcha_provider == 'anti-captcha' and settings.anticaptcha.anti_captcha_key != "":

View File

@ -6,6 +6,7 @@ import logging
import string
from config import settings, url_sonarr, url_radarr
from utils import get_sonarr_version, get_radarr_version
headers = {"User-Agent": os.environ["SZ_USER_AGENT"]}
@ -45,11 +46,17 @@ def browse_bazarr_filesystem(path='#'):
def browse_sonarr_filesystem(path='#'):
sonarr_version = get_sonarr_version()
if path == '#':
path = ''
url_sonarr_api_filesystem = url_sonarr() + "/api/filesystem?path=" + path + \
"&allowFoldersWithoutTrailingSlashes=true&includeFiles=false&apikey=" + \
settings.sonarr.apikey
if sonarr_version.startswith('2'):
url_sonarr_api_filesystem = url_sonarr() + "/api/filesystem?path=" + path + \
"&allowFoldersWithoutTrailingSlashes=true&includeFiles=false&apikey=" + \
settings.sonarr.apikey
else:
url_sonarr_api_filesystem = url_sonarr() + "/api/v3/filesystem?path=" + path + \
"&allowFoldersWithoutTrailingSlashes=true&includeFiles=false&apikey=" + \
settings.sonarr.apikey
try:
r = requests.get(url_sonarr_api_filesystem, timeout=60, verify=False, headers=headers)
r.raise_for_status()
@ -70,12 +77,18 @@ def browse_sonarr_filesystem(path='#'):
def browse_radarr_filesystem(path='#'):
radarr_version = get_radarr_version()
if path == '#':
path = ''
url_radarr_api_filesystem = url_radarr() + "/api/filesystem?path=" + path + \
"&allowFoldersWithoutTrailingSlashes=true&includeFiles=false&apikey=" + \
settings.radarr.apikey
if radarr_version.startswith('0'):
url_radarr_api_filesystem = url_radarr() + "/api/filesystem?path=" + path + \
"&allowFoldersWithoutTrailingSlashes=true&includeFiles=false&apikey=" + \
settings.radarr.apikey
else:
url_radarr_api_filesystem = url_radarr() + "/api/v3/filesystem?path=" + path + \
"&allowFoldersWithoutTrailingSlashes=true&includeFiles=false&apikey=" + \
settings.radarr.apikey
try:
r = requests.get(url_radarr_api_filesystem, timeout=60, verify=False, headers=headers)
r.raise_for_status()

View File

@ -12,6 +12,7 @@ from helper import path_mappings
from list_subtitles import store_subtitles, series_full_scan_subtitles
from get_subtitle import episode_download_subtitles
from event_handler import event_stream, show_progress, hide_progress
from utils import get_sonarr_version
headers = {"User-Agent": os.environ["SZ_USER_AGENT"]}
@ -24,6 +25,7 @@ def update_all_episodes():
def sync_episodes(series_id=None, send_event=True):
logging.debug('BAZARR Starting episodes sync from Sonarr.')
apikey_sonarr = settings.sonarr.apikey
sonarr_version = get_sonarr_version()
# Get current episodes id in DB
current_episodes_db = TableEpisodes.select(TableEpisodes.sonarrEpisodeId,
@ -40,7 +42,8 @@ def sync_episodes(series_id=None, send_event=True):
altered_episodes = []
# Get sonarrId for each series from database
seriesIdList = get_series_from_sonarr_api(series_id=series_id, url=url_sonarr(), apikey_sonarr=apikey_sonarr)
seriesIdList = get_series_from_sonarr_api(series_id=series_id, url=url_sonarr(), apikey_sonarr=apikey_sonarr,
sonarr_version=sonarr_version)
series_count = len(seriesIdList)
for i, seriesId in enumerate(seriesIdList, 1):
@ -54,10 +57,21 @@ def sync_episodes(series_id=None, send_event=True):
# Get episodes data for a series from Sonarr
episodes = get_episodes_from_sonarr_api(url=url_sonarr(), apikey_sonarr=apikey_sonarr,
series_id=seriesId['sonarrSeriesId'])
series_id=seriesId['sonarrSeriesId'],
sonarr_version=sonarr_version)
if not episodes:
continue
else:
# For Sonarr v3, we need to update episodes to integrate the episodeFile API endpoint results
if sonarr_version.startswith('3'):
episodeFiles = get_episodesFiles_from_sonarr_api(url=url_sonarr(), apikey_sonarr=apikey_sonarr,
series_id=seriesId['sonarrSeriesId'])
for episode in episodes:
if episode['hasFile']:
item = [x for x in episodeFiles if x['id'] == episode['episodeFileId']]
if item:
episode['episodeFile'] = item[0]
for episode in episodes:
sleep()
if 'hasFile' in episode:
@ -67,7 +81,7 @@ def sync_episodes(series_id=None, send_event=True):
# Add episodes in sonarr to current episode list
current_episodes_sonarr.append(episode['id'])
# Parse episdoe data
# Parse episode data
if episode['id'] in current_episodes_db_list:
episodes_to_update.append(episodeParser(episode))
else:
@ -150,10 +164,13 @@ def sync_episodes(series_id=None, send_event=True):
def sync_one_episode(episode_id):
logging.debug('BAZARR syncing this specific episode from Sonarr: {}'.format(episode_id))
url = url_sonarr()
apikey_sonarr = settings.sonarr.apikey
sonarr_version = get_sonarr_version()
# Check if there's a row in database for this episode ID
try:
existing_episode = TableEpisodes.select(TableEpisodes.path)\
existing_episode = TableEpisodes.select(TableEpisodes.path, TableEpisodes.episode_file_id)\
.where(TableEpisodes.sonarrEpisodeId == episode_id)\
.dicts()\
.get()
@ -163,11 +180,19 @@ def sync_one_episode(episode_id):
try:
# Get episode data from sonarr api
episode = None
episode_data = get_episodes_from_sonarr_api(url=url_sonarr(), apikey_sonarr=settings.sonarr.apikey,
episode_id=episode_id)
episode_data = get_episodes_from_sonarr_api(url=url, apikey_sonarr=apikey_sonarr,
episode_id=episode_id, sonarr_version=sonarr_version)
if not episode_data:
return
else:
# For Sonarr v3, we need to update episodes to integrate the episodeFile API endpoint results
if sonarr_version.startswith('3'):
episodeFile = get_episodesFiles_from_sonarr_api(url=url, apikey_sonarr=apikey_sonarr,
episode_file_id=existing_episode['episode_file_id'])
if episode_data['hasFile']:
episode_data['episodeFile'] = episodeFile
episode = episodeParser(episode_data)
except Exception:
logging.debug('BAZARR cannot get episode returned by SignalR feed from Sonarr API.')
@ -311,11 +336,13 @@ def episodeParser(episode):
'file_size': episode['episodeFile']['size']}
def get_series_from_sonarr_api(series_id, url, apikey_sonarr):
def get_series_from_sonarr_api(series_id, url, apikey_sonarr, sonarr_version):
if series_id:
url_sonarr_api_series = url + "/api/series/{0}?apikey={1}".format(series_id, apikey_sonarr)
url_sonarr_api_series = url + "/api/{0}series/{1}?apikey={2}".format(
'' if sonarr_version.startswith('2') else 'v3/', series_id, apikey_sonarr)
else:
url_sonarr_api_series = url + "/api/series?apikey={}".format(apikey_sonarr)
url_sonarr_api_series = url + "/api/{0}series?apikey={1}".format(
'' if sonarr_version.startswith('2') else 'v3/', apikey_sonarr)
try:
r = requests.get(url_sonarr_api_series, timeout=60, verify=False, headers=headers)
r.raise_for_status()
@ -345,11 +372,13 @@ def get_series_from_sonarr_api(series_id, url, apikey_sonarr):
return series_list
def get_episodes_from_sonarr_api(url, apikey_sonarr, series_id=None, episode_id=None):
def get_episodes_from_sonarr_api(url, apikey_sonarr, sonarr_version, series_id=None, episode_id=None):
if series_id:
url_sonarr_api_episode = url + "/api/episode?seriesId={}&apikey=".format(series_id) + apikey_sonarr
url_sonarr_api_episode = url + "/api/{0}episode?seriesId={1}&apikey={2}".format(
'' if sonarr_version.startswith('2') else 'v3/', series_id, apikey_sonarr)
elif episode_id:
url_sonarr_api_episode = url + "/api/episode/{}?apikey=".format(episode_id) + apikey_sonarr
url_sonarr_api_episode = url + "/api/{0}episode/{1}?apikey={2}".format(
'' if sonarr_version.startswith('2') else 'v3/', episode_id, apikey_sonarr)
else:
return
@ -370,3 +399,31 @@ def get_episodes_from_sonarr_api(url, apikey_sonarr, series_id=None, episode_id=
return
else:
return r.json()
def get_episodesFiles_from_sonarr_api(url, apikey_sonarr, series_id=None, episode_file_id=None):
if series_id:
url_sonarr_api_episodeFiles = url + "/api/v3/episodeFile?seriesId={0}&apikey={1}".format(series_id,
apikey_sonarr)
elif episode_file_id:
url_sonarr_api_episodeFiles = url + "/api/v3/episodeFile/{0}?apikey={1}".format(episode_file_id, apikey_sonarr)
else:
return
try:
r = requests.get(url_sonarr_api_episodeFiles, timeout=60, verify=False, headers=headers)
r.raise_for_status()
except requests.exceptions.HTTPError:
logging.exception("BAZARR Error trying to get episodeFiles from Sonarr. Http error.")
return
except requests.exceptions.ConnectionError:
logging.exception("BAZARR Error trying to get episodeFiles from Sonarr. Connection Error.")
return
except requests.exceptions.Timeout:
logging.exception("BAZARR Error trying to get episodeFiles from Sonarr. Timeout Error.")
return
except requests.exceptions.RequestException:
logging.exception("BAZARR Error trying to get episodeFiles from Sonarr.")
return
else:
return r.json()

View File

@ -7,7 +7,7 @@ import logging
from config import settings, url_sonarr, url_radarr
from helper import path_mappings
from database import TableShowsRootfolder, TableMoviesRootfolder, TableShows, TableMovies
from utils import get_radarr_version
from utils import get_sonarr_version, get_radarr_version
headers = {"User-Agent": os.environ["SZ_USER_AGENT"]}
@ -15,9 +15,13 @@ headers = {"User-Agent": os.environ["SZ_USER_AGENT"]}
def get_sonarr_rootfolder():
apikey_sonarr = settings.sonarr.apikey
sonarr_rootfolder = []
sonarr_version = get_sonarr_version()
# Get root folder data from Sonarr
url_sonarr_api_rootfolder = url_sonarr() + "/api/rootfolder?apikey=" + apikey_sonarr
if sonarr_version.startswith('2'):
url_sonarr_api_rootfolder = url_sonarr() + "/api/rootfolder?apikey=" + apikey_sonarr
else:
url_sonarr_api_rootfolder = url_sonarr() + "/api/v3/rootfolder?apikey=" + apikey_sonarr
try:
rootfolder = requests.get(url_sonarr_api_rootfolder, timeout=60, verify=False, headers=headers)
@ -58,14 +62,17 @@ def check_sonarr_rootfolder():
get_sonarr_rootfolder()
rootfolder = TableShowsRootfolder.select(TableShowsRootfolder.id, TableShowsRootfolder.path).dicts()
for item in rootfolder:
if not os.path.isdir(path_mappings.path_replace(item['path'])):
root_path = item['path']
if not root_path.endswith(os.path.sep):
root_path += os.path.sep
if not os.path.isdir(path_mappings.path_replace(root_path)):
TableShowsRootfolder.update({TableShowsRootfolder.accessible: 0,
TableShowsRootfolder.error: 'This Sonarr root directory does not seems to '
'be accessible by Bazarr. Please check path '
'mapping.'})\
.where(TableShowsRootfolder.id == item['id'])\
.execute()
elif not os.access(path_mappings.path_replace(item['path']), os.W_OK):
elif not os.access(path_mappings.path_replace(root_path), os.W_OK):
TableShowsRootfolder.update({TableShowsRootfolder.accessible: 0,
TableShowsRootfolder.error: 'Bazarr cannot write to this directory.'}) \
.where(TableShowsRootfolder.id == item['id']) \

View File

@ -38,7 +38,8 @@ def update_series(send_event=True):
tagsDict = get_tags()
# Get shows data from Sonarr
series = get_series_from_sonarr_api(url=url_sonarr(), apikey_sonarr=apikey_sonarr)
series = get_series_from_sonarr_api(url=url_sonarr(), apikey_sonarr=apikey_sonarr,
sonarr_version=sonarr_version)
if not series:
return
else:
@ -172,7 +173,7 @@ def update_one_series(series_id, action):
series = None
series_data = get_series_from_sonarr_api(url=url_sonarr(), apikey_sonarr=settings.sonarr.apikey,
sonarr_series_id=int(series_id))
sonarr_series_id=int(series_id), sonarr_version=get_sonarr_version())
if not series_data:
return
@ -252,7 +253,10 @@ def get_tags():
tagsDict = []
# Get tags data from Sonarr
url_sonarr_api_series = url_sonarr() + "/api/tag?apikey=" + apikey_sonarr
if get_sonarr_version().startswith('2'):
url_sonarr_api_series = url_sonarr() + "/api/tag?apikey=" + apikey_sonarr
else:
url_sonarr_api_series = url_sonarr() + "/api/v3/tag?apikey=" + apikey_sonarr
try:
tagsDict = requests.get(url_sonarr_api_series, timeout=60, verify=False, headers=headers)
@ -328,9 +332,9 @@ def seriesParser(show, action, sonarr_version, tags_dict, serie_default_profile,
'profileId': serie_default_profile}
def get_series_from_sonarr_api(url, apikey_sonarr, sonarr_series_id=None):
url_sonarr_api_series = url + "/api/series" + ("/{}".format(sonarr_series_id) if sonarr_series_id else "") + \
"?apikey=" + apikey_sonarr
def get_series_from_sonarr_api(url, apikey_sonarr, sonarr_version, sonarr_series_id=None):
url_sonarr_api_series = url + "/api/{0}series/{1}?apikey={2}".format(
'' if sonarr_version.startswith('2') else 'v3/', sonarr_series_id if sonarr_series_id else "", apikey_sonarr)
try:
r = requests.get(url_sonarr_api_series, timeout=60, verify=False, headers=headers)
r.raise_for_status()

View File

@ -43,7 +43,7 @@ from signalr_client import sonarr_signalr_client, radarr_signalr_client
from check_update import apply_update, check_if_new_update, check_releases
from server import app, webserver
from functools import wraps
from utils import check_credentials, get_radarr_version
from utils import check_credentials, get_sonarr_version, get_radarr_version
# Install downloaded update
if bazarr_version != '':
@ -131,7 +131,13 @@ def series_images(url):
url = url.strip("/")
apikey = settings.sonarr.apikey
baseUrl = settings.sonarr.base_url
url_image = (url_sonarr() + '/api/' + url.lstrip(baseUrl) + '?apikey=' + apikey).replace('poster-250', 'poster-500')
sonarr_version = get_sonarr_version()
if sonarr_version.startswith('2'):
url_image = (url_sonarr() + '/api/' + url.lstrip(baseUrl) + '?apikey=' +
apikey).replace('poster-250', 'poster-500')
else:
url_image = (url_sonarr() + '/api/v3/' + url.lstrip(baseUrl) + '?apikey=' +
apikey).replace('poster-250', 'poster-500')
try:
req = requests.get(url_image, stream=True, timeout=15, verify=False, headers=headers)
except:

View File

@ -241,7 +241,12 @@ def get_sonarr_version():
if settings.general.getboolean('use_sonarr'):
try:
sv = url_sonarr() + "/api/system/status?apikey=" + settings.sonarr.apikey
sonarr_version = requests.get(sv, timeout=60, verify=False, headers=headers).json()['version']
sonarr_json = requests.get(sv, timeout=60, verify=False, headers=headers).json()
if 'version' in sonarr_json:
sonarr_version = sonarr_json['version']
else:
sv = url_sonarr() + "/api/v3/system/status?apikey=" + settings.sonarr.apikey
sonarr_version = requests.get(sv, timeout=60, verify=False, headers=headers).json()['version']
except Exception:
logging.debug('BAZARR cannot get Sonarr version')
sonarr_version = 'unknown'
@ -252,7 +257,10 @@ def get_sonarr_platform():
sonarr_platform = ''
if settings.general.getboolean('use_sonarr'):
try:
sv = url_sonarr() + "/api/system/status?apikey=" + settings.sonarr.apikey
if get_sonarr_version().startswith('2'):
sv = url_sonarr() + "/api/system/status?apikey=" + settings.sonarr.apikey
else:
sv = url_sonarr() + "/api/v3/system/status?apikey=" + settings.sonarr.apikey
response = requests.get(sv, timeout=60, verify=False, headers=headers).json()
if response['isLinux'] or response['isOsx']:
sonarr_platform = 'posix'
@ -265,7 +273,10 @@ def get_sonarr_platform():
def notify_sonarr(sonarr_series_id):
try:
url = url_sonarr() + "/api/command?apikey=" + settings.sonarr.apikey
if get_sonarr_version().startswith('2'):
url = url_sonarr() + "/api/command?apikey=" + settings.sonarr.apikey
else:
url = url_sonarr() + "/api/v3/command?apikey=" + settings.sonarr.apikey
data = {
'name': 'RescanSeries',
'seriesId': int(sonarr_series_id)