Plex-Meta-Manager/modules/sonarr.py

165 lines
7 KiB
Python
Raw Normal View History

2021-04-05 02:29:11 +00:00
import logging, requests
2021-04-05 04:09:26 +00:00
from json.decoder import JSONDecodeError
2021-01-20 21:37:59 +00:00
from modules import util
from modules.util import Failed
from retrying import retry
logger = logging.getLogger("Plex Meta Manager")
series_type = ["standard", "daily", "anime"]
monitor_translation = {
"all": "all",
"future": "future",
"missing": "missing",
"existing": "existing",
"pilot": "pilot",
"first": "firstSeason",
"latest": "latestSeason",
"none": "none"
}
2021-01-20 21:37:59 +00:00
class SonarrAPI:
2021-04-02 20:15:59 +00:00
def __init__(self, params, language):
self.url = params["url"]
2021-04-02 20:15:59 +00:00
self.token = params["token"]
self.version = params["version"]
self.base_url = f"{self.url}/api{'/v3/' if self.version == 'v3' else '/'}"
2021-01-20 21:37:59 +00:00
try:
2021-04-02 20:15:59 +00:00
result = requests.get(f"{self.base_url}system/status", params={"apikey": f"{self.token}"}).json()
2021-02-24 06:42:58 +00:00
except Exception:
2021-01-20 21:37:59 +00:00
util.print_stacktrace()
raise Failed(f"Sonarr Error: Could not connect to Sonarr at {self.url}")
2021-01-20 21:37:59 +00:00
if "error" in result and result["error"] == "Unauthorized":
raise Failed("Sonarr Error: Invalid API Key")
if "version" not in result:
raise Failed("Sonarr Error: Unexpected Response Check URL")
self.add = params["add"]
self.root_folder_path = params["root_folder_path"]
self.monitor = params["monitor"]
self.quality_profile_id = self.get_profile_id(params["quality_profile"], "quality_profile")
2021-04-02 15:45:29 +00:00
self.language_profile_id = None
if self.version == "v3" and params["language_profile"] is not None:
self.language_profile_id = self.get_profile_id(params["language_profile"], "language_profile")
2021-04-02 15:45:29 +00:00
if self.language_profile_id is None:
self.language_profile_id = 1
self.series_type = params["series_type"]
2021-03-01 22:25:38 +00:00
self.season_folder = params["season_folder"]
2021-02-16 14:31:15 +00:00
self.tag = params["tag"]
self.tags = self.get_tags()
self.search = params["search"]
self.cutoff_search = params["cutoff_search"]
self.language = language
def get_profile_id(self, profile_name, profile_type):
profiles = ""
if profile_type == "quality_profile" and self.version == "v3":
endpoint = "qualityProfile"
elif profile_type == "language_profile":
endpoint = "languageProfile"
else:
endpoint = "profile"
2021-05-07 19:53:54 +00:00
for profile in self._get(endpoint):
if len(profiles) > 0:
profiles += ", "
profiles += profile["name"]
if profile["name"] == profile_name:
return profile["id"]
raise Failed(f"Sonarr Error: {profile_type}: {profile_name} does not exist in sonarr. Profiles available: {profiles}")
2021-01-20 21:37:59 +00:00
2021-04-02 18:15:43 +00:00
def get_tags(self):
2021-05-07 19:53:54 +00:00
return {tag["label"]: tag["id"] for tag in self._get("tag")}
2021-04-02 18:15:43 +00:00
def add_tags(self, tags):
added = False
for label in tags:
if str(label).lower() not in self.tags:
2021-04-02 18:15:43 +00:00
added = True
2021-05-07 19:53:54 +00:00
self._post("tag", {"label": str(label).lower()})
2021-04-02 18:15:43 +00:00
if added:
self.tags = self.get_tags()
2021-04-02 20:15:59 +00:00
def lookup(self, tvdb_id):
2021-05-07 19:53:54 +00:00
results = self._get("series/lookup", params={"term": f"tvdb:{tvdb_id}"})
2021-04-02 20:15:59 +00:00
if results:
return results[0]
else:
raise Failed(f"Sonarr Error: TVDb ID: {tvdb_id} not found")
def add_tvdb(self, tvdb_ids, **options):
2021-01-20 21:37:59 +00:00
logger.info("")
2021-02-24 06:44:06 +00:00
logger.debug(f"TVDb IDs: {tvdb_ids}")
2021-02-16 14:31:15 +00:00
tag_nums = []
2021-01-20 21:37:59 +00:00
add_count = 0
folder = options["folder"] if "folder" in options else self.root_folder_path
monitor = options["monitor"] if "monitor" in options else self.monitor
quality_profile_id = self.get_profile_id(options["quality"], "quality_profile") if "quality" in options else self.quality_profile_id
2021-04-06 17:55:04 +00:00
language_profile_id = self.get_profile_id(options["language"], "language_profile") if "quality" in options else self.language_profile_id
series = options["series"] if "series" in options else self.series_type
season = options["season"] if "season" in options else self.season_folder
tags = options["tag"] if "tag" in options else self.tag
search = options["search"] if "search" in options else self.search
cutoff_search = options["cutoff_search"] if "cutoff_search" in options else self.cutoff_search
2021-04-02 18:15:43 +00:00
if tags:
self.add_tags(tags)
tag_nums = [self.tags[label.lower()] for label in tags if label.lower() in self.tags]
2021-01-20 21:37:59 +00:00
for tvdb_id in tvdb_ids:
try:
2021-04-02 20:15:59 +00:00
show_info = self.lookup(tvdb_id)
2021-01-20 21:37:59 +00:00
except Failed as e:
logger.error(e)
continue
2021-04-02 20:15:59 +00:00
poster_url = None
for image in show_info["images"]:
if "coverType" in image and image["coverType"] == "poster" and "remoteUrl" in image:
poster_url = image["remoteUrl"]
2021-01-20 21:37:59 +00:00
url_json = {
2021-04-02 20:15:59 +00:00
"title": show_info["title"],
f"{'qualityProfileId' if self.version == 'v3' else 'profileId'}": quality_profile_id,
"languageProfileId": language_profile_id,
2021-01-20 21:37:59 +00:00
"tvdbId": int(tvdb_id),
2021-04-02 20:15:59 +00:00
"titleslug": show_info["titleSlug"],
2021-01-20 21:37:59 +00:00
"language": self.language,
"monitored": monitor != "none",
"seasonFolder": season,
"seriesType": series,
"rootFolderPath": folder,
2021-02-24 06:42:58 +00:00
"seasons": [],
2021-04-02 20:15:59 +00:00
"images": [{"covertype": "poster", "url": poster_url}],
"addOptions": {
"searchForMissingEpisodes": search,
"searchForCutoffUnmetEpisodes": cutoff_search,
"monitor": monitor_translation[monitor]
}
2021-01-20 21:37:59 +00:00
}
2021-02-16 14:31:15 +00:00
if tag_nums:
url_json["tags"] = tag_nums
2021-05-07 19:53:54 +00:00
response = self._post("series", url_json)
2021-01-20 21:37:59 +00:00
if response.status_code < 400:
2021-04-02 20:15:59 +00:00
logger.info(f"Added to Sonarr | {tvdb_id:<6} | {show_info['title']}")
2021-01-20 21:37:59 +00:00
add_count += 1
else:
2021-02-11 06:11:48 +00:00
try:
2021-04-02 20:15:59 +00:00
logger.error(f"Sonarr Error: ({tvdb_id}) {show_info['title']}: ({response.status_code}) {response.json()[0]['errorMessage']}")
2021-02-24 06:42:58 +00:00
except KeyError:
2021-02-11 06:11:48 +00:00
logger.debug(url_json)
2021-02-24 06:44:06 +00:00
logger.error(f"Sonarr Error: {response.json()}")
2021-04-05 04:09:26 +00:00
except JSONDecodeError:
logger.debug(url_json)
logger.error(f"Sonarr Error: {response}")
2021-02-24 06:44:06 +00:00
logger.info(f"{add_count} Show{'s' if add_count > 1 else ''} added to Sonarr")
2021-01-20 21:37:59 +00:00
2021-02-16 14:31:15 +00:00
@retry(stop_max_attempt_number=6, wait_fixed=10000)
2021-05-07 19:53:54 +00:00
def _get(self, url, params=None):
2021-04-02 20:15:59 +00:00
url_params = {"apikey": f"{self.token}"}
if params:
for param in params:
url_params[param] = params[param]
return requests.get(f"{self.base_url}{url}", params=url_params).json()
2021-02-16 14:31:15 +00:00
2021-01-20 21:37:59 +00:00
@retry(stop_max_attempt_number=6, wait_fixed=10000)
2021-05-07 19:53:54 +00:00
def _post(self, url, url_json):
2021-04-02 20:15:59 +00:00
return requests.post(f"{self.base_url}{url}", json=url_json, params={"apikey": f"{self.token}"})